Skip to content

Commit

Permalink
Changes to support future desc templates
Browse files Browse the repository at this point in the history
Update the changes made to DescriptorUpdateTemplateDecoder::Decode
to support future descriptor templates, clean up some variable
names, and added comments to indicate what's going on..
  • Loading branch information
MarkY-LunarG committed Feb 6, 2024
1 parent a4b495f commit a4a4640
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 44 deletions.
7 changes: 5 additions & 2 deletions framework/decode/custom_vulkan_struct_to_json.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
** Copyright (c) 2022-2023 LunarG, Inc.
** Copyright (c) 2022-2024 LunarG, Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -245,8 +245,11 @@ void FieldToJson(nlohmann::ordered_json& jdata, const Decoded_VkWriteDescriptorS
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
HandleToJson(jdata["pTexelBufferView"], &meta_struct.pTexelBufferView, options);
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
// Nothing to do here for acceleration structures as the rest of the data is stored
// in the pNext chain
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
GFXRECON_LOG_WARNING("Descriptor type not supported at " __FILE__ ", line: %d.", __LINE__);
Expand Down
163 changes: 121 additions & 42 deletions framework/decode/descriptor_update_template_decoder.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
** Copyright (c) 2018 Valve Corporation
** Copyright (c) 2018 LunarG, Inc.
** Copyright (c) 2018-2024 LunarG, Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -63,35 +63,101 @@ size_t DescriptorUpdateTemplateDecoder::Decode(const uint8_t* buffer, size_t buf
bytes_read += ValueDecoder::DecodeSizeTValue(
(buffer + bytes_read), (buffer_size - bytes_read), &texel_buffer_view_count_);

// Offsets of the various result structures in the allocated block that is used to store the decoded
// descriptor template information.
const size_t buffer_info_offset = image_info_count_ * sizeof(VkDescriptorImageInfo);
const size_t texel_buffer_view_offset =
buffer_info_offset + (buffer_info_count_ * sizeof(VkDescriptorBufferInfo));
size_t total_size = texel_buffer_view_offset + (texel_buffer_view_count_ * sizeof(VkBufferView));

// Calculate how many bytes we will read for obligatory information
size_t bytes_to_read = image_info_count_ * (sizeof(format::HandleId) * 2 + sizeof(format::EnumEncodeType));
bytes_to_read += buffer_info_count_ * (sizeof(format::HandleId) + 2 * sizeof(format::DeviceSizeEncodeType));
// Calculate how many bytes we will read for obligatory information.
// - Image descriptors are composed of 2 handle IDs and an enum
// (see "DecodeStruct" for Decoded_VkDescriptorBufferInfo in generated_custom_vulkan_struct_decoders.cpp)
// - Buffer descriptors are composed of 1 handle ID and 2 sizes
// (see "DecodeStruct" for Decoded_VkDescriptorImageInfo in custom_vulkan_struct_decoder.cpp)
// - Texture descriptors are composed of 1 handle ID (for the VkBufferView)
size_t bytes_to_read = image_info_count_ * ((sizeof(format::HandleId) * 2) + sizeof(format::EnumEncodeType));
bytes_to_read += buffer_info_count_ * (sizeof(format::HandleId) + (2 * sizeof(format::DeviceSizeEncodeType)));
bytes_to_read += texel_buffer_view_count_ * sizeof(format::HandleId);

// This means that there are optional descriptor types in the capture file
if (bytes_read + bytes_to_read < buffer_size)
// If there is room still left, then it indicates that there might be optional descriptor types in the capture
// file. It is easier to look forward now and calculate all the memory that is needed to allocate the storage
// memory for all the descriptor templates.
struct OptionalDescriptorInfo
{
// Try to read the optional data
const size_t offset = bytes_read + bytes_to_read;
const size_t read = ValueDecoder::DecodeSizeTValue(
(buffer + offset), (buffer_size - offset), &acceleration_structure_khr_count_);
if (offset + read == buffer_size)
VkDescriptorType type;
size_t offset;
size_t count;
};
std::vector<OptionalDescriptorInfo> optional_info{};
while ((bytes_read + bytes_to_read) < buffer_size)
{
// Calculate the size of the optional data and make sure we don't exceed
const size_t optional_start = bytes_read + bytes_to_read;
size_t required_alloc_memory_size = 0;
size_t required_read_memory_size = 0;
size_t optional_data_count = 0;
size_t optional_read_len = ValueDecoder::DecodeSizeTValue(
(buffer + optional_start), (buffer_size - optional_start), &optional_data_count);
if (optional_start + optional_read_len == buffer_size)
{
acceleration_structure_khr_count_ = 0;
optional_data_count = 0;
// A few captures in the wild were written with an uninitialized
// struct_count and no additional bytes. Commit 7d190ac9 fixed the encoding format.
GFXRECON_LOG_WARNING_ONCE(
"A deprecated incorrect encoding of DescriptorUpdateTemplate was detected. This "
"capture is probably invalid. Replay may subsequently fail or crash.");
break;
}
else if (acceleration_structure_khr_count_ > 0)
else if (optional_data_count > 0)
{
total_size += sizeof(VkAccelerationStructureKHR) * acceleration_structure_khr_count_;
OptionalDescriptorInfo cur_type{};
cur_type.count = optional_data_count;

const size_t offset_to_type = optional_start + optional_read_len;
optional_read_len += ValueDecoder::DecodeEnumValue(
(buffer + offset_to_type), (buffer_size - offset_to_type), &cur_type.type);
bool invalid_optional_desc = false;
switch (cur_type.type)
{
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
// The start of the data in the allocated block will be at the end of all the
// previous data.
cur_type.offset = total_size;

// We will read HandleIds but produce VkAccelerationStructureKHR in the allocated
// memory block. They should be the same, but just make sure that the calculations
// are correct.
required_read_memory_size = sizeof(format::HandleId) * cur_type.count;
required_alloc_memory_size = sizeof(VkAccelerationStructureKHR) * cur_type.count;
break;
default:
invalid_optional_desc = true;
// If descriptor_type is not recognized, it is possible the capture file was created with a
// newer version of the capture layer that had support for additional optional descriptor types.
// Display a warning and exit the processing loop.
GFXRECON_LOG_ERROR_ONCE(
"Unrecognized VkDescriptorType %d found when decoding data for descriptor "
"update with template.",
static_cast<int>(cur_type.type));
break;
}

if (invalid_optional_desc)
{
// We can not continue because we don't know how large the actual unknown block is.
break;
}

// Update the total size of what we need to allocate
total_size += required_alloc_memory_size;

// Upate the bytes to read to include this block of data so we can get to the next
// block.
bytes_to_read += optional_read_len + required_read_memory_size;

// Save the new optional info to the end of the vector so it stays in order
optional_info.push_back(std::move(cur_type));
}
}

Expand Down Expand Up @@ -134,38 +200,51 @@ size_t DescriptorUpdateTemplateDecoder::Decode(const uint8_t* buffer, size_t buf
texel_buffer_view_count_);
}

if (acceleration_structure_khr_count_ > 0)
// If we discovered valid optional descriptor types after the standard ones, handle them appropriately
if (optional_info.size() > 0)
{
VkDescriptorType descriptor_type;

// Account for reading acceleration structure count beforehand
bytes_read += sizeof(size_t);
bytes_read +=
ValueDecoder::DecodeEnumValue((buffer + bytes_read), (buffer_size - bytes_read), &descriptor_type);
if (descriptor_type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
// They have to be in order because if the above code hits an invalid one, it and anything after
// the invalid block will not be appended to the vector.
for (auto& cur_type : optional_info)
{
const size_t acceleration_structure_offset =
texel_buffer_view_offset + (texel_buffer_view_count_ * sizeof(VkBufferView));
acceleration_structures_khr_ =
reinterpret_cast<VkAccelerationStructureKHR*>(template_memory_ + acceleration_structure_offset);
decoded_acceleration_structure_khr_handle_ids_ =
DecodeAllocator::Allocate<format::HandleId>(acceleration_structure_khr_count_);

bytes_read += ValueDecoder::DecodeHandleIdArray((buffer + bytes_read),
(buffer_size - bytes_read),
decoded_acceleration_structure_khr_handle_ids_,
acceleration_structure_khr_count_);
}
else
{
// If descriptor_type is not recognized, it is possible the capture file was created with a
// newer version of the capture layer that had support for additional optional descriptor types.
// Display a warning and exit the processing loop.
GFXRECON_LOG_WARNING("Unrecognized VkDescriptorType %d found when decoding data for descriptor "
"update with template.",
static_cast<int>(descriptor_type));
// Read the descriptor count and type again and verify it matches what was pre-read.
// This is just to make sure the previous read actual read the data properly.
size_t current_count = 0;
bytes_read +=
ValueDecoder::DecodeSizeTValue((buffer + bytes_read), (buffer_size - bytes_read), &current_count);
VkDescriptorType current_descriptor_type;
bytes_read += ValueDecoder::DecodeEnumValue(
(buffer + bytes_read), (buffer_size - bytes_read), &current_descriptor_type);
assert(current_count == cur_type.count);
assert(current_descriptor_type == cur_type.type);

switch (cur_type.type)
{
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
{
// Just double check that we haven't already created an acceleration struct section
assert(acceleration_structure_khr_count_ == 0);

acceleration_structure_khr_count_ = cur_type.count;
acceleration_structures_khr_ =
reinterpret_cast<VkAccelerationStructureKHR*>(template_memory_ + cur_type.offset);
decoded_acceleration_structure_khr_handle_ids_ =
DecodeAllocator::Allocate<format::HandleId>(acceleration_structure_khr_count_);

bytes_read += ValueDecoder::DecodeHandleIdArray((buffer + bytes_read),
(buffer_size - bytes_read),
decoded_acceleration_structure_khr_handle_ids_,
acceleration_structure_khr_count_);
break;
}
default:
// This should only trigger if someone added a type to the above while loop and not down here.
assert(false);
break;
}
}
}

assert(bytes_read <= buffer_size);
}

Expand Down

0 comments on commit a4a4640

Please sign in to comment.