mirror of
https://github.com/godotengine/godot.git
synced 2026-02-07 19:32:36 +00:00
Metal: Fix dynamic uniform buffer offset corruption when rebinding sets
When the same uniform set is bound multiple times within a render pass (e.g., OPAQUE pass then ALPHA pass with different instance buffers), the dynamic offset bits were being OR'd together, corrupting the packed frame indices. For example, if OPAQUE binds set 1 with frame_idx=1 (0x10) and ALPHA binds set 1 with frame_idx=2 (0x20), the OR produces 0x30 instead of the correct 0x20, causing the shader to read from the wrong buffer offset. This fix clears the relevant bits for each set being bound before OR'ing the new values, ensuring only the latest frame indices are used. Fixes rendering artifacts in the mobile renderer which uses two dynamic uniforms (uniform buffer + storage buffer) in set 1, unlike the clustered renderer which only has one.
This commit is contained in:
@@ -722,8 +722,6 @@ void MDCommandBuffer::encodeRenderCommandEncoderWithDescriptor(MTLRenderPassDesc
|
||||
void MDCommandBuffer::render_bind_uniform_sets(VectorView<RDD::UniformSetID> p_uniform_sets, RDD::ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets) {
|
||||
DEV_ASSERT(type == MDCommandBufferStateType::Render);
|
||||
|
||||
render.dynamic_offsets |= p_dynamic_offsets;
|
||||
|
||||
if (uint32_t new_size = p_first_set_index + p_set_count; render.uniform_sets.size() < new_size) {
|
||||
uint32_t s = render.uniform_sets.size();
|
||||
render.uniform_sets.resize(new_size);
|
||||
@@ -734,6 +732,20 @@ void MDCommandBuffer::render_bind_uniform_sets(VectorView<RDD::UniformSetID> p_u
|
||||
const MDShader *shader = (const MDShader *)p_shader.id;
|
||||
DynamicOffsetLayout layout = shader->dynamic_offset_layout;
|
||||
|
||||
// Clear bits for sets being rebound before OR'ing new values.
|
||||
// This prevents corruption when the same set is bound multiple times
|
||||
// with different frame indices (e.g., OPAQUE pass then ALPHA pass).
|
||||
for (uint32_t i = 0; i < p_set_count && render.dynamic_offsets != 0; i++) {
|
||||
uint32_t set_index = p_first_set_index + i;
|
||||
uint32_t count = layout.get_count(set_index);
|
||||
if (count > 0) {
|
||||
uint32_t shift = layout.get_offset_index_shift(set_index);
|
||||
uint32_t mask = ((1u << (count * 4u)) - 1u) << shift;
|
||||
render.dynamic_offsets &= ~mask;
|
||||
}
|
||||
}
|
||||
render.dynamic_offsets |= p_dynamic_offsets;
|
||||
|
||||
for (size_t i = 0; i < p_set_count; ++i) {
|
||||
MDUniformSet *set = (MDUniformSet *)(p_uniform_sets[i].id);
|
||||
|
||||
@@ -1620,8 +1632,6 @@ void MDCommandBuffer::ComputeState::reset() {
|
||||
void MDCommandBuffer::compute_bind_uniform_sets(VectorView<RDD::UniformSetID> p_uniform_sets, RDD::ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets) {
|
||||
DEV_ASSERT(type == MDCommandBufferStateType::Compute);
|
||||
|
||||
compute.dynamic_offsets |= p_dynamic_offsets;
|
||||
|
||||
if (uint32_t new_size = p_first_set_index + p_set_count; compute.uniform_sets.size() < new_size) {
|
||||
uint32_t s = compute.uniform_sets.size();
|
||||
compute.uniform_sets.resize(new_size);
|
||||
@@ -1632,6 +1642,20 @@ void MDCommandBuffer::compute_bind_uniform_sets(VectorView<RDD::UniformSetID> p_
|
||||
const MDShader *shader = (const MDShader *)p_shader.id;
|
||||
DynamicOffsetLayout layout = shader->dynamic_offset_layout;
|
||||
|
||||
// Clear bits for sets being rebound before OR'ing new values.
|
||||
// This prevents corruption when the same set is bound multiple times
|
||||
// with different frame indices.
|
||||
for (uint32_t i = 0; i < p_set_count && compute.dynamic_offsets != 0; i++) {
|
||||
uint32_t set_index = p_first_set_index + i;
|
||||
uint32_t count = layout.get_count(set_index);
|
||||
if (count > 0) {
|
||||
uint32_t shift = layout.get_offset_index_shift(set_index);
|
||||
uint32_t mask = ((1u << (count * 4u)) - 1u) << shift;
|
||||
compute.dynamic_offsets &= ~mask;
|
||||
}
|
||||
}
|
||||
compute.dynamic_offsets |= p_dynamic_offsets;
|
||||
|
||||
for (size_t i = 0; i < p_set_count; ++i) {
|
||||
MDUniformSet *set = (MDUniformSet *)(p_uniform_sets[i].id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user