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 }