move shader debug implementation to backend layer

This commit is contained in:
jacob 2025-12-09 15:34:50 -06:00
parent 3bf89a8911
commit bb8f105309
13 changed files with 265 additions and 249 deletions

View File

@ -765,23 +765,24 @@ Struct(SamplerStateHandle) { u32 v; };
//- Shader constants //- Shader constants
/* D3D12: 64 maximum root constants /*
* Vulkan: 32 maximum push constants * NOTE: D3d12 exposes 64 root constants, and vulkan 32 push constants.
* * Other constants past the max can be used by the graphics
* implementation backend layer.
*/ */
#define MaxShaderConstants (32) #define MaxShaderConstants (8)
#define MaxDeclarableShaderConstants (MaxShaderConstants - 1) /* 1 constant reserved for generic async compute queue check */
#if IsLanguageC #if IsLanguageC
#define ShaderConstant(type, name, slot) \ #define ForceShaderConstant(type, name, slot) \
StaticAssert(sizeof(type) <= 4); \
StaticAssert(slot < MaxDeclarableShaderConstants); \
Enum(name##__shaderconstantenum) { name = slot }; \ Enum(name##__shaderconstantenum) { name = slot }; \
Struct(name##__shaderconstanttype) { type v; } Struct(name##__shaderconstanttype) { type v; }
#define ShaderConstant(type, name, slot) \
StaticAssert(sizeof(type) <= 4); \
StaticAssert(slot < MaxShaderConstants); \
ForceShaderConstant(type, name, slot)
#elif IsLanguageG #elif IsLanguageG
#define ShaderConstant(type, name, slot) cbuffer name : register(b##slot) { type name; } #define ForceShaderConstant(type, name, slot) cbuffer name : register(b##slot) { type name; }
#define ShaderConstant(type, name, slot) ForceShaderConstant(type, name, slot)
cbuffer IsAsyncCompute : register(b31) { b32 IsAsyncCompute; }
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -115,3 +115,203 @@ Vec2 NdcFromUv(Vec2 uv)
result += Vec2(-1, 1); result += Vec2(-1, 1);
return result; return result;
} }
////////////////////////////////////////////////////////////
//~ String helpers
/* https://therealmjp.github.io/posts/hlsl-printf/ */
template<typename T>
u32 U32FromChar(in T c)
{
if(c == ' ')
return 32;
if(c == '!')
return 33;
if(c == '\"' || c == '\"')
return 34;
if(c == '#')
return 35;
if(c == '$')
return 36;
if(c == '%')
return 37;
if(c == '&')
return 38;
if(c == '\'')
return 39;
if(c == '(')
return 40;
if(c == ')')
return 41;
if(c == '*')
return 42;
if(c == '+')
return 43;
if(c == ',')
return 44;
if(c == '-')
return 45;
if(c == '.')
return 46;
if(c == '/')
return 47;
if(c == '0')
return 48;
if(c == '1')
return 49;
if(c == '2')
return 50;
if(c == '3')
return 51;
if(c == '4')
return 52;
if(c == '5')
return 53;
if(c == '6')
return 54;
if(c == '7')
return 55;
if(c == '8')
return 56;
if(c == '9')
return 57;
if(c == ':')
return 58;
if(c == ';')
return 59;
if(c == '<')
return 60;
if(c == '=')
return 61;
if(c == '>')
return 62;
if(c == '?')
return 63;
if(c == '@')
return 64;
if(c == 'A')
return 65;
if(c == 'B')
return 66;
if(c == 'C')
return 67;
if(c == 'D')
return 68;
if(c == 'E')
return 69;
if(c == 'F')
return 70;
if(c == 'G')
return 71;
if(c == 'H')
return 72;
if(c == 'I')
return 73;
if(c == 'J')
return 74;
if(c == 'K')
return 75;
if(c == 'L')
return 76;
if(c == 'M')
return 77;
if(c == 'N')
return 78;
if(c == 'O')
return 79;
if(c == 'P')
return 80;
if(c == 'Q')
return 81;
if(c == 'R')
return 82;
if(c == 'S')
return 83;
if(c == 'T')
return 84;
if(c == 'U')
return 85;
if(c == 'V')
return 86;
if(c == 'W')
return 87;
if(c == 'X')
return 88;
if(c == 'Y')
return 89;
if(c == 'Z')
return 90;
if(c == '[')
return 91;
if(c == '\\')
return 92;
if(c == ']')
return 93;
if(c == '^')
return 94;
if(c == '_')
return 95;
if(c == '`')
return 96;
if(c == 'a')
return 97;
if(c == 'b')
return 98;
if(c == 'c')
return 99;
if(c == 'd')
return 100;
if(c == 'e')
return 101;
if(c == 'f')
return 102;
if(c == 'g')
return 103;
if(c == 'h')
return 104;
if(c == 'i')
return 105;
if(c == 'j')
return 106;
if(c == 'k')
return 107;
if(c == 'l')
return 108;
if(c == 'm')
return 109;
if(c == 'n')
return 110;
if(c == 'o')
return 111;
if(c == 'p')
return 112;
if(c == 'q')
return 113;
if(c == 'r')
return 114;
if(c == 's')
return 115;
if(c == 't')
return 116;
if(c == 'u')
return 117;
if(c == 'v')
return 118;
if(c == 'w')
return 119;
if(c == 'x')
return 120;
if(c == 'y')
return 121;
if(c == 'z')
return 122;
if(c == '{')
return 123;
if(c == '|')
return 124;
if(c == '}')
return 125;
if(c == '~')
return 126;
return 0;
}

