D3D12渲染技术之光栅化与管道

光栅化状态

虽然渲染管道的许多部分都是可编程的,但某些部分只是可配置的, 由D3D12_RASTERIZER_DESC结构表示的光栅化器状态组用于配置渲染管道的光栅化阶段:

typedef struct D3D12_RASTERIZER_DESC {
D3D12_FILL_MODE FillMode;   // Default: D3D12_FILL_SOLID
  D3D12_CULL_MODE CullMode;   // Default: D3D12_CULL_BACK
  BOOL FrontCounterClockwise; // Default: false
  INT DepthBias;              // Default: 0
  FLOAT DepthBiasClamp;       // Default: 0.0f
  FLOAT SlopeScaledDepthBias; // Default: 0.0f
  BOOL DepthClipEnable;       // Default: true
  BOOL ScissorEnable;         // Default: false
  BOOL MultisampleEnable;     // Default: false
  BOOL AntialiasedLineEnable; // Default: false
  UINT ForcedSampleCount;     // Default: 0

  // Default: D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF
  D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster;
} D3D12_RASTERIZER_DESC;

这个结构体有很多项,我们要使用它,就必须搞清楚这些项的含义,DX文档都有详细的介绍。本篇博客就不一一说明了,接下来我们看看如何使用。
以下代码显示如何创建启用线框模式并禁用背面剔除的栅格化状态:

CD3DX12_RASTERIZER_DESC rsDesc(D3D12_DEFAULT);
rsDesc.FillMode = D3D12_FILL_WIREFRAME;
rsDesc.CullMode = D3D12_CULL_NONE;

CD3DX12_RASTERIZER_DESC是一个扩展类,它扩展了D3D12_RASTERIZER_DESC并添加了一些辅助构造函数。 特别是,它有一个构造函数,它接受类型为CD3D12_DEFAULT的对象,它只是一个用于重载的伪类型,表示光栅化器状态成员应初始化为默认值。 CD3D12_DEFAULT和D3D12_DEFAULT的定义如下:

struct CD3D12_DEFAULT {};
extern const DECLSPEC_SELECTANY CD3D12_DEFAULT D3D12_DEFAULT;

管道状态

前面,我们已经展示了如何描述输入布局描述,如何创建顶点和像素着色器,以及如何配置光栅化器状态组,我们还没有展示如何将这些对象绑定到图形管道以供实际使用。 控制图形管道状态的大多数对象被指定称为管道状态对象(PSO)的聚合,它由ID3D12PipelineState接口表示。 要创建PSO,我们首先通过填写D3D12_GRAPHICS_PIPELINE_STATE_DESC实例来描述它:

typedef struct D3D12_GRAPHICS_PIPELINE_STATE_DESC
{  ID3D12RootSignature *pRootSignature;
  D3D12_SHADER_BYTECODE VS;
  D3D12_SHADER_BYTECODE PS;
  D3D12_SHADER_BYTECODE DS;
  D3D12_SHADER_BYTECODE HS;
  D3D12_SHADER_BYTECODE GS;
  D3D12_STREAM_OUTPUT_DESC StreamOutput;
  D3D12_BLEND_DESC BlendState;
  UINT SampleMask;
  D3D12_RASTERIZER_DESC RasterizerState;
  D3D12_DEPTH_STENCIL_DESC DepthStencilState;
  D3D12_INPUT_LAYOUT_DESC InputLayout;
  D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType;
  UINT NumRenderTargets;
  DXGI_FORMAT RTVFormats[8];
  DXGI_FORMAT DSVFormat;
  DXGI_SAMPLE_DESC SampleDesc;
} D3D12_GRAPHICS_PIPELINE_STATE_DESC;

在我们填写了D3D12_GRAPHICS_PIPELINE_STATE_DESC实例之后,我们使用ID3D12Device :: CreateGraphicsPipelineState方法创建了一个ID3D12PipelineState对象:

ComPtr<ID3D12RootSignature> mRootSignature;
std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
ComPtr<ID3DBlob> mvsByteCode;
ComPtr<ID3DBlob> mpsByteCode;
…
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.PS = 
{ 
  reinterpret_cast<BYTE*>(mpsByteCode->GetBufferPointer()), 
  mpsByteCode->GetBufferSize() 
};
psoDesc.RasterizerState = CD3D12_RASTERIZER_DESC(D3D12_DEFAULT);
psoDesc.BlendState = CD3D12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState = CD3D12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = mBackBufferFormat;
psoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
psoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
psoDesc.DSVFormat = mDepthStencilFormat;

ComPtr<ID3D12PipelineState> mPSO;
md3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&mPSO)));

这在一个ID3D12PipelineState对象中是相当多的状态,Direct3D可以验证所有状态是否兼容,并且驱动程序可以预先生成所有代码以编程硬件状态。在Direct3D 11状态模型中,这些渲染状态块分别设置,但是,如果一个状态发生变化,则可能还需要驱动程序将硬件重新编程为另一个依赖状态,由于许多状态已更改为配置管道,因此硬件状态可能会被重新编程,为了避免这种冗余,驱动程序通常推迟编程硬件状态,直到在整个流水线状态已发出绘制调用,它需要跟踪哪些状态已更改,然后生成代码以在运行时对硬件状态进行编程。在新的Direct3D 12模型中,驱动程序可以生成在初始化时编程管道状态所需的所有代码。

注意,由于PSO验证和创建可能非常耗时,因此应在初始化时生成PSO。 一个例外可能是在第一次引用时根据需要在运行时创建PSO; 然后将其存储在一个集合(如哈希表)中,以便快速获取以供将来使用。

并非所有渲染状态都封装在PSO中, 视口和裁剪矩形等某些状态是独立于PSO指定的。 这种状态可以有效地独立地设置到另一个流水线状态,因此通过将它们包括在PSO中没有什么优势。
Direct3D基本上是一个状态机, 在我们改变之前,事情一直保持现状, 如果我们正在绘制的某些对象使用一个PSO,而我们正在绘制的其他对象需要不同的PSO,那么我们需要构建代码,如下所示:

// Reset specifies initial PSO.
mCommandList->Reset(mDirectCmdListAlloc.Get(), mPSO1.Get())
/* …draw objects using PSO 1… */

// Change PSO
mCommandList->SetPipelineState(mPSO2.Get());
/* …draw objects using PSO 2… */

// Change PSO
mCommandList->SetPipelineState(mPSO3.Get());
/* …draw objects using PSO 3… */

换句话说,当PSO绑定到命令列表时,它将不会更改,直到覆盖它(或重置命令列表)。

已标记关键词 清除标记
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页