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

Fix struct variable size with out-of-order offsets #264

Merged
merged 2 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 41 additions & 41 deletions spirv_reflect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2711,67 +2711,67 @@ static SpvReflectResult ParseDescriptorBlockVariableSizes(SpvReflectPrvParser* p
}
}

if (p_var->member_count > 0) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

first commit is just removing this line, ParseDescriptorBlockVariableSizes starts with a check for this

// Structs can offset order don't need to match the index order, so first order by offset
// example:
// OpMemberDecorate %struct 0 Offset 4
// OpMemberDecorate %struct 1 Offset 0
SpvReflectBlockVariable** pp_member_offset_order =
(SpvReflectBlockVariable**)calloc(p_var->member_count, sizeof(SpvReflectBlockVariable*));
if (IsNull(pp_member_offset_order)) {
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
}

uint32_t bottom_bound = 0;
for (uint32_t i = 0; i < p_var->member_count; ++i) {
uint32_t lowest_offset = UINT32_MAX;
uint32_t member_index = 0;
for (uint32_t j = 0; j < p_var->member_count; ++j) {
const uint32_t offset = p_var->members[j].offset;
if (offset < lowest_offset && offset >= bottom_bound) {
member_index = j;
lowest_offset = offset;
}
}
pp_member_offset_order[i] = &p_var->members[member_index];
bottom_bound = lowest_offset + 1; // 2 index can't share the same offset
}
// Structs can offset order don't need to match the index order, so first order by offset
// example:
// OpMemberDecorate %struct 0 Offset 4
// OpMemberDecorate %struct 1 Offset 0
SpvReflectBlockVariable** pp_member_offset_order =
(SpvReflectBlockVariable**)calloc(p_var->member_count, sizeof(SpvReflectBlockVariable*));
if (IsNull(pp_member_offset_order)) {
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
}

// Parse padded size using offset difference for all member except for the last entry...
for (uint32_t i = 0; i < (p_var->member_count - 1); ++i) {
SpvReflectBlockVariable* p_member_var = pp_member_offset_order[i];
SpvReflectBlockVariable* p_next_member_var = pp_member_offset_order[i + 1];
p_member_var->padded_size = p_next_member_var->offset - p_member_var->offset;
if (p_member_var->size > p_member_var->padded_size) {
p_member_var->size = p_member_var->padded_size;
}
if (is_parent_rta) {
p_member_var->padded_size = p_member_var->size;
uint32_t bottom_bound = 0;
for (uint32_t i = 0; i < p_var->member_count; ++i) {
uint32_t lowest_offset = UINT32_MAX;
uint32_t member_index = 0;
for (uint32_t j = 0; j < p_var->member_count; ++j) {
const uint32_t offset = p_var->members[j].offset;
if (offset < lowest_offset && offset >= bottom_bound) {
member_index = j;
lowest_offset = offset;
}
}
pp_member_offset_order[i] = &p_var->members[member_index];
bottom_bound = lowest_offset + 1; // 2 index can't share the same offset
}

// ...last entry just gets rounded up to near multiple of SPIRV_DATA_ALIGNMENT, which is 16 and
// subtract the offset.
SpvReflectBlockVariable* p_member_var = pp_member_offset_order[p_var->member_count - 1];
p_member_var->padded_size = RoundUp(p_member_var->offset + p_member_var->size, SPIRV_DATA_ALIGNMENT) - p_member_var->offset;
// Parse padded size using offset difference for all member except for the last entry...
for (uint32_t i = 0; i < (p_var->member_count - 1); ++i) {
SpvReflectBlockVariable* p_member_var = pp_member_offset_order[i];
SpvReflectBlockVariable* p_next_member_var = pp_member_offset_order[i + 1];
p_member_var->padded_size = p_next_member_var->offset - p_member_var->offset;
if (p_member_var->size > p_member_var->padded_size) {
p_member_var->size = p_member_var->padded_size;
}
if (is_parent_rta) {
p_member_var->padded_size = p_member_var->size;
}
}

SafeFree(pp_member_offset_order);
// ...last entry just gets rounded up to near multiple of SPIRV_DATA_ALIGNMENT, which is 16 and
// subtract the offset.
// last entry == entry with largest offset value
SpvReflectBlockVariable* p_last_member_var = pp_member_offset_order[p_var->member_count - 1];
p_last_member_var->padded_size =
RoundUp(p_last_member_var->offset + p_last_member_var->size, SPIRV_DATA_ALIGNMENT) - p_last_member_var->offset;
if (p_last_member_var->size > p_last_member_var->padded_size) {
p_last_member_var->size = p_last_member_var->padded_size;
}
if (is_parent_rta) {
p_last_member_var->padded_size = p_last_member_var->size;
}

SafeFree(pp_member_offset_order);

// If buffer ref, sizes are same as uint64_t
if (is_parent_ref) {
p_var->size = p_var->padded_size = 8;
return SPV_REFLECT_RESULT_SUCCESS;
}

// @TODO validate this with assertion
p_var->size = p_var->members[p_var->member_count - 1].offset + p_var->members[p_var->member_count - 1].padded_size;
p_var->size = p_last_member_var->offset + p_last_member_var->padded_size;
p_var->padded_size = p_var->size;

return SPV_REFLECT_RESULT_SUCCESS;
Expand Down
4 changes: 2 additions & 2 deletions tests/glsl/struct_offset_order.spv.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,8 @@ all_block_variables:
name: "ubo2"
offset: 0
absolute_offset: 0
size: 16
padded_size: 16
size: 32
padded_size: 32
decorations: 0x00000000 # NONE
numeric:
scalar: { width: 0, signedness: 0 }
Expand Down
4 changes: 2 additions & 2 deletions tests/push_constants/non_zero_block_offset.spv.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ all_block_variables:
name: "pc"
offset: 4
absolute_offset: 0
size: 8
padded_size: 8
size: 32
padded_size: 32
decorations: 0x00000000 # NONE
numeric:
scalar: { width: 0, signedness: 0 }
Expand Down
Loading