Mesh 파이프라인은 전통적인 그래픽스 파이프라인보다 더 유연하고 강력한 구조를 제공합니다. 특히 병렬 처리에 특화되어 있어, 대규모 지오메트리 데이터를 효율적으로 처리할 수 있습니다.
이제 Mesh 파이프라인을 살펴봅시다.
Resources
Mesh Shader 파이프라인에서도 역시 다양한 리소스들이 필요합니다. 구조화 버퍼(Structured Buffer), UAV, 상수 버퍼 등은 기존과 동일하게 활용됩니다.
그러나 Mesh Shader는 IA(Input Assembler) 단계가 비활성화되어 있어, 인덱스 버퍼 및 입력 레이아웃을 사용하지 않습니다. 따라서 모든 정점 및 프리미티브 데이터는 셰이더 내부에서 직접 생성되거나 구조화된 형태로 접근해야 합니다.
Amplification Shader / Mesh Shader Structure
Mesh Shader는 두 개의 셰이더 단계로 구성됩니다:
1. Amplification Shader (AS)
•
선택적(Optional) 단계입니다.
•
DispatchMesh()를 호출하여 여러 개의 Mesh Shader 그룹을 생성합니다.
•
예전의 Hull Shader 역할 + 구조 분해 및 증폭 기능 수행
[numthreads(1, 1, 1)]
void ASMain(uint3 dispatchThreadID : SV_DispatchThreadID)
{
MeshPayload payload = ...;
DispatchMesh(4, 1, 1, payload);
}
Plain Text
복사
2. Mesh Shader (MS)
•
Vertex Shader + Geometry Shader의 역할을 통합
•
각 스레드는 정점, 프리미티브를 자유롭게 출력
•
SetMeshOutputCounts(vertexCount, primitiveCount) 호출 필요
입력
•
SV_GroupID, SV_GroupThreadID 등 스레드 정보
•
(선택적) Amplification Shader로부터의 Payload 구조체
•
필요한 리소스들 (구조화 버퍼, 텍스처, 상수 버퍼 등)
동작 흐름
1.
SetMeshOutputCounts(vertexCount, primitiveCount) 호출
→ 출력할 정점/프리미티브 개수 지정
2.
그룹 공유 배열에 출력 기록
•
vertices[]: 정점 속성 (SV_Position 등 포함 필수)
•
primitiveIndices[]: uint2/uint3로 프리미티브 구성
•
primitives[]: 프리미티브 속성 (컬링, 뷰포트 지정 등)
[outputtopology("triangle")]
[numthreads(32, 1, 1)]
void MSMain(in uint3 groupThreadID : SV_GroupThreadID,
out vertices VertexAttributes verts[256],
out indices uint3 tris[128])
{
SetMeshOutputCounts(3, 1);
verts[0].position = float4(-0.5, -0.5, 0, 1);
verts[1].position = float4(0.0, 0.5, 0, 1);
verts[2].position = float4(0.5, -0.5, 0, 1);
tris[0] = uint3(0, 1, 2);
}
Plain Text
복사
Pipeline State
Mesh Shader 파이프라인은 IA, VS, GS, HS, DS를 포함하지 않고, 대신 아래와 같이 구성됩니다:
•
Root Signature
•
Amplification Shader (선택)
•
Mesh Shader (필수)
•
Rasterization (하드웨어)
•
Pixel Shader (선택)
struct PSO_STREAM
{
CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE rootSig;
CD3DX12_PIPELINE_STATE_STREAM_AS AS;
CD3DX12_PIPELINE_STATE_STREAM_MS MS;
CD3DX12_PIPELINE_STATE_STREAM_PS PS;
};
D3D12_PIPELINE_STATE_STREAM_DESC desc = { &stream, sizeof(stream) };
device->CreatePipelineState(&desc, IID_PPV_ARGS(&pipelineState));
C++
복사
Mesh Shader Output
Mesh Shader는 다음과 같은 출력을 가집니다:
•
vertices[]: 정점 구조체 배열, 반드시 SV_Position 포함
•
primitiveIndices[]: uint3 배열, 삼각형 정점 인덱스
•
primitives[]: 프리미티브 속성 (선택 사항, SV_CullPrimitive, SV_RenderTargetIndex 등)
struct VertexAttributes {
float4 position : SV_Position;
float3 normal : NORMAL;
};
struct PrimitiveAttributes {
uint RTIndex : SV_RenderTargetArrayIndex;
};
Plain Text
복사
Execution Flow
1.
DispatchMesh(x, y, z) 호출 → (AS 생략 시 직접 MS 실행)
2.
Amplification Shader가 Mesh Shader 그룹 런칭 (선택 사항)
3.
Mesh Shader 그룹 내 각 스레드가 정점/프리미티브 출력
4.
래스터라이저가 출력 순서대로 픽셀 셰이더로 전달
주의: SetMeshOutputCounts를 호출하지 않으면 아무 것도 출력되지 않음!
성능 추적 (통계)
D3D12_QUERY_DATA_PIPELINE_STATISTICS1 stats;
stats.MSInvocations; // 호출 횟수
stats.MSPrimitives; // 출력 프리미티브 수
C++
복사
D3D12_FEATURE_DATA_D3D12_OPTIONS7 opt7 = {};
CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &opt7, sizeof(opt7));
if (opt7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) {
// 지원됨
}
C++
복사