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

Add debug_printf! and debug_printfln! macros that uses the DebugPrintf extension #768

Merged
merged 33 commits into from
Oct 23, 2021

Conversation

expenses
Copy link
Contributor

See #151.

This will probably require some work before being merged. These macros and different from the core rust print and println macros as the type of variables needs to be specified in the format string. There's probably a way to change this as mentioned here: #151 (comment) but for now I'm doing the simpler thing.

I have a branch here: main...expenses:printf-working that modifies the sky shader and ash runner for testing. It requires 'Debug Printf' to be checked in the Vulkan Configuration app.

One important caveat is that using DebugPrintf seems to SEGFAULT (on Windows I get a (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)) the Vulkan program if you build a single module with multiple entry points. This is truely bizarre, no clue what's going on here. The only difference between working code and segfaulting code is this: expenses/rust-gpu@expenses:printf-not-working...printf-working.

At first I thought this was a driver issue but I'm getting this on both an integrated intel gpu and an external amd gpu.

@expenses expenses changed the title Add printf and printfln macros that uses the DebugPrintf extension Add printf! and printfln! macros that uses the DebugPrintf extension Oct 16, 2021
@expenses
Copy link
Contributor Author

Actually, I do get this validation error so it's not like the segfault is coming out of nowhere:
[ERROR] [Debug Msg][validation] "Validation Error: [ UNASSIGNED-Debug-Printf ] Object 0: handle = 0x24b805bb370, name = Device, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x9472fbd3 | Error during shader instrumentation: line 0: Mixed stage shader module not supported"

@expenses
Copy link
Contributor Author

expenses commented Oct 16, 2021

Fun fact: you can print emojis using these macros. I was pleasantly surprised that unicode didn't get mangled somehow.

Copy link
Contributor

@khyperia khyperia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add some sort of check on vulkan to avoid the "Mixed stage shader module not supported" obscure issue, seems pretty confusing especially if validation layers are disabled.

It's also rather unfortunate that we can't do typechecking on the format string, that really sucks, but oh well I guess.

Also, I have a vague preference to call it debug_printf, but I could go either way.

Out of curiosity, what's the error message when calling it outside of an unsafe block?

crates/spirv-std/macros/src/lib.rs Outdated Show resolved Hide resolved
crates/spirv-std/macros/src/lib.rs Outdated Show resolved Hide resolved
tests/ui/arch/printf.rs Outdated Show resolved Hide resolved
@expenses
Copy link
Contributor Author

It's also rather unfortunate that we can't do typechecking on the format string, that really sucks, but oh well I guess.

I think we probably could do some kind of typechecking. If we had a function like this:

fn assert_is_type<T>(ty: T) -> T {
  ty
}

we could map each format argument to the rust type - %f to f32 for example - and wrap each one in assert_is_type::<T> before using them. It's a bit gross but it would work.

What I believe we can't do is any kind of type inference.

Also, I have a vague preference to call it debug_printf, but I could go either way.

👍

Out of curiosity, what's the error message when calling it outside of an unsafe block?

It's the same as calling an asm! macro outside of unsafe - use of inline assembly is unsafe and requires unsafe function or block

@expenses expenses requested a review from khyperia October 18, 2021 11:39
@expenses
Copy link
Contributor Author

expenses commented Oct 18, 2021

we could map each format argument to the rust type - %f to f32 for example - and wrap each one in assert_is_type::<T> before using them. It's a bit gross but it would work.

I did a test of this (just assuming every format argument is f32) and it actually works quite nicely:

error[E0308]: mismatched types
  --> $DIR/debug_printf.rs:41:31
   |
41 |         debug_printfln!("%f", vec);
   |                               ^^^ expected `f32`, found struct `Vec2`

Commit: expenses@a76222b updated: expenses@b545f6b

Copy link
Contributor

@khyperia khyperia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fantastic! feel free to merge the typechecking, too, that'd be really nice to have.

