Direct3D 12——计算着色器——纹理输出与无序访问视图

能与计算着色器绑定的资源类型有缓冲区与纹理两种。

纹理输出与无序访问视图

在计算着色器代码中,我们定义了一个输出资源:

RWTexture2D<float4> gOutput;

计算着色器处理输出资源的方式比较特殊,它们的类型还有一个特别的前缀“RW”,意为读与写。 顾名思义,我们可以对计算着色器中的这类资源元素进行读写操作。

输出资源与输入资源的绑定方法是全然不同的。为了绑定在计算着色器中要执行写操作的资源,我们 需要将其与称为无序访问视图(Unordered Access View, UAV )的新型视图关联在一起。在代码中,我们用 描述符句柄来表示无序访问视图,且通过结构体D3D12_UNORDERED_ACCESS_VIEW_DESC来对它进行 描述。创建这种视图的整个过程与着色器资源视图很相似。这里给出一个为纹理资源创建UAV的示例:

D3D12_RESOURCE_DESC texDesc;
ZeroMemory(&texDesc, sizeof(D3D12_RESOURCE_DESC));
texDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
texDesc.Alignment = 0;
texDesc.Width = mWidth;
texDesc.Height = mHeight;
texDesc.DepthOrArraySize = 1;
texDesc.MipLevels = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Layout = D3 DI2_TEXTURE_LAYOUT_UNKNOWN;
texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;

ThrowlfFailed(md3dDevice->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&texDesc,
D3D12_RESOURCE_STATE_COMMON, 
nullptr,
IID_PPV_ARGS(&mBlurMap0)));

D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};

srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = mFormat;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = 1;

D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};

uavDesc.Format = mFormat;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
uavDesc.Texture2D.MipSlice = 0;

md3dDevice->CreateShaderResourceview(mBlurMap0.Get(),
&srvDescz mBlur0CpuSrv);
md3dDevice->CreateUnorderedAccessView(mBlurMap0.Get(), nullptr, &uavDesc, mBlur0CpuUav);

从代码中可以看出,如果一个纹理需要与UAV相绑定,则此纹理必须用标志D3D12_RESOURCE_ FLAG_ALLOW_UNORDERED_ACCESS来创建。在上面的示例中,我们将纹理分别绑定为一个UAV与一 个SRV (但是两者却不能同时生效)。这是一种很常见的手段,因为我们通常会在计算着色器中对纹理执行某些操作(所以将纹理作为UAV绑定到计算着色器),而后还可能用此纹理对几何体进行贴图,因此 需要再将它以SRV绑定到顶点着色器或像素着色器。
类型为D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV的描述符堆可以混合存放 CBV (常量缓冲区视图)、SRV和UAV。因此,我们就能将UAV描述符置于这种堆中。这些描述符一旦 位于堆中,我们就能方便地将描述符句柄作为参数传至根参数,使资源绑定到流水线上,以供分派调用 使用。试考虑以下用于计算着色器的根签名:

void BlurApp::BuildPostProcessRootSignature()
{
	CD3DX12_DESCRIPTOR_RANGE srvTable;
	srvTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);

	CD3DX12_DESCRIPTOR_RANGE uavTable;
	uavTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0);

	//根参数可以是描述符表、根描述符或根常量
	// Root parameter can be a table, root descriptor or root constants.
	CD3DX12_ROOT_PARAMETER slotRootParameter[3];

	//提高程序性能的小窍门:按变更频率由髙至低的顺序来填写根参数
	// Perfomance TIP: Order from most frequent to least frequent.
	slotRootParameter[0].InitAsConstants(12, 0);
	slotRootParameter[1].InitAsDescriptorTable(1, &srvTable);
	slotRootParameter[2].InitAsDescriptorTable(1, &uavTable);

	//根签名由一系列根参数构成
	// A root signature is an array of root parameters.
	CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(3, slotRootParameter,
		0, nullptr,
		D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

	//创建一个具有3个槽位的根签名,第一个指向常量缓冲区,第二个指向含有单个着色器资源视图的描述符 //表,第三个指向含有单个无序访问视图的描述符表
	// 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(mPostProcessRootSignature.GetAddressOf())));
}

这个根签名的定义为:根参数槽0指向一个常量缓冲区、根参数槽1指向一个SRV,根参数槽2指 向一个UAV。在分派调用开始之前,我们先要为计算着色器绑定常量数据与资源描述符以供其使用:

cmdList->SetComputeRootSignature(rootSig);

	cmdList->SetComputeRoot32BitConstants(0, 1, &blurRadius, 0);
	cmdList->SetComputeRoot32BitConstants(0, (UINT)weights.size(), weights.data(), 1);
	cmdList->SetComputeRootDescriptorTable(1, mBlur0GpuSrv);
	cmdList->SetComputeRootDescriptorTable(2, mBlur1GpuUav);

    UINT numGroupsX = (UINT)ceilf(mWidth / 256.0f);
	cmdList->Dispatch(numGroupsX, mHeight, 1);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值