View File

@ -16,8 +16,9 @@
@IncludeC gpu_core.h @IncludeC gpu_core.h
@IncludeC gpu_shader_extras.cgh @IncludeC gpu_shader_extras.cgh
@IncludeC gpu_common.h @IncludeC gpu_common.h
@IncludeG gpu_shader_core.gh
@IncludeG gpu_shader_extras.cgh @IncludeG gpu_shader_extras.cgh
@IncludeG gpu_shader_extras.gh
@Bootstrap GPU_Bootstrap @Bootstrap GPU_Bootstrap
@Bootstrap GPU_BootstrapExtra @Bootstrap GPU_BootstrapExtra

View File

@ -3,9 +3,11 @@
////////////////////////////// //////////////////////////////
//- Api //- Api
@IncludeC gpu_dx12.h @IncludeC gpu_dx12_core.h
@IncludeG gpu_dx12_shader_core.gh
////////////////////////////// //////////////////////////////
//- Impl //- Impl
@IncludeC gpu_dx12.c @IncludeC gpu_dx12_core.c

View File

@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////
//~ Debug types
////////////////////////////////////////////////////////////
//~ Debug globals
// RWByteAddressBufferHandle print_buff;
StaticAssert(MaxShaderConstants == 8); /* Slots used below assume they won't overlap user shader constants */
ForceShaderConstant(RWByteAddressBufferHandle, GPU_D12_DebugPrintBuff, 9);
// cbuffer GPU_D12_DebugPrintCbuff_ : register(b9) { RWByteAddressBufferHandle print_buff; }
////////////////////////////////////////////////////////////
//~ @hookimpl Shader printf
/* This technique comes from MJP's article: https://therealmjp.github.io/posts/hlsl-printf/ */
#if GPU_DEBUG
#define DebugPrintImpl_(fmt_cstr) do { \
u32 __strlen = 0; \
for (;;) { if (U32FromChar(fmt_cstr[__strlen]) == 0) { break; } ++__strlen; } \
RWByteAddressBuffer __print_buff; \
__print_buff = RWByteAddressBufferFromHandle(GPU_D12_DebugPrintBuff); \
u32 __pos; \
__print_buff.InterlockedAdd(0, __strlen, __pos); \
if (__pos < countof(__print_buff)) \
{ \
for (u32 char_idx = 0; char_idx < __strlen; ++char_idx) \
{ \
__print_buff.Store(__pos + char_idx, U32FromChar(fmt_cstr[char_idx])); \
} \
} \
} while (0)
#else
#define DebugPrintImpl_(fmt_cstr)
#endif

View File

@ -0,0 +1,5 @@
////////////////////////////////////////////////////////////
//~ @hookdecl Shader printf
/* Implemented per graphics platform layer */
#define DebugPrint(msg) DebugPrintImpl_(msg)

View File

@ -7,9 +7,5 @@
#define GPU_SharedHandle(type, v) (type(v)) #define GPU_SharedHandle(type, v) (type(v))
#endif #endif
#define GPU_DebugPrintBufferSize Mebi(128) #define GPU_BasicPointSampler GPU_SharedHandle(SamplerStateHandle, 1)
#define GPU_BasicNoiseTexture GPU_SharedHandle(Texture3DHandle, 2)
#define GPU_DirectQueueDebugPrintBuffer GPU_SharedHandle(RWByteAddressBufferHandle, 1)
#define GPU_AsyncComputeQueueDebugPrintBuffer GPU_SharedHandle(RWByteAddressBufferHandle, 2)
#define GPU_BasicPointSampler GPU_SharedHandle(SamplerStateHandle, 3)
#define GPU_BasicNoiseTexture GPU_SharedHandle(Texture3DHandle, 4)

View File

