New To D3D12: Unable to render in D3D12

Started by
3 comments, last by JoeJ 6 months, 1 week ago

Hi All,

Good day! I know D3D11 pretty much. But I'm a beginner (I know raytracing 🙂) in D3D12. First, I'm trying to render a 3d object, no error even ops up in debug mode yet it only renders the color of I chose. To my knowledge, everything checks out. This is part of my research. I can send the code. I'm at a dead end here.

Advertisement
#include "RESrcLoader.h"

RESrcLoader::RESrcLoader(HWND hWnd, ComPtr<ID3D12Device> inDevice, ComPtr<ID3D12GraphicsCommandList> inCommandList, ComPtr<ID3D12CommandQueue> inCommandQueue, DXGI_FORMAT inBackBufferFormat, DXGI_FORMAT inDepthStencilFormat, int inMSAAQuality, bool inMSAA4X)
{
	mHasAnimation = false;
	mMeshCount = 0;
	RE_hWnd = hWnd;
	md3dDevice = inDevice;
	mCommandList = inCommandList;
	mCommandQueue = inCommandQueue;
	m4xMsaaState = inMSAA4X;    // 4X MSAA enabled
	m4xMsaaQuality = inMSAAQuality;      // quality level of 4X MSAA

	mBackBufferFormat = inBackBufferFormat;
	mDepthStencilFormat = inDepthStencilFormat;
}


void RESrcLoader::BuildDescriptorHeaps()
{
	D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc;
	cbvHeapDesc.NumDescriptors = 1;
	cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	cbvHeapDesc.NodeMask = 0;
	ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap)));

	D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
	srvHeapDesc.NumDescriptors = 1;
	srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvHeap)));
}

void RESrcLoader::BuildConstantBuffers()
{
	mCB = make_unique<UploadBuffer<RE_CB>>(md3dDevice.Get(), 1, true);

	UINT objCBByteSize = Common::CalcConstantBufferByteSize(sizeof(RE_CB));

	D3D12_GPU_VIRTUAL_ADDRESS cbAddress = mCB->Resource()->GetGPUVirtualAddress();

	D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
	cbvDesc.BufferLocation = 0;
	cbvDesc.SizeInBytes = Common::CalcConstantBufferByteSize(sizeof(RE_CB));

	md3dDevice->CreateConstantBufferView(
		&cbvDesc,
		mCbvHeap->GetCPUDescriptorHandleForHeapStart());
}

void RESrcLoader::BuildRootSignature()
{
	// Shader programs typically require resources as input (constant buffers,
	// textures, samplers).  The root signature defines the resources the shader
	// programs expect.  If we think of the shader programs as a function, and
	// the input resources as function parameters, then the root signature can be
	// thought of as defining the function signature.  

	// Root parameter can be a table, root descriptor or root constants.
	CD3DX12_ROOT_PARAMETER slotRootParameter[2];

	// Create a single descriptor table of CBVs.
	CD3DX12_DESCRIPTOR_RANGE cbvTable;
	cbvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
	CD3DX12_DESCRIPTOR_RANGE srvTable;
	srvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

	slotRootParameter[0].InitAsDescriptorTable(1, &cbvTable);
	slotRootParameter[1].InitAsDescriptorTable(1, &srvTable, D3D12_SHADER_VISIBILITY_PIXEL);

	D3D12_STATIC_SAMPLER_DESC sampler = {};
	sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
	sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
	sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
	sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
	sampler.MipLODBias = 0;
	sampler.MaxAnisotropy = 0;
	sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
	sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
	sampler.MinLOD = 0.0f;
	sampler.MaxLOD = D3D12_FLOAT32_MAX;
	sampler.ShaderRegister = 0;
	sampler.RegisterSpace = 0;
	sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;

	// A root signature is an array of root parameters.
	CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(2, slotRootParameter, 1, &sampler,
		D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

	// create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
	ComPtr<ID3DBlob> serializedRootSig = nullptr;
	ComPtr<ID3DBlob> errorBlob = nullptr;
	HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
		serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());

	if (errorBlob != nullptr)
	{
		::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
	}
	ThrowIfFailed(hr);

	ThrowIfFailed(md3dDevice->CreateRootSignature(
		0,
		serializedRootSig->GetBufferPointer(),
		serializedRootSig->GetBufferSize(),
		IID_PPV_ARGS(&mRootSignature)));
}

