[C++]DirectX 12 3D游戏开发实战—第13章 学习笔记02 2019.5.11
个人学习使用,请勿转载
词汇
无序访问视图:Unordered Access View, UAV
内容
13.2 一个简单的计算着色器
cbuffer cbSettings { //计算着色器能访问的常量缓冲区数据 }; //数据源及着色器的输出 Texture2D gInputA; Texture2D gInputB; RWTexture2D<float4> gOutput; //线程组中的线程数。组中的线程可以被设置为1D2D或者3D网格布局 [numthreads(16,16,1)] void CS(int3 dispatchThreadID : SV_DispatchThreadID) //线程ID { //对两种源像素中纵横坐标分别为x,y出的纹素进行求和,并将结果保存到相应的gOutput gOutput [dispatchThreadID.xy]=gInputA[dispatchThreadID.xy]+gInputB[dispatchThreadID.xy]; }
计算着色器由下列要素构成:
- 通过常量缓冲区访问的全局变量
- 输入与输出资源
- [numthreads(x,y,z)]属性,指定3D线程网格中的线程数量
- 每个线程都要进行的着色器指令
- 线程ID系统值参数
我们能够根据需求定义出不同线程组布局。
计算流水线状态对象
为了开启计算着色器,还需要使用特定的计算流水线状态描述。此描述中的字段远少于D3D12_GRAPHICS_PIPELINE_STATE_DESC结构体,因为计算着色器位于图形流水线之外,因此所有图形流水线状态都不适用于计算着色器,示例如下:
D3D12_COMPUTE_PIPELINE_STATE_DESC wavesUpdatePSO = {}; wavesUpdatePSO.pRootSignature = mWaveRootSignature.Get(); wavesUpdatePSO.CS= { reinterpret_cast<BYTE*>(mShaders["wavesUpdateCS"]->GetBufferPointer()), mShaders["wavespdateCS"]->GetBufferSize() }; wavesUpdatePSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; ThrowIfFaild(md3dDevice->CreateComputePipelineState( &wavesUpdatePSO,IID_PPV_ARGS(&mPSOs["wavesUpdate"])));
根签名定义了什么参数才是着色器所期望的输入,而cs字段就是所指定的计算着色器。
一个将着色器编译为字节码的示例:
mShaders["wavesUpdateCS"] = d3dUtil::CompileShader( L"Shaders\\waveSim.hlsl",nullptr,"UpdateWavesCS","cs_5_0");
13.3数据的输入与输出资源
能与计算着色器绑定的资源类型有缓冲区与纹理两种。
13.3.1纹理输入
通过各输入纹理gInputA与gInputB分别创建SRV,再将他们作为参数传入根参数,就能令这两个纹理都绑定为着色器的输入资源。
cmdList->SetComputeRootDescriptorTable(1,mSrvA); cmdList->SetComputeRootDescriptorTable(2,mSrvB);
13.3.2纹理输出与无序访问视图
对于输出资源:
RWTexture2D<float4> gOutput;
计算着色器的处理输出资源的方式比较特殊,它们的类型还有一个特别的前缀“RW”,意为读写,可以对计算着色器中的这类资源元素进行读写操作。gInputA和gInputB仅为只读,使用尖括号模板语法。来指定输出资源的类型与维数,若输出DXGI_FORMAT_R8G8_SINT类型的2D整形资源,则在HLSL中这样定义:
RWTexture2D<int2> gOutput;
输出资源与输入资源的绑定方法是截然不同的。为了绑定在计算着色器中要执行写操作的资源。需要将其与称为无序访问视图(Unorderd Access View)的新型视图关联在一起。代码中,用描述符句柄来标识无序访问视图,且通过结构体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; tex.DepthOrArraySize = 1; texDesc.MipLevels = 1; texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; texDesc.SampleDesc.Count = 1; texDesc.SampleDesc.Quality = 0; texDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; ThrowIfFaild(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(), &srvDesc,mBlur0CpuSrv); md3dDevice->CreateUnorderedAccessView(mBlurMap.Get(), nullptr,&uavDesc,mBlur0CpuUav);
如果一个纹理要与UAV绑定,则此纹理必须用标志D3D_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS来创建,示例中,我们将纹理分别绑定为一个UAV和一个SRV(不同时生效)。这是一种常见手段,通常会在计算着色器中对纹理执行某些操作,然后还可能用此纹理对几何体进行贴图,因此需要再将它与SRV绑定到顶点着色器或像素着色器。
类型为D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV的描述符堆可以混合存放CBV、SRV和UAV,因此,就能将UAV描述符置于这种堆中,将描述符句柄作为参数传至根参数,是资源绑定到流水线上以供分派调用。
void BlurApp::BuildPostProcessRootSignature() { CD3DX12_DESCRIPTOR_RANGE srvTable; } 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); // 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, mBlur1GpuSrv); cmdList->SetComputeRootDescriptorTable(2, mBlur0GpuUav); UINT numGroupsY = (UINT)ceilf(mHeight / 256.0f); cmdList->Dispatch(mWidth, numGroupsY, 1);
13.3.3利用索引对纹理进行采样
- [C++]DirectX 12 3D游戏开发实战—第13章 学习笔记02 2019.5.20
- [C++]DirectX 12 3D游戏开发实战—第13章 学习笔记05 2019.5.14
- [C++]DirectX 12 3D 4000 游戏开发实战—第13章 学习笔记04 2019.5.13
- [C++]DirectX 12 3D游戏开发实战—第13章 学习笔记06 2019.5.16
- [C++]DirectX 12 3D游戏开发实战—第14章 学习笔记01
- DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之10: Chap12: Blending
- DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之9: Chap11: Texturing
- 【麦可网】Cocos2d-X跨平台游戏开发学习笔记---第二十六课:Cocos2D-X物理引擎之Box2D11-12
- HTML网页开发学习笔记(燕十八)-12 margin首页实战
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十一章:模板测试
- Layabox 3D游戏开发学习笔记---射线检测,鼠标控制物体运动
- 逐梦旅程学习笔记 DirectX开发入门02:旋转的彩色立方体
- DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之6: Chap8: Drawing in Direct3D ---- Part II
- DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之2: Chap4: Direct3D Initialization
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第六章:在Direct3D中绘制
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十章:混合
- 【Unity 3D游戏开发学习笔记】总结摄像机和光源的使用方法
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线
- DirectX 9.0c游戏开发手记之“龙书”第二版学习笔记之4: Chap6: The Rendering Pipeline