Comment on lines 466 to 469
quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #count> }
} else {
let ty = map_specifier_to_type(specifier);
quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that this assumes that spirv_std is in scope like this. Not sure what else we can do though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it's an open issue rust-lang/rust#54363

@expenses expenses requested a review from khyperia October 21, 2021 08:16
"ul" => quote::quote! { u64 },
"lu" => quote::quote! { u64 },
"lx" => quote::quote! { u64 },
_ => unreachable!(),
Copy link
Contributor

@khyperia khyperia Oct 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized, there's no support here for f64 or int sizes under 32 bits - I would have expected there to be support, where are you finding the docs for what specifiers correspond to what types? sorry, missed the bit in the linked document

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh haha, I actually missed the

  • No length modifiers. Everything except ul, lu, and lx is 32 bits, and ul and lx values are printed in hex

line when I read the document before, it's good to know that this is doing things correctly.

@expenses
Copy link
Contributor Author

I had to change how this does argument count checking, as

debug_printf!("%r", 11_i32);

was being accepted as invalid before when it shouldn't have been. I also added a compile-fail test to check this.

We have another slight problem though that it won't accept

debug_printfln!("%%r %%f");

as valid even though it should. I'm not sure if we can change the regex to check for an odd number of %s (as %% is treated as a single % so %%%f is treated as %<f>). The solution to this is to probably capture all the %s and filter out matches with an even number of them.

This is getting into edge-cases though. Not sure how much effort should be put into those.

@khyperia
Copy link
Contributor

khyperia commented Oct 21, 2021

Is it actually specified/defined what the behavior of debug_printf!("%r") is? (as opposed to "%%r")

As for parsing validity, the proper solution here is probably to drop the regex and do lexing ourselves - regex probably isn't the right tool for this job.

This is getting into edge-cases though. Not sure how much effort should be put into those.

Compilers are entirely about edge cases, this is really important to get right~

@expenses
Copy link
Contributor Author

expenses commented Oct 21, 2021

Is it actually specified/defined what the behavior of debug_printf!("%r") is? (as opposed to "%%r")

Just tested this - it just prints r without a %.

As for parsing validity, the proper solution here is probably to drop the regex and do lexing ourselves - regex probably isn't the right tool for this job.

Yeah, it almost certainly isn't.

Compilers are entirely about edge cases, this is really important to get right~

For sure :) but right now, I don't think anyone would really mind if they had to do "%% %f..." (with a gap) instead of "%%%f...". But as long as you're okay with these macros having a fair but of validation code, then I'm happy to work on that.

@khyperia
Copy link
Contributor

khyperia commented Oct 21, 2021

Just tested this - it just prints r without a %.

what in the absolute heckity goodness, lmao, that's wild

anyway, yeah, probably fine to merge as-is and work on full validation later if you'd prefer that PR model!

as for the path test failure, I thiiink there might be a way to work around that with something like this, although that might have to be tweaked slightly (not sure - might be fine copypasting that as-is? - it's been a long time since I've dealt with a failure like that)

@expenses
Copy link
Contributor Author

what in the absolute heckity goodness, lmao, that's wild

C does the same thing actually 😅😅😅 at least you get a warning

x.c:4:11: warning: invalid conversion specifier 'r' [-Wformat-invalid-specifier]
        printf("%r\n");
                ~^
1 warning generated.

I do generally prefer making more small PRs but here I'd like to work on the validation more before merging. Is there any way of lexing that would be best or you'd prefer? I feel like just iterating over the string and doing a bit of look-ahead would work fine.

@khyperia
Copy link
Contributor

Is there any way of lexing that would be best or you'd prefer? I feel like just iterating over the string and doing a bit of look-ahead would work fine.

Yeah, sounds fine! There's the bit of lexing in this project I did here, something like that, or whatever lookahead stuff you think might make things cleaner.

@expenses
Copy link
Contributor Author

expenses commented Oct 21, 2021

Okay, I've got something that works quite well now. It could be a bit more concise though.

@khyperia
Copy link
Contributor

heck yeah, that looks super good! thanks so much for doing that~

@expenses expenses changed the title Add printf! and printfln! macros that uses the DebugPrintf extension Add debug_printf! and debug_printfln! macros that uses the DebugPrintf extension Oct 22, 2021
@khyperia khyperia merged commit e5c2953 into EmbarkStudios:main Oct 23, 2021
@khyperia
Copy link
Contributor

🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants