天天看點

在DirectX12中使用Dynamic Indexing

dynamic indexing是shader model 5.1才支援的功能,目的是在CPU層減少有關material const buffer和texture descriptor的切換,提高繪制效率。要使用dynamic indexing,首先要對shader代碼進行調整:

struct MaterialData
{
	float4   diffuseAlbedo;
	float3   fresnelR0;
	float    shininess;
	uint     diffuseMapIndex;
	uint     matPad0;
	uint     matPad1;
	uint     matPad2;
};

Texture2D gDiffuseMap[4] : register(t0);
StructuredBuffer<MaterialData> gMaterialData : register(t0, space1);

cbuffer cbPerObject : register(b0)
{
	float4x4 gWorld;
	float4x4 gInvWorld;
	float4x4 gWorldViewProj; 
	uint gMaterialIndex;
	uint gObjPad0;
	uint gObjPad1;
	uint gObjPad2;
};
           

這裡我們直接使用了Texture2D的數組,意味着我們把用到的texture組合在了一起,可以通過MaterialData中的diffuseMapIndex動态索引。類似地,gMaterialData是一個StructuredBuffer,相當于我們把用到的material const buffer組合在一起,通過object const buffer中的gMaterialIndex動态索引。有了這兩個index,我們就不必在繪制每個物體是去設定它的texture和material,隻需要調整object const buffer的index即可。

另外,注意到shader的gDiffuseMap和gMaterialData都使用的register t0,但位于不同的space,是以我們需要調整一下根簽名的建立:

CD3DX12_DESCRIPTOR_RANGE cbvSrvTable[4];
	cbvSrvTable[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0);
	cbvSrvTable[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 1);
	cbvSrvTable[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 2);
	cbvSrvTable[3].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);

	CD3DX12_ROOT_PARAMETER rootParams[4];
	rootParams[0].InitAsDescriptorTable(1, &cbvSrvTable[0]);
	rootParams[1].InitAsDescriptorTable(1, &cbvSrvTable[1]);
	// rootParams[2].InitAsDescriptorTable(1, &cbvSrvTable[2]);
	rootParams[2].InitAsShaderResourceView(0, 1);
	rootParams[3].InitAsDescriptorTable(1, &cbvSrvTable[3]);
           

然後,就是将原先繪制每個物體的過程中切換的代碼提前到繪制之前:

mCommandList->SetGraphicsRootShaderResourceView(2, res.mMaterialConstBuffer->GetGPUVirtualAddress());

	CD3DX12_GPU_DESCRIPTOR_HANDLE cpuSrvHandle = CD3DX12_GPU_DESCRIPTOR_HANDLE(
		mCbvSrvHeap->GetGPUDescriptorHandleForHeapStart());
	cpuSrvHandle.Offset(srvHeapIndex, mCbvSrvHeapIncSize);
	mCommandList->SetGraphicsRootDescriptorTable(3, cpuSrvHandle);
           
objConstants.MaterialIndex = object->mMaterial->mID;
matConstants.diffuseMapIndex = object->mTexture->mID;