DirectXShaderCompiler icon indicating copy to clipboard operation
DirectXShaderCompiler copied to clipboard

Request for basic string support in HLSL

Open TheRealMJP opened this issue 2 years ago • 3 comments

Hello,

Since DXC + D3D12 currently don't have support for a shader printf (it's supported for Vulkan/SPIR-V, and fxc supported it for the old reference rasterizer), we currently have our own system built into our engine that can emulate basic debug printing through shader atomics and readback buffers. However, this functionality is quite awkward to use since HLSL also lacks any support for passing string literals and iterating over the characters. To work around this, we currently have many overloads of our DebugPrint function and pass characters one by one as uint arguments:

DebugPrint('H', 'e, 'l', 'l', 'o', '!');

It would be really great if we could properly pass a string literal instead, and also be able to know the number of characters and iterate over them as integers. For this use case we really only care about strings that are defined at compile-time, and we don't need to modify the strings in any way. Even something that could convert the string literal to an array of uint could potentially be a lot more usable than what we currently do.

Thanks in advance!

-Matt

TheRealMJP avatar Oct 16 '21 01:10 TheRealMJP

In my opinion, the thing that would be more useful/interesting here would be the ability to write a string in a shader and get a unique handle/pointer to it. If that unique value is then written into a buffer, then the CPU-side code would be able to use shader reflection to convert it back into the original string literal - i.e. store the actual string data in reflection metadata rather than the shader code itself.

IMO this has 2 advantages:

  1. Smaller shader code actually running on the GPU.
  2. The writes are then fixed-size, aligned (4-byte or 8-byte depending on how the handle is implemented) writes, rather than arbitrary strings that could be any number of unaligned bytes.

This is essentially what I did for implementing printf in OpenCLOn12, except I had a separate side channel for the string identifiers that wasn't in DXIL reflection data.

jenatali avatar Oct 16 '21 12:10 jenatali

@jenatali Both static reflectable strings and more dynamic c-style character array strings are useful. The use case for the latter is a GPU-timeline dynamic debug text printing / visualizations, without CPU involvement. This kind of thing is necessary if one wants to overlay debug visualizations on top of the exact frame that was rendered, without readback lag.

In Unreal Engine we have implemented a custom shader preprocessing pass that sifts through the code and pulls out all instances of TEXT("foo") into a global string character table that's just dumped at the top of the original shader code as uint g_strings[...];. Original macro use sites are replaced with offset+length integer pairs (i.e. GPU string_view). The consumer of this string view then just loops over the characters and dumps them into a buffer that's later used by debug font blitter in the same frame.

While we can just continue to use our custom preprocessor in UE, I believe having built-in functionality like this in DXC will be very useful to many others.

kayru avatar Oct 16 '21 19:10 kayru

I'm going to voice my support for this request here. I agree that both the reflected and C-style representations have their merit based on the points @kayru mentioned. This would open up a large amount of debugging avenues for developers without requiring a heavy investment or added complexity in their shader compilation pipeline.

gkaerts avatar Oct 16 '21 21:10 gkaerts