Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request for basic string support in HLSL #279

Open
TheRealMJP opened this issue Oct 16, 2021 · 4 comments
Open

Request for basic string support in HLSL #279

TheRealMJP opened this issue Oct 16, 2021 · 4 comments
Labels
enhancement New feature or request
Milestone

Comments

@TheRealMJP
Copy link

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

@jenatali
Copy link
Member

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.

@kayru
Copy link

kayru commented Oct 16, 2021

@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.

@gkaerts
Copy link

gkaerts commented Oct 16, 2021

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.

@bob80905 bob80905 self-assigned this Aug 22, 2022
@osor-io
Copy link

osor-io commented May 8, 2023

In case this can help aleviate the pain @TheRealMJP (or anyone else that ends up in this issue). I found out a couple of ways that you can pass in a string as an array of uints and still have access to the count, so you can iterate or do more fancy stuff.

The most somewhat sensible way to do this that I found is by using templates (forgive me shader gods, for I have sinned), if you have access to HLSL 2021. You can just do:

template<uint STRING_SIZE>
void use_my_string(uint the_string[STRING_SIZE])
{
    for (uint i = 0; i < STRING_SIZE; ++i)
    {
        uint character = the_string[i];
        /* . . . do stuff . . . */
    }
}

uint hello[] = { 'H', 'e', 'l', 'l', 'o', '!' };
use_my_string(hello);

You can do this without templates by using a macro, although if you want to return something you'll want something like "statement expressions", which looks something like int a = ({ int b = 1; b; }) since this lets you put arbitrary code in there and keep it scoped, while still "returning" the last expression. It can look something like this:

#define use_my_string(the_string)                                  \
({                                                                 \
    uint string_size = (sizeof(the_string)/sizeof(the_string[0])); \
    for (uint i = 0; i < string_size; ++i)                         \
    {                                                              \
        uint character = the_string[i];                            \
        /* . . . do stuff . . . */                                 \
    }                                                              \
})

uint hello[] = { 'H', 'e', 'l', 'l', 'o', '!' };
use_my_string(hello);

This said, the most annoying bit is to write the string itself. Where you still need to write each character in the array separately. It would be super nice if the following was possible, as @TheRealMJP was saying:

uint hello[] = "Hello!";

@damyanp damyanp transferred this issue from microsoft/DirectXShaderCompiler Jul 23, 2024
@damyanp damyanp added the enhancement New feature or request label Aug 8, 2024
@damyanp damyanp moved this to Triaged in HLSL Triage Aug 8, 2024
@damyanp damyanp added this to the HLSL Backlog milestone Aug 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Triaged
Development

No branches or pull requests

7 participants