@ -1,229 +0,0 @@
////////////////////////////////////////////////////////////
//~ Shader printf
/* This technique comes from MJP's article:
* https://therealmjp.github.io/posts/hlsl-printf/
*/
template<typename T>
u32 U32FromChar(in T c)
{
if(c == ' ')
return 32;
if(c == '!')
return 33;
if(c == '\"' || c == '\"')
return 34;
if(c == '#')
return 35;
if(c == '$')
return 36;
if(c == '%')
return 37;
if(c == '&')
return 38;
if(c == '\'')
return 39;
if(c == '(')
return 40;
if(c == ')')
return 41;
if(c == '*')
return 42;
if(c == '+')
return 43;
if(c == ',')
return 44;
if(c == '-')
return 45;
if(c == '.')
return 46;
if(c == '/')
return 47;
if(c == '0')
return 48;
if(c == '1')
return 49;
if(c == '2')
return 50;
if(c == '3')
return 51;
if(c == '4')
return 52;
if(c == '5')
return 53;
if(c == '6')
return 54;
if(c == '7')
return 55;
if(c == '8')
return 56;
if(c == '9')
return 57;
if(c == ':')
return 58;
if(c == ';')
return 59;
if(c == '<')
return 60;
if(c == '=')
return 61;
if(c == '>')
return 62;
if(c == '?')
return 63;
if(c == '@')
return 64;
if(c == 'A')
return 65;
if(c == 'B')
return 66;
if(c == 'C')
return 67;
if(c == 'D')
return 68;
if(c == 'E')
return 69;
if(c == 'F')
return 70;
if(c == 'G')
return 71;
if(c == 'H')
return 72;
if(c == 'I')
return 73;
if(c == 'J')
return 74;
if(c == 'K')
return 75;
if(c == 'L')
return 76;
if(c == 'M')
return 77;
if(c == 'N')
return 78;
if(c == 'O')
return 79;
if(c == 'P')
return 80;
if(c == 'Q')
return 81;
if(c == 'R')
return 82;
if(c == 'S')
return 83;
if(c == 'T')
return 84;
if(c == 'U')
return 85;
if(c == 'V')
return 86;
if(c == 'W')
return 87;
if(c == 'X')
return 88;
if(c == 'Y')
return 89;
if(c == 'Z')
return 90;
if(c == '[')
return 91;
if(c == '\\')
return 92;
if(c == ']')
return 93;
if(c == '^')
return 94;
if(c == '_')
return 95;
if(c == '`')
return 96;
if(c == 'a')
return 97;
if(c == 'b')
return 98;
if(c == 'c')
return 99;
if(c == 'd')
return 100;
if(c == 'e')
return 101;
if(c == 'f')
return 102;
if(c == 'g')
return 103;
if(c == 'h')
return 104;
if(c == 'i')
return 105;
if(c == 'j')
return 106;
if(c == 'k')
return 107;
if(c == 'l')
return 108;
if(c == 'm')
return 109;
if(c == 'n')
return 110;
if(c == 'o')
return 111;
if(c == 'p')
return 112;
if(c == 'q')
return 113;
if(c == 'r')
return 114;
if(c == 's')
return 115;
if(c == 't')
return 116;
if(c == 'u')
return 117;
if(c == 'v')
return 118;
if(c == 'w')
return 119;
if(c == 'x')
return 120;
if(c == 'y')
return 121;
if(c == 'z')
return 122;
if(c == '{')
return 123;
if(c == '|')
return 124;
if(c == '}')
return 125;
if(c == '~')
return 126;
return 0;
}
#if GPU_DEBUG
#define DebugPrint(fmt_cstr) do { \
u32 __strlen = 0; \
for (;;) { if (U32FromChar(fmt_cstr[__strlen]) == 0) { break; } ++__strlen; } \
RWByteAddressBuffer __print_buff; \
if (IsAsyncCompute) \
{ \
__print_buff = RWByteAddressBufferFromHandle(GPU_AsyncComputeQueueDebugPrintBuffer); \
} \
else \
{ \
__print_buff = RWByteAddressBufferFromHandle(GPU_DirectQueueDebugPrintBuffer); \
} \
u32 __pos; \
__print_buff.InterlockedAdd(0, __strlen, __pos); \
if (__pos < countof(__print_buff)) \
{ \
for (u32 char_idx = 0; char_idx < __strlen; ++char_idx) \
{ \
__print_buff.Store(__pos + char_idx, U32FromChar(fmt_cstr[char_idx])); \
} \
} \
} while (0)
#else
#define DebugPrint(...)
#endif

View File

@ -28,6 +28,7 @@
@IncludeC pp_vis_shaders.cgh @IncludeC pp_vis_shaders.cgh
@IncludeC pp_vis_draw.h @IncludeC pp_vis_draw.h
@IncludeC pp_vis_core.h @IncludeC pp_vis_core.h
@IncludeG pp_vis_shaders.cgh @IncludeG pp_vis_shaders.cgh
@Bootstrap V_Bootstrap @Bootstrap V_Bootstrap
@ -38,4 +39,5 @@
@IncludeC pp_vis_widgets.c @IncludeC pp_vis_widgets.c
@IncludeC pp_vis_draw.c @IncludeC pp_vis_draw.c
@IncludeC pp_vis_core.c @IncludeC pp_vis_core.c
@IncludeG pp_vis_shaders.g @IncludeG pp_vis_shaders.g

View File

@ -26,4 +26,5 @@
//- Impl //- Impl
@IncludeC proto.c @IncludeC proto.c
@IncludeG proto_shaders.g @IncludeG proto_shaders.g

View File

@ -23,6 +23,7 @@
@IncludeC ui_core.h @IncludeC ui_core.h
@IncludeC ui_extras.h @IncludeC ui_extras.h
@IncludeC ui_shaders.cgh @IncludeC ui_shaders.cgh
@IncludeG ui_shaders.cgh @IncludeG ui_shaders.cgh
@Bootstrap UI_Bootstrap @Bootstrap UI_Bootstrap