A game about forced loneliness, made by TACStudios
1#ifndef SHADER_DEBUG_PRINT_INCLUDED
2#define SHADER_DEBUG_PRINT_INCLUDED
3
4// NOTE: For URP - set ENABLE_SHADER_DEBUG_PRINT in the project to enable CPU-side integration.
5// NOTE: Currently works in game view/play mode.
6//
7// Include this header to any shader to enable debug printing values from shader code to console.
8//
9// Select threads/pixels to print using plain 'if'.
10//
11// Example:
12// float4 colorRGBA = float4(0.1, 0.2, 0.3, 0.4);
13// if(all(int2(pixel.xy) == int2(100, 100)))
14// ShaderDebugPrint(ShaderDebugTag('C','o','l'), colorRGBA);
15// ----
16// Output:
17// Frame #270497: Col float4(0.1f, 0.2f, 0.3f, 0.4f)
18// ----
19//
20// Example:
21// #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ShaderDebugPrint.hlsl"
22//
23// Print pixel at mouse position.
24// ShaderDebugPrintMouseOver(int2(thisPixel.xy), pixelColor);
25//
26// Print pixel at mouse position on button press.
27// ShaderDebugPrintMouseButtonOver(int2(thisPixel.xy), pixelColor);
28
29// Output buffer bound with cmd.SetGlobalTexture().
30RWStructuredBuffer<uint> shaderDebugOutputData;
31
32static const uint MaxShaderDebugOutputElements = 1024 * 16; // Must match the C# side buffer size (16K elems / 6 (header+tag+payload) ~= 2730 uint4s)
33
34// Input Constants
35CBUFFER_START(ShaderDebugPrintInput)
36float4 _ShaderDebugPrintInputMouse;
37int _ShaderDebugPrintInputFrame;
38CBUFFER_END
39
40// Mouse coordinates in pixels
41// Relative to game view surface/rendertarget
42// (Typically (0,0) is bottom-left in Unity. TIP: print mouse coords to check if unsure.)
43int2 ShaderDebugMouseCoords() { return _ShaderDebugPrintInputMouse.xy; }
44
45// Mouse buttons
46// Returns true on button down.
47int ShaderDebugMouseButtonLeft() { return _ShaderDebugPrintInputMouse.z; }
48int ShaderDebugMouseButtonRight() { return _ShaderDebugPrintInputMouse.w; }
49int ShaderDebugMouseButton(int button) { return button == 0 ? ShaderDebugMouseButtonLeft() : ShaderDebugMouseButtonRight(); }
50
51int ShaderDebugFrameNumber() { return _ShaderDebugPrintInputFrame; }
52
53// Output Data type encodings
54// Must match C# side decoding
55static const uint ValueTypeUint = 1;
56static const uint ValueTypeInt = 2;
57static const uint ValueTypeFloat = 3;
58static const uint ValueTypeUint2 = 4;
59static const uint ValueTypeInt2 = 5;
60static const uint ValueTypeFloat2 = 6;
61static const uint ValueTypeUint3 = 7;
62static const uint ValueTypeInt3 = 8;
63static const uint ValueTypeFloat3 = 9;
64static const uint ValueTypeUint4 = 10;
65static const uint ValueTypeInt4 = 11;
66static const uint ValueTypeFloat4 = 12;
67static const uint ValueTypeBool = 13;
68static const uint ValueTypeHasTag = 128;
69
70// Data-buffer format
71// 1 uint header
72// 1 uint tag (optional)
73// 1-4 uint value (type dependent)
74//
75// Header format
76// 1 byte Type id + tag flag
77// bits 0..6 value type id/enum
78// bit 7 has tag flag
79// 3 bytes (empty)
80#define PRINT1(TYPE, VALUE, HASTAG, TAG) \
81{ \
82 if (shaderDebugOutputData[0] < MaxShaderDebugOutputElements) \
83 { \
84 uint index; \
85 uint elements = 2; \
86 if (HASTAG) elements++; \
87 InterlockedAdd(shaderDebugOutputData[0], elements, index); \
88 index++; \
89 if (index < MaxShaderDebugOutputElements) \
90 { \
91 shaderDebugOutputData[index++] = TYPE | HASTAG; \
92 if (HASTAG) shaderDebugOutputData[index++] = TAG; \
93 shaderDebugOutputData[index++] = VALUE; \
94 } \
95 } \
96}
97
98#define PRINT2(TYPE, VALUE, HASTAG, TAG) \
99{ \
100 if (shaderDebugOutputData[0] < MaxShaderDebugOutputElements) \
101 { \
102 uint index; \
103 uint elements = 3; \
104 if (HASTAG) elements++; \
105 InterlockedAdd(shaderDebugOutputData[0], elements, index); \
106 index++; \
107 if (index < MaxShaderDebugOutputElements) \
108 { \
109 shaderDebugOutputData[index++] = TYPE | HASTAG; \
110 if (HASTAG) shaderDebugOutputData[index++] = TAG; \
111 shaderDebugOutputData[index++] = VALUE.x; \
112 shaderDebugOutputData[index++] = VALUE.y; \
113 } \
114 } \
115}
116
117#define PRINT3(TYPE, VALUE, HASTAG, TAG) \
118{ \
119 if (shaderDebugOutputData[0] < MaxShaderDebugOutputElements) \
120 { \
121 uint index; \
122 uint elements = 4; \
123 if (HASTAG) elements++; \
124 InterlockedAdd(shaderDebugOutputData[0], elements, index); \
125 index++; \
126 if (index < MaxShaderDebugOutputElements) \
127 { \
128 shaderDebugOutputData[index++] = TYPE | HASTAG; \
129 if (HASTAG) shaderDebugOutputData[index++] = TAG; \
130 shaderDebugOutputData[index++] = VALUE.x; \
131 shaderDebugOutputData[index++] = VALUE.y; \
132 shaderDebugOutputData[index++] = VALUE.z; \
133 } \
134 } \
135}
136
137#define PRINT4(TYPE, VALUE, HASTAG, TAG) \
138{ \
139 if (shaderDebugOutputData[0] < MaxShaderDebugOutputElements) \
140 { \
141 uint index; \
142 uint elements = 5; \
143 if (HASTAG) elements++; \
144 InterlockedAdd(shaderDebugOutputData[0], elements, index); \
145 index++; \
146 if (index < MaxShaderDebugOutputElements) \
147 { \
148 shaderDebugOutputData[index++] = TYPE | HASTAG; \
149 if (HASTAG) shaderDebugOutputData[index++] = TAG; \
150 shaderDebugOutputData[index++] = VALUE.x; \
151 shaderDebugOutputData[index++] = VALUE.y; \
152 shaderDebugOutputData[index++] = VALUE.z; \
153 shaderDebugOutputData[index++] = VALUE.w; \
154 } \
155 } \
156}
157
158static const uint ShaderDebugNoTag;
159
160// Create 1-4 letter tags encoded into a uint
161// For example
162// ShaderDebugTag( 'M', 'y', 'I', 'd' );
163uint ShaderDebugTag(uint a, uint b, uint c, uint d) { return a | (b << 8) | (c << 16) | (d << 24); }
164uint ShaderDebugTag(uint a, uint b, uint c) { return ShaderDebugTag( a, b, c, 0); }
165uint ShaderDebugTag(uint a, uint b) { return ShaderDebugTag( a, b, 0); }
166uint ShaderDebugTag(uint a) { return ShaderDebugTag( a, 0); }
167
168// Print value to (Unity) console
169// Be careful to not print all N threads (thousands). Use if statements and thread ids to pick values only from a few threads.
170// (tag), an optional text tag for the print. Use ShaderDebugTag() helper to create.
171// value, to be printed
172void ShaderDebugPrint(uint tag, bool value) PRINT1(ValueTypeBool, uint(value), ValueTypeHasTag, tag);
173void ShaderDebugPrint(uint tag, uint value) PRINT1(ValueTypeUint, value, ValueTypeHasTag, tag);
174void ShaderDebugPrint(uint tag, int value) PRINT1(ValueTypeInt, asuint(value), ValueTypeHasTag, tag);
175void ShaderDebugPrint(uint tag, float value) PRINT1(ValueTypeFloat, asuint(value), ValueTypeHasTag, tag);
176void ShaderDebugPrint(uint tag, uint2 value) PRINT2(ValueTypeUint2, value, ValueTypeHasTag, tag)
177void ShaderDebugPrint(uint tag, int2 value) PRINT2(ValueTypeInt2, asuint(value), ValueTypeHasTag, tag)
178void ShaderDebugPrint(uint tag, float2 value) PRINT2(ValueTypeFloat2, asuint(value), ValueTypeHasTag, tag)
179void ShaderDebugPrint(uint tag, uint3 value) PRINT3(ValueTypeUint3, value, ValueTypeHasTag, tag)
180void ShaderDebugPrint(uint tag, int3 value) PRINT3(ValueTypeInt3, asuint(value), ValueTypeHasTag, tag)
181void ShaderDebugPrint(uint tag, float3 value) PRINT3(ValueTypeFloat3, asuint(value), ValueTypeHasTag, tag)
182void ShaderDebugPrint(uint tag, uint4 value) PRINT4(ValueTypeUint4, value, ValueTypeHasTag, tag)
183void ShaderDebugPrint(uint tag, int4 value) PRINT4(ValueTypeInt4, asuint(value), ValueTypeHasTag, tag)
184void ShaderDebugPrint(uint tag, float4 value) PRINT4(ValueTypeFloat4, asuint(value), ValueTypeHasTag, tag)
185void ShaderDebugPrint(bool value) PRINT1(ValueTypeBool, uint(value), 0, ShaderDebugNoTag)
186void ShaderDebugPrint(uint value) PRINT1(ValueTypeUint, value, 0, ShaderDebugNoTag)
187void ShaderDebugPrint(int value) PRINT1(ValueTypeInt, asuint(value), 0, ShaderDebugNoTag)
188void ShaderDebugPrint(float value) PRINT1(ValueTypeFloat, asuint(value), 0, ShaderDebugNoTag)
189void ShaderDebugPrint(uint2 value) PRINT2(ValueTypeUint2, value, 0, ShaderDebugNoTag)
190void ShaderDebugPrint(int2 value) PRINT2(ValueTypeInt2, asuint(value), 0, ShaderDebugNoTag)
191void ShaderDebugPrint(float2 value) PRINT2(ValueTypeFloat2, asuint(value), 0, ShaderDebugNoTag)
192void ShaderDebugPrint(uint3 value) PRINT3(ValueTypeUint3, value, 0, ShaderDebugNoTag)
193void ShaderDebugPrint(int3 value) PRINT3(ValueTypeInt3, asuint(value), 0, ShaderDebugNoTag)
194void ShaderDebugPrint(float3 value) PRINT3(ValueTypeFloat3, asuint(value), 0, ShaderDebugNoTag)
195void ShaderDebugPrint(uint4 value) PRINT4(ValueTypeUint4, value, 0, ShaderDebugNoTag)
196void ShaderDebugPrint(int4 value) PRINT4(ValueTypeInt4, asuint(value), 0, ShaderDebugNoTag)
197void ShaderDebugPrint(float4 value) PRINT4(ValueTypeFloat4, asuint(value), 0, ShaderDebugNoTag)
198
199#undef PRINT1
200#undef PRINT2
201#undef PRINT3
202#undef PRINT4
203
204#define PRINT_MOUSE(VALUE) \
205{ \
206 if(all(pixelPos == ShaderDebugMouseCoords())) \
207 ShaderDebugPrint(VALUE); \
208}
209
210#define PRINT_MOUSE_WITH_TAG(VALUE, TAG) \
211{ \
212 if(all(pixelPos == ShaderDebugMouseCoords())) \
213 ShaderDebugPrint(TAG, VALUE); \
214}
215
216// Print value for pixel under mouse cursor
217// pixelPos, screen pixel coordinates for this fragment shader thread. Typically .xy of fragment shader input parameter with SV_Position semantic.
218// NOTE: Any render target scaling (or offset) is NOT taken into account as that can be arbitrary. You must correct scaling manually.
219// (For example: fragment.xy * _ScreenParams.xy / _ScaledScreenParams.xy or similar)
220// TIP: Color the pixel (or a box) at mouse coords to debug scaling/offset.
221// (tag), an optional text tag for the print. Use ShaderDebugTag() helper to create.
222// value, to be printed
223void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, bool value) PRINT_MOUSE_WITH_TAG(value, tag);
224void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, uint value) PRINT_MOUSE_WITH_TAG(value, tag);
225void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, int value) PRINT_MOUSE_WITH_TAG(value, tag);
226void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, float value) PRINT_MOUSE_WITH_TAG(value, tag);
227void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, uint2 value) PRINT_MOUSE_WITH_TAG(value, tag);
228void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, int2 value) PRINT_MOUSE_WITH_TAG(value, tag);
229void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, float2 value) PRINT_MOUSE_WITH_TAG(value, tag);
230void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, uint3 value) PRINT_MOUSE_WITH_TAG(value, tag);
231void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, int3 value) PRINT_MOUSE_WITH_TAG(value, tag);
232void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, float3 value) PRINT_MOUSE_WITH_TAG(value, tag);
233void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, uint4 value) PRINT_MOUSE_WITH_TAG(value, tag);
234void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, int4 value) PRINT_MOUSE_WITH_TAG(value, tag);
235void ShaderDebugPrintMouseOver(int2 pixelPos, uint tag, float4 value) PRINT_MOUSE_WITH_TAG(value, tag);
236void ShaderDebugPrintMouseOver(int2 pixelPos, bool value) PRINT_MOUSE(value);
237void ShaderDebugPrintMouseOver(int2 pixelPos, uint value) PRINT_MOUSE(value);
238void ShaderDebugPrintMouseOver(int2 pixelPos, int value) PRINT_MOUSE(value);
239void ShaderDebugPrintMouseOver(int2 pixelPos, float value) PRINT_MOUSE(value);
240void ShaderDebugPrintMouseOver(int2 pixelPos, uint2 value) PRINT_MOUSE(value);
241void ShaderDebugPrintMouseOver(int2 pixelPos, int2 value) PRINT_MOUSE(value);
242void ShaderDebugPrintMouseOver(int2 pixelPos, float2 value) PRINT_MOUSE(value);
243void ShaderDebugPrintMouseOver(int2 pixelPos, uint3 value) PRINT_MOUSE(value);
244void ShaderDebugPrintMouseOver(int2 pixelPos, int3 value) PRINT_MOUSE(value);
245void ShaderDebugPrintMouseOver(int2 pixelPos, float3 value) PRINT_MOUSE(value);
246void ShaderDebugPrintMouseOver(int2 pixelPos, uint4 value) PRINT_MOUSE(value);
247void ShaderDebugPrintMouseOver(int2 pixelPos, int4 value) PRINT_MOUSE(value);
248void ShaderDebugPrintMouseOver(int2 pixelPos, float4 value) PRINT_MOUSE(value);
249
250#undef PRINT_MOUSE
251#undef PRINT_MOUSE_WITH_TAG
252
253#define PRINT_MOUSE_BUTTON(BUTTON, VALUE) \
254{ \
255 if(ShaderDebugMouseButton(BUTTON) && all(pixelPos == ShaderDebugMouseCoords())) \
256 ShaderDebugPrint(VALUE); \
257}
258
259#define PRINT_MOUSE_BUTTON_WITH_TAG(BUTTON, VALUE, TAG) \
260{ \
261 if(ShaderDebugMouseButton(BUTTON) && all(pixelPos == ShaderDebugMouseCoords())) \
262 ShaderDebugPrint(TAG, VALUE); \
263}
264
265// Print value for pixel under mouse cursor when mouse left button is pressed
266// pixelPos, screen pixel coordinates for this fragment shader thread. Typically .xy of fragment shader input parameter with SV_Position semantic.
267// (tag), an optional text tag for the print. Use ShaderDebugTag() helper to create.
268// value, to be printed
269void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, bool value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
270void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, uint value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
271void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, int value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
272void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, float value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
273void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, uint2 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
274void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, int2 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
275void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, float2 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
276void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, uint3 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
277void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, int3 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
278void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, float3 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
279void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, uint4 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
280void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, int4 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
281void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint tag, float4 value) PRINT_MOUSE_BUTTON_WITH_TAG(0, value, tag);
282void ShaderDebugPrintMouseButtonOver(int2 pixelPos, bool value) PRINT_MOUSE_BUTTON(0, value);
283void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint value) PRINT_MOUSE_BUTTON(0, value);
284void ShaderDebugPrintMouseButtonOver(int2 pixelPos, int value) PRINT_MOUSE_BUTTON(0, value);
285void ShaderDebugPrintMouseButtonOver(int2 pixelPos, float value) PRINT_MOUSE_BUTTON(0, value);
286void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint2 value) PRINT_MOUSE_BUTTON(0, value);
287void ShaderDebugPrintMouseButtonOver(int2 pixelPos, int2 value) PRINT_MOUSE_BUTTON(0, value);
288void ShaderDebugPrintMouseButtonOver(int2 pixelPos, float2 value) PRINT_MOUSE_BUTTON(0, value);
289void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint3 value) PRINT_MOUSE_BUTTON(0, value);
290void ShaderDebugPrintMouseButtonOver(int2 pixelPos, int3 value) PRINT_MOUSE_BUTTON(0, value);
291void ShaderDebugPrintMouseButtonOver(int2 pixelPos, float3 value) PRINT_MOUSE_BUTTON(0, value);
292void ShaderDebugPrintMouseButtonOver(int2 pixelPos, uint4 value) PRINT_MOUSE_BUTTON(0, value);
293void ShaderDebugPrintMouseButtonOver(int2 pixelPos, int4 value) PRINT_MOUSE_BUTTON(0, value);
294void ShaderDebugPrintMouseButtonOver(int2 pixelPos, float4 value) PRINT_MOUSE_BUTTON(0, value);
295
296#undef PRINT_MOUSE_BUTTON
297#undef PRINT_MOUSE_BUTTON_WITH_TAG
298
299#endif // SHADER_DEBUG_PRINT_INCLUDED