DirecX12 개인 메모 | Shader Model
DirectX12 Shader Model에 관한 글입니다.
DirecX12 개인 메모 | Shader Model
이 문서는 Direct3D 12에 Shader Model 버젼 간 차이점과 6.6모델을 적용하는 것에 대해 정리한 것입니다.
Shader Model 6.6
다음 모델을 사용하기 위해서는 기존의 D3DCompileFromFile
대신 IDxcCompiler3
의 Compile
함수를 사용해야 한다.
항목 | SM 5.1 | SM 6.6 |
---|---|---|
컴파일러 | fxc | dxc |
Windows SDK | 낮아도 됨 | 최신 필요 |
GPU 드라이버 | 보통 호환 | 최신 필요 |
문법 호환성 | 넓음 | 최신 문법 포함 |
항목 | 설명 |
---|---|
기존 방식 | D3DCompileFromFile → FXC |
변경 방식 | IDxcCompiler3::Compile → DXC |
파일 인코딩 | UTF-8 권장 |
필요 파일 | dxcapi.h , dxcompiler.lib , dxcompiler.dll , dxil.dll |
Shader Target | "vs_6_6" , "ps_6_6" 등 문자열로 전달 |
ComlieShaderWithDXC 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
bool Shader::CompileShaderWithDXC(const std::wstring& path, const std::wstring& name, const std::wstring& version, ComPtr<IDxcBlob>& blob, D3D12_SHADER_BYTECODE& shaderByteCode)
{
ComPtr<IDxcUtils> utils;
ComPtr<IDxcCompiler3> compiler;
ComPtr<IDxcIncludeHandler> includeHandler;
// 1. DXC 인스턴스 생성
if (FAILED(DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&utils))))
{
return false;
}
if (FAILED(DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler))))
{
return false;
}
if (FAILED(utils->CreateDefaultIncludeHandler(&includeHandler)))
{
return false;
}
// 2. HLSL 파일을 읽어서 메모리에 적재 + 3. 컴파일용 DxcBuffer 생성
ComPtr<IDxcBlobEncoding> file = nullptr;
utils->LoadFile(path.c_str(), nullptr, &file);
DxcBuffer sourceBuffer;
sourceBuffer.Ptr = file->GetBufferPointer();
sourceBuffer.Size = file->GetBufferSize();
sourceBuffer.Encoding = DXC_CP_UTF8; // Assume BOM says UTF8 or UTF16 or this is ANSI text.
// 2. HLSL 파일을 읽어서 메모리에 적재
//std::ifstream file(path, std::ios::binary | std::ios::ate);
//if (!file)
//{
// return false;
//}
//std::streamsize size = file.tellg();
//file.seekg(0, std::ios::beg);
//std::vector<char> buffer(size);
//if (!file.read(buffer.data(), size))
//{
// return false;
//}
// 3. 컴파일용 DxcBuffer 생성
//DxcBuffer sourceBuffer{};
//sourceBuffer.Ptr = buffer.data();
//sourceBuffer.Size = static_cast<UINT32>(buffer.size());
//sourceBuffer.Encoding = DXC_CP_UTF8;
// 4. 컴파일 옵션 설정
std::vector<LPCWSTR> arguments;
arguments.push_back(path.c_str()); // Shader file name
arguments.push_back(L"-E");
arguments.push_back(name.c_str()); // Entry point
arguments.push_back(L"-T");
arguments.push_back(version.c_str()); // Target (vs_6_6)
arguments.push_back(L"-Zi"); // Debug info
arguments.push_back(L"-Qembed_debug"); // Embed debug info
arguments.push_back(L"-Zpr"); // Row-major
arguments.push_back(L"-Od"); // Disable optimizations (for dev)
// 5. 컴파일 실행
ComPtr<IDxcResult> result;
if (FAILED(compiler->Compile( &sourceBuffer, arguments.data(), static_cast<UINT32>(arguments.size()), includeHandler.Get(), IID_PPV_ARGS(&result))))
{
::MessageBoxA(nullptr, "Shader Create Failed !", nullptr, MB_OK);
return false;
}
// 6. 에러 메시지 확인
ComPtr<IDxcBlobUtf16> dummyName;
result->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&mErrorBlobDxc), dummyName.GetAddressOf());
if (mErrorBlobDxc && mErrorBlobDxc->GetStringLength() > 0)
{
OutputDebugStringA((char*)mErrorBlobDxc->GetStringPointer());
}
// 7. 최종 Shader Blob 가져오기
ComPtr<IDxcBlob> shaderBlob;
result->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&shaderBlob), dummyName.GetAddressOf());
blob = shaderBlob;
shaderByteCode = { blob->GetBufferPointer(), blob->GetBufferSize() };
return true;
}
Arguments
arguments
는 DXC(DX Shader Compiler)에 넘길 커맨드라인 옵션 리스트로, 마치 콘솔에서 dxc.exe
를 호출할 때 사용하는 것과 동일한 역할
인자 | 역할 |
---|---|
path.c_str() | 소스 파일 이름 (디버그용) |
-E | Entry Point 지정 |
-T | Target Profile (vs_6_6 등) |
-Zi | 디버그 정보 생성 |
-Qembed_debug | 디버그 정보 내장 |
-Zpr | 행 우선 행렬 |
-Od | 최적화 비활성화 (디버깅용) |
항목 | 필수 여부 | 설명 |
---|---|---|
파일 이름 (path.c_str() ) | ✅ 권장 | 디버깅 경로 및 오류 메시지에 필요 |
-E (entry point) | ✅ 필수 | 없으면 어떤 함수부터 시작할지 모름 |
-T (target profile) | ✅ 필수 | 어떤 타입/버전의 쉐이더인지 모름 |
-Zi , -Od , -Zpr | ❌ 선택 | 디버깅/행렬 방식/최적화 등 설정용 |
Shader Model 버전 비교표 ✅
버전 | 컴파일러 | 주요 기능 | DXIL | DX12 연계 기능 |
---|---|---|---|---|
5.1 | FXC | SM 5.0에서 개선, 64-bit 지원 | ❌ | 기본 지원 |
6.0 | DXC | DXIL 도입, wave 명령어 일부 도입 | ✅ | DXIL 기반 렌더링 시작 |
6.1 | DXC | WaveOps , ViewID , barycentrics 도입 | ✅ | 멀티뷰 / Geometry 향상 |
6.2 | DXC | WaveMatch , WaveReduce , float16 타입 | ✅ | Half precision 지원 |
6.3 | DXC | SV_Barycentrics , bitfield , atomic64 등 | ✅ | 정밀 제어 연산 |
6.4 | DXC | ResourceDescriptorHeap , SamplerFeedback 지원 시작 | ✅ | DX12 Sampler Feedback API |
6.5 | DXC | RayQuery , RelaxedPrecision , 64-bit Atomics | ✅ | DXR 1.1 등 고급 RT 기능 |
6.6 | DXC | bindless resources , packed resources , DXIL validation 강화 | ✅ | DX12 Ultimate 기능 연동 완성 |
주요 기능 변화 요약 🔍
SM 5.1 (FXC 기반)
- DX12 초기와 호환되지만, DXIL 및 최신 기능 불가
SM 6.0~6.2 (DXIL 도입기)
- DXIL 사용 시작
- WaveOps, 16-bit 연산 지원
- DXC 필수
SM 6.3~6.4
SV_Barycentrics
등 고급 셰이딩 기법Sampler Feedback
등장 (DX12 Ultimate 일부 시작)
SM 6.5
RayQuery
등장 (DXR 1.1)- Relaxed Precision, 64-bit atomic 등 고성능 연산 지원
SM 6.6
- 최신 하드웨어 특화 기능:
bindless descriptor heap
packed resource
- 최적화된 Validation
어떤 버전을 선택해야 할까? 🧠
목표 | 권장 Shader Model |
---|---|
구형 하드웨어 호환성 | SM 5.1 |
일반적인 DX12 렌더러 | SM 6.2 이상 |
WaveOps / 정밀 연산 | SM 6.3 이상 |
Sampler Feedback, RT | SM 6.4~6.6 |
DX12 Ultimate 대응 | SM 6.6 권장 |
참고
URL
https://learn.microsoft.com/ko-kr/windows/win32/api/dxcapi/
https://github.com/microsoft/DirectXShaderCompiler/wiki/Using-dxc.exe-and-dxcompiler.dll
용어
용어 | 설명 |
---|---|
DXIL | DirectX Intermediate Language (SM 6.x부터 도입) |
DXC | DXIL 컴파일러 (dxc.exe , IDxcCompiler3 ) |
FXC | 구버전 HLSL 컴파일러 (D3DCompileFromFile ) |
WaveOps | SIMD 수준에서 Thread 간 통신 명령 (e.g. WaveActiveSum ) |
Barycentrics | 픽셀 쉐이더에서 보간 정보 직접 접근 |
d3d12shader.h
#include <d3d12shader.h>
는 DirectX 12에서 HLSL 셰이더의 메타데이터(리소스 정보 등)를 런타임에서 분석(reflection) 하기 위한 셰이더 리플렉션 API를 사용하기 위한 헤더
목적: 셰이더 리플렉션 (Shader Reflection)
셰이더 컴파일 결과물(.cso
또는 DXIL
)에서 다음과 같은 셰이더의 구조 정보를 런타임에 추출할 수 있습니다:
- 바인딩된 상수 버퍼 (CBV)
- 텍스처 (SRV/UAV)
- 정점 입력 시그니처
- 출력 시그니처
- 쓰레드 그룹 정보 (컴퓨트 셰이더)
주요 인터페이스
이 헤더에서 가장 중요한 인터페이스는 다음과 같습니다:
인터페이스 | 설명 |
---|---|
ID3D12ShaderReflection | 셰이더 리소스에 대한 전반적인 정보 |
ID3D12ShaderReflectionConstantBuffer | 상수 버퍼 내부 필드 정보 |
ID3D12ShaderReflectionVariable | 개별 변수 정보 |
ID3D12ShaderReflectionType | 변수 타입 정보 |
분석 가능한 것들 (정적 정보, 컴파일 결과 기반)
항목 | 설명 |
---|---|
셰이더에 선언된 CBV/SRV/UAV | 어떤 이름으로 몇 번째 슬롯에 있는지 |
셰이더 상수 버퍼 구조체 내부 변수 이름과 오프셋 | 패딩 포함 여부 확인 가능 |
텍스처/샘플러 바인딩 개수와 타입 | 예: Texture2D , SamplerState 등 |
셰이더의 입력/출력 시그니처 | 정점 셰이더의 입력, 픽셀 셰이더의 출력 등 |
쓰레드 그룹 크기 (컴퓨트 셰이더) | [numthreads(x, y, z)] 정보 |
분석 불가능한 것들 (런타임 GPU 상태)
항목 | 설명 |
---|---|
현재 GPU 사용량 | GPU 점유율, VRAM 사용량, 대기열 상태 등 |
실시간 파이프라인 상태 | 현재 어떤 셰이더가 실행 중인지, GPU idle 여부 등 |
바인딩된 리소스의 실제 값 | 예: GPU에 올라간 CBV에 어떤 값이 있는지 |
GPU 스레드 실행 흐름 | Wave 상태, SIMD 상태, occupancy 등 |
이런 정보들은 Shader Reflection API로는 불가능하며, GPU 디버거/분석기 또는 D3D12의 low-level 디버깅/쿼리 API를 사용해야 합니다.
GPU 상태를 실시간 분석하려면?
도구/기술 | 설명 |
---|---|
PIX for Windows | GPU 명령 분석, GPU 타이밍, 메모리 사용량 추적 |
NVIDIA Nsight Graphics | NVIDIA GPU에 최적화된 런타임 분석 및 셰이더 디버깅 |
AMD Radeon GPU Profiler | AMD GPU 타겟 분석 도구 |
D3D12 Query Heap | GPU 타이밍/오버헤드/오쿼리 통계 수집용 |
D3D12 Performance Counters | 디바이스/드라이버에 따라 GPU 내부 상태 측정 가능 (벤더 전용 API 포함 가능) |
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.