πŸŽ‰ Celebrating 25 Years of GameDev.net! πŸŽ‰

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

New To D3D12: Unable to render in D3D12

Started by
3 comments, last by JoeJ 7Β months, 3Β weeks 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