iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0

要介紹 Graphics Pipeline 前,就得先把 Micorsoft 官方的圖片拿出來

從圖可以看到,要實際讓 DX 可以把資料繪製出來,會需要至少以下的流程

  • index 與 vertex 資料
  • Shader (Ex : HLSL)
  • Pipeline State Object
  • Root Signature
  • Descriptor Heap
  • Render Target / Depth Buffer
  • Command List
  • Command Queue

其中 Shader 的部分又可以細拆成以下的部分

  • Vertex / Index Buffer
  • Input Assembler
  • Vertex Shader
  • Hull Shader
  • Tessellator
  • Domain Shader
  • Geometry Shader
  • Rasterizer
  • Pixel Shader
  • Output Merger
  • Render Target / Depth Buffer

其中有些階段是可程式化的 Shader Stage,有些則是由 GPU 硬體執行的 Fixed-function Stage。

文章會拆成六篇,邊介紹功能與設定、邊把範例程式展現出來。

此範例會先以輸出三角形為目標,介紹最基本的 Graphics Pipeline 流程。

Pipeline State Object

簡稱為 PSO,是 DX 用來保存固定狀態的物件,PSO 建立後是無法改變的,需要套不同設定的話就必須另外再建一套 PSO。

typedef struct D3D12_GRAPHICS_PIPELINE_STATE_DESC
{
    ID3D12RootSignature* pRootSignature; // 指定此 Graphics Pipeline 使用的 Root Signature

    D3D12_SHADER_BYTECODE VS; // 指定 Vertex Shader 的編譯後位元碼
    D3D12_SHADER_BYTECODE PS; // 指定 Pixel Shader 的編譯後位元碼
    D3D12_SHADER_BYTECODE DS; // 指定 Tessellation 使用的 Domain Shader 位元碼
    D3D12_SHADER_BYTECODE HS; // 指定 Tessellation 使用的 Hull Shader 位元碼
    D3D12_SHADER_BYTECODE GS; // 指定 Geometry Shader 的編譯後位元碼

    D3D12_STREAM_OUTPUT_DESC StreamOutput; // 設定是否將 Shader 輸出的頂點資料寫回 Buffer

    D3D12_BLEND_DESC BlendState; // 設定 Render Target 的顏色混合方式

    UINT SampleMask; // 設定 Multisampling 中允許被寫入的 Sample

    D3D12_RASTERIZER_DESC RasterizerState; // 設定 Rasterizer 的填充模式 剔除模式與 Depth Bias

    D3D12_DEPTH_STENCIL_DESC DepthStencilState; // 設定 Depth Test 與 Stencil Test 的行為

    D3D12_INPUT_LAYOUT_DESC InputLayout; // 定義 Vertex Buffer 傳入 Vertex Shader 的資料格式

    D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue; // 設定 Triangle Strip 或 Line Strip 中用來切斷 Strip 的 Index 值

    D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType; // 指定 Pipeline 使用的 Primitive 類型

    UINT NumRenderTargets; // 指定同時使用的 Render Target 數量 最大為 8 個

    DXGI_FORMAT RTVFormats[8]; // 指定每個 Render Target View 對應的像素格式

    DXGI_FORMAT DSVFormat; // 指定 Depth Stencil View 使用的資料格式

    DXGI_SAMPLE_DESC SampleDesc; // 設定 MSAA 的 Sample 數量與品質等級

    UINT NodeMask; // 指定 Multi GPU 環境中此 Pipeline State 所屬的 GPU Node

    D3D12_CACHED_PIPELINE_STATE CachedPSO; // 指定可以重複使用的已快取 Pipeline State 資料

    D3D12_PIPELINE_STATE_FLAGS Flags; // 設定 Pipeline State 的額外控制 Flag

} D3D12_GRAPHICS_PIPELINE_STATE_DESC;

其中常用的部份為以下幾個,之後的介紹可以更加理解其作用

pRootSignature

VS
PS

BlendState
SampleMask

RasterizerState
DepthStencilState

InputLayout
PrimitiveTopologyType

NumRenderTargets
RTVFormats
DSVFormat

SampleDesc

最後,為此專案中的相關的程式設定

//pipeline_state.h

#pragma once
#include <directx/d3d12.h>
#include <wrl/client.h>

class PipelineState
{
public:
    // 初始化 Graphics Pipeline State
    void init(D3D12_GRAPHICS_PIPELINE_STATE_DESC decs);

    [[nodiscard]]
    ID3D12PipelineState* get() const
    {
        return m_pipelineState.Get();
    }

private:
    Microsoft::WRL::ComPtr<ID3D12PipelineState> m_pipelineState;
};
//pipeline_state.cpp

#include "pipeline_state.h"
#include <stdexcept>
#include "graphics_engine.h"

void PipelineState::init(D3D12_GRAPHICS_PIPELINE_STATE_DESC desc)
{
    if (g_graphicsEngine == nullptr || g_graphicsEngine->getD3DDevice() == nullptr)
        throw std::runtime_error("PipelineState: Graphics device is not initialized.");

    const auto d3dDevice = g_graphicsEngine->getD3DDevice();

    if (auto hr = d3dDevice->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&m_pipelineState)); FAILED(hr))
    {
        throw std::runtime_error("PipelineState: Failed to create the graphics pipeline state.");
    }
}

參考資料

Pipelines and Shaders with Direct3D 12


上一篇
Day 4:C++ 使用到的功能介紹
系列文
因為 AI 看不懂老舊程式,只好乖乖從零開始學 DirectX 12 與 HLSL5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言