Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
      2  * Copyright (c) 2015-2016 Valve Corporation
      3  * Copyright (c) 2015-2016 LunarG, Inc.
      4  * Copyright (C) 2015-2016 Google Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Tobin Ehlis <tobine (at) google.com>
     19  */
     20 
     21 #include "descriptor_sets.h"
     22 #include "vk_enum_string_helper.h"
     23 #include "vk_safe_struct.h"
     24 #include <sstream>
     25 
     26 // Construct DescriptorSetLayout instance from given create info
     27 cvdescriptorset::DescriptorSetLayout::DescriptorSetLayout(debug_report_data *report_data,
     28                                                           const VkDescriptorSetLayoutCreateInfo *p_create_info,
     29                                                           const VkDescriptorSetLayout layout)
     30     : layout_(layout), binding_count_(p_create_info->bindingCount), descriptor_count_(0), dynamic_descriptor_count_(0) {
     31     uint32_t global_index = 0;
     32     for (uint32_t i = 0; i < binding_count_; ++i) {
     33         descriptor_count_ += p_create_info->pBindings[i].descriptorCount;
     34         if (!binding_to_index_map_.emplace(p_create_info->pBindings[i].binding, i).second) {
     35             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
     36                     reinterpret_cast<uint64_t &>(layout_), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
     37                     "duplicated binding number in "
     38                     "VkDescriptorSetLayoutBinding");
     39         }
     40         binding_to_global_start_index_map_[p_create_info->pBindings[i].binding] = global_index;
     41         global_index += p_create_info->pBindings[i].descriptorCount ? p_create_info->pBindings[i].descriptorCount - 1 : 0;
     42         binding_to_global_end_index_map_[p_create_info->pBindings[i].binding] = global_index;
     43         global_index++;
     44         bindings_.push_back(safe_VkDescriptorSetLayoutBinding(&p_create_info->pBindings[i]));
     45         // In cases where we should ignore pImmutableSamplers make sure it's NULL
     46         if ((p_create_info->pBindings[i].pImmutableSamplers) &&
     47             ((p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) &&
     48              (p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))) {
     49             bindings_.back().pImmutableSamplers = nullptr;
     50         }
     51         if (p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
     52             p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
     53             dynamic_descriptor_count_++;
     54         }
     55     }
     56 }
     57 // put all bindings into the given set
     58 void cvdescriptorset::DescriptorSetLayout::FillBindingSet(std::unordered_set<uint32_t> *binding_set) const {
     59     for (auto binding_index_pair : binding_to_index_map_)
     60         binding_set->insert(binding_index_pair.first);
     61 }
     62 
     63 VkDescriptorSetLayoutBinding const *
     64 cvdescriptorset::DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) const {
     65     const auto &bi_itr = binding_to_index_map_.find(binding);
     66     if (bi_itr != binding_to_index_map_.end()) {
     67         return bindings_[bi_itr->second].ptr();
     68     }
     69     return nullptr;
     70 }
     71 VkDescriptorSetLayoutBinding const *
     72 cvdescriptorset::DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) const {
     73     if (index >= bindings_.size())
     74         return nullptr;
     75     return bindings_[index].ptr();
     76 }
     77 // Return descriptorCount for given binding, 0 if index is unavailable
     78 uint32_t cvdescriptorset::DescriptorSetLayout::GetDescriptorCountFromBinding(const uint32_t binding) const {
     79     const auto &bi_itr = binding_to_index_map_.find(binding);
     80     if (bi_itr != binding_to_index_map_.end()) {
     81         return bindings_[bi_itr->second].descriptorCount;
     82     }
     83     return 0;
     84 }
     85 // Return descriptorCount for given index, 0 if index is unavailable
     86 uint32_t cvdescriptorset::DescriptorSetLayout::GetDescriptorCountFromIndex(const uint32_t index) const {
     87     if (index >= bindings_.size())
     88         return 0;
     89     return bindings_[index].descriptorCount;
     90 }
     91 // For the given binding, return descriptorType
     92 VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromBinding(const uint32_t binding) const {
     93     assert(binding_to_index_map_.count(binding));
     94     const auto &bi_itr = binding_to_index_map_.find(binding);
     95     if (bi_itr != binding_to_index_map_.end()) {
     96         return bindings_[bi_itr->second].descriptorType;
     97     }
     98     return VK_DESCRIPTOR_TYPE_MAX_ENUM;
     99 }
    100 // For the given index, return descriptorType
    101 VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) const {
    102     assert(index < bindings_.size());
    103     return bindings_[index].descriptorType;
    104 }
    105 // For the given global index, return descriptorType
    106 //  Currently just counting up through bindings_, may improve this in future
    107 VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromGlobalIndex(const uint32_t index) const {
    108     uint32_t global_offset = 0;
    109     for (auto binding : bindings_) {
    110         global_offset += binding.descriptorCount;
    111         if (index < global_offset)
    112             return binding.descriptorType;
    113     }
    114     assert(0); // requested global index is out of bounds
    115     return VK_DESCRIPTOR_TYPE_MAX_ENUM;
    116 }
    117 // For the given binding, return stageFlags
    118 VkShaderStageFlags cvdescriptorset::DescriptorSetLayout::GetStageFlagsFromBinding(const uint32_t binding) const {
    119     assert(binding_to_index_map_.count(binding));
    120     const auto &bi_itr = binding_to_index_map_.find(binding);
    121     if (bi_itr != binding_to_index_map_.end()) {
    122         return bindings_[bi_itr->second].stageFlags;
    123     }
    124     return VkShaderStageFlags(0);
    125 }
    126 // For the given binding, return start index
    127 uint32_t cvdescriptorset::DescriptorSetLayout::GetGlobalStartIndexFromBinding(const uint32_t binding) const {
    128     assert(binding_to_global_start_index_map_.count(binding));
    129     const auto &btgsi_itr = binding_to_global_start_index_map_.find(binding);
    130     if (btgsi_itr != binding_to_global_start_index_map_.end()) {
    131         return btgsi_itr->second;
    132     }
    133     // In error case max uint32_t so index is out of bounds to break ASAP
    134     return 0xFFFFFFFF;
    135 }
    136 // For the given binding, return end index
    137 uint32_t cvdescriptorset::DescriptorSetLayout::GetGlobalEndIndexFromBinding(const uint32_t binding) const {
    138     assert(binding_to_global_end_index_map_.count(binding));
    139     const auto &btgei_itr = binding_to_global_end_index_map_.find(binding);
    140     if (btgei_itr != binding_to_global_end_index_map_.end()) {
    141         return btgei_itr->second;
    142     }
    143     // In error case max uint32_t so index is out of bounds to break ASAP
    144     return 0xFFFFFFFF;
    145 }
    146 // For given binding, return ptr to ImmutableSampler array
    147 VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) const {
    148     assert(binding_to_index_map_.count(binding));
    149     const auto &bi_itr = binding_to_index_map_.find(binding);
    150     if (bi_itr != binding_to_index_map_.end()) {
    151         return bindings_[bi_itr->second].pImmutableSamplers;
    152     }
    153     return nullptr;
    154 }
    155 // For given index, return ptr to ImmutableSampler array
    156 VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
    157     assert(index < bindings_.size());
    158     return bindings_[index].pImmutableSamplers;
    159 }
    160 // If our layout is compatible with rh_ds_layout, return true,
    161 //  else return false and fill in error_msg will description of what causes incompatibility
    162 bool cvdescriptorset::DescriptorSetLayout::IsCompatible(const DescriptorSetLayout *rh_ds_layout, std::string *error_msg) const {
    163     // Trivial case
    164     if (layout_ == rh_ds_layout->GetDescriptorSetLayout())
    165         return true;
    166     if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
    167         std::stringstream error_str;
    168         error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
    169                   << rh_ds_layout->GetDescriptorSetLayout() << " has " << rh_ds_layout->descriptor_count_ << " descriptors.";
    170         *error_msg = error_str.str();
    171         return false; // trivial fail case
    172     }
    173     // Descriptor counts match so need to go through bindings one-by-one
    174     //  and verify that type and stageFlags match
    175     for (auto binding : bindings_) {
    176         // TODO : Do we also need to check immutable samplers?
    177         // VkDescriptorSetLayoutBinding *rh_binding;
    178         if (binding.descriptorCount != rh_ds_layout->GetDescriptorCountFromBinding(binding.binding)) {
    179             std::stringstream error_str;
    180             error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
    181                       << binding.descriptorCount << " but binding " << binding.binding << " for DescriptorSetLayout "
    182                       << rh_ds_layout->GetDescriptorSetLayout() << " has a descriptorCount of "
    183                       << rh_ds_layout->GetDescriptorCountFromBinding(binding.binding);
    184             *error_msg = error_str.str();
    185             return false;
    186         } else if (binding.descriptorType != rh_ds_layout->GetTypeFromBinding(binding.binding)) {
    187             std::stringstream error_str;
    188             error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " is type '"
    189                       << string_VkDescriptorType(binding.descriptorType) << "' but binding " << binding.binding
    190                       << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout() << " is type '"
    191                       << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding.binding)) << "'";
    192             *error_msg = error_str.str();
    193             return false;
    194         } else if (binding.stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding.binding)) {
    195             std::stringstream error_str;
    196             error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
    197                       << binding.stageFlags << " but binding " << binding.binding << " for DescriptorSetLayout "
    198                       << rh_ds_layout->GetDescriptorSetLayout() << " has stageFlags "
    199                       << rh_ds_layout->GetStageFlagsFromBinding(binding.binding);
    200             *error_msg = error_str.str();
    201             return false;
    202         }
    203     }
    204     return true;
    205 }
    206 
    207 bool cvdescriptorset::DescriptorSetLayout::IsNextBindingConsistent(const uint32_t binding) const {
    208     if (!binding_to_index_map_.count(binding + 1))
    209         return false;
    210     auto const &bi_itr = binding_to_index_map_.find(binding);
    211     if (bi_itr != binding_to_index_map_.end()) {
    212         const auto &next_bi_itr = binding_to_index_map_.find(binding + 1);
    213         if (next_bi_itr != binding_to_index_map_.end()) {
    214             auto type = bindings_[bi_itr->second].descriptorType;
    215             auto stage_flags = bindings_[bi_itr->second].stageFlags;
    216             auto immut_samp = bindings_[bi_itr->second].pImmutableSamplers ? true : false;
    217             if ((type != bindings_[next_bi_itr->second].descriptorType) ||
    218                 (stage_flags != bindings_[next_bi_itr->second].stageFlags) ||
    219                 (immut_samp != (bindings_[next_bi_itr->second].pImmutableSamplers ? true : false))) {
    220                 return false;
    221             }
    222             return true;
    223         }
    224     }
    225     return false;
    226 }
    227 // Starting at offset descriptor of given binding, parse over update_count
    228 //  descriptor updates and verify that for any binding boundaries that are crossed, the next binding(s) are all consistent
    229 //  Consistency means that their type, stage flags, and whether or not they use immutable samplers matches
    230 //  If so, return true. If not, fill in error_msg and return false
    231 bool cvdescriptorset::DescriptorSetLayout::VerifyUpdateConsistency(uint32_t current_binding, uint32_t offset, uint32_t update_count,
    232                                                                    const char *type, const VkDescriptorSet set,
    233                                                                    std::string *error_msg) const {
    234     // Verify consecutive bindings match (if needed)
    235     auto orig_binding = current_binding;
    236     // Track count of descriptors in the current_bindings that are remaining to be updated
    237     auto binding_remaining = GetDescriptorCountFromBinding(current_binding);
    238     // First, it's legal to offset beyond your own binding so handle that case
    239     //  Really this is just searching for the binding in which the update begins and adjusting offset accordingly
    240     while (offset >= binding_remaining) {
    241         // Advance to next binding, decrement offset by binding size
    242         offset -= binding_remaining;
    243         binding_remaining = GetDescriptorCountFromBinding(++current_binding);
    244     }
    245     binding_remaining -= offset;
    246     while (update_count > binding_remaining) { // While our updates overstep current binding
    247         // Verify next consecutive binding matches type, stage flags & immutable sampler use
    248         if (!IsNextBindingConsistent(current_binding++)) {
    249             std::stringstream error_str;
    250             error_str << "Attempting " << type << " descriptor set " << set << " binding #" << orig_binding << " with #"
    251                       << update_count << " descriptors being updated but this update oversteps the bounds of this binding and the "
    252                                          "next binding is not consistent with current binding so this update is invalid.";
    253             *error_msg = error_str.str();
    254             return false;
    255         }
    256         // For sake of this check consider the bindings updated and grab count for next binding
    257         update_count -= binding_remaining;
    258         binding_remaining = GetDescriptorCountFromBinding(current_binding);
    259     }
    260     return true;
    261 }
    262 
    263 cvdescriptorset::DescriptorSet::DescriptorSet(const VkDescriptorSet set, const DescriptorSetLayout *layout,
    264                                               const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map,
    265                                               const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *memory_map,
    266                                               const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *buffer_view_map,
    267                                               const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map,
    268                                               const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
    269                                               const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
    270                                               const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
    271                                               const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map)
    272     : some_update_(false), set_(set), p_layout_(layout), buffer_map_(buffer_map), memory_map_(memory_map),
    273       buffer_view_map_(buffer_view_map), sampler_map_(sampler_map), image_view_map_(image_view_map), image_map_(image_map),
    274       image_to_swapchain_map_(image_to_swapchain_map), swapchain_map_(swapchain_map) {
    275     // Foreach binding, create default descriptors of given type
    276     for (uint32_t i = 0; i < p_layout_->GetBindingCount(); ++i) {
    277         auto type = p_layout_->GetTypeFromIndex(i);
    278         switch (type) {
    279         case VK_DESCRIPTOR_TYPE_SAMPLER: {
    280             auto immut_sampler = p_layout_->GetImmutableSamplerPtrFromIndex(i);
    281             for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di) {
    282                 if (immut_sampler)
    283                     descriptors_.emplace_back(std::unique_ptr<Descriptor>(new SamplerDescriptor(immut_sampler + di)));
    284                 else
    285                     descriptors_.emplace_back(std::unique_ptr<Descriptor>(new SamplerDescriptor()));
    286             }
    287             break;
    288         }
    289         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
    290             auto immut = p_layout_->GetImmutableSamplerPtrFromIndex(i);
    291             for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di) {
    292                 if (immut)
    293                     descriptors_.emplace_back(std::unique_ptr<Descriptor>(new ImageSamplerDescriptor(immut + di)));
    294                 else
    295                     descriptors_.emplace_back(std::unique_ptr<Descriptor>(new ImageSamplerDescriptor()));
    296             }
    297             break;
    298         }
    299         // ImageDescriptors
    300         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
    301         case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
    302         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
    303             for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
    304                 descriptors_.emplace_back(std::unique_ptr<Descriptor>(new ImageDescriptor(type)));
    305             break;
    306         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
    307         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
    308             for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
    309                 descriptors_.emplace_back(std::unique_ptr<Descriptor>(new TexelDescriptor(type)));
    310             break;
    311         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
    312         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
    313         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
    314         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
    315             for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
    316                 descriptors_.emplace_back(std::unique_ptr<Descriptor>(new BufferDescriptor(type)));
    317             break;
    318         default:
    319             assert(0); // Bad descriptor type specified
    320             break;
    321         }
    322     }
    323 }
    324 
    325 cvdescriptorset::DescriptorSet::~DescriptorSet() {
    326     InvalidateBoundCmdBuffers();
    327     // Remove link to any cmd buffers
    328     for (auto cb : bound_cmd_buffers_) {
    329         for (uint32_t i=0; i<VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
    330             cb->lastBound[i].uniqueBoundSets.erase(this);
    331         }
    332     }
    333 }
    334 // Is this sets underlying layout compatible with passed in layout according to "Pipeline Layout Compatibility" in spec?
    335 bool cvdescriptorset::DescriptorSet::IsCompatible(const DescriptorSetLayout *layout, std::string *error) const {
    336     return layout->IsCompatible(p_layout_, error);
    337 }
    338 // Validate that the state of this set is appropriate for the given bindings and dynami_offsets at Draw time
    339 //  This includes validating that all descriptors in the given bindings are updated,
    340 //  that any update buffers are valid, and that any dynamic offsets are within the bounds of their buffers.
    341 // Return true if state is acceptable, or false and write an error message into error string
    342 bool cvdescriptorset::DescriptorSet::ValidateDrawState(const std::unordered_set<uint32_t> &bindings,
    343                                                        const std::vector<uint32_t> &dynamic_offsets, std::string *error) const {
    344     for (auto binding : bindings) {
    345         auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(binding);
    346         if (descriptors_[start_idx]->IsImmutableSampler()) {
    347             // Nothing to do for strictly immutable sampler
    348         } else {
    349             auto end_idx = p_layout_->GetGlobalEndIndexFromBinding(binding);
    350             auto dyn_offset_index = 0;
    351             for (uint32_t i = start_idx; i <= end_idx; ++i) {
    352                 if (!descriptors_[i]->updated) {
    353                     std::stringstream error_str;
    354                     error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
    355                               << " is being used in draw but has not been updated.";
    356                     *error = error_str.str();
    357                     return false;
    358                 } else {
    359                     if (GeneralBuffer == descriptors_[i]->GetClass()) {
    360                         // Verify that buffers are valid
    361                         auto buffer = static_cast<BufferDescriptor *>(descriptors_[i].get())->GetBuffer();
    362                         auto buffer_node = buffer_map_->find(buffer);
    363                         if (buffer_node == buffer_map_->end()) {
    364                             std::stringstream error_str;
    365                             error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
    366                                       << " references invalid buffer " << buffer << ".";
    367                             *error = error_str.str();
    368                             return false;
    369                         } else {
    370                             auto mem_entry = memory_map_->find(buffer_node->second.mem);
    371                             if (mem_entry == memory_map_->end()) {
    372                                 std::stringstream error_str;
    373                                 error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
    374                                           << " uses buffer " << buffer << " that references invalid memory "
    375                                           << buffer_node->second.mem << ".";
    376                                 *error = error_str.str();
    377                                 return false;
    378                             }
    379                         }
    380                         if (descriptors_[i]->IsDynamic()) {
    381                             // Validate that dynamic offsets are within the buffer
    382                             auto buffer_size = buffer_node->second.createInfo.size;
    383                             auto range = static_cast<BufferDescriptor *>(descriptors_[i].get())->GetRange();
    384                             auto desc_offset = static_cast<BufferDescriptor *>(descriptors_[i].get())->GetOffset();
    385                             auto dyn_offset = dynamic_offsets[dyn_offset_index++];
    386                             if (VK_WHOLE_SIZE == range) {
    387                                 if ((dyn_offset + desc_offset) > buffer_size) {
    388                                     std::stringstream error_str;
    389                                     error_str << "Dynamic descriptor in binding #" << binding << " at global descriptor index " << i
    390                                               << " uses buffer " << buffer
    391                                               << " with update range of VK_WHOLE_SIZE has dynamic offset " << dyn_offset
    392                                               << " combined with offset " << desc_offset << " that oversteps the buffer size of "
    393                                               << buffer_size << ".";
    394                                     *error = error_str.str();
    395                                     return false;
    396                                 }
    397                             } else {
    398                                 if ((dyn_offset + desc_offset + range) > buffer_size) {
    399                                     std::stringstream error_str;
    400                                     error_str << "Dynamic descriptor in binding #" << binding << " at global descriptor index " << i
    401                                               << " uses buffer " << buffer << " with dynamic offset " << dyn_offset
    402                                               << " combined with offset " << desc_offset << " and range " << range
    403                                               << " that oversteps the buffer size of " << buffer_size << ".";
    404                                     *error = error_str.str();
    405                                     return false;
    406                                 }
    407                             }
    408                         }
    409                     }
    410                 }
    411             }
    412         }
    413     }
    414     return true;
    415 }
    416 // For given bindings, place any update buffers or images into the passed-in unordered_sets
    417 uint32_t cvdescriptorset::DescriptorSet::GetStorageUpdates(const std::unordered_set<uint32_t> &bindings,
    418                                                            std::unordered_set<VkBuffer> *buffer_set,
    419                                                            std::unordered_set<VkImageView> *image_set) const {
    420     auto num_updates = 0;
    421     for (auto binding : bindings) {
    422         auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(binding);
    423         if (descriptors_[start_idx]->IsStorage()) {
    424             if (Image == descriptors_[start_idx]->descriptor_class) {
    425                 for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
    426                     if (descriptors_[start_idx + i]->updated) {
    427                         image_set->insert(static_cast<ImageDescriptor *>(descriptors_[start_idx + i].get())->GetImageView());
    428                         num_updates++;
    429                     }
    430                 }
    431             } else if (TexelBuffer == descriptors_[start_idx]->descriptor_class) {
    432                 for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
    433                     if (descriptors_[start_idx + i]->updated) {
    434                         auto bufferview = static_cast<TexelDescriptor *>(descriptors_[start_idx + i].get())->GetBufferView();
    435                         const auto &buff_pair = buffer_view_map_->find(bufferview);
    436                         if (buff_pair != buffer_view_map_->end()) {
    437                             buffer_set->insert(buff_pair->second.buffer);
    438                             num_updates++;
    439                         }
    440                     }
    441                 }
    442             } else if (GeneralBuffer == descriptors_[start_idx]->descriptor_class) {
    443                 for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
    444                     if (descriptors_[start_idx + i]->updated) {
    445                         buffer_set->insert(static_cast<BufferDescriptor *>(descriptors_[start_idx + i].get())->GetBuffer());
    446                         num_updates++;
    447                     }
    448                 }
    449             }
    450         }
    451     }
    452     return num_updates;
    453 }
    454 // This is a special case for compute shaders that should eventually be removed once we have proper valid binding info for compute
    455 // case
    456 uint32_t cvdescriptorset::DescriptorSet::GetAllStorageUpdates(std::unordered_set<VkBuffer> *buffer_set,
    457                                                               std::unordered_set<VkImageView> *image_set) const {
    458     std::unordered_set<uint32_t> binding_set;
    459     p_layout_->FillBindingSet(&binding_set);
    460     return GetStorageUpdates(binding_set, buffer_set, image_set);
    461 }
    462 // Set is being deleted or updates so invalidate all bound cmd buffers
    463 void cvdescriptorset::DescriptorSet::InvalidateBoundCmdBuffers() {
    464     for (auto cb_node : bound_cmd_buffers_) {
    465         cb_node->state = CB_INVALID;
    466     }
    467 }
    468 // Perform write update in given update struct
    469 void cvdescriptorset::DescriptorSet::PerformWriteUpdate(const VkWriteDescriptorSet *update) {
    470     auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
    471     // perform update
    472     for (uint32_t di = 0; di < update->descriptorCount; ++di) {
    473         descriptors_[start_idx + di]->WriteUpdate(update, di);
    474     }
    475     if (update->descriptorCount)
    476         some_update_ = true;
    477 
    478     InvalidateBoundCmdBuffers();
    479 }
    480 // Validate Copy update
    481 bool cvdescriptorset::DescriptorSet::ValidateCopyUpdate(const debug_report_data *report_data, const VkCopyDescriptorSet *update,
    482                                                         const DescriptorSet *src_set, std::string *error) {
    483     // Verify idle ds
    484     if (in_use.load()) {
    485         std::stringstream error_str;
    486         error_str << "Cannot call vkUpdateDescriptorSets() to perform copy update on descriptor set " << set_
    487                   << " that is in use by a command buffer.";
    488         *error = error_str.str();
    489         return false;
    490     }
    491     if (!p_layout_->HasBinding(update->dstBinding)) {
    492         std::stringstream error_str;
    493         error_str << "DescriptorSet " << set_ << " does not have copy update dest binding of " << update->dstBinding << ".";
    494         *error = error_str.str();
    495         return false;
    496     }
    497     if (!src_set->HasBinding(update->srcBinding)) {
    498         std::stringstream error_str;
    499         error_str << "DescriptorSet " << set_ << " does not have copy update src binding of " << update->srcBinding << ".";
    500         *error = error_str.str();
    501         return false;
    502     }
    503     // src & dst set bindings are valid
    504     // Check bounds of src & dst
    505     auto src_start_idx = src_set->GetGlobalStartIndexFromBinding(update->srcBinding) + update->srcArrayElement;
    506     if ((src_start_idx + update->descriptorCount) > src_set->GetTotalDescriptorCount()) {
    507         // SRC update out of bounds
    508         std::stringstream error_str;
    509         error_str << "Attempting copy update from descriptorSet " << update->srcSet << " binding#" << update->srcBinding
    510                   << " with offset index of " << src_set->GetGlobalStartIndexFromBinding(update->srcBinding)
    511                   << " plus update array offset of " << update->srcArrayElement << " and update of " << update->descriptorCount
    512                   << " descriptors oversteps total number of descriptors in set: " << src_set->GetTotalDescriptorCount() << ".";
    513         *error = error_str.str();
    514         return false;
    515     }
    516     auto dst_start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
    517     if ((dst_start_idx + update->descriptorCount) > p_layout_->GetTotalDescriptorCount()) {
    518         // DST update out of bounds
    519         std::stringstream error_str;
    520         error_str << "Attempting copy update to descriptorSet " << set_ << " binding#" << update->dstBinding
    521                   << " with offset index of " << p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding)
    522                   << " plus update array offset of " << update->dstArrayElement << " and update of " << update->descriptorCount
    523                   << " descriptors oversteps total number of descriptors in set: " << p_layout_->GetTotalDescriptorCount() << ".";
    524         *error = error_str.str();
    525         return false;
    526     }
    527     // Check that types match
    528     auto src_type = src_set->GetTypeFromBinding(update->srcBinding);
    529     auto dst_type = p_layout_->GetTypeFromBinding(update->dstBinding);
    530     if (src_type != dst_type) {
    531         std::stringstream error_str;
    532         error_str << "Attempting copy update to descriptorSet " << set_ << " binding #" << update->dstBinding << " with type "
    533                   << string_VkDescriptorType(dst_type) << " from descriptorSet " << src_set->GetSet() << " binding #"
    534                   << update->srcBinding << " with type " << string_VkDescriptorType(src_type) << ". Types do not match.";
    535         *error = error_str.str();
    536         return false;
    537     }
    538     // Verify consistency of src & dst bindings if update crosses binding boundaries
    539     if ((!src_set->GetLayout()->VerifyUpdateConsistency(update->srcBinding, update->srcArrayElement, update->descriptorCount,
    540                                                         "copy update from", src_set->GetSet(), error)) ||
    541         (!p_layout_->VerifyUpdateConsistency(update->dstBinding, update->dstArrayElement, update->descriptorCount, "copy update to",
    542                                              set_, error))) {
    543         return false;
    544     }
    545     // First make sure source descriptors are updated
    546     for (uint32_t i = 0; i < update->descriptorCount; ++i) {
    547         if (!src_set->descriptors_[src_start_idx + i]) {
    548             std::stringstream error_str;
    549             error_str << "Attempting copy update from descriptorSet " << src_set << " binding #" << update->srcBinding << " but descriptor at array offset "
    550                       << update->srcArrayElement + i << " has not been updated.";
    551             *error = error_str.str();
    552             return false;
    553         }
    554     }
    555     // Update parameters all look good and descriptor updated so verify update contents
    556     if (!VerifyCopyUpdateContents(update, src_set, src_start_idx, error))
    557         return false;
    558 
    559     // All checks passed so update is good
    560     return true;
    561 }
    562 // Perform Copy update
    563 void cvdescriptorset::DescriptorSet::PerformCopyUpdate(const VkCopyDescriptorSet *update, const DescriptorSet *src_set) {
    564     auto src_start_idx = src_set->GetGlobalStartIndexFromBinding(update->srcBinding) + update->srcArrayElement;
    565     auto dst_start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
    566     // Update parameters all look good so perform update
    567     for (uint32_t di = 0; di < update->descriptorCount; ++di) {
    568         descriptors_[dst_start_idx + di]->CopyUpdate(src_set->descriptors_[src_start_idx + di].get());
    569     }
    570     if (update->descriptorCount)
    571         some_update_ = true;
    572 
    573     InvalidateBoundCmdBuffers();
    574 }
    575 
    576 cvdescriptorset::SamplerDescriptor::SamplerDescriptor() : sampler_(VK_NULL_HANDLE), immutable_(false) {
    577     updated = false;
    578     descriptor_class = PlainSampler;
    579 };
    580 
    581 cvdescriptorset::SamplerDescriptor::SamplerDescriptor(const VkSampler *immut) : sampler_(VK_NULL_HANDLE), immutable_(false) {
    582     updated = false;
    583     descriptor_class = PlainSampler;
    584     if (immut) {
    585         sampler_ = *immut;
    586         immutable_ = true;
    587         updated = true;
    588     }
    589 }
    590 
    591 bool cvdescriptorset::ValidateSampler(const VkSampler sampler,
    592                                       const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map) {
    593     return (sampler_map->count(sampler) != 0);
    594 }
    595 
    596 bool cvdescriptorset::ValidateImageUpdate(const VkImageView image_view, const VkImageLayout image_layout,
    597                                           const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
    598                                           const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
    599                                           const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
    600                                           const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map,
    601                                           std::string *error) {
    602     auto image_pair = image_view_map->find(image_view);
    603     if (image_pair == image_view_map->end()) {
    604         std::stringstream error_str;
    605         error_str << "Invalid VkImageView: " << image_view;
    606         *error = error_str.str();
    607         return false;
    608     } else {
    609         // Validate that imageLayout is compatible with aspect_mask and image format
    610         VkImageAspectFlags aspect_mask = image_pair->second.subresourceRange.aspectMask;
    611         VkImage image = image_pair->second.image;
    612         VkFormat format = VK_FORMAT_MAX_ENUM;
    613         auto img_pair = image_map->find(image);
    614         if (img_pair != image_map->end()) {
    615             format = img_pair->second.createInfo.format;
    616         } else {
    617             // Also need to check the swapchains.
    618             auto swapchain_pair = image_to_swapchain_map->find(image);
    619             if (swapchain_pair != image_to_swapchain_map->end()) {
    620                 VkSwapchainKHR swapchain = swapchain_pair->second;
    621                 auto swapchain_pair = swapchain_map->find(swapchain);
    622                 if (swapchain_pair != swapchain_map->end()) {
    623                     format = swapchain_pair->second->createInfo.imageFormat;
    624                 }
    625             }
    626         }
    627         if (format == VK_FORMAT_MAX_ENUM) {
    628             std::stringstream error_str;
    629             error_str << "Invalid image (" << image << ") in imageView (" << image_view << ").";
    630             *error = error_str.str();
    631             return false;
    632         } else {
    633             bool ds = vk_format_is_depth_or_stencil(format);
    634             switch (image_layout) {
    635             case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
    636                 // Only Color bit must be set
    637                 if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
    638                     std::stringstream error_str;
    639                     error_str << "ImageView (" << image_view << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but does "
    640                                                                 "not have VK_IMAGE_ASPECT_COLOR_BIT set.";
    641                     *error = error_str.str();
    642                     return false;
    643                 }
    644                 // format must NOT be DS
    645                 if (ds) {
    646                     std::stringstream error_str;
    647                     error_str << "ImageView (" << image_view
    648                               << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but the image format is "
    649                               << string_VkFormat(format) << " which is not a color format.";
    650                     *error = error_str.str();
    651                     return false;
    652                 }
    653                 break;
    654             case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
    655             case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
    656                 // Depth or stencil bit must be set, but both must NOT be set
    657                 if (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
    658                     if (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
    659                         // both  must NOT be set
    660                         std::stringstream error_str;
    661                         error_str << "ImageView (" << image_view << ") has both STENCIL and DEPTH aspects set";
    662                         *error = error_str.str();
    663                         return false;
    664                     }
    665                 } else if (!(aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
    666                     // Neither were set
    667                     std::stringstream error_str;
    668                     error_str << "ImageView (" << image_view << ") has layout " << string_VkImageLayout(image_layout)
    669                               << " but does not have STENCIL or DEPTH aspects set";
    670                     *error = error_str.str();
    671                     return false;
    672                 }
    673                 // format must be DS
    674                 if (!ds) {
    675                     std::stringstream error_str;
    676                     error_str << "ImageView (" << image_view << ") has layout " << string_VkImageLayout(image_layout)
    677                               << " but the image format is " << string_VkFormat(format) << " which is not a depth/stencil format.";
    678                     *error = error_str.str();
    679                     return false;
    680                 }
    681                 break;
    682             default:
    683                 // anything to check for other layouts?
    684                 break;
    685             }
    686         }
    687     }
    688     return true;
    689 }
    690 
    691 void cvdescriptorset::SamplerDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
    692     sampler_ = update->pImageInfo[index].sampler;
    693     updated = true;
    694 }
    695 
    696 void cvdescriptorset::SamplerDescriptor::CopyUpdate(const Descriptor *src) {
    697     if (!immutable_) {
    698         auto update_sampler = static_cast<const SamplerDescriptor *>(src)->sampler_;
    699         sampler_ = update_sampler;
    700     }
    701     updated = true;
    702 }
    703 
    704 cvdescriptorset::ImageSamplerDescriptor::ImageSamplerDescriptor()
    705     : sampler_(VK_NULL_HANDLE), immutable_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
    706     updated = false;
    707     descriptor_class = ImageSampler;
    708 }
    709 
    710 cvdescriptorset::ImageSamplerDescriptor::ImageSamplerDescriptor(const VkSampler *immut)
    711     : sampler_(VK_NULL_HANDLE), immutable_(true), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
    712     updated = false;
    713     descriptor_class = ImageSampler;
    714     if (immut) {
    715         sampler_ = *immut;
    716         immutable_ = true;
    717         updated = true;
    718     }
    719 }
    720 
    721 void cvdescriptorset::ImageSamplerDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
    722     updated = true;
    723     const auto &image_info = update->pImageInfo[index];
    724     sampler_ = image_info.sampler;
    725     image_view_ = image_info.imageView;
    726     image_layout_ = image_info.imageLayout;
    727 }
    728 
    729 void cvdescriptorset::ImageSamplerDescriptor::CopyUpdate(const Descriptor *src) {
    730     if (!immutable_) {
    731         auto update_sampler = static_cast<const ImageSamplerDescriptor *>(src)->sampler_;
    732         sampler_ = update_sampler;
    733     }
    734     auto image_view = static_cast<const ImageSamplerDescriptor *>(src)->image_view_;
    735     auto image_layout = static_cast<const ImageSamplerDescriptor *>(src)->image_layout_;
    736     updated = true;
    737     image_view_ = image_view;
    738     image_layout_ = image_layout;
    739 }
    740 
    741 cvdescriptorset::ImageDescriptor::ImageDescriptor(const VkDescriptorType type)
    742     : storage_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
    743     updated = false;
    744     descriptor_class = Image;
    745     if (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE == type)
    746         storage_ = true;
    747 };
    748 
    749 void cvdescriptorset::ImageDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
    750     updated = true;
    751     const auto &image_info = update->pImageInfo[index];
    752     image_view_ = image_info.imageView;
    753     image_layout_ = image_info.imageLayout;
    754 }
    755 
    756 void cvdescriptorset::ImageDescriptor::CopyUpdate(const Descriptor *src) {
    757     auto image_view = static_cast<const ImageDescriptor *>(src)->image_view_;
    758     auto image_layout = static_cast<const ImageDescriptor *>(src)->image_layout_;
    759     updated = true;
    760     image_view_ = image_view;
    761     image_layout_ = image_layout;
    762 }
    763 
    764 cvdescriptorset::BufferDescriptor::BufferDescriptor(const VkDescriptorType type)
    765     : storage_(false), dynamic_(false), buffer_(VK_NULL_HANDLE), offset_(0), range_(0) {
    766     updated = false;
    767     descriptor_class = GeneralBuffer;
    768     if (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == type) {
    769         dynamic_ = true;
    770     } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == type) {
    771         storage_ = true;
    772     } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == type) {
    773         dynamic_ = true;
    774         storage_ = true;
    775     }
    776 }
    777 void cvdescriptorset::BufferDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
    778     updated = true;
    779     const auto &buffer_info = update->pBufferInfo[index];
    780     buffer_ = buffer_info.buffer;
    781     offset_ = buffer_info.offset;
    782     range_ = buffer_info.range;
    783 }
    784 
    785 void cvdescriptorset::BufferDescriptor::CopyUpdate(const Descriptor *src) {
    786     auto buff_desc = static_cast<const BufferDescriptor *>(src);
    787     updated = true;
    788     buffer_ = buff_desc->buffer_;
    789     offset_ = buff_desc->offset_;
    790     range_ = buff_desc->range_;
    791 }
    792 
    793 cvdescriptorset::TexelDescriptor::TexelDescriptor(const VkDescriptorType type) : buffer_view_(VK_NULL_HANDLE), storage_(false) {
    794     updated = false;
    795     descriptor_class = TexelBuffer;
    796     if (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER == type)
    797         storage_ = true;
    798 };
    799 
    800 void cvdescriptorset::TexelDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index) {
    801     updated = true;
    802     buffer_view_ = update->pTexelBufferView[index];
    803 }
    804 
    805 void cvdescriptorset::TexelDescriptor::CopyUpdate(const Descriptor *src) {
    806     updated = true;
    807     buffer_view_ = static_cast<const TexelDescriptor *>(src)->buffer_view_;
    808 }
    809 // This is a helper function that iterates over a set of Write and Copy updates, pulls the DescriptorSet* for updated
    810 //  sets, and then calls their respective Validate[Write|Copy]Update functions.
    811 // If the update hits an issue for which the callback returns "true", meaning that the call down the chain should
    812 //  be skipped, then true is returned.
    813 // If there is no issue with the update, then false is returned.
    814 bool cvdescriptorset::ValidateUpdateDescriptorSets(
    815     const debug_report_data *report_data, const std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> &set_map,
    816     uint32_t write_count, const VkWriteDescriptorSet *p_wds, uint32_t copy_count, const VkCopyDescriptorSet *p_cds) {
    817     bool skip_call = false;
    818     // Validate Write updates
    819     for (uint32_t i = 0; i < write_count; i++) {
    820         auto dest_set = p_wds[i].dstSet;
    821         auto set_pair = set_map.find(dest_set);
    822         if (set_pair == set_map.end()) {
    823             skip_call |=
    824                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
    825                         reinterpret_cast<uint64_t &>(dest_set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
    826                         "Cannot call vkUpdateDescriptorSets() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.",
    827                         reinterpret_cast<uint64_t &>(dest_set));
    828         } else {
    829             std::string error_str;
    830             if (!set_pair->second->ValidateWriteUpdate(report_data, &p_wds[i], &error_str)) {
    831                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
    832                                      reinterpret_cast<uint64_t &>(dest_set), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
    833                                      "vkUpdateDescriptorsSets() failed write update validation for Descriptor Set 0x%" PRIx64
    834                                      " with error: %s",
    835                                      reinterpret_cast<uint64_t &>(dest_set), error_str.c_str());
    836             }
    837         }
    838     }
    839     // Now validate copy updates
    840     for (uint32_t i = 0; i < copy_count; ++i) {
    841         auto dst_set = p_cds[i].dstSet;
    842         auto src_set = p_cds[i].srcSet;
    843         auto src_pair = set_map.find(src_set);
    844         auto dst_pair = set_map.find(dst_set);
    845         if (src_pair == set_map.end()) {
    846             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
    847                                  reinterpret_cast<uint64_t &>(src_set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
    848                                  "Cannot call vkUpdateDescriptorSets() to copy from descriptor set 0x%" PRIxLEAST64
    849                                  " that has not been allocated.",
    850                                  reinterpret_cast<uint64_t &>(src_set));
    851         } else if (dst_pair == set_map.end()) {
    852             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
    853                                  reinterpret_cast<uint64_t &>(dst_set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
    854                                  "Cannot call vkUpdateDescriptorSets() to copy to descriptor set 0x%" PRIxLEAST64
    855                                  " that has not been allocated.",
    856                                  reinterpret_cast<uint64_t &>(dst_set));
    857         } else {
    858             std::string error_str;
    859             if (!dst_pair->second->ValidateCopyUpdate(report_data, &p_cds[i], src_pair->second, &error_str)) {
    860                 skip_call |=
    861                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
    862                             reinterpret_cast<uint64_t &>(dst_set), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
    863                             "vkUpdateDescriptorsSets() failed copy update from Descriptor Set 0x%" PRIx64
    864                             " to Descriptor Set 0x%" PRIx64 " with error: %s",
    865                             reinterpret_cast<uint64_t &>(src_set), reinterpret_cast<uint64_t &>(dst_set), error_str.c_str());
    866             }
    867         }
    868     }
    869     return skip_call;
    870 }
    871 // This is a helper function that iterates over a set of Write and Copy updates, pulls the DescriptorSet* for updated
    872 //  sets, and then calls their respective Perform[Write|Copy]Update functions.
    873 // Prerequisite : ValidateUpdateDescriptorSets() should be called and return "false" prior to calling PerformUpdateDescriptorSets()
    874 //  with the same set of updates.
    875 // This is split from the validate code to allow validation prior to calling down the chain, and then update after
    876 //  calling down the chain.
    877 void cvdescriptorset::PerformUpdateDescriptorSets(
    878     const std::unordered_map<VkDescriptorSet, cvdescriptorset::DescriptorSet *> &set_map, uint32_t write_count,
    879     const VkWriteDescriptorSet *p_wds, uint32_t copy_count, const VkCopyDescriptorSet *p_cds) {
    880     // Write updates first
    881     uint32_t i = 0;
    882     for (i = 0; i < write_count; ++i) {
    883         auto dest_set = p_wds[i].dstSet;
    884         auto set_pair = set_map.find(dest_set);
    885         if (set_pair != set_map.end()) {
    886             set_pair->second->PerformWriteUpdate(&p_wds[i]);
    887         }
    888     }
    889     // Now copy updates
    890     for (i = 0; i < copy_count; ++i) {
    891         auto dst_set = p_cds[i].dstSet;
    892         auto src_set = p_cds[i].srcSet;
    893         auto src_pair = set_map.find(src_set);
    894         auto dst_pair = set_map.find(dst_set);
    895         if (src_pair != set_map.end() && dst_pair != set_map.end()) {
    896             dst_pair->second->PerformCopyUpdate(&p_cds[i], src_pair->second);
    897         }
    898     }
    899 }
    900 // Validate the state for a given write update but don't actually perform the update
    901 //  If an error would occur for this update, return false and fill in details in error_msg string
    902 bool cvdescriptorset::DescriptorSet::ValidateWriteUpdate(const debug_report_data *report_data, const VkWriteDescriptorSet *update,
    903                                                          std::string *error_msg) {
    904     // Verify idle ds
    905     if (in_use.load()) {
    906         std::stringstream error_str;
    907         error_str << "Cannot call vkUpdateDescriptorSets() to perform write update on descriptor set " << set_
    908                   << " that is in use by a command buffer.";
    909         *error_msg = error_str.str();
    910         return false;
    911     }
    912     // Verify dst binding exists
    913     if (!p_layout_->HasBinding(update->dstBinding)) {
    914         std::stringstream error_str;
    915         error_str << "DescriptorSet " << set_ << " does not have binding " << update->dstBinding << ".";
    916         *error_msg = error_str.str();
    917         return false;
    918     } else {
    919         // We know that binding is valid, verify update and do update on each descriptor
    920         auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
    921         auto type = p_layout_->GetTypeFromBinding(update->dstBinding);
    922         if (type != update->descriptorType) {
    923             std::stringstream error_str;
    924             error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with type "
    925                       << string_VkDescriptorType(type) << " but update type is " << string_VkDescriptorType(update->descriptorType);
    926             *error_msg = error_str.str();
    927             return false;
    928         }
    929         if ((start_idx + update->descriptorCount) > p_layout_->GetTotalDescriptorCount()) {
    930             std::stringstream error_str;
    931             error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
    932                       << p_layout_->GetTotalDescriptorCount() << " total descriptors but update of " << update->descriptorCount
    933                       << " descriptors starting at binding offset of "
    934                       << p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding)
    935                       << " combined with update array element offset of " << update->dstArrayElement
    936                       << " oversteps the size of this descriptor set.";
    937             *error_msg = error_str.str();
    938             return false;
    939         }
    940         // Verify consecutive bindings match (if needed)
    941         if (!p_layout_->VerifyUpdateConsistency(update->dstBinding, update->dstArrayElement, update->descriptorCount,
    942                                                 "write update to", set_, error_msg))
    943             return false;
    944         // Update is within bounds and consistent so last step is to validate update contents
    945         if (!VerifyWriteUpdateContents(update, start_idx, error_msg)) {
    946             std::stringstream error_str;
    947             error_str << "Write update to descriptor in set " << set_ << " binding #" << update->dstBinding
    948                       << " failed with error message: " << error_msg->c_str();
    949             *error_msg = error_str.str();
    950             return false;
    951         }
    952     }
    953     // All checks passed, update is clean
    954     return true;
    955 }
    956 // Verify that the contents of the update are ok, but don't perform actual update
    957 bool cvdescriptorset::DescriptorSet::VerifyWriteUpdateContents(const VkWriteDescriptorSet *update, const uint32_t index,
    958                                                                std::string *error) const {
    959     switch (update->descriptorType) {
    960     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
    961         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
    962             // Validate image
    963             auto image_view = update->pImageInfo[di].imageView;
    964             auto image_layout = update->pImageInfo[di].imageLayout;
    965             if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
    966                                      error)) {
    967                 std::stringstream error_str;
    968                 error_str << "Attempted write update to combined image sampler descriptor failed due to: " << error->c_str();
    969                 *error = error_str.str();
    970                 return false;
    971             }
    972         }
    973         // Intentional fall-through to validate sampler
    974     }
    975     case VK_DESCRIPTOR_TYPE_SAMPLER: {
    976         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
    977             if (!descriptors_[index + di].get()->IsImmutableSampler()) {
    978                 if (!ValidateSampler(update->pImageInfo[di].sampler, sampler_map_)) {
    979                     std::stringstream error_str;
    980                     error_str << "Attempted write update to sampler descriptor with invalid sampler: "
    981                               << update->pImageInfo[di].sampler << ".";
    982                     *error = error_str.str();
    983                     return false;
    984                 }
    985             } else {
    986                 // TODO : Warn here
    987             }
    988         }
    989         break;
    990     }
    991     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
    992     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
    993     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
    994         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
    995             auto image_view = update->pImageInfo[di].imageView;
    996             auto image_layout = update->pImageInfo[di].imageLayout;
    997             if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
    998                                      error)) {
    999                 std::stringstream error_str;
   1000                 error_str << "Attempted write update to image descriptor failed due to: " << error->c_str();
   1001                 *error = error_str.str();
   1002                 return false;
   1003             }
   1004         }
   1005         break;
   1006     }
   1007     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
   1008     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
   1009         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1010             auto buffer_view = update->pTexelBufferView[di];
   1011             if (!buffer_view_map_->count(buffer_view)) {
   1012                 std::stringstream error_str;
   1013                 error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: " << buffer_view;
   1014                 *error = error_str.str();
   1015                 return false;
   1016             }
   1017         }
   1018         break;
   1019     }
   1020     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
   1021     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
   1022     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
   1023     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
   1024         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1025             auto buffer = update->pBufferInfo[di].buffer;
   1026             if (!buffer_map_->count(buffer)) {
   1027                 std::stringstream error_str;
   1028                 error_str << "Attempted write update to buffer descriptor with invalid buffer: " << buffer;
   1029                 *error = error_str.str();
   1030                 return false;
   1031             }
   1032         }
   1033         break;
   1034     }
   1035     default:
   1036         assert(0); // We've already verified update type so should never get here
   1037         break;
   1038     }
   1039     // All checks passed so update contents are good
   1040     return true;
   1041 }
   1042 // Verify that the contents of the update are ok, but don't perform actual update
   1043 bool cvdescriptorset::DescriptorSet::VerifyCopyUpdateContents(const VkCopyDescriptorSet *update, const DescriptorSet *src_set,
   1044                                                               const uint32_t index, std::string *error) const {
   1045     switch (src_set->descriptors_[index]->descriptor_class) {
   1046     case PlainSampler: {
   1047         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1048             if (!src_set->descriptors_[index + di]->IsImmutableSampler()) {
   1049                 auto update_sampler = static_cast<SamplerDescriptor *>(src_set->descriptors_[index + di].get())->GetSampler();
   1050                 if (!ValidateSampler(update_sampler, sampler_map_)) {
   1051                     std::stringstream error_str;
   1052                     error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
   1053                     *error = error_str.str();
   1054                     return false;
   1055                 }
   1056             } else {
   1057                 // TODO : Warn here
   1058             }
   1059         }
   1060         break;
   1061     }
   1062     case ImageSampler: {
   1063         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1064             auto img_samp_desc = static_cast<const ImageSamplerDescriptor *>(src_set->descriptors_[index + di].get());
   1065             // First validate sampler
   1066             if (!img_samp_desc->IsImmutableSampler()) {
   1067                 auto update_sampler = img_samp_desc->GetSampler();
   1068                 if (!ValidateSampler(update_sampler, sampler_map_)) {
   1069                     std::stringstream error_str;
   1070                     error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
   1071                     *error = error_str.str();
   1072                     return false;
   1073                 }
   1074             } else {
   1075                 // TODO : Warn here
   1076             }
   1077             // Validate image
   1078             auto image_view = img_samp_desc->GetImageView();
   1079             auto image_layout = img_samp_desc->GetImageLayout();
   1080             if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
   1081                                      error)) {
   1082                 std::stringstream error_str;
   1083                 error_str << "Attempted write update to combined image sampler descriptor failed due to: " << error->c_str();
   1084                 *error = error_str.str();
   1085                 return false;
   1086             }
   1087         }
   1088     }
   1089     case Image: {
   1090         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1091             auto img_desc = static_cast<const ImageDescriptor *>(src_set->descriptors_[index + di].get());
   1092             auto image_view = img_desc->GetImageView();
   1093             auto image_layout = img_desc->GetImageLayout();
   1094             if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
   1095                                      error)) {
   1096                 std::stringstream error_str;
   1097                 error_str << "Attempted write update to image descriptor failed due to: " << error->c_str();
   1098                 *error = error_str.str();
   1099                 return false;
   1100             }
   1101         }
   1102         break;
   1103     }
   1104     case TexelBuffer: {
   1105         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1106             auto buffer_view = static_cast<TexelDescriptor *>(src_set->descriptors_[index + di].get())->GetBufferView();
   1107             if (!buffer_view_map_->count(buffer_view)) {
   1108                 std::stringstream error_str;
   1109                 error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: " << buffer_view;
   1110                 *error = error_str.str();
   1111                 return false;
   1112             }
   1113         }
   1114         break;
   1115     }
   1116     case GeneralBuffer: {
   1117         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
   1118             auto buffer = static_cast<BufferDescriptor *>(src_set->descriptors_[index + di].get())->GetBuffer();
   1119             if (!buffer_map_->count(buffer)) {
   1120                 std::stringstream error_str;
   1121                 error_str << "Attempted write update to buffer descriptor with invalid buffer: " << buffer;
   1122                 *error = error_str.str();
   1123                 return false;
   1124             }
   1125         }
   1126         break;
   1127     }
   1128     default:
   1129         assert(0); // We've already verified update type so should never get here
   1130         break;
   1131     }
   1132     // All checks passed so update contents are good
   1133     return true;
   1134 }