| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- texture
- 번역
- DX12
- unrealengine
- DirectX12
- optimization
- Wavefront
- SIMD
- deferred
- RayTracing
- ue4
- atmospheric
- GPU Driven Rendering
- Nanite
- Graphics
- Study
- SGPR
- ShadowMap
- scattering
- GPU
- rendering
- hzb
- VGPR
- vulkan
- scalar
- forward
- wave
- shader
- UE5
- Shadow
- Today
- Total
RenderLog
VGPR, SGPR 사용여부 확인 본문
GPU에 대해서 더 공부하고 싶은 차에 [번역] INTRO TO GPU SCALARIZATION – PART 1 글을 봤었고, SGPR/SALU를 사용하는 경우 Wave내에 모든 Thread가 동일한 코드를 사용하게 되어서 성능 향상이 있을 것이라고 했습니다.
사실 이쪽은 완전히 새로운 영역이라... 성능차이가 정말 나는 것인가? 한 번해보고 싶었는데, 현재 Shader 코드가 VGPR/VALU or SGPR/SALU를 사용하는지 여부도 확인하는 법을 몰랐습니다. 최근에 렌더독을 이용하면 이 것을 확인 할 수 있다는 것을 알게 되었고, 실제로 Shader 코드가 사용하는 레지스터를 판별 할 수 있는지 한번 테스트 해봤습니다.
[번역] INTRO TO GPU SCALARIZATION – PART 1에서는 Note[0]에 SALU에는 ISA에 부동소수점 연산 명령어가 없어서 VALU가 될 거라고 하던데, 실제 AMD "Vega" Instruction Set Architecture에 나와있는 것을 확인했습니다.

