포스트

DirecX12 개인 메모 | Shader Model

DirectX12 Shader Model에 관한 글입니다.

DirecX12 개인 메모 | Shader Model

이 문서는 Direct3D 12에 Shader Model 버젼 간 차이점과 6.6모델을 적용하는 것에 대해 정리한 것입니다.


Shader Model 6.6

다음 모델을 사용하기 위해서는 기존의 D3DCompileFromFile대신 IDxcCompiler3Compile 함수를 사용해야 한다.

항목SM 5.1SM 6.6
컴파일러fxcdxc
Windows SDK낮아도 됨최신 필요
GPU 드라이버보통 호환최신 필요
문법 호환성넓음최신 문법 포함
항목설명
기존 방식D3DCompileFromFileFXC
변경 방식IDxcCompiler3::CompileDXC
파일 인코딩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

argumentsDXC(DX Shader Compiler)에 넘길 커맨드라인 옵션 리스트로, 마치 콘솔에서 dxc.exe를 호출할 때 사용하는 것과 동일한 역할

인자역할
path.c_str()소스 파일 이름 (디버그용)
-EEntry Point 지정
-TTarget Profile (vs_6_6 등)
-Zi디버그 정보 생성
-Qembed_debug디버그 정보 내장
-Zpr행 우선 행렬
-Od최적화 비활성화 (디버깅용)
항목필수 여부설명
파일 이름 (path.c_str())✅ 권장디버깅 경로 및 오류 메시지에 필요
-E (entry point)✅ 필수없으면 어떤 함수부터 시작할지 모름
-T (target profile)✅ 필수어떤 타입/버전의 쉐이더인지 모름
-Zi, -Od, -Zpr❌ 선택디버깅/행렬 방식/최적화 등 설정용

Shader Model 버전 비교표 ✅

버전컴파일러주요 기능DXILDX12 연계 기능
5.1FXCSM 5.0에서 개선, 64-bit 지원기본 지원
6.0DXCDXIL 도입, wave 명령어 일부 도입DXIL 기반 렌더링 시작
6.1DXCWaveOps, ViewID, barycentrics 도입멀티뷰 / Geometry 향상
6.2DXCWaveMatch, WaveReduce, float16 타입Half precision 지원
6.3DXCSV_Barycentrics, bitfield, atomic64정밀 제어 연산
6.4DXCResourceDescriptorHeap, SamplerFeedback 지원 시작DX12 Sampler Feedback API
6.5DXCRayQuery, RelaxedPrecision, 64-bit AtomicsDXR 1.1 등 고급 RT 기능
6.6DXCbindless 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, RTSM 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

용어

용어설명
DXILDirectX Intermediate Language (SM 6.x부터 도입)
DXCDXIL 컴파일러 (dxc.exe, IDxcCompiler3)
FXC구버전 HLSL 컴파일러 (D3DCompileFromFile)
WaveOpsSIMD 수준에서 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 WindowsGPU 명령 분석, GPU 타이밍, 메모리 사용량 추적
NVIDIA Nsight GraphicsNVIDIA GPU에 최적화된 런타임 분석 및 셰이더 디버깅
AMD Radeon GPU ProfilerAMD GPU 타겟 분석 도구
D3D12 Query HeapGPU 타이밍/오버헤드/오쿼리 통계 수집용
D3D12 Performance Counters디바이스/드라이버에 따라 GPU 내부 상태 측정 가능 (벤더 전용 API 포함 가능)

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.