void RESrcLoader::BuildShadersAndInputLayout()
{
	mvsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "VSMAIN", "vs_5_0");
	mpsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "PSMAIN", "ps_5_0");
	mhsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "HSMAIN", "hs_5_0");
	mdsByteCode = Common::CompileShader(L"Shaders\\REMain.hlsl", nullptr, "DSMAIN", "ds_5_0");

	mInputLayout = { {"POSITION",	0, DXGI_FORMAT_R32G32B32_FLOAT,		0, 0,  D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
					 {"TEXCOORD",	0, DXGI_FORMAT_R32G32_FLOAT,		0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
					 {"NORMAL",		0, DXGI_FORMAT_R32G32B32_FLOAT,		0, 20, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}/*,
					 {"BONEINDICES", 0, DXGI_FORMAT_R32G32B32A32_UINT,   0, 32, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
					 {"WEIGHTS",		0, DXGI_FORMAT_R32G32B32A32_FLOAT,	0, 48, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}*/ };
}

void RESrcLoader::BuildPSO()
{
	D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
	ZeroMemory(&psoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
	psoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
	psoDesc.pRootSignature = mRootSignature.Get();
	psoDesc.VS =
	{
		reinterpret_cast<BYTE*>(mvsByteCode->GetBufferPointer()),
		mvsByteCode->GetBufferSize()
	};
	psoDesc.HS =
	{
		reinterpret_cast<BYTE*>(mhsByteCode->GetBufferPointer()),
		mhsByteCode->GetBufferSize()
	};
	psoDesc.DS =
	{
		reinterpret_cast<BYTE*>(mdsByteCode->GetBufferPointer()),
		mdsByteCode->GetBufferSize()
	};
	psoDesc.PS =
	{
		reinterpret_cast<BYTE*>(mpsByteCode->GetBufferPointer()),
		mpsByteCode->GetBufferSize()
	};
	D3D12_RASTERIZER_DESC rastdesc = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
	rastdesc.CullMode = D3D12_CULL_MODE_NONE;
	psoDesc.RasterizerState = rastdesc;
	psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
	psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
	psoDesc.SampleMask = UINT_MAX;
	psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
	psoDesc.NumRenderTargets = 1;
	psoDesc.RTVFormats[0] = mBackBufferFormat;
	psoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
	psoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
	psoDesc.DSVFormat = mDepthStencilFormat;
	ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO)));
}



void RESrcLoader::Draw(Camera *ActiveCamera)
{
	RE_CB cb;
	for (UINT i = 0; i < 96; ++i)
		XMStoreFloat4x4(&cb.Bones[i], XMMatrixIdentity());

	cb.LightDirection = XMFLOAT3(0, 1, 0);
	cb.TessellationFactor = 1.0f;
	XMStoreFloat4x4(&cb.mView, XMMatrixTranspose(ActiveCamera->mView));
	XMStoreFloat4x4(&cb.mProjection, XMMatrixTranspose(ActiveCamera->mProjection));
	XMStoreFloat4x4(&cb.mWorld, XMMatrixTranspose(XMMatrixTranslation(0,0,-10)));
	cb.mHasAnimation = 0;
	mCB->CopyData(0, cb);

	// Set necessary state.
	mCommandList->SetGraphicsRootSignature(mRootSignature.Get());

	{
		ID3D12DescriptorHeap* ppHeaps[] = { mCbvHeap.Get() };
		mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
		mCommandList->SetGraphicsRootDescriptorTable(0, mCbvHeap->GetGPUDescriptorHandleForHeapStart());
	}
	{
		ID3D12DescriptorHeap* ppHeaps[] = { mSrvHeap.Get() };
		mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
		mCommandList->SetGraphicsRootDescriptorTable(1, mSrvHeap->GetGPUDescriptorHandleForHeapStart());
	}

	for (auto md : Model)
	{
		md.DrawMesh(mCommandList);
	}
}