그리고 렌더독으로 쉐이더 코드를 테스트 해본 결과 float인 경우 SGPR의 데이터를 VGPR에 올린 뒤 VALU로 연산되는 것을 아래 코드로 확인할 수 있습니다. 렌더독에서 Disassembly type을 Vega20으로 하여 디버깅 한 예 입니다.
//////////////////////////////////////////////////////////////////////////////////
// 아래 코드가 주석대로 SGPR과 VGPR에 올라가는지 확인 해보자.
//
// This will be in a SGPR
// -> [OK 잘 올라감]
float s_value = LightDirection.x;
// This will be put in VGPRs via a VMEM load as pixelCoord is in VGPRs
// -> [VGPR에 잘 올라감]
float4 v_textureSample = ShaderTextures[0].Sample(SamplerType, Input.Tex);
// This will be put in SGPRs via a SMEM load as 0 is constant.
// -> [SGPR에 잘 올라감]
TestInput s_someData = TestStructuredBuffer.Load(0);
// This should be an SALU op (output in SGPR) since both operands are in SGPRs
// (Note, check note [0])
// -> [여기서 SALU가 사용될 것이라고 했지만 아니었음. SGPR에는 32bit Integer와
// 32 bit or 64 bit Bit연산만 지원해서 VGPR로 옮긴 뒤 VALU로 연산함]
// * s_someData.Color.x 는 float임 *
float s_someModifier = s_value + s_someData.Color.x;
//// This will be a VALU (output in VGPR) since one operand is VGPR.
// -> [VGPR에 잘 올라감]
float4 v_finalResult = s_someModifier * v_textureSample;
return v_finalResult;
//////////////////////////////////////////////////////////////////////////////////
; Disassembly for GCN (Vega 20)
; -------- Statistics ---------------------
; SGPRs: 27 out of 104 used
; VGPRs: 5 out of 256 used
; LDS: 0 out of 65536 bytes used
; 0 bytes scratch space used
; Instructions: 12 ALU, 3 Control Flow, 1 TFETCH
; -------- Disassembly --------------------
; ****** 각 어셈블리 라인의 우측에 HLSL 코드의 실제 라인을 써뒀으니 참고. ******
shader main
asic(GFX9)
type(PS)
// s_ps_state in s0
s_mov_b32 m0, s24 // 000000000000: BEFC0018
s_mov_b64 s[2:3], exec // 000000000004: BE82017E
s_wqm_b64 exec, exec // 000000000008: BEFE077E // 여기서 float4 v_textureSample = ShaderTextures[0].Sample(SamplerType, Input.Tex);
v_interp_p1_f32 v2, v0, attr0.x // 00000000000C: D4080000 //
v_interp_p1_f32 v3, v0, attr0.y // 000000000010: D40C0100 //
v_interp_p2_f32 v2, v1, attr0.x // 000000000014: D4090001 // 이까지
v_interp_p2_f32 v3, v1, attr0.y // 000000000018: D40D0101
image_sample v[0:3], v[2:4], s[4:11], s[16:19] dmask:0xf // 00000000001C: F0800F00 00810002
s_buffer_load_dword s0, s[20:23], 0x10 // 000000000024: C022000A 00000010 // float s_value = LightDirection.x;
s_buffer_load_dword s1, s[12:15], 0x00 // 00000000002C: C0220046 00000000 // TestInput s_someData = TestStructuredBuffer.Load(0);
s_waitcnt lgkmcnt(0) // 000000000034: BF8CC07F
v_mov_b32 v4, s0 // 000000000038: 7E080200 // float s_value = LightDirection.x;
v_add_f32 v4, s1, v4 // 00000000003C: 02080801 // float s_someModifier = s_value + s_someData.Color.x;
s_waitcnt vmcnt(0) // 000000000040: BF8C0F70
v_mul_f32 v0, v4, v0 // 000000000044: 0A000104 // 여기서 float4 v_finalResult = s_someModifier * v_textureSample;
v_mul_f32 v1, v4, v1 // 000000000048: 0A020304 //
v_mul_f32 v2, v4, v2 // 00000000004C: 0A040504 //
v_mul_f32 v3, v4, v3 // 000000000050: 0A060704 // 이까지
s_mov_b64 exec, s[2:3] // 000000000054: BEFE0102
v_cvt_pkrtz_f16_f32 v0, v0, v1 // 000000000058: D2960000 00020300
v_cvt_pkrtz_f16_f32 v1, v2, v3 // 000000000060: D2960001 00020702
exp mrt0, v0, v0, v1, v1 done compr vm // 000000000068: C4001C0F 00000100 // return v_finalResult;
s_endpgm // 000000000070: BF810000
end
그 외에 더 다양한 툴을 프로파일링에 사용할 수 있는데, 대부분 DX12나 Vulkan에서 사용가능한 것 같네요. 특히, DX12 부터는 Wave intrinsics의 사용이 가능합니다. [번역] INTRO TO GPU SCALARIZATION – PART 1 에서 설명하는 나머지 부분은 API를 숙지하고 다시 해봐야겠네요.
추가
StructuredBuffer에 int를 전달하여 SGPR로 ALU연산이 되는지 한번 확인해봤는데, 실제로 그렇게 됩니다.
/////////////////////////////////////////////////////////////
TestInput s_someData = TestStructuredBuffer.Load(0);
int k = s_someData.Color * s_someData.Color * 2.0;
return k;
/////////////////////////////////////////////////////////////
; Disassembly for GCN (Vega 20)
; -------- Statistics ---------------------
; SGPRs: 11 out of 104 used
; VGPRs: 3 out of 256 used
; LDS: 0 out of 65536 bytes used
; 0 bytes scratch space used
; Instructions: 2 ALU, 2 Control Flow, 0 TFETCH
; -------- Disassembly --------------------
shader main
asic(GFX9)
type(PS)
// s_ps_state in s0
s_buffer_load_dword s0, s[4:7], 0x00 // 000000000000: C0220002 00000000
s_waitcnt lgkmcnt(0) // 000000000008: BF8CC07F
s_mul_i32 s0, s0, s0 // 00000000000C: 92000000 // int k = s_someData.Color * s_someData.Color 부분에 해당
v_cvt_f32_i32 v0, s0 mul:2 // 000000000010: D1450000 08000000 // 위의 결과에 2를 곱함
v_cvt_pkrtz_f16_f32 v0, v0, v0 // 000000000018: D2960000 00020100
s_nop 0x0000 // 000000000020: BF800000
s_nop 0x0000 // 000000000024: BF800000
exp mrt0, v0, v0, v0, v0 done compr vm // 000000000028: C4001C0F 00000000
s_endpgm // 000000000030: BF810000
end
'Graphics > Graphics' 카테고리의 다른 글
| [GPU Gems 3]Advanced Techniques for Realistic Real-Time Skin Rendering (2) | 2020.11.10 |
|---|---|
| Radiometric Quantities (0) | 2020.10.26 |
| Physically-Based Cosmetic Rendering (0) | 2020.09.09 |
| The Structure Buffer (0) | 2020.09.04 |
| Accurate atmospheric scattering (0) | 2020.09.01 |