-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Metal: Fix crash when uniform set is empty for classic binding mode #100766
base: master
Are you sure you want to change the base?
Conversation
drivers/metal/metal_objects.mm
Outdated
@@ -1082,7 +1083,7 @@ | |||
|
|||
UniformSet const &set = p_shader->sets[index]; | |||
|
|||
for (uint32_t i = 0; i < uniforms.size(); i++) { | |||
for (uint32_t i = 0; i < std::min(uniforms.size(), set.uniforms.size()); i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (uint32_t i = 0; i < std::min(uniforms.size(), set.uniforms.size()); i++) { | |
for (uint32_t i = 0; i < MIN(uniforms.size(), set.uniforms.size()); i++) { |
This should use our math library instead of std
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was having trouble, as NSObjCRuntime.h
defines them. I've #undef
'd them, so it uses Godot's constexpr functions now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's weird, as core/typedefs.h
which defines our MIN
and MAX
also undef
's the pre-existing ones.
Maybe you need an explicit core/typedefs.h
include here? It's kind of taken for granted usually as most Godot headers include it one way or another, but maybe this specific file of the Metal driver doesn't as it's relatively self-contained?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I'd have to include typedefs.h
before the system libraries, and then NSObjCRuntime.h
re-defines it again. Quite a nuisance!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what it looks like:
#if !defined(MIN)
#define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })
#define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)
#endif
8110193
to
6662164
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good to me.
6662164
to
5568f79
Compare
Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
5568f79
to
b643599
Compare
// For rendering devices that do not support empty arrays (like C++), | ||
// we need to size the buffer with at least 1 element. | ||
particles->unused_emission_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleEmissionBuffer)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm creating an empty buffer with enough data for one element, which is required for backends, like Metal, that don't support empty arrays in struct
definitions, similar to C++.
} | ||
} | ||
|
||
void ParticlesStorage::_particles_ensure_unused_trail_buffer(Particles *particles) { | ||
if (particles->unused_trail_storage_buffer.is_null()) { | ||
particles->unused_trail_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4); | ||
particles->unused_trail_storage_buffer = RD::get_singleton()->storage_buffer_create(16 * sizeof(float)); // Size of mat4. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was incorrectly sized, so was causing validation errors when using Metal's slot-based binding API (A12 devices)
@TCROC can you try this, as it should resolve your issues |
@stuartcarnie Yep. I'll merge it into my fork now and let you know how it goes :). |
@stuartcarnie I can confirm, this PR appears to fix the issue! Thank you for the quick response and patch! :) |
Closes #100764
Resolves a
CRASH_BAD_INDEX
error when binding uniform sets that are empty, specifically for A12 devices and earlier, which use classic ABI vs argument buffers.Resolves a Metal CPU API validation error when binding "empty" particle buffers, that were incorrectly sized. Metal doesn't support defining a struct with an empty array.
Overview
An example of this in GLSL is:
The minimum size of
SourceEmission
is 16 bytes when binding a buffer for backends that support empty arrays.However, when this is converted to Metal, note the data member is an array of size
1
:This means that the minimum size of the struct when binding an "empty" array is 32 bytes. This doesn't cause an issue when Metal API validation is disabled, but this feature is often enabled when running code from Xcode, which iPhone developers are likely to do.