struct Mesh_Data
{
	string mMeshName;
	string mMeshTextureName;
	int mVertexCount;
	vector<RE_VERTEX> mMeshGeometry;
	ComPtr<ID3D12Resource> Mesh_Vertex_Buffer_GPU;
	ComPtr<ID3D12Resource> Mesh_Vertex_Buffer_Uploader;
	UINT VertexByteStride;
	UINT VertexBufferByteSize;

	Mesh_Data()
	{
		Mesh_Vertex_Buffer_GPU = nullptr;
		VertexByteStride = 0;
		VertexBufferByteSize = 0;
	}

	void CreateMeshVertexBuffer(ComPtr<ID3D12Device> inDevice, ComPtr<ID3D12GraphicsCommandList> inCommandList)
	{
		const UINT vbByteSize = (UINT)mMeshGeometry.size() * sizeof(RE_VERTEX);

		Mesh_Vertex_Buffer_GPU = Common::CreateDefaultBuffer(inDevice.Get(),
			inCommandList.Get(), mMeshGeometry.data(), vbByteSize, Mesh_Vertex_Buffer_Uploader);

		VertexByteStride = sizeof(RE_VERTEX);
		VertexBufferByteSize = vbByteSize;
	}

	D3D12_VERTEX_BUFFER_VIEW VertexBufferView()const
	{
		D3D12_VERTEX_BUFFER_VIEW vbv;
		vbv.BufferLocation = Mesh_Vertex_Buffer_GPU->GetGPUVirtualAddress();
		vbv.StrideInBytes = VertexByteStride;
		vbv.SizeInBytes = VertexBufferByteSize;
		return vbv;
	}

	void DrawMesh(ComPtr<ID3D12GraphicsCommandList> inCommandList)
	{
		inCommandList->IASetVertexBuffers(0, 1, &VertexBufferView());
		inCommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST);
		inCommandList->DrawInstanced((UINT)mMeshGeometry.size(), 1, 0, 0);
	}
};

void Core::Render()
{
	if (mREnder)
	{
		__int64 PrevCount, CurrCount;
		QueryPerformanceCounter((LARGE_INTEGER*)&PrevCount);

		cam->Update(XM_PI / 3, (float)1024 / (float)768, 0.1f, 100.0f);

		// Reuse the memory associated with command recording.
		// We can only reset when the associated command lists have finished execution on the GPU.
		ThrowIfFailed(mDirectCmdListAlloc->Reset());

		// A command list can be reset after it has been added to the command queue via ExecuteCommandList.
		// Reusing the command list reuses memory.
		ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), m3DObj->mPSO.Get()));

		// Indicate a state transition on the resource usage.
		mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
			D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

		// Set necessary state.
		//mCommandList->SetGraphicsRootSignature(m3DObj->mRootSignature.Get());
	/*
		{
			ID3D12DescriptorHeap* ppHeaps[] = { m3DObj->mCbvHeap.Get() };
			mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
			mCommandList->SetGraphicsRootDescriptorTable(0, m3DObj->mCbvHeap->GetGPUDescriptorHandleForHeapStart());
		}
		{
			ID3D12DescriptorHeap* ppHeaps[] = { m3DObj->mSrvHeap.Get() };
			mCommandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);
			mCommandList->SetGraphicsRootDescriptorTable(1, m3DObj->mSrvHeap->GetGPUDescriptorHandleForHeapStart());
		}
	*/
	// Set the viewport and scissor rect.  This needs to be reset whenever the command list is reset.
		mCommandList->RSSetViewports(1, &mScreenViewport);
		mCommandList->RSSetScissorRects(1, &mScissorRect);

		// Clear the back buffer and depth buffer.
		mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
		mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);

		// Specify the buffers we are going to render to.
		mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());

		m3DObj->Draw(cam);

		// Indicate a state transition on the resource usage.
		mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
			D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));

		// Done recording commands.
		ThrowIfFailed(mCommandList->Close());

		// Add the command list to the queue for execution.
		ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
		mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

		// swap the back and front buffers
		ThrowIfFailed(mSwapChain->Present(0, 0));
		mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;

		// Wait until frame commands are complete.  This waiting is inefficient and is
		// done for simplicity.  Later we will show how to organize our rendering code
		// so we do not have to wait per frame.
		FlushCommandQueue();

		FrameCount++;

		if (ttmp >= 1.0)
		{
			FPS = (FrameCount / ttmp);
			ttmp = 0;
			FrameCount = 0;
		}

		QueryPerformanceCounter((LARGE_INTEGER*)&CurrCount);
		tDelta = (double)(CurrCount - PrevCount) * SecondsPerCount;
		if (tDelta < 0)
			tDelta = 0;
		tElapsed += tDelta;
		ttmp += tDelta;

		char str[256];
		sprintf_s(str, "FPS %.2f (Frame Time %.3f)", FPS, tDelta);
		SetWindowTextA(tmphWnd, str);
	}
}

void Core::InitDirect3D(HWND hWnd, int Width, int Height)
{
	tmphWnd = hWnd;

	#if defined(DEBUG) || defined(_DEBUG) 
		// Enable the D3D12 debug layer.
		{
			ComPtr<ID3D12Debug> debugController;
			ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)));
			debugController->EnableDebugLayer();
		}
	#endif

	ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&mdxgiFactory)));

	// Try to create hardware device.
	ThrowIfFailed(D3D12CreateDevice(
		nullptr,             // default adapter
		D3D_FEATURE_LEVEL_12_0,
		IID_PPV_ARGS(&md3dDevice)));


	ThrowIfFailed(md3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE,
		IID_PPV_ARGS(&mFence)));

	mRtvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
	mDsvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
	mCbvSrvUavDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

	// Check 4X MSAA quality support for our back buffer format.
	// All Direct3D 11 capable devices support 4X MSAA for all render 
	// target formats, so we only need to check quality support.

	D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
	msQualityLevels.Format = mBackBufferFormat;
	msQualityLevels.SampleCount = 4;
	msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
	msQualityLevels.NumQualityLevels = 0;
	ThrowIfFailed(md3dDevice->CheckFeatureSupport(
		D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
		&msQualityLevels,
		sizeof(msQualityLevels)));

	m4xMsaaQuality = msQualityLevels.NumQualityLevels;
	assert(m4xMsaaQuality > 0 && "Unexpected MSAA quality level.");

	#ifdef _DEBUG
	LogAdapters();
	#endif

	CreateCommandObjects();
	CreateSwapChain(hWnd, Width, Height);
	CreateRtvAndDsvDescriptorHeaps();

	cam = new Camera(XMVectorSet(0, 0, -20, 0.0f), XMVectorSet(0, 0, -10, 0.0f));

	ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));

	m3DObj = new RESrcLoader(hWnd, md3dDevice, mCommandList, mCommandQueue, mBackBufferFormat, mDepthStencilFormat, m4xMsaaQuality, m4xMsaaState);
	m3DObj->LoadFromRE3DM("ball.RE3DM");
	m3DObj->InitializeResource();

	// Execute the initialization commands.
	ThrowIfFailed(mCommandList->Close());
	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

	// Wait until initialization is complete.
	FlushCommandQueue();

	mREnder = true;
}

I figured it out by myself. Thanks for the big help.

cbvDesc.BufferLocation = cbAddress; <- for this case. u need to handle differently for several 3d objects

Texture didn't work too.

srvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); fixed it

isu diss said:
I figured it out by myself. Thanks for the big help.

Haha, if i would not know you, this quote might sound rather sarcastic. :D

This topic is closed to new replies.

Advertisement