blob: 851e1932fbdb275dca45568b42d3bd81bcf65cd4 [file] [log] [blame]
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001/* Copyright (c) 2015-2022 The Khronos Group Inc.
2 * Copyright (c) 2015-2022 Valve Corporation
3 * Copyright (c) 2015-2022 LunarG, Inc.
4 * Copyright (C) 2015-2022 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@google.com>
19 * John Zulauf <jzulauf@lunarg.com>
20 * Jeremy Kniager <jeremyk@lunarg.com>
21 * Jeremy Gebben <jeremyg@lunarg.com>
22 */
23
24#include "core_validation_error_enums.h"
25#include "core_validation.h"
26#include "descriptor_sets.h"
27
28using DescriptorSet = cvdescriptorset::DescriptorSet;
29using DescriptorSetLayout = cvdescriptorset::DescriptorSetLayout;
30using DescriptorSetLayoutDef = cvdescriptorset::DescriptorSetLayoutDef;
31using DescriptorSetLayoutId = cvdescriptorset::DescriptorSetLayoutId;
32
33// TODO: Find a way to add smarts to the autogenerated version of this
34static std::string smart_string_VkShaderStageFlags(VkShaderStageFlags stage_flags) {
35 if (stage_flags == VK_SHADER_STAGE_ALL) {
36 return string_VkShaderStageFlagBits(VK_SHADER_STAGE_ALL);
37 }
38
39 return string_VkShaderStageFlags(stage_flags);
40}
41
Nathaniel Cesario5da09762022-06-07 13:33:58 -060042template <typename DSLayoutBindingA, typename DSLayoutBindingB>
43bool ImmutableSamplersAreEqual(const DSLayoutBindingA &b1, const DSLayoutBindingB &b2) {
44 if (b1.pImmutableSamplers == b2.pImmutableSamplers) {
45 return true;
46 } else if (b1.pImmutableSamplers && b2.pImmutableSamplers) {
47 if ((b1.descriptorType == b2.descriptorType) &&
48 ((b1.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) || (b1.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)) &&
49 (b1.descriptorCount == b2.descriptorCount)) {
50 for (uint32_t i = 0; i < b1.descriptorCount; ++i) {
51 if (b1.pImmutableSamplers[i] != b2.pImmutableSamplers[i]) {
52 return false;
53 }
54 }
55 return true;
56 } else {
57 return false;
58 }
59 } else {
60 // One pointer is null, the other is not
61 return false;
62 }
63}
64
Jeremy Gebbenbb718a32022-05-12 08:51:10 -060065// If our layout is compatible with bound_dsl, return true,
66// else return false and fill in error_msg will description of what causes incompatibility
Jeremy Gebben567a5be2022-05-12 09:14:47 -060067bool CoreChecks::VerifySetLayoutCompatibility(const DescriptorSetLayout &layout_dsl, const DescriptorSetLayout &bound_dsl,
68 std::string &error_msg) const {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -060069 // Short circuit the detailed check.
Jeremy Gebben567a5be2022-05-12 09:14:47 -060070 if (layout_dsl.IsCompatible(&bound_dsl)) return true;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -060071
72 // Do a detailed compatibility check of this lhs def (referenced by layout_dsl), vs. the rhs (layout and def)
73 // Should only be run if trivial accept has failed, and in that context should return false.
Jeremy Gebben567a5be2022-05-12 09:14:47 -060074 VkDescriptorSetLayout layout_dsl_handle = layout_dsl.GetDescriptorSetLayout();
75 VkDescriptorSetLayout bound_dsl_handle = bound_dsl.GetDescriptorSetLayout();
76 DescriptorSetLayoutDef const *layout_ds_layout_def = layout_dsl.GetLayoutDef();
77 DescriptorSetLayoutDef const *bound_ds_layout_def = bound_dsl.GetLayoutDef();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -060078
79 // Check descriptor counts
80 const auto bound_total_count = bound_ds_layout_def->GetTotalDescriptorCount();
81 if (layout_ds_layout_def->GetTotalDescriptorCount() != bound_ds_layout_def->GetTotalDescriptorCount()) {
82 std::stringstream error_str;
83 error_str << report_data->FormatHandle(layout_dsl_handle) << " from pipeline layout has "
84 << layout_ds_layout_def->GetTotalDescriptorCount() << " total descriptors, but "
85 << report_data->FormatHandle(bound_dsl_handle) << ", which is bound, has " << bound_total_count
86 << " total descriptors.";
Jeremy Gebben567a5be2022-05-12 09:14:47 -060087 error_msg = error_str.str();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -060088 return false; // trivial fail case
89 }
90
91 // Descriptor counts match so need to go through bindings one-by-one
92 // and verify that type and stageFlags match
93 for (const auto &layout_binding : layout_ds_layout_def->GetBindings()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -060094 const auto bound_binding = bound_ds_layout_def->GetBindingInfoFromBinding(layout_binding.binding);
95 if (layout_binding.descriptorCount != bound_binding->descriptorCount) {
96 std::stringstream error_str;
97 error_str << "Binding " << layout_binding.binding << " for " << report_data->FormatHandle(layout_dsl_handle)
98 << " from pipeline layout has a descriptorCount of " << layout_binding.descriptorCount << " but binding "
99 << layout_binding.binding << " for " << report_data->FormatHandle(bound_dsl_handle)
100 << ", which is bound, has a descriptorCount of " << bound_binding->descriptorCount;
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600101 error_msg = error_str.str();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600102 return false;
103 } else if (layout_binding.descriptorType != bound_binding->descriptorType) {
104 std::stringstream error_str;
105 error_str << "Binding " << layout_binding.binding << " for " << report_data->FormatHandle(layout_dsl_handle)
106 << " from pipeline layout is type '" << string_VkDescriptorType(layout_binding.descriptorType)
107 << "' but binding " << layout_binding.binding << " for " << report_data->FormatHandle(bound_dsl_handle)
108 << ", which is bound, is type '" << string_VkDescriptorType(bound_binding->descriptorType) << "'";
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600109 error_msg = error_str.str();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600110 return false;
111 } else if (layout_binding.stageFlags != bound_binding->stageFlags) {
112 std::stringstream error_str;
113 error_str << "Binding " << layout_binding.binding << " for " << report_data->FormatHandle(layout_dsl_handle)
114 << " from pipeline layout has stageFlags " << smart_string_VkShaderStageFlags(layout_binding.stageFlags)
115 << " but binding " << layout_binding.binding << " for " << report_data->FormatHandle(bound_dsl_handle)
116 << ", which is bound, has stageFlags " << smart_string_VkShaderStageFlags(bound_binding->stageFlags);
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600117 error_msg = error_str.str();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600118 return false;
Nathaniel Cesario5da09762022-06-07 13:33:58 -0600119 } else if (!ImmutableSamplersAreEqual(layout_binding, *bound_binding)) {
120 error_msg = "Immutable samplers from binding " + std::to_string(layout_binding.binding) + " in pipeline layout " +
121 report_data->FormatHandle(layout_dsl_handle) +
122 " do not match the immutable samplers in the layout currently bound (" +
123 report_data->FormatHandle(bound_dsl_handle) + ")";
124 return false;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600125 }
126 }
127
128 const auto &ds_layout_flags = layout_ds_layout_def->GetBindingFlags();
129 const auto &bound_layout_flags = bound_ds_layout_def->GetBindingFlags();
130 if (bound_layout_flags != ds_layout_flags) {
131 std::stringstream error_str;
132 assert(ds_layout_flags.size() == bound_layout_flags.size());
133 size_t i;
134 for (i = 0; i < ds_layout_flags.size(); i++) {
135 if (ds_layout_flags[i] != bound_layout_flags[i]) break;
136 }
137 error_str << report_data->FormatHandle(layout_dsl_handle)
138 << " from pipeline layout does not have the same binding flags at binding " << i << " ( "
139 << string_VkDescriptorBindingFlagsEXT(ds_layout_flags[i]) << " ) as "
140 << report_data->FormatHandle(bound_dsl_handle) << " ( "
141 << string_VkDescriptorBindingFlagsEXT(bound_layout_flags[i]) << " ), which is bound";
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600142 error_msg = error_str.str();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600143 return false;
144 }
145
146 // No detailed check should succeed if the trivial check failed -- or the dictionary has failed somehow.
147 bool compatible = true;
148 assert(!compatible);
149 return compatible;
150}
151
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600152// For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
153// pipelineLayout[layoutIndex]
154bool CoreChecks::VerifySetLayoutCompatibility(const cvdescriptorset::DescriptorSet &descriptor_set,
155 const PIPELINE_LAYOUT_STATE &pipeline_layout, const uint32_t layoutIndex,
156 std::string &errorMsg) const {
157 auto num_sets = pipeline_layout.set_layouts.size();
158 if (layoutIndex >= num_sets) {
159 std::stringstream error_str;
160 error_str << report_data->FormatHandle(pipeline_layout.layout()) << ") only contains " << num_sets
161 << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
162 << layoutIndex;
163 errorMsg = error_str.str();
164 return false;
165 }
166 if (descriptor_set.IsPushDescriptor()) return true;
167 const auto *layout_node = pipeline_layout.set_layouts[layoutIndex].get();
168 if (layout_node && (descriptor_set.GetBindingCount() > 0) && (layout_node->GetBindingCount() > 0)) {
169 return VerifySetLayoutCompatibility(*layout_node, *descriptor_set.GetLayout(), errorMsg);
170 } else {
171 // It's possible the DSL is null when creating a graphics pipeline library, in which case we can't verify compatibility
172 // here.
173 return true;
174 }
175}
176
177bool CoreChecks::PreCallValidateCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
178 VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
179 const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
180 const uint32_t *pDynamicOffsets) const {
181 auto cb_state = GetRead<CMD_BUFFER_STATE>(commandBuffer);
182 assert(cb_state);
183 bool skip = false;
184 skip |= ValidateCmd(cb_state.get(), CMD_BINDDESCRIPTORSETS);
185 // Track total count of dynamic descriptor types to make sure we have an offset for each one
186 uint32_t total_dynamic_descriptors = 0;
187 std::string error_string = "";
188
189 auto pipeline_layout = Get<PIPELINE_LAYOUT_STATE>(layout);
190 for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
191 auto descriptor_set = Get<cvdescriptorset::DescriptorSet>(pDescriptorSets[set_idx]);
192 if (descriptor_set) {
193 // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
194 if (!VerifySetLayoutCompatibility(*descriptor_set, *pipeline_layout, set_idx + firstSet, error_string)) {
195 skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358",
196 "vkCmdBindDescriptorSets(): descriptorSet #%u being bound is not compatible with overlapping "
197 "descriptorSetLayout at index %u of "
198 "%s due to: %s.",
199 set_idx, set_idx + firstSet, report_data->FormatHandle(layout).c_str(), error_string.c_str());
200 }
201
202 auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
203 if (set_dynamic_descriptor_count) {
204 // First make sure we won't overstep bounds of pDynamicOffsets array
205 if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
206 // Test/report this here, such that we don't run past the end of pDynamicOffsets in the else clause
207 skip |=
208 LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359",
209 "vkCmdBindDescriptorSets(): descriptorSet #%u (%s) requires %u dynamicOffsets, but only %u "
210 "dynamicOffsets are left in "
211 "pDynamicOffsets array. There must be one dynamic offset for each dynamic descriptor being bound.",
212 set_idx, report_data->FormatHandle(pDescriptorSets[set_idx]).c_str(),
213 descriptor_set->GetDynamicDescriptorCount(), (dynamicOffsetCount - total_dynamic_descriptors));
214 // Set the number found to the maximum to prevent duplicate messages, or subsquent descriptor sets from
215 // testing against the "short tail" we're skipping below.
216 total_dynamic_descriptors = dynamicOffsetCount;
217 } else { // Validate dynamic offsets and Dynamic Offset Minimums
218 // offset for all sets (pDynamicOffsets)
219 uint32_t cur_dyn_offset = total_dynamic_descriptors;
220 // offset into this descriptor set
221 uint32_t set_dyn_offset = 0;
222 const auto &dsl = descriptor_set->GetLayout();
223 const auto binding_count = dsl->GetBindingCount();
224 const auto &limits = phys_dev_props.limits;
225 for (uint32_t i = 0; i < binding_count; i++) {
226 const auto *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(i);
227 // skip checking binding if not needed
228 if (cvdescriptorset::IsDynamicDescriptor(binding->descriptorType) == false) {
229 continue;
230 }
231
232 // If a descriptor set has only binding 0 and 2 the binding_index will be 0 and 2
233 const uint32_t binding_index = binding->binding;
234 const uint32_t descriptorCount = binding->descriptorCount;
235
236 // Need to loop through each descriptor count inside the binding
237 // if descriptorCount is zero the binding with a dynamic descriptor type does not count
238 for (uint32_t j = 0; j < descriptorCount; j++) {
239 const uint32_t offset = pDynamicOffsets[cur_dyn_offset];
240 if (offset == 0) {
241 // offset of zero is equivalent of not having the dynamic offset
242 cur_dyn_offset++;
243 set_dyn_offset++;
244 continue;
245 }
246
247 // Validate alignment with limit
248 if ((binding->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) &&
249 (SafeModulo(offset, limits.minUniformBufferOffsetAlignment) != 0)) {
250 skip |= LogError(commandBuffer, "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971",
251 "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is %u, but must be a multiple of "
252 "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
253 cur_dyn_offset, offset, limits.minUniformBufferOffsetAlignment);
254 }
255 if ((binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) &&
256 (SafeModulo(offset, limits.minStorageBufferOffsetAlignment) != 0)) {
257 skip |= LogError(commandBuffer, "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972",
258 "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is %u, but must be a multiple of "
259 "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
260 cur_dyn_offset, offset, limits.minStorageBufferOffsetAlignment);
261 }
262
263 auto *descriptor = descriptor_set->GetDescriptorFromDynamicOffsetIndex(set_dyn_offset);
264 assert(descriptor != nullptr);
265 // Currently only GeneralBuffer are dynamic and need to be checked
266 if (descriptor->GetClass() == cvdescriptorset::DescriptorClass::GeneralBuffer) {
267 const auto *buffer_descriptor = static_cast<const cvdescriptorset::BufferDescriptor *>(descriptor);
268 const VkDeviceSize bound_range = buffer_descriptor->GetRange();
269 const VkDeviceSize bound_offset = buffer_descriptor->GetOffset();
270 // NOTE: null / invalid buffers may show up here, errors are raised elsewhere for this.
271 auto buffer_state = buffer_descriptor->GetBufferState();
272
273 // Validate offset didn't go over buffer
274 if ((bound_range == VK_WHOLE_SIZE) && (offset > 0)) {
275 LogObjectList objlist(commandBuffer);
276 objlist.add(pDescriptorSets[set_idx]);
277 objlist.add(buffer_descriptor->GetBuffer());
278 skip |=
279 LogError(objlist, "VUID-vkCmdBindDescriptorSets-pDescriptorSets-06715",
280 "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is 0x%x, but must be zero since "
281 "the buffer descriptor's range is VK_WHOLE_SIZE in descriptorSet #%u binding #%u "
282 "descriptor[%u].",
283 cur_dyn_offset, offset, set_idx, binding_index, j);
284
285 } else if (buffer_state && (bound_range != VK_WHOLE_SIZE) &&
286 ((offset + bound_range + bound_offset) > buffer_state->createInfo.size)) {
287 LogObjectList objlist(commandBuffer);
288 objlist.add(pDescriptorSets[set_idx]);
289 objlist.add(buffer_descriptor->GetBuffer());
290 skip |=
291 LogError(objlist, "VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979",
292 "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is 0x%x which when added to the "
293 "buffer descriptor's range (0x%" PRIxLEAST64
294 ") is greater than the size of the buffer (0x%" PRIxLEAST64
295 ") in descriptorSet #%u binding #%u descriptor[%u].",
296 cur_dyn_offset, offset, bound_range, buffer_state->createInfo.size, set_idx,
297 binding_index, j);
298 }
299 }
300 cur_dyn_offset++;
301 set_dyn_offset++;
302 } // descriptorCount loop
303 } // bindingCount loop
304 // Keep running total of dynamic descriptor count to verify at the end
305 total_dynamic_descriptors += set_dynamic_descriptor_count;
306 }
307 }
308 if (descriptor_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE) {
309 skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-pDescriptorSets-04616",
310 "vkCmdBindDescriptorSets(): pDescriptorSets[%" PRIu32
311 "] was allocated from a pool that was created with VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE.",
312 set_idx);
313 }
314 } else {
315 if (!IsExtEnabled(device_extensions.vk_ext_graphics_pipeline_library)) {
316 skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-pDescriptorSets-06563",
317 "vkCmdBindDescriptorSets(): Attempt to bind pDescriptorSets[%" PRIu32
318 "] (%s) that does not exist, and %s is not enabled.",
319 set_idx, report_data->FormatHandle(pDescriptorSets[set_idx]).c_str(),
320 VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
Nathaniel Cesarioc97b4d72022-05-26 23:19:56 -0600321 } else if (!enabled_features.graphics_pipeline_library_features.graphicsPipelineLibrary) {
322 skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-graphicsPipelineLibrary-06754",
323 "vkCmdBindDescriptorSets(): Attempt to bind pDescriptorSets[%" PRIu32
324 "] (%s) that does not exist, and the layout was not created "
325 "VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT.",
326 set_idx, report_data->FormatHandle(pDescriptorSets[set_idx]).c_str());
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600327 }
328 }
329 }
330 // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
331 if (total_dynamic_descriptors != dynamicOffsetCount) {
332 skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359",
333 "vkCmdBindDescriptorSets(): Attempting to bind %u descriptorSets with %u dynamic descriptors, but "
334 "dynamicOffsetCount is %u. It should "
335 "exactly match the number of dynamic descriptors.",
336 setCount, total_dynamic_descriptors, dynamicOffsetCount);
337 }
338 // firstSet and descriptorSetCount sum must be less than setLayoutCount
339 if ((firstSet + setCount) > static_cast<uint32_t>(pipeline_layout->set_layouts.size())) {
340 skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindDescriptorSets-firstSet-00360",
341 "vkCmdBindDescriptorSets(): Sum of firstSet (%u) and descriptorSetCount (%u) is greater than "
342 "VkPipelineLayoutCreateInfo::setLayoutCount "
343 "(%zu) when pipeline layout was created",
344 firstSet, setCount, pipeline_layout->set_layouts.size());
345 }
346
347 static const std::map<VkPipelineBindPoint, std::string> bindpoint_errors = {
348 std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361"),
349 std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361"),
350 std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361")};
351 skip |= ValidatePipelineBindPoint(cb_state.get(), pipelineBindPoint, "vkCmdBindPipeline()", bindpoint_errors);
352
353 return skip;
354}
355
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600356// Validate descriptor set layout create info
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600357static bool ValidateDescriptorSetLayoutCreateInfo(
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600358 const ValidationObject *val_obj, const VkDescriptorSetLayoutCreateInfo *create_info, const bool push_descriptor_ext,
359 const uint32_t max_push_descriptors, const bool descriptor_indexing_ext,
360 const VkPhysicalDeviceVulkan12Features *core12_features, const VkPhysicalDeviceVulkan13Features *core13_features,
361 const VkPhysicalDeviceInlineUniformBlockPropertiesEXT *inline_uniform_block_props,
362 const VkPhysicalDeviceAccelerationStructureFeaturesKHR *acceleration_structure_features,
363 const DeviceExtensions *device_extensions) {
364 bool skip = false;
365 layer_data::unordered_set<uint32_t> bindings;
366 uint64_t total_descriptors = 0;
367
368 const auto *flags_create_info = LvlFindInChain<VkDescriptorSetLayoutBindingFlagsCreateInfo>(create_info->pNext);
369
370 const bool push_descriptor_set = !!(create_info->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR);
371 if (push_descriptor_set && !push_descriptor_ext) {
372 skip |= val_obj->LogError(
373 val_obj->device, kVUID_Core_DrawState_ExtensionNotEnabled,
374 "vkCreateDescriptorSetLayout(): Attempted to use %s in %s but its required extension %s has not been enabled.\n",
375 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR", "VkDescriptorSetLayoutCreateInfo::flags",
376 VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
377 }
378
379 const bool update_after_bind_set = !!(create_info->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
380 if (update_after_bind_set && !descriptor_indexing_ext) {
381 skip |= val_obj->LogError(
382 val_obj->device, kVUID_Core_DrawState_ExtensionNotEnabled,
383 "vkCreateDescriptorSetLayout(): Attemped to use %s in %s but its required extension %s has not been enabled.\n",
384 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT", "VkDescriptorSetLayoutCreateInfo::flags",
385 VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
386 }
387
388 auto valid_type = [push_descriptor_set](const VkDescriptorType type) {
389 return !push_descriptor_set ||
390 ((type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) && (type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) &&
391 (type != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT));
392 };
393
394 uint32_t max_binding = 0;
395
396 uint32_t update_after_bind = create_info->bindingCount;
397 uint32_t uniform_buffer_dynamic = create_info->bindingCount;
398 uint32_t storage_buffer_dynamic = create_info->bindingCount;
399
400 for (uint32_t i = 0; i < create_info->bindingCount; ++i) {
401 const auto &binding_info = create_info->pBindings[i];
402 max_binding = std::max(max_binding, binding_info.binding);
403
404 if (!bindings.insert(binding_info.binding).second) {
405 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutCreateInfo-binding-00279",
406 "vkCreateDescriptorSetLayout(): pBindings[%u] has duplicated binding number (%u).", i,
407 binding_info.binding);
408 }
409 if (!valid_type(binding_info.descriptorType)) {
410 skip |= val_obj->LogError(val_obj->device,
411 (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
412 ? "VUID-VkDescriptorSetLayoutCreateInfo-flags-02208"
413 : "VUID-VkDescriptorSetLayoutCreateInfo-flags-00280",
414 "vkCreateDescriptorSetLayout(): pBindings[%u] has invalid type %s , for push descriptors.", i,
415 string_VkDescriptorType(binding_info.descriptorType));
416 }
417
418 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
419 if (!core13_features->inlineUniformBlock) {
420 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBinding-descriptorType-04604",
421 "vkCreateDescriptorSetLayout(): pBindings[%u] is creating VkDescriptorSetLayout with "
422 "descriptor type VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT "
423 "but the inlineUniformBlock feature is not enabled",
424 i);
425 } else {
426 if ((binding_info.descriptorCount % 4) != 0) {
427 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBinding-descriptorType-02209",
428 "vkCreateDescriptorSetLayout(): pBindings[%u] has descriptorCount =(%" PRIu32
429 ") but must be a multiple of 4",
430 i, binding_info.descriptorCount);
431 }
432 if (binding_info.descriptorCount > inline_uniform_block_props->maxInlineUniformBlockSize) {
433 skip |=
434 val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBinding-descriptorType-02210",
435 "vkCreateDescriptorSetLayout(): pBindings[%u] has descriptorCount =(%" PRIu32
436 ") but must be less than or equal to maxInlineUniformBlockSize (%u)",
437 i, binding_info.descriptorCount, inline_uniform_block_props->maxInlineUniformBlockSize);
438 }
439 }
440 } else if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
441 uniform_buffer_dynamic = i;
442 } else if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
443 storage_buffer_dynamic = i;
444 }
445
446 if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
447 binding_info.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
448 binding_info.pImmutableSamplers && IsExtEnabled(device_extensions->vk_ext_custom_border_color)) {
449 const CoreChecks *core_checks = reinterpret_cast<const CoreChecks *>(val_obj);
450 for (uint32_t j = 0; j < binding_info.descriptorCount; j++) {
451 auto sampler_state = core_checks->Get<SAMPLER_STATE>(binding_info.pImmutableSamplers[j]);
452 if (sampler_state && (sampler_state->createInfo.borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT ||
453 sampler_state->createInfo.borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT)) {
454 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBinding-pImmutableSamplers-04009",
455 "vkCreateDescriptorSetLayout(): pBindings[%u].pImmutableSamplers[%u] has VkSampler %s"
456 " presented as immutable has a custom border color",
457 i, j, val_obj->report_data->FormatHandle(binding_info.pImmutableSamplers[j]).c_str());
458 }
459 }
460 }
461
462 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE && binding_info.pImmutableSamplers != nullptr) {
463 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBinding-descriptorType-04605",
464 "vkCreateDescriptorSetLayout(): pBindings[%u] has descriptorType "
465 "VK_DESCRIPTOR_TYPE_MUTABLE_VALVE but pImmutableSamplers is not NULL.",
466 i);
467 }
468
469 total_descriptors += binding_info.descriptorCount;
470 }
471
472 if (flags_create_info) {
473 if (flags_create_info->bindingCount != 0 && flags_create_info->bindingCount != create_info->bindingCount) {
474 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-bindingCount-03002",
475 "vkCreateDescriptorSetLayout(): VkDescriptorSetLayoutCreateInfo::bindingCount (%d) != "
476 "VkDescriptorSetLayoutBindingFlagsCreateInfo::bindingCount (%d)",
477 create_info->bindingCount, flags_create_info->bindingCount);
478 }
479
480 if (flags_create_info->bindingCount == create_info->bindingCount) {
481 for (uint32_t i = 0; i < create_info->bindingCount; ++i) {
482 const auto &binding_info = create_info->pBindings[i];
483
484 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT) {
485 update_after_bind = i;
486 if (!update_after_bind_set) {
487 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutCreateInfo-flags-03000",
488 "vkCreateDescriptorSetLayout(): pBindings[%u] does not have "
489 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT.",
490 i);
491 }
492
493 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER &&
494 !core12_features->descriptorBindingUniformBufferUpdateAfterBind) {
495 skip |= val_obj->LogError(
496 val_obj->device,
497 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
498 "descriptorBindingUniformBufferUpdateAfterBind-03005",
499 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
500 "for %s since descriptorBindingUniformBufferUpdateAfterBind is not enabled.",
501 i, string_VkDescriptorType(binding_info.descriptorType));
502 }
503 if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
504 binding_info.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ||
505 binding_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) &&
506 !core12_features->descriptorBindingSampledImageUpdateAfterBind) {
507 skip |= val_obj->LogError(
508 val_obj->device,
509 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
510 "descriptorBindingSampledImageUpdateAfterBind-03006",
511 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
512 "for %s since descriptorBindingSampledImageUpdateAfterBind is not enabled.",
513 i, string_VkDescriptorType(binding_info.descriptorType));
514 }
515 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE &&
516 !core12_features->descriptorBindingStorageImageUpdateAfterBind) {
517 skip |= val_obj->LogError(
518 val_obj->device,
519 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
520 "descriptorBindingStorageImageUpdateAfterBind-03007",
521 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
522 "for %s since descriptorBindingStorageImageUpdateAfterBind is not enabled.",
523 i, string_VkDescriptorType(binding_info.descriptorType));
524 }
525 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER &&
526 !core12_features->descriptorBindingStorageBufferUpdateAfterBind) {
527 skip |= val_obj->LogError(
528 val_obj->device,
529 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
530 "descriptorBindingStorageBufferUpdateAfterBind-03008",
531 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
532 "for %s since descriptorBindingStorageBufferUpdateAfterBind is not enabled.",
533 i, string_VkDescriptorType(binding_info.descriptorType));
534 }
535 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER &&
536 !core12_features->descriptorBindingUniformTexelBufferUpdateAfterBind) {
537 skip |= val_obj->LogError(
538 val_obj->device,
539 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
540 "descriptorBindingUniformTexelBufferUpdateAfterBind-03009",
541 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
542 "for %s since descriptorBindingUniformTexelBufferUpdateAfterBind is not enabled.",
543 i, string_VkDescriptorType(binding_info.descriptorType));
544 }
545 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER &&
546 !core12_features->descriptorBindingStorageTexelBufferUpdateAfterBind) {
547 skip |= val_obj->LogError(
548 val_obj->device,
549 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
550 "descriptorBindingStorageTexelBufferUpdateAfterBind-03010",
551 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
552 "for %s since descriptorBindingStorageTexelBufferUpdateAfterBind is not enabled.",
553 i, string_VkDescriptorType(binding_info.descriptorType));
554 }
555 if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ||
556 binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
557 binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
558 skip |= val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-None-03011",
559 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have "
560 "VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT for %s.",
561 i, string_VkDescriptorType(binding_info.descriptorType));
562 }
563
564 if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT &&
565 !core13_features->descriptorBindingInlineUniformBlockUpdateAfterBind) {
566 skip |= val_obj->LogError(
567 val_obj->device,
568 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
569 "descriptorBindingInlineUniformBlockUpdateAfterBind-02211",
570 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
571 "for %s since descriptorBindingInlineUniformBlockUpdateAfterBind is not enabled.",
572 i, string_VkDescriptorType(binding_info.descriptorType));
573 }
574 if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR ||
575 binding_info.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV) &&
576 !acceleration_structure_features->descriptorBindingAccelerationStructureUpdateAfterBind) {
577 skip |= val_obj->LogError(val_obj->device,
578 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-"
579 "descriptorBindingAccelerationStructureUpdateAfterBind-03570",
580 "vkCreateDescriptorSetLayout(): pBindings[%" PRIu32
581 "] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
582 "for %s if "
583 "VkPhysicalDeviceAccelerationStructureFeaturesKHR::"
584 "descriptorBindingAccelerationStructureUpdateAfterBind is not enabled.",
585 i, string_VkDescriptorType(binding_info.descriptorType));
586 }
587 }
588
589 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT) {
590 if (!core12_features->descriptorBindingUpdateUnusedWhilePending) {
591 skip |= val_obj->LogError(
592 val_obj->device,
593 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingUpdateUnusedWhilePending-03012",
594 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have "
595 "VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT for %s since "
596 "descriptorBindingUpdateUnusedWhilePending is not enabled.",
597 i, string_VkDescriptorType(binding_info.descriptorType));
598 }
599 }
600
601 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT) {
602 if (!core12_features->descriptorBindingPartiallyBound) {
603 skip |= val_obj->LogError(
604 val_obj->device,
605 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingPartiallyBound-03013",
606 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT for "
607 "%s since descriptorBindingPartiallyBound is not enabled.",
608 i, string_VkDescriptorType(binding_info.descriptorType));
609 }
610 }
611
612 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) {
613 if (binding_info.binding != max_binding) {
614 skip |= val_obj->LogError(
615 val_obj->device, "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03004",
616 "vkCreateDescriptorSetLayout(): pBindings[%u] has VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT "
617 "but %u is the largest value of all the bindings.",
618 i, binding_info.binding);
619 }
620
621 if (!core12_features->descriptorBindingVariableDescriptorCount) {
622 skip |= val_obj->LogError(
623 val_obj->device,
624 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014",
625 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have "
626 "VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT for %s since "
627 "descriptorBindingVariableDescriptorCount is not enabled.",
628 i, string_VkDescriptorType(binding_info.descriptorType));
629 }
630 if ((binding_info.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
631 (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
632 skip |= val_obj->LogError(val_obj->device,
633 "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03015",
634 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have "
635 "VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT for %s.",
636 i, string_VkDescriptorType(binding_info.descriptorType));
637 }
638 }
639
640 if (push_descriptor_set &&
641 (flags_create_info->pBindingFlags[i] &
642 (VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT |
643 VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT))) {
644 skip |= val_obj->LogError(
645 val_obj->device, "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003",
646 "vkCreateDescriptorSetLayout(): pBindings[%u] can't have VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, "
647 "VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, or "
648 "VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT for with "
649 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR.",
650 i);
651 }
652 }
653 }
654 }
655
656 if (update_after_bind < create_info->bindingCount) {
657 if (uniform_buffer_dynamic < create_info->bindingCount) {
658 skip |=
659 val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001",
660 "vkCreateDescriptorSetLayout(): binding (%" PRIi32
661 ") has VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
662 "flag, but binding (%" PRIi32 ") has descriptor type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC.",
663 update_after_bind, uniform_buffer_dynamic);
664 }
665 if (storage_buffer_dynamic < create_info->bindingCount) {
666 skip |=
667 val_obj->LogError(val_obj->device, "VUID-VkDescriptorSetLayoutCreateInfo-descriptorType-03001",
668 "vkCreateDescriptorSetLayout(): binding (%" PRIi32
669 ") has VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT "
670 "flag, but binding (%" PRIi32 ") has descriptor type VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC.",
671 update_after_bind, storage_buffer_dynamic);
672 }
673 }
674
675 if ((push_descriptor_set) && (total_descriptors > max_push_descriptors)) {
676 const char *undefined = push_descriptor_ext ? "" : " -- undefined";
677 skip |= val_obj->LogError(
678 val_obj->device, "VUID-VkDescriptorSetLayoutCreateInfo-flags-00281",
679 "vkCreateDescriptorSetLayout(): for push descriptor, total descriptor count in layout (%" PRIu64
680 ") must not be greater than VkPhysicalDevicePushDescriptorPropertiesKHR::maxPushDescriptors (%" PRIu32 "%s).",
681 total_descriptors, max_push_descriptors, undefined);
682 }
683
684 return skip;
685}
686
Jeremy Gebben567a5be2022-05-12 09:14:47 -0600687bool CoreChecks::PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
688 const VkAllocationCallbacks *pAllocator,
689 VkDescriptorSetLayout *pSetLayout) const {
690 return ValidateDescriptorSetLayoutCreateInfo(
691 this, pCreateInfo, IsExtEnabled(device_extensions.vk_khr_push_descriptor),
692 phys_dev_ext_props.push_descriptor_props.maxPushDescriptors, IsExtEnabled(device_extensions.vk_ext_descriptor_indexing),
693 &enabled_features.core12, &enabled_features.core13, &phys_dev_ext_props.inline_uniform_block_props,
694 &enabled_features.ray_tracing_acceleration_structure_features, &device_extensions);
695}
696
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600697static std::string StringDescriptorReqViewType(DescriptorReqFlags req) {
698 std::string result("");
699 for (unsigned i = 0; i <= VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; i++) {
700 if (req & (1 << i)) {
701 if (result.size()) result += ", ";
702 result += string_VkImageViewType(VkImageViewType(i));
703 }
704 }
705
706 if (!result.size()) result = "(none)";
707
708 return result;
709}
710
711static char const *StringDescriptorReqComponentType(DescriptorReqFlags req) {
712 if (req & DESCRIPTOR_REQ_COMPONENT_TYPE_SINT) return "SINT";
713 if (req & DESCRIPTOR_REQ_COMPONENT_TYPE_UINT) return "UINT";
714 if (req & DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT) return "FLOAT";
715 return "(none)";
716}
717
718unsigned DescriptorRequirementsBitsFromFormat(VkFormat fmt) {
719 if (FormatIsSINT(fmt)) return DESCRIPTOR_REQ_COMPONENT_TYPE_SINT;
720 if (FormatIsUINT(fmt)) return DESCRIPTOR_REQ_COMPONENT_TYPE_UINT;
721 // Formats such as VK_FORMAT_D16_UNORM_S8_UINT are both
722 if (FormatIsDepthAndStencil(fmt)) return DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT | DESCRIPTOR_REQ_COMPONENT_TYPE_UINT;
723 if (fmt == VK_FORMAT_UNDEFINED) return 0;
724 // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
725 return DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT;
726}
727
728// Validate that the state of this set is appropriate for the given bindings and dynamic_offsets at Draw time
729// This includes validating that all descriptors in the given bindings are updated,
730// that any update buffers are valid, and that any dynamic offsets are within the bounds of their buffers.
731// Return true if state is acceptable, or false and write an error message into error string
732bool CoreChecks::ValidateDrawState(const DescriptorSet *descriptor_set, const BindingReqMap &bindings,
733 const std::vector<uint32_t> &dynamic_offsets, const CMD_BUFFER_STATE *cb_node,
734 const std::vector<IMAGE_VIEW_STATE *> *attachments, const std::vector<SUBPASS_INFO> *subpasses,
735 const char *caller, const DrawDispatchVuid &vuids) const {
736 layer_data::optional<layer_data::unordered_map<VkImageView, VkImageLayout>> checked_layouts;
737 if (descriptor_set->GetTotalDescriptorCount() > cvdescriptorset::PrefilterBindRequestMap::kManyDescriptors_) {
738 checked_layouts.emplace();
739 }
740 bool result = false;
741 VkFramebuffer framebuffer = cb_node->activeFramebuffer ? cb_node->activeFramebuffer->framebuffer() : VK_NULL_HANDLE;
Jeremy Gebben080210f2022-05-05 13:37:08 -0600742 DescriptorContext context{caller, vuids, cb_node, descriptor_set, attachments,
743 subpasses, framebuffer, true, dynamic_offsets, checked_layouts};
744
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600745 for (const auto &binding_pair : bindings) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600746 const auto *binding = descriptor_set->GetBinding(binding_pair.first);
747 if (!binding) { // End at construction is the condition for an invalid binding.
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600748 auto set = descriptor_set->GetSet();
749 result |= LogError(set, vuids.descriptor_valid,
750 "%s encountered the following validation error at %s time: Attempting to "
751 "validate DrawState for binding #%u which is an invalid binding for this descriptor set.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600752 report_data->FormatHandle(set).c_str(), caller, binding_pair.first);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600753 return result;
754 }
755
Jeremy Gebben080210f2022-05-05 13:37:08 -0600756 if (binding->IsBindless()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600757 // Can't validate the descriptor because it may not have been updated,
758 // or the view could have been destroyed
759 continue;
760 }
Jeremy Gebben080210f2022-05-05 13:37:08 -0600761 result |= ValidateDescriptorSetBindingData(context, binding_pair, *binding);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600762 }
763 return result;
764}
765
Jeremy Gebben080210f2022-05-05 13:37:08 -0600766template <typename T>
767bool CoreChecks::ValidateDescriptors(const DescriptorContext &context, const DescriptorBindingInfo &binding_info,
768 const T &binding) const {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600769 bool skip = false;
Jeremy Gebben080210f2022-05-05 13:37:08 -0600770 for (uint32_t index = 0; !skip && index < binding.count; index++) {
771 const auto &descriptor = binding.descriptors[index];
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600772
Jeremy Gebben080210f2022-05-05 13:37:08 -0600773 if (!descriptor.updated) {
774 auto set = context.descriptor_set->GetSet();
775 return LogError(set, context.vuids.descriptor_valid,
776 "Descriptor set %s encountered the following validation error at %s time: Descriptor in binding "
777 "#%" PRIu32 " index %" PRIu32
778 " is being used in draw but has never been updated via vkUpdateDescriptorSets() or a similar call.",
779 report_data->FormatHandle(set).c_str(), context.caller, binding_info.first, index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600780 }
Jeremy Gebben080210f2022-05-05 13:37:08 -0600781 skip = ValidateDescriptor(context, binding_info, index, descriptor);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600782 }
783 return skip;
784}
785
Jeremy Gebben080210f2022-05-05 13:37:08 -0600786bool CoreChecks::ValidateDescriptorSetBindingData(const DescriptorContext &context, const DescriptorBindingInfo &binding_info,
787 const cvdescriptorset::DescriptorBinding &binding) const {
788 using DescriptorClass = cvdescriptorset::DescriptorClass;
789 bool skip = false;
790 switch (binding.descriptor_class) {
791 case DescriptorClass::InlineUniform:
792 // Can't validate the descriptor because it may not have been updated.
793 break;
794 case DescriptorClass::GeneralBuffer:
795 skip = ValidateDescriptors(context, binding_info, static_cast<const cvdescriptorset::BufferBinding &>(binding));
796 break;
797 case DescriptorClass::ImageSampler:
798 skip = ValidateDescriptors(context, binding_info, static_cast<const cvdescriptorset::ImageSamplerBinding &>(binding));
799 break;
800 case DescriptorClass::Image:
801 skip = ValidateDescriptors(context, binding_info, static_cast<const cvdescriptorset::ImageBinding &>(binding));
802 break;
803 case DescriptorClass::PlainSampler:
804 skip = ValidateDescriptors(context, binding_info, static_cast<const cvdescriptorset::SamplerBinding &>(binding));
805 break;
806 case DescriptorClass::TexelBuffer:
807 skip = ValidateDescriptors(context, binding_info, static_cast<const cvdescriptorset::TexelBinding &>(binding));
808 break;
809 case DescriptorClass::AccelerationStructure:
810 skip = ValidateDescriptors(context, binding_info,
811 static_cast<const cvdescriptorset::AccelerationStructureBinding &>(binding));
812 break;
813 default:
814 break;
815 }
816 return skip;
817}
818
819bool CoreChecks::ValidateDescriptor(const DescriptorContext &context, const DescriptorBindingInfo &binding_info, uint32_t index,
820 const cvdescriptorset::BufferDescriptor &descriptor) const {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600821 // Verify that buffers are valid
822 auto buffer = descriptor.GetBuffer();
823 auto buffer_node = descriptor.GetBufferState();
824 if ((!buffer_node && !enabled_features.robustness2_features.nullDescriptor) || (buffer_node && buffer_node->Destroyed())) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600825 auto set = context.descriptor_set->GetSet();
826 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600827 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
828 "binding #%" PRIu32 " index %" PRIu32 " is using buffer %s that is invalid or has been destroyed.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600829 report_data->FormatHandle(set).c_str(), context.caller, binding_info.first, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600830 report_data->FormatHandle(buffer).c_str());
831 }
832 if (buffer) {
Aitor Camacho3294edd2022-05-16 22:34:19 +0200833 if (buffer_node /* && !buffer_node->sparse*/) {
834 for (const auto &binding : buffer_node->GetInvalidMemory()) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600835 auto set = context.descriptor_set->GetSet();
836 return LogError(set, context.vuids.descriptor_valid,
Aitor Camacho3294edd2022-05-16 22:34:19 +0200837 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
838 "binding #%" PRIu32 " index %" PRIu32 " is uses buffer %s that references invalid memory %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600839 report_data->FormatHandle(set).c_str(), context.caller, binding_info.first, index,
Aitor Camacho3294edd2022-05-16 22:34:19 +0200840 report_data->FormatHandle(buffer).c_str(), report_data->FormatHandle(binding->mem()).c_str());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600841 }
842 }
843 if (enabled_features.core11.protectedMemory == VK_TRUE) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600844 if (ValidateProtectedBuffer(context.cb_node, buffer_node, context.caller, context.vuids.unprotected_command_buffer,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600845 "Buffer is in a descriptorSet")) {
846 return true;
847 }
848 if (binding_info.second.is_writable &&
Jeremy Gebben080210f2022-05-05 13:37:08 -0600849 ValidateUnprotectedBuffer(context.cb_node, buffer_node, context.caller, context.vuids.protected_command_buffer,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600850 "Buffer is in a descriptorSet")) {
851 return true;
852 }
853 }
854 }
855 return false;
856}
857
Jeremy Gebben080210f2022-05-05 13:37:08 -0600858bool CoreChecks::ValidateDescriptor(const DescriptorContext &context, const DescriptorBindingInfo &binding_info, uint32_t index,
859 const cvdescriptorset::ImageDescriptor &image_descriptor) const {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600860 std::vector<const SAMPLER_STATE *> sampler_states;
861 VkImageView image_view = image_descriptor.GetImageView();
862 const IMAGE_VIEW_STATE *image_view_state = image_descriptor.GetImageViewState();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600863 const auto binding = binding_info.first;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600864
865 if (image_descriptor.GetClass() == cvdescriptorset::DescriptorClass::ImageSampler) {
866 sampler_states.emplace_back(
867 static_cast<const cvdescriptorset::ImageSamplerDescriptor &>(image_descriptor).GetSamplerState());
868 } else {
869 if (binding_info.second.samplers_used_by_image.size() > index) {
870 for (const auto &desc_index : binding_info.second.samplers_used_by_image[index]) {
871 const auto *desc =
Jeremy Gebben080210f2022-05-05 13:37:08 -0600872 context.descriptor_set->GetDescriptorFromBinding(desc_index.sampler_slot.binding, desc_index.sampler_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600873 // NOTE: This check _shouldn't_ be necessary due to the checks made in IsSpecificDescriptorType in
874 // shader_validation.cpp. However, without this check some traces still crash.
875 if (desc && (desc->GetClass() == cvdescriptorset::DescriptorClass::PlainSampler)) {
876 const auto *sampler_state = static_cast<const cvdescriptorset::SamplerDescriptor *>(desc)->GetSamplerState();
877 if (sampler_state) sampler_states.emplace_back(sampler_state);
878 }
879 }
880 }
881 }
882
883 if ((!image_view_state && !enabled_features.robustness2_features.nullDescriptor) ||
884 (image_view_state && image_view_state->Destroyed())) {
885 // Image view must have been destroyed since initial update. Could potentially flag the descriptor
886 // as "invalid" (updated = false) at DestroyImageView() time and detect this error at bind time
887
Jeremy Gebben080210f2022-05-05 13:37:08 -0600888 auto set = context.descriptor_set->GetSet();
889 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600890 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
891 "binding #%" PRIu32 " index %" PRIu32 " is using imageView %s that is invalid or has been destroyed.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600892 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600893 report_data->FormatHandle(image_view).c_str());
894 }
895 if (image_view) {
Jeremy Gebben288fa572022-06-02 11:48:10 -0600896 const auto reqs = binding_info.second.reqs;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600897 const auto &image_view_ci = image_view_state->create_info;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600898
899 if (reqs & DESCRIPTOR_REQ_ALL_VIEW_TYPE_BITS) {
900 if (~reqs & (1 << image_view_ci.viewType)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600901 auto set = context.descriptor_set->GetSet();
902 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600903 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
904 "in binding #%" PRIu32 " index %" PRIu32 " requires an image view of type %s but got %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600905 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600906 StringDescriptorReqViewType(reqs).c_str(), string_VkImageViewType(image_view_ci.viewType));
907 }
908
909 if (!(reqs & image_view_state->descriptor_format_bits)) {
910 // bad component type
Jeremy Gebben080210f2022-05-05 13:37:08 -0600911 auto set = context.descriptor_set->GetSet();
912 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600913 "Descriptor set %s encountered the following validation error at %s time: "
914 "Descriptor in binding "
915 "#%" PRIu32 " index %" PRIu32 " requires %s component type, but bound descriptor format is %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600916 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600917 StringDescriptorReqComponentType(reqs), string_VkFormat(image_view_ci.format));
918 }
919 }
920
921 // NOTE: Submit time validation of UPDATE_AFTER_BIND image layout is not possible with the
922 // image layout tracking as currently implemented, so only record_time_validation is done
Jeremy Gebben080210f2022-05-05 13:37:08 -0600923 if (!disabled[image_layout_validation] && context.record_time_validate) {
Jeremy Gebben288fa572022-06-02 11:48:10 -0600924 VkImageLayout image_layout = image_descriptor.GetImageLayout();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600925 // Verify Image Layout
926 // No "invalid layout" VUID required for this call, since the optimal_layout parameter is UNDEFINED.
927 // The caller provides a checked_layouts map when there are a large number of layouts to check,
928 // making it worthwhile to keep track of verified layouts and not recheck them.
929 bool already_validated = false;
Jeremy Gebben080210f2022-05-05 13:37:08 -0600930 if (context.checked_layouts) {
931 auto search = context.checked_layouts->find(image_view);
932 if (search != context.checked_layouts->end() && search->second == image_layout) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600933 already_validated = true;
934 }
935 }
936 if (!already_validated) {
937 bool hit_error = false;
Jeremy Gebben080210f2022-05-05 13:37:08 -0600938 VerifyImageLayout(*context.cb_node, *image_view_state, image_layout, context.caller,
939 "VUID-VkDescriptorImageInfo-imageLayout-00344", &hit_error);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600940 if (hit_error) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600941 auto set = context.descriptor_set->GetSet();
942 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600943 "Descriptor set %s encountered the following validation error at %s time: Image layout "
944 "specified "
945 "at vkUpdateDescriptorSet* or vkCmdPushDescriptorSet* time "
946 "doesn't match actual image layout at time descriptor is used. See previous error callback for "
947 "specific details.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600948 report_data->FormatHandle(set).c_str(), context.caller);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600949 }
Jeremy Gebben080210f2022-05-05 13:37:08 -0600950 if (context.checked_layouts) {
951 context.checked_layouts->emplace(image_view, image_layout);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600952 }
953 }
954 }
955
956 // Verify Sample counts
957 if ((reqs & DESCRIPTOR_REQ_SINGLE_SAMPLE) && image_view_state->samples != VK_SAMPLE_COUNT_1_BIT) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600958 auto set = context.descriptor_set->GetSet();
959 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600960 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
961 "binding #%" PRIu32 " index %" PRIu32 " requires bound image to have VK_SAMPLE_COUNT_1_BIT but got %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600962 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600963 string_VkSampleCountFlagBits(image_view_state->samples));
964 }
965 if ((reqs & DESCRIPTOR_REQ_MULTI_SAMPLE) && image_view_state->samples == VK_SAMPLE_COUNT_1_BIT) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600966 auto set = context.descriptor_set->GetSet();
967 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600968 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
969 "in binding #%" PRIu32 " index %" PRIu32
970 " requires bound image to have multiple samples, but got VK_SAMPLE_COUNT_1_BIT.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600971 report_data->FormatHandle(set).c_str(), context.caller, binding, index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600972 }
973
974 // Verify VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT
Jeremy Gebben080210f2022-05-05 13:37:08 -0600975 if ((reqs & DESCRIPTOR_REQ_VIEW_ATOMIC_OPERATION) &&
976 (image_descriptor.active_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) &&
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600977 !(image_view_state->format_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600978 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600979 LogObjectList objlist(set);
980 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -0600981 return LogError(objlist, context.vuids.imageview_atomic,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600982 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
983 "in binding #%" PRIu32 " index %" PRIu32
984 ", %s, format %s, doesn't "
985 "contain VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT.",
Jeremy Gebben080210f2022-05-05 13:37:08 -0600986 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600987 report_data->FormatHandle(image_view).c_str(), string_VkFormat(image_view_ci.format));
988 }
989
990 // When KHR_format_feature_flags2 is supported, the read/write without
991 // format support is reported per format rather as a blankey physical
992 // device feature.
993 if (has_format_feature2) {
994 const VkFormatFeatureFlags2 format_features = image_view_state->format_features;
995
Jeremy Gebben080210f2022-05-05 13:37:08 -0600996 if (image_descriptor.active_descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -0600997 if ((reqs & DESCRIPTOR_REQ_IMAGE_READ_WITHOUT_FORMAT) &&
998 !(format_features & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -0600999 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001000 LogObjectList objlist(set);
1001 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001002 return LogError(objlist, context.vuids.storage_image_read_without_format,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001003 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
1004 "in binding #%" PRIu32 " index %" PRIu32
1005 ", %s, image view format %s feature flags (%s) doesn't "
1006 "contain VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001007 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001008 report_data->FormatHandle(image_view).c_str(), string_VkFormat(image_view_ci.format),
1009 string_VkFormatFeatureFlags2(format_features).c_str());
1010 }
1011
1012 if ((reqs & DESCRIPTOR_REQ_IMAGE_WRITE_WITHOUT_FORMAT) &&
1013 !(format_features & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001014 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001015 LogObjectList objlist(set);
1016 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001017 return LogError(objlist, context.vuids.storage_image_write_without_format,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001018 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
1019 "in binding #%" PRIu32 " index %" PRIu32
1020 ", %s, image view format %s feature flags (%s) doesn't "
1021 "contain VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001022 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001023 report_data->FormatHandle(image_view).c_str(), string_VkFormat(image_view_ci.format),
1024 string_VkFormatFeatureFlags2(format_features).c_str());
1025 }
1026 }
1027
1028 if ((reqs & DESCRIPTOR_REQ_IMAGE_DREF) && !(format_features & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001029 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001030 LogObjectList objlist(set);
1031 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001032 return LogError(objlist, context.vuids.depth_compare_sample,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001033 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
1034 "in binding #%" PRIu32 " index %" PRIu32
1035 ", %s, image view format %s feature flags (%s) doesn't "
1036 "contain VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001037 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001038 report_data->FormatHandle(image_view).c_str(), string_VkFormat(image_view_ci.format),
1039 string_VkFormatFeatureFlags2(format_features).c_str());
1040 }
1041 }
1042
1043 // Verify if attachments are used in DescriptorSet
Jeremy Gebben080210f2022-05-05 13:37:08 -06001044 if (context.attachments && context.attachments->size() > 0 && context.subpasses &&
1045 (image_descriptor.active_descriptor_type != VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
1046 for (uint32_t att_index = 0; att_index < context.attachments->size(); ++att_index) {
1047 const auto &view_state = (*context.attachments)[att_index];
1048 const SUBPASS_INFO &subpass = (*context.subpasses)[att_index];
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001049 if (!view_state || view_state->Destroyed()) {
1050 continue;
1051 }
1052 bool same_view = view_state->image_view() == image_view;
1053 bool overlapping_view = image_view_state->OverlapSubresource(*view_state);
1054 if (!same_view && !overlapping_view) {
1055 continue;
1056 }
1057
1058 bool descriptor_readable = false;
1059 bool descriptor_writable = false;
1060 uint32_t set_index = std::numeric_limits<uint32_t>::max();
Jeremy Gebben080210f2022-05-05 13:37:08 -06001061 for (uint32_t i = 0; i < context.cb_node->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].per_set.size(); ++i) {
1062 const auto &set = context.cb_node->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].per_set[i];
1063 if (set.bound_descriptor_set.get() == context.descriptor_set) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001064 set_index = i;
1065 break;
1066 }
1067 }
1068 assert(set_index != std::numeric_limits<uint32_t>::max());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001069 const auto pipeline = context.cb_node->GetCurrentPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001070 for (const auto &stage : pipeline->stage_state) {
1071 for (const auto &descriptor : stage.descriptor_uses) {
1072 if (descriptor.first.set == set_index && descriptor.first.binding == binding) {
1073 descriptor_writable |= descriptor.second.is_writable;
1074 descriptor_readable |=
1075 descriptor.second.is_readable | descriptor.second.is_sampler_implicitLod_dref_proj;
1076 break;
1077 }
1078 }
1079 }
1080
1081 bool layout_read_only = IsImageLayoutReadOnly(subpass.layout);
1082 bool write_attachment =
1083 (subpass.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) > 0 &&
1084 !layout_read_only;
1085 if (write_attachment && descriptor_readable) {
1086 if (same_view) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001087 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001088 LogObjectList objlist(set);
1089 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001090 objlist.add(context.framebuffer);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001091 return LogError(
Jeremy Gebben080210f2022-05-05 13:37:08 -06001092 objlist, context.vuids.image_subresources_subpass_read,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001093 "Descriptor set %s encountered the following validation error at %s time: %s is being read from in "
1094 "Descriptor in binding #%" PRIu32 " index %" PRIu32
1095 " and will be written to as %s attachment # %" PRIu32 ".",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001096 report_data->FormatHandle(set).c_str(), context.caller, report_data->FormatHandle(image_view).c_str(),
1097 binding, index, report_data->FormatHandle(context.framebuffer).c_str(), att_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001098 } else if (overlapping_view) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001099 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001100 LogObjectList objlist(set);
1101 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001102 objlist.add(context.framebuffer);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001103 objlist.add(view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001104 return LogError(objlist, context.vuids.image_subresources_subpass_read,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001105 "Descriptor set %s encountered the following validation error at %s time: "
1106 "Image subresources of %s is being read from in "
1107 "Descriptor in binding #%" PRIu32 " index %" PRIu32
1108 " and will be written to as %s in %s attachment # %" PRIu32 " overlap.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001109 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001110 report_data->FormatHandle(image_view).c_str(), binding, index,
1111 report_data->FormatHandle(view_state->image_view()).c_str(),
Jeremy Gebben080210f2022-05-05 13:37:08 -06001112 report_data->FormatHandle(context.framebuffer).c_str(), att_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001113 }
1114 }
1115 bool read_attachment = (subpass.usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) > 0;
1116 if (read_attachment && descriptor_writable) {
1117 if (same_view) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001118 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001119 LogObjectList objlist(set);
1120 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001121 objlist.add(context.framebuffer);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001122 return LogError(
Jeremy Gebben080210f2022-05-05 13:37:08 -06001123 objlist, context.vuids.image_subresources_subpass_write,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001124 "Descriptor set %s encountered the following validation error at %s time: %s is being written to in "
1125 "Descriptor in binding #%" PRIu32 " index %" PRIu32 " and read from as %s attachment # %" PRIu32 ".",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001126 report_data->FormatHandle(set).c_str(), context.caller, report_data->FormatHandle(image_view).c_str(),
1127 binding, index, report_data->FormatHandle(context.framebuffer).c_str(), att_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001128 } else if (overlapping_view) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001129 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001130 LogObjectList objlist(set);
1131 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001132 objlist.add(context.framebuffer);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001133 objlist.add(view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001134 return LogError(objlist, context.vuids.image_subresources_subpass_write,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001135 "Descriptor set %s encountered the following validation error at %s time: "
1136 "Image subresources of %s is being written to in "
1137 "Descriptor in binding #%" PRIu32 " index %" PRIu32
1138 " and will be read from as %s in %s attachment # %" PRIu32 " overlap.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001139 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001140 report_data->FormatHandle(image_view).c_str(), binding, index,
1141 report_data->FormatHandle(view_state->image_view()).c_str(),
Jeremy Gebben080210f2022-05-05 13:37:08 -06001142 report_data->FormatHandle(context.framebuffer).c_str(), att_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001143 }
1144 }
1145
1146 if (descriptor_writable && !layout_read_only) {
1147 if (same_view) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001148 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001149 LogObjectList objlist(set);
1150 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001151 objlist.add(context.framebuffer);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001152 return LogError(
Jeremy Gebben080210f2022-05-05 13:37:08 -06001153 objlist, context.vuids.image_subresources_render_pass_write,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001154 "Descriptor set %s encountered the following validation error at %s time: %s is used in "
1155 "Descriptor in binding #%" PRIu32 " index %" PRIu32 " as writable and %s attachment # %" PRIu32 ".",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001156 report_data->FormatHandle(set).c_str(), context.caller, report_data->FormatHandle(image_view).c_str(),
1157 binding, index, report_data->FormatHandle(context.framebuffer).c_str(), att_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001158 } else if (overlapping_view) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001159 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001160 LogObjectList objlist(set);
1161 objlist.add(image_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001162 objlist.add(context.framebuffer);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001163 objlist.add(view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001164 return LogError(objlist, context.vuids.image_subresources_render_pass_write,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001165 "Descriptor set %s encountered the following validation error at %s time: "
1166 "Image subresources of %s in "
1167 "writable Descriptor in binding #%" PRIu32 " index %" PRIu32
1168 " and %s in %s attachment # %" PRIu32 " overlap.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001169 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001170 report_data->FormatHandle(image_view).c_str(), binding, index,
1171 report_data->FormatHandle(view_state->image_view()).c_str(),
Jeremy Gebben080210f2022-05-05 13:37:08 -06001172 report_data->FormatHandle(context.framebuffer).c_str(), att_index);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001173 }
1174 }
1175 }
1176 if (enabled_features.core11.protectedMemory == VK_TRUE) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001177 if (ValidateProtectedImage(context.cb_node, image_view_state->image_state.get(), context.caller,
1178 context.vuids.unprotected_command_buffer, "Image is in a descriptorSet")) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001179 return true;
1180 }
1181 if (binding_info.second.is_writable &&
Jeremy Gebben080210f2022-05-05 13:37:08 -06001182 ValidateUnprotectedImage(context.cb_node, image_view_state->image_state.get(), context.caller,
1183 context.vuids.protected_command_buffer, "Image is in a descriptorSet")) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001184 return true;
1185 }
1186 }
1187 }
1188
1189 for (const auto *sampler_state : sampler_states) {
1190 if (!sampler_state || sampler_state->Destroyed()) {
1191 continue;
1192 }
1193
1194 // TODO: Validate 04015 for DescriptorClass::PlainSampler
1195 if ((sampler_state->createInfo.borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT ||
1196 sampler_state->createInfo.borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT) &&
1197 (sampler_state->customCreateInfo.format == VK_FORMAT_UNDEFINED)) {
1198 if (image_view_state->create_info.format == VK_FORMAT_B4G4R4A4_UNORM_PACK16 ||
1199 image_view_state->create_info.format == VK_FORMAT_B5G6R5_UNORM_PACK16 ||
1200 image_view_state->create_info.format == VK_FORMAT_B5G5R5A1_UNORM_PACK16) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001201 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001202 LogObjectList objlist(set);
1203 objlist.add(sampler_state->sampler());
1204 objlist.add(image_view_state->image_view());
1205 return LogError(objlist, "VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04015",
1206 "Descriptor set %s encountered the following validation error at %s time: Sampler %s in "
1207 "binding #%" PRIu32 " index %" PRIu32
1208 " has a custom border color with format = VK_FORMAT_UNDEFINED and is used to "
1209 "sample an image view %s with format %s",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001210 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001211 report_data->FormatHandle(sampler_state->sampler()).c_str(), binding, index,
1212 report_data->FormatHandle(image_view_state->image_view()).c_str(),
1213 string_VkFormat(image_view_state->create_info.format));
1214 }
1215 }
1216 VkFilter sampler_mag_filter = sampler_state->createInfo.magFilter;
1217 VkFilter sampler_min_filter = sampler_state->createInfo.minFilter;
1218 VkBool32 sampler_compare_enable = sampler_state->createInfo.compareEnable;
1219 if ((sampler_mag_filter == VK_FILTER_LINEAR || sampler_min_filter == VK_FILTER_LINEAR) &&
1220 (sampler_compare_enable == VK_FALSE) &&
1221 !(image_view_state->format_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001222 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001223 LogObjectList objlist(set);
1224 objlist.add(sampler_state->sampler());
1225 objlist.add(image_view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001226 return LogError(objlist, context.vuids.linear_sampler,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001227 "Descriptor set %s encountered the following validation error at %s time: Sampler "
1228 "(%s) is set to use VK_FILTER_LINEAR with "
1229 "compareEnable is set to VK_FALSE, but image view's (%s) format (%s) does not "
1230 "contain VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT in its format features.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001231 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001232 report_data->FormatHandle(sampler_state->sampler()).c_str(),
1233 report_data->FormatHandle(image_view_state->image_view()).c_str(),
1234 string_VkFormat(image_view_state->create_info.format));
1235 }
1236 if (sampler_mag_filter == VK_FILTER_CUBIC_EXT || sampler_min_filter == VK_FILTER_CUBIC_EXT) {
1237 if (!(image_view_state->format_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001238 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001239 LogObjectList objlist(set);
1240 objlist.add(sampler_state->sampler());
1241 objlist.add(image_view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001242 return LogError(objlist, context.vuids.cubic_sampler,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001243 "Descriptor set %s encountered the following validation error at %s time: "
1244 "Sampler (%s) is set to use VK_FILTER_CUBIC_EXT, then "
1245 "image view's (%s) format (%s) MUST contain "
1246 "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT in its format features.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001247 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001248 report_data->FormatHandle(sampler_state->sampler()).c_str(),
1249 report_data->FormatHandle(image_view_state->image_view()).c_str(),
1250 string_VkFormat(image_view_state->create_info.format));
1251 }
1252
1253 if (IsExtEnabled(device_extensions.vk_ext_filter_cubic)) {
1254 const auto reduction_mode_info =
1255 LvlFindInChain<VkSamplerReductionModeCreateInfo>(sampler_state->createInfo.pNext);
1256 if (reduction_mode_info &&
1257 (reduction_mode_info->reductionMode == VK_SAMPLER_REDUCTION_MODE_MIN ||
1258 reduction_mode_info->reductionMode == VK_SAMPLER_REDUCTION_MODE_MAX) &&
1259 !image_view_state->filter_cubic_props.filterCubicMinmax) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001260 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001261 LogObjectList objlist(set);
1262 objlist.add(sampler_state->sampler());
1263 objlist.add(image_view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001264 return LogError(objlist, context.vuids.filter_cubic_min_max,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001265 "Descriptor set %s encountered the following validation error at %s time: "
1266 "Sampler (%s) is set to use VK_FILTER_CUBIC_EXT & %s, "
1267 "but image view (%s) doesn't support filterCubicMinmax.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001268 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001269 report_data->FormatHandle(sampler_state->sampler()).c_str(),
1270 string_VkSamplerReductionMode(reduction_mode_info->reductionMode),
1271 report_data->FormatHandle(image_view_state->image_view()).c_str());
1272 }
1273
1274 if (!image_view_state->filter_cubic_props.filterCubic) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001275 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001276 LogObjectList objlist(set);
1277 objlist.add(sampler_state->sampler());
1278 objlist.add(image_view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001279 return LogError(objlist, context.vuids.filter_cubic,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001280 "Descriptor set %s encountered the following validation error at %s time: "
1281 "Sampler (%s) is set to use VK_FILTER_CUBIC_EXT, "
1282 "but image view (%s) doesn't support filterCubic.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001283 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001284 report_data->FormatHandle(sampler_state->sampler()).c_str(),
1285 report_data->FormatHandle(image_view_state->image_view()).c_str());
1286 }
1287 }
1288
1289 if (IsExtEnabled(device_extensions.vk_img_filter_cubic)) {
1290 if (image_view_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_3D ||
1291 image_view_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_CUBE ||
1292 image_view_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001293 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001294 LogObjectList objlist(set);
1295 objlist.add(sampler_state->sampler());
1296 objlist.add(image_view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001297 return LogError(objlist, context.vuids.img_filter_cubic,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001298 "Descriptor set %s encountered the following validation error at %s time: Sampler "
1299 "(%s)is set to use VK_FILTER_CUBIC_EXT while the VK_IMG_filter_cubic extension "
1300 "is enabled, but image view (%s) has an invalid imageViewType (%s).",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001301 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001302 report_data->FormatHandle(sampler_state->sampler()).c_str(),
1303 report_data->FormatHandle(image_view_state->image_view()).c_str(),
1304 string_VkImageViewType(image_view_state->create_info.viewType));
1305 }
1306 }
1307 }
Jeremy Gebben288fa572022-06-02 11:48:10 -06001308 const auto image_state = image_view_state->image_state.get();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001309 if ((image_state->createInfo.flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) &&
1310 (sampler_state->createInfo.addressModeU != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ||
1311 sampler_state->createInfo.addressModeV != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ||
1312 sampler_state->createInfo.addressModeW != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)) {
1313 std::string address_mode_letter =
1314 (sampler_state->createInfo.addressModeU != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
1315 ? "U"
1316 : (sampler_state->createInfo.addressModeV != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) ? "V" : "W";
1317 VkSamplerAddressMode address_mode =
1318 (sampler_state->createInfo.addressModeU != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
1319 ? sampler_state->createInfo.addressModeU
1320 : (sampler_state->createInfo.addressModeV != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
1321 ? sampler_state->createInfo.addressModeV
1322 : sampler_state->createInfo.addressModeW;
Jeremy Gebben080210f2022-05-05 13:37:08 -06001323 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001324 LogObjectList objlist(set);
1325 objlist.add(sampler_state->sampler());
1326 objlist.add(image_state->image());
1327 objlist.add(image_view_state->image_view());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001328 return LogError(objlist, context.vuids.corner_sampled_address_mode,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001329 "Descriptor set %s encountered the following validation error at %s time: Image "
1330 "(%s) in image view (%s) is created with flag "
1331 "VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV and can only be sampled using "
1332 "VK_SAMPLER_ADDRESS_MODE_CLAMP_EDGE, but sampler (%s) has "
1333 "createInfo.addressMode%s set to %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001334 report_data->FormatHandle(set).c_str(), context.caller,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001335 report_data->FormatHandle(image_state->image()).c_str(),
1336 report_data->FormatHandle(image_view_state->image_view()).c_str(),
1337 report_data->FormatHandle(sampler_state->sampler()).c_str(), address_mode_letter.c_str(),
1338 string_VkSamplerAddressMode(address_mode));
1339 }
1340
1341 // UnnormalizedCoordinates sampler validations
1342 if (sampler_state->createInfo.unnormalizedCoordinates) {
1343 // If ImageView is used by a unnormalizedCoordinates sampler, it needs to check ImageView type
1344 if (image_view_ci.viewType == VK_IMAGE_VIEW_TYPE_3D || image_view_ci.viewType == VK_IMAGE_VIEW_TYPE_CUBE ||
1345 image_view_ci.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY ||
1346 image_view_ci.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY ||
1347 image_view_ci.viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001348 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001349 LogObjectList objlist(set);
1350 objlist.add(image_view);
1351 objlist.add(sampler_state->sampler());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001352 return LogError(objlist, context.vuids.sampler_imageview_type,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001353 "Descriptor set %s encountered the following validation error at %s time: %s, type: %s in "
1354 "Descriptor in binding #%" PRIu32 " index %" PRIu32 "is used by %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001355 report_data->FormatHandle(set).c_str(), context.caller,
1356 report_data->FormatHandle(image_view).c_str(), string_VkImageViewType(image_view_ci.viewType),
1357 binding, index, report_data->FormatHandle(sampler_state->sampler()).c_str());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001358 }
1359
1360 // sampler must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample*
1361 // instructions with ImplicitLod, Dref or Proj in their name
1362 if (reqs & DESCRIPTOR_REQ_SAMPLER_IMPLICITLOD_DREF_PROJ) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001363 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001364 LogObjectList objlist(set);
1365 objlist.add(image_view);
1366 objlist.add(sampler_state->sampler());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001367 return LogError(
1368 objlist, context.vuids.sampler_implicitLod_dref_proj,
1369 "Descriptor set %s encountered the following validation error at %s time: %s in "
1370 "Descriptor in binding #%" PRIu32 " index %" PRIu32 " is used by %s that uses invalid operator.",
1371 report_data->FormatHandle(set).c_str(), context.caller, report_data->FormatHandle(image_view).c_str(),
1372 binding, index, report_data->FormatHandle(sampler_state->sampler()).c_str());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001373 }
1374
1375 // sampler must not be used with any of the SPIR-V OpImageSample* or OpImageSparseSample*
1376 // instructions that includes a LOD bias or any offset values
1377 if (reqs & DESCRIPTOR_REQ_SAMPLER_BIAS_OFFSET) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001378 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001379 LogObjectList objlist(set);
1380 objlist.add(image_view);
1381 objlist.add(sampler_state->sampler());
Jeremy Gebben080210f2022-05-05 13:37:08 -06001382 return LogError(objlist, context.vuids.sampler_bias_offset,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001383 "Descriptor set %s encountered the following validation error at %s time: %s in "
1384 "Descriptor in binding #%" PRIu32 " index %" PRIu32
1385 " is used by %s that uses invalid bias or offset operator.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001386 report_data->FormatHandle(set).c_str(), context.caller,
1387 report_data->FormatHandle(image_view).c_str(), binding, index,
1388 report_data->FormatHandle(sampler_state->sampler()).c_str());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001389 }
1390 }
1391 }
1392 }
1393 return false;
1394}
1395
Jeremy Gebben080210f2022-05-05 13:37:08 -06001396bool CoreChecks::ValidateDescriptor(const DescriptorContext &context, const DescriptorBindingInfo &binding_info, uint32_t index,
1397 const cvdescriptorset::ImageSamplerDescriptor &descriptor) const {
1398 bool skip = ValidateDescriptor(context, binding_info, index, static_cast<const cvdescriptorset::ImageDescriptor &>(descriptor));
1399 if (!skip) {
1400 skip =
1401 ValidateSamplerDescriptor(context.caller, context.vuids, context.cb_node, context.descriptor_set, binding_info, index,
1402 descriptor.GetSampler(), descriptor.IsImmutableSampler(), descriptor.GetSamplerState());
1403 }
1404 return skip;
1405}
1406
1407bool CoreChecks::ValidateDescriptor(const DescriptorContext &context, const DescriptorBindingInfo &binding_info, uint32_t index,
1408 const cvdescriptorset::TexelDescriptor &texel_descriptor) const {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001409 auto buffer_view = texel_descriptor.GetBufferView();
1410 auto buffer_view_state = texel_descriptor.GetBufferViewState();
1411 const auto binding = binding_info.first;
1412 const auto reqs = binding_info.second.reqs;
1413 if ((!buffer_view_state && !enabled_features.robustness2_features.nullDescriptor) ||
1414 (buffer_view_state && buffer_view_state->Destroyed())) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001415 auto set = context.descriptor_set->GetSet();
1416 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001417 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
1418 "binding #%" PRIu32 " index %" PRIu32 " is using bufferView %s that is invalid or has been destroyed.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001419 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001420 report_data->FormatHandle(buffer_view).c_str());
1421 }
1422 if (buffer_view) {
1423 auto buffer = buffer_view_state->create_info.buffer;
1424 const auto *buffer_state = buffer_view_state->buffer_state.get();
1425 const VkFormat buffer_view_format = buffer_view_state->create_info.format;
1426 if (buffer_state->Destroyed()) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001427 auto set = context.descriptor_set->GetSet();
1428 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001429 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
1430 "binding #%" PRIu32 " index %" PRIu32 " is using buffer %s that has been destroyed.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001431 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001432 report_data->FormatHandle(buffer).c_str());
1433 }
1434 auto format_bits = DescriptorRequirementsBitsFromFormat(buffer_view_format);
1435
1436 if (!(reqs & format_bits)) {
1437 // bad component type
Jeremy Gebben080210f2022-05-05 13:37:08 -06001438 auto set = context.descriptor_set->GetSet();
1439 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001440 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
1441 "binding #%" PRIu32 " index %" PRIu32 " requires %s component type, but bound descriptor format is %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001442 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
1443 StringDescriptorReqComponentType(reqs), string_VkFormat(buffer_view_format));
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001444 }
1445
1446 const VkFormatFeatureFlags2KHR buf_format_features = buffer_view_state->buf_format_features;
1447 const VkFormatFeatureFlags2KHR img_format_features = buffer_view_state->img_format_features;
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001448 const VkDescriptorType descriptor_type = context.descriptor_set->GetBinding(binding)->type;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001449
1450 // Verify VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT
1451 if ((reqs & DESCRIPTOR_REQ_VIEW_ATOMIC_OPERATION) && (descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) &&
1452 !(buf_format_features & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001453 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001454 LogObjectList objlist(set);
1455 objlist.add(buffer_view);
1456 return LogError(objlist, "UNASSIGNED-None-MismatchAtomicBufferFeature",
1457 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
1458 "in binding #%" PRIu32 " index %" PRIu32
1459 ", %s, format %s, doesn't "
1460 "contain VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001461 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001462 report_data->FormatHandle(buffer_view).c_str(), string_VkFormat(buffer_view_format));
1463 }
1464
1465 if (descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
1466 if ((reqs & DESCRIPTOR_REQ_IMAGE_READ_WITHOUT_FORMAT) &&
1467 !(img_format_features & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001468 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001469 LogObjectList objlist(set);
1470 objlist.add(buffer_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001471 return LogError(objlist, context.vuids.storage_image_read_without_format,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001472 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
1473 "in binding #%" PRIu32 " index %" PRIu32
1474 ", %s, buffer view format %s feature flags (%s) doesn't "
1475 "contain VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001476 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001477 report_data->FormatHandle(buffer_view).c_str(), string_VkFormat(buffer_view_format),
1478 string_VkFormatFeatureFlags2KHR(img_format_features).c_str());
1479 }
1480
1481 if ((reqs & DESCRIPTOR_REQ_IMAGE_WRITE_WITHOUT_FORMAT) &&
1482 !(img_format_features & VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR)) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001483 auto set = context.descriptor_set->GetSet();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001484 LogObjectList objlist(set);
1485 objlist.add(buffer_view);
Jeremy Gebben080210f2022-05-05 13:37:08 -06001486 return LogError(objlist, context.vuids.storage_image_write_without_format,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001487 "Descriptor set %s encountered the following validation error at %s time: Descriptor "
1488 "in binding #%" PRIu32 " index %" PRIu32
1489 ", %s, buffer view format %s feature flags (%s) doesn't "
1490 "contain VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001491 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001492 report_data->FormatHandle(buffer_view).c_str(), string_VkFormat(buffer_view_format),
1493 string_VkFormatFeatureFlags2KHR(img_format_features).c_str());
1494 }
1495 }
1496
1497 if (enabled_features.core11.protectedMemory == VK_TRUE) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001498 if (ValidateProtectedBuffer(context.cb_node, buffer_view_state->buffer_state.get(), context.caller,
1499 context.vuids.unprotected_command_buffer, "Buffer is in a descriptorSet")) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001500 return true;
1501 }
1502 if (binding_info.second.is_writable &&
Jeremy Gebben080210f2022-05-05 13:37:08 -06001503 ValidateUnprotectedBuffer(context.cb_node, buffer_view_state->buffer_state.get(), context.caller,
1504 context.vuids.protected_command_buffer, "Buffer is in a descriptorSet")) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001505 return true;
1506 }
1507 }
1508 }
1509 return false;
1510}
1511
Jeremy Gebben080210f2022-05-05 13:37:08 -06001512bool CoreChecks::ValidateDescriptor(const DescriptorContext &context, const DescriptorBindingInfo &binding_info, uint32_t index,
1513 const cvdescriptorset::AccelerationStructureDescriptor &descriptor) const {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001514 // Verify that acceleration structures are valid
1515 const auto binding = binding_info.first;
1516 if (descriptor.is_khr()) {
1517 auto acc = descriptor.GetAccelerationStructure();
1518 auto acc_node = descriptor.GetAccelerationStructureStateKHR();
1519 if (!acc_node || acc_node->Destroyed()) {
1520 if (acc != VK_NULL_HANDLE || !enabled_features.robustness2_features.nullDescriptor) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001521 auto set = context.descriptor_set->GetSet();
1522 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001523 "Descriptor set %s encountered the following validation error at %s time: "
1524 "Descriptor in binding #%" PRIu32 " index %" PRIu32
1525 " is using acceleration structure %s that is invalid or has been destroyed.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001526 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001527 report_data->FormatHandle(acc).c_str());
1528 }
1529 } else {
Aitor Camacho3294edd2022-05-16 22:34:19 +02001530 for (const auto &mem_binding : acc_node->buffer_state->GetInvalidMemory()) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001531 auto set = context.descriptor_set->GetSet();
1532 return LogError(set, context.vuids.descriptor_valid,
Aitor Camacho3294edd2022-05-16 22:34:19 +02001533 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
1534 "binding #%" PRIu32 " index %" PRIu32
1535 " is using acceleration structure %s that references invalid memory %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001536 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Aitor Camacho3294edd2022-05-16 22:34:19 +02001537 report_data->FormatHandle(acc).c_str(), report_data->FormatHandle(mem_binding->mem()).c_str());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001538 }
1539 }
1540 } else {
1541 auto acc = descriptor.GetAccelerationStructureNV();
1542 auto acc_node = descriptor.GetAccelerationStructureStateNV();
1543 if (!acc_node || acc_node->Destroyed()) {
1544 if (acc != VK_NULL_HANDLE || !enabled_features.robustness2_features.nullDescriptor) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001545 auto set = context.descriptor_set->GetSet();
1546 return LogError(set, context.vuids.descriptor_valid,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001547 "Descriptor set %s encountered the following validation error at %s time: "
1548 "Descriptor in binding #%" PRIu32 " index %" PRIu32
1549 " is using acceleration structure %s that is invalid or has been destroyed.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001550 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001551 report_data->FormatHandle(acc).c_str());
1552 }
1553 } else {
Aitor Camacho3294edd2022-05-16 22:34:19 +02001554 for (const auto &mem_binding : acc_node->GetInvalidMemory()) {
Jeremy Gebben080210f2022-05-05 13:37:08 -06001555 auto set = context.descriptor_set->GetSet();
1556 return LogError(set, context.vuids.descriptor_valid,
Aitor Camacho3294edd2022-05-16 22:34:19 +02001557 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
1558 "binding #%" PRIu32 " index %" PRIu32
1559 " is using acceleration structure %s that references invalid memory %s.",
Jeremy Gebben080210f2022-05-05 13:37:08 -06001560 report_data->FormatHandle(set).c_str(), context.caller, binding, index,
Aitor Camacho3294edd2022-05-16 22:34:19 +02001561 report_data->FormatHandle(acc).c_str(), report_data->FormatHandle(mem_binding->mem()).c_str());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001562 }
1563 }
1564 }
1565 return false;
1566}
1567
1568// If the validation is related to both of image and sampler,
1569// please leave it in (descriptor_class == DescriptorClass::ImageSampler || descriptor_class ==
1570// DescriptorClass::Image) Here is to validate for only sampler.
1571bool CoreChecks::ValidateSamplerDescriptor(const char *caller, const DrawDispatchVuid &vuids, const CMD_BUFFER_STATE *cb_node,
1572 const cvdescriptorset::DescriptorSet *descriptor_set,
1573 const std::pair<const uint32_t, DescriptorRequirement> &binding_info, uint32_t index,
1574 VkSampler sampler, bool is_immutable, const SAMPLER_STATE *sampler_state) const {
1575 // Verify Sampler still valid
1576 if (!sampler_state || sampler_state->Destroyed()) {
1577 auto set = descriptor_set->GetSet();
1578 return LogError(set, vuids.descriptor_valid,
1579 "Descriptor set %s encountered the following validation error at %s time: Descriptor in "
1580 "binding #%" PRIu32 " index %" PRIu32 " is using sampler %s that is invalid or has been destroyed.",
1581 report_data->FormatHandle(set).c_str(), caller, binding_info.first, index,
1582 report_data->FormatHandle(sampler).c_str());
1583 } else {
1584 if (sampler_state->samplerConversion && !is_immutable) {
1585 auto set = descriptor_set->GetSet();
1586 return LogError(set, vuids.descriptor_valid,
1587 "Descriptor set %s encountered the following validation error at %s time: sampler (%s) "
1588 "in the descriptor set (%s) contains a YCBCR conversion (%s), then the sampler MUST "
1589 "also exist as an immutable sampler.",
1590 report_data->FormatHandle(set).c_str(), caller, report_data->FormatHandle(sampler).c_str(),
1591 report_data->FormatHandle(descriptor_set->GetSet()).c_str(),
1592 report_data->FormatHandle(sampler_state->samplerConversion).c_str());
1593 }
1594 }
1595 return false;
1596}
1597
Jeremy Gebben080210f2022-05-05 13:37:08 -06001598bool CoreChecks::ValidateDescriptor(const DescriptorContext &context, const DescriptorBindingInfo &binding_info, uint32_t index,
1599 const cvdescriptorset::SamplerDescriptor &descriptor) const {
1600 return ValidateSamplerDescriptor(context.caller, context.vuids, context.cb_node, context.descriptor_set, binding_info, index,
1601 descriptor.GetSampler(), descriptor.IsImmutableSampler(), descriptor.GetSamplerState());
1602}
1603
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001604// Starting at offset descriptor of given binding, parse over update_count
1605// descriptor updates and verify that for any binding boundaries that are crossed, the next binding(s) are all consistent
1606// Consistency means that their type, stage flags, and whether or not they use immutable samplers matches
1607// If so, return true. If not, fill in error_msg and return false
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001608static bool VerifyUpdateConsistency(debug_report_data *report_data, const DescriptorSet &set, uint32_t binding, uint32_t offset,
1609 uint32_t update_count, const char *type, std::string *error_msg) {
1610 auto current_iter = set.FindBinding(binding);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001611 bool pass = true;
1612 // Verify consecutive bindings match (if needed)
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001613 auto &orig_binding = **current_iter;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001614 while (pass && update_count) {
1615 // First, it's legal to offset beyond your own binding so handle that case
1616 if (offset > 0) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001617 // index_range.start + offset is which descriptor is needed to update. If it > index_range.end, it means the descriptor
1618 // isn't in this binding, maybe in next binding.
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001619 if (offset > (*current_iter)->count) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001620 // Advance to next binding, decrement offset by binding size
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001621 offset -= (*current_iter)->count;
1622 ++current_iter;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001623 // Verify next consecutive binding matches type, stage flags & immutable sampler use and if AtEnd
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001624 if (current_iter == set.end() || !orig_binding.IsConsistent(**current_iter)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001625 pass = false;
1626 }
1627 continue;
1628 }
1629 }
1630
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001631 update_count -= std::min(update_count, (*current_iter)->count - offset);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001632 if (update_count) {
1633 // Starting offset is beyond the current binding. Check consistency, update counters and advance to the next binding,
1634 // looking for the start point. All bindings (even those skipped) must be consistent with the update and with the
1635 // original binding.
1636 offset = 0;
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001637 ++current_iter;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001638 // Verify next consecutive binding matches type, stage flags & immutable sampler use and if AtEnd
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001639 if (current_iter == set.end() || !orig_binding.IsConsistent(**current_iter)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001640 pass = false;
1641 }
1642 }
1643 }
1644
1645 if (!pass) {
1646 std::stringstream error_str;
1647 error_str << "Attempting " << type;
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001648 if (set.IsPushDescriptor()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001649 error_str << " push descriptors";
1650 } else {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001651 error_str << " descriptor set " << report_data->FormatHandle(set.Handle());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001652 }
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001653 error_str << " binding #" << orig_binding.binding << " with #" << update_count
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001654 << " descriptors being updated but this update oversteps the bounds of this binding and the next binding is "
1655 "not consistent with current binding";
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001656 if (current_iter == set.end()) {
1657 error_str << " (update past the end of the descriptor set)";
1658 } else {
1659 auto current_binding = current_iter->get();
1660 // Get what was not consistent in IsConsistent() as a more detailed error message
1661 if (current_binding->type != orig_binding.type) {
1662 error_str << " (" << string_VkDescriptorType(current_binding->type)
1663 << " != " << string_VkDescriptorType(orig_binding.type) << ")";
1664 } else if (current_binding->stage_flags != orig_binding.stage_flags) {
1665 error_str << " (" << string_VkShaderStageFlags(current_binding->stage_flags)
1666 << " != " << string_VkShaderStageFlags(orig_binding.stage_flags) << ")";
1667 } else if (current_binding->has_immutable_samplers != orig_binding.has_immutable_samplers) {
1668 error_str << " (pImmutableSamplers don't match)";
1669 } else if (current_binding->binding_flags != orig_binding.binding_flags) {
1670 error_str << " (" << string_VkDescriptorBindingFlags(current_binding->binding_flags)
1671 << " != " << string_VkDescriptorBindingFlags(orig_binding.binding_flags) << ")";
1672 }
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001673 }
1674
1675 error_str << " so this update is invalid";
1676 *error_msg = error_str.str();
1677 }
1678 return pass;
1679}
1680
1681// Validate Copy update
1682bool CoreChecks::ValidateCopyUpdate(const VkCopyDescriptorSet *update, const DescriptorSet *dst_set, const DescriptorSet *src_set,
1683 const char *func_name, std::string *error_code, std::string *error_msg) const {
1684 const auto *dst_layout = dst_set->GetLayout().get();
1685 const auto *src_layout = src_set->GetLayout().get();
1686
1687 // Verify dst layout still valid
1688 if (dst_layout->Destroyed()) {
1689 *error_code = "VUID-VkCopyDescriptorSet-dstSet-parameter";
1690 std::ostringstream str;
1691 str << "Cannot call " << func_name << " to perform copy update on dstSet " << report_data->FormatHandle(dst_set->GetSet())
1692 << " created with destroyed " << report_data->FormatHandle(dst_layout->GetDescriptorSetLayout()) << ".";
1693 *error_msg = str.str();
1694 return false;
1695 }
1696
1697 // Verify src layout still valid
1698 if (src_layout->Destroyed()) {
1699 *error_code = "VUID-VkCopyDescriptorSet-srcSet-parameter";
1700 std::ostringstream str;
1701 str << "Cannot call " << func_name << " to perform copy update on dstSet " << report_data->FormatHandle(dst_set->GetSet())
1702 << " from srcSet " << report_data->FormatHandle(src_set->GetSet()) << " created with destroyed "
1703 << report_data->FormatHandle(src_layout->GetDescriptorSetLayout()) << ".";
1704 *error_msg = str.str();
1705 return false;
1706 }
1707
1708 if (!dst_layout->HasBinding(update->dstBinding)) {
1709 *error_code = "VUID-VkCopyDescriptorSet-dstBinding-00347";
1710 std::stringstream error_str;
1711 error_str << "DescriptorSet " << report_data->FormatHandle(dst_set->GetSet())
1712 << " does not have copy update dest binding of " << update->dstBinding;
1713 *error_msg = error_str.str();
1714 return false;
1715 }
1716 if (!src_set->HasBinding(update->srcBinding)) {
1717 *error_code = "VUID-VkCopyDescriptorSet-srcBinding-00345";
1718 std::stringstream error_str;
1719 error_str << "DescriptorSet " << report_data->FormatHandle(src_set->GetSet())
1720 << " does not have copy update src binding of " << update->srcBinding;
1721 *error_msg = error_str.str();
1722 return false;
1723 }
1724 // Verify idle ds
1725 if (dst_set->InUse() &&
1726 !(dst_layout->GetDescriptorBindingFlagsFromBinding(update->dstBinding) &
1727 (VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT))) {
1728 *error_code = "VUID-vkUpdateDescriptorSets-None-03047";
1729 std::stringstream error_str;
1730 error_str << "Cannot call " << func_name << " to perform copy update on descriptor set "
1731 << report_data->FormatHandle(dst_set->GetSet()) << " that is in use by a command buffer";
1732 *error_msg = error_str.str();
1733 return false;
1734 }
1735 // src & dst set bindings are valid
1736 // Check bounds of src & dst
1737 auto src_start_idx = src_set->GetGlobalIndexRangeFromBinding(update->srcBinding).start + update->srcArrayElement;
1738 if ((src_start_idx + update->descriptorCount) > src_set->GetTotalDescriptorCount()) {
1739 // SRC update out of bounds
1740 *error_code = "VUID-VkCopyDescriptorSet-srcArrayElement-00346";
1741 std::stringstream error_str;
1742 error_str << "Attempting copy update from descriptorSet " << report_data->FormatHandle(update->srcSet) << " binding#"
1743 << update->srcBinding << " with offset index of "
1744 << src_set->GetGlobalIndexRangeFromBinding(update->srcBinding).start << " plus update array offset of "
1745 << update->srcArrayElement << " and update of " << update->descriptorCount
1746 << " descriptors oversteps total number of descriptors in set: " << src_set->GetTotalDescriptorCount();
1747 *error_msg = error_str.str();
1748 return false;
1749 }
1750 auto dst_start_idx = dst_layout->GetGlobalIndexRangeFromBinding(update->dstBinding).start + update->dstArrayElement;
1751 if ((dst_start_idx + update->descriptorCount) > dst_layout->GetTotalDescriptorCount()) {
1752 // DST update out of bounds
1753 *error_code = "VUID-VkCopyDescriptorSet-dstArrayElement-00348";
1754 std::stringstream error_str;
1755 error_str << "Attempting copy update to descriptorSet " << report_data->FormatHandle(dst_set->GetSet()) << " binding#"
1756 << update->dstBinding << " with offset index of "
1757 << dst_layout->GetGlobalIndexRangeFromBinding(update->dstBinding).start << " plus update array offset of "
1758 << update->dstArrayElement << " and update of " << update->descriptorCount
1759 << " descriptors oversteps total number of descriptors in set: " << dst_layout->GetTotalDescriptorCount();
1760 *error_msg = error_str.str();
1761 return false;
1762 }
1763 // Check that types match
1764 // TODO : Base default error case going from here is "VUID-VkAcquireNextImageInfoKHR-semaphore-parameter" 2ba which covers all
1765 // consistency issues, need more fine-grained error codes
1766 *error_code = "VUID-VkCopyDescriptorSet-srcSet-00349";
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001767 auto src_type = src_layout->GetTypeFromBinding(update->srcBinding);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001768 auto dst_type = dst_layout->GetTypeFromBinding(update->dstBinding);
1769 if (src_type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE && dst_type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE && src_type != dst_type) {
1770 *error_code = "VUID-VkCopyDescriptorSet-dstBinding-02632";
1771 std::stringstream error_str;
1772 error_str << "Attempting copy update to descriptorSet " << report_data->FormatHandle(dst_set->GetSet()) << " binding #"
1773 << update->dstBinding << " with type " << string_VkDescriptorType(dst_type) << " from descriptorSet "
1774 << report_data->FormatHandle(src_set->GetSet()) << " binding #" << update->srcBinding << " with type "
1775 << string_VkDescriptorType(src_type) << ". Types do not match";
1776 *error_msg = error_str.str();
1777 return false;
1778 }
1779 // Verify consistency of src & dst bindings if update crosses binding boundaries
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001780 if ((!VerifyUpdateConsistency(report_data, *src_set, update->srcBinding, update->srcArrayElement, update->descriptorCount,
1781 "copy update from", error_msg)) ||
1782 (!VerifyUpdateConsistency(report_data, *dst_set, update->dstBinding, update->dstArrayElement, update->descriptorCount,
1783 "copy update to", error_msg))) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001784 return false;
1785 }
1786
1787 if ((src_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT) &&
1788 !(dst_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)) {
1789 *error_code = "VUID-VkCopyDescriptorSet-srcSet-01918";
1790 std::stringstream error_str;
1791 error_str << "If pname:srcSet's (" << report_data->FormatHandle(update->srcSet)
1792 << ") layout was created with the "
1793 "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT flag "
1794 "set, then pname:dstSet's ("
1795 << report_data->FormatHandle(update->dstSet)
1796 << ") layout must: also have been created with the "
1797 "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT flag set";
1798 *error_msg = error_str.str();
1799 return false;
1800 }
1801
1802 if (IsExtEnabled(device_extensions.vk_valve_mutable_descriptor_type)) {
1803 if (!(src_layout->GetCreateFlags() & (VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT |
1804 VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE)) &&
1805 (dst_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)) {
1806 *error_code = "VUID-VkCopyDescriptorSet-srcSet-04885";
1807 std::stringstream error_str;
1808 error_str << "If pname:srcSet's (" << report_data->FormatHandle(update->srcSet)
1809 << ") layout was created with neither ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT nor "
1810 "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE flags set, then pname:dstSet's ("
1811 << report_data->FormatHandle(update->dstSet)
1812 << ") layout must: have been created without the "
1813 "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT flag set";
1814 *error_msg = error_str.str();
1815 return false;
1816 }
1817 } else {
1818 if (!(src_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT) &&
1819 (dst_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)) {
1820 *error_code = "VUID-VkCopyDescriptorSet-srcSet-04886";
1821 std::stringstream error_str;
1822 error_str << "If pname:srcSet's (" << report_data->FormatHandle(update->srcSet)
1823 << ") layout was created without the ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT flag "
1824 "set, then pname:dstSet's ("
1825 << report_data->FormatHandle(update->dstSet)
1826 << ") layout must: also have been created without the "
1827 "ename:VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT flag set";
1828 *error_msg = error_str.str();
1829 return false;
1830 }
1831 }
1832
1833 if ((src_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT) &&
1834 !(dst_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT)) {
1835 *error_code = "VUID-VkCopyDescriptorSet-srcSet-01920";
1836 std::stringstream error_str;
1837 error_str << "If the descriptor pool from which pname:srcSet (" << report_data->FormatHandle(update->srcSet)
1838 << ") was allocated was created "
1839 "with the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT flag "
1840 "set, then the descriptor pool from which pname:dstSet ("
1841 << report_data->FormatHandle(update->dstSet)
1842 << ") was allocated must: "
1843 "also have been created with the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT flag set";
1844 *error_msg = error_str.str();
1845 return false;
1846 }
1847
1848 if (IsExtEnabled(device_extensions.vk_valve_mutable_descriptor_type)) {
1849 if (!(src_set->GetPoolState()->createInfo.flags &
1850 (VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT | VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE)) &&
1851 (dst_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT)) {
1852 *error_code = "VUID-VkCopyDescriptorSet-srcSet-04887";
1853 std::stringstream error_str;
1854 error_str << "If the descriptor pool from which pname:srcSet (" << report_data->FormatHandle(update->srcSet)
1855 << ") was allocated was created with neither ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT nor "
1856 "ename:VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE flags set, then the descriptor pool from which "
1857 "pname:dstSet ("
1858 << report_data->FormatHandle(update->dstSet)
1859 << ") was allocated must: have been created without the "
1860 "ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT flag set";
1861 *error_msg = error_str.str();
1862 return false;
1863 }
1864 } else {
1865 if (!(src_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT) &&
1866 (dst_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT)) {
1867 *error_code = "VUID-VkCopyDescriptorSet-srcSet-04888";
1868 std::stringstream error_str;
1869 error_str << "If the descriptor pool from which pname:srcSet (" << report_data->FormatHandle(update->srcSet)
1870 << ") was allocated was created without the ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT flag set, "
1871 "then the descriptor pool from which pname:dstSet ("
1872 << report_data->FormatHandle(update->dstSet)
1873 << ") was allocated must: also have been created without the "
1874 "ename:VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT flag set";
1875 *error_msg = error_str.str();
1876 return false;
1877 }
1878 }
1879
1880 if (src_type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
1881 if ((update->srcArrayElement % 4) != 0) {
1882 *error_code = "VUID-VkCopyDescriptorSet-srcBinding-02223";
1883 std::stringstream error_str;
1884 error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
1885 << "srcArrayElement " << update->srcArrayElement << " not a multiple of 4";
1886 *error_msg = error_str.str();
1887 return false;
1888 }
1889 if ((update->dstArrayElement % 4) != 0) {
1890 *error_code = "VUID-VkCopyDescriptorSet-dstBinding-02224";
1891 std::stringstream error_str;
1892 error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
1893 << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
1894 *error_msg = error_str.str();
1895 return false;
1896 }
1897 if ((update->descriptorCount % 4) != 0) {
1898 *error_code = "VUID-VkCopyDescriptorSet-srcBinding-02225";
1899 std::stringstream error_str;
1900 error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
1901 << "descriptorCount " << update->descriptorCount << " not a multiple of 4";
1902 *error_msg = error_str.str();
1903 return false;
1904 }
1905 }
1906
1907 if (dst_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
1908 if (src_type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
1909 if (!dst_layout->IsTypeMutable(src_type, update->dstBinding)) {
1910 *error_code = "VUID-VkCopyDescriptorSet-dstSet-04612";
1911 std::stringstream error_str;
1912 error_str << "Attempting copy update with dstBinding descriptor type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, but the new "
1913 "active descriptor type "
1914 << string_VkDescriptorType(src_type) << " is not in the corresponding pMutableDescriptorTypeLists list.";
1915 *error_msg = error_str.str();
1916 return false;
1917 }
1918 }
1919 } else if (src_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001920 const auto *descriptor = src_set->GetDescriptorFromBinding(update->srcBinding, update->srcArrayElement);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001921 if (descriptor->active_descriptor_type != dst_type) {
1922 *error_code = "VUID-VkCopyDescriptorSet-srcSet-04613";
1923 std::stringstream error_str;
1924 error_str << "Attempting copy update with srcBinding descriptor type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, but the "
1925 "active descriptor type ("
1926 << string_VkDescriptorType(descriptor->active_descriptor_type)
1927 << ") does not match the dstBinding descriptor type " << string_VkDescriptorType(dst_type) << ".";
1928 *error_msg = error_str.str();
1929 return false;
1930 }
1931 }
1932
1933 if (dst_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
1934 if (src_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
1935 const auto &mutable_src_types = src_layout->GetMutableTypes(update->srcBinding);
1936 const auto &mutable_dst_types = dst_layout->GetMutableTypes(update->dstBinding);
1937 bool complete_match = mutable_src_types.size() == mutable_dst_types.size();
1938 if (complete_match) {
1939 for (const auto mutable_src_type : mutable_src_types) {
1940 if (std::find(mutable_dst_types.begin(), mutable_dst_types.end(), mutable_src_type) ==
1941 mutable_dst_types.end()) {
1942 complete_match = false;
1943 break;
1944 }
1945 }
1946 }
1947 if (!complete_match) {
1948 *error_code = "VUID-VkCopyDescriptorSet-dstSet-04614";
1949 std::stringstream error_str;
1950 error_str << "Attempting copy update with dstBinding and new active descriptor type being "
1951 "VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, but their corresponding pMutableDescriptorTypeLists do not match.";
1952 *error_msg = error_str.str();
1953 return false;
1954 }
1955 }
1956 }
1957
1958 // Update mutable types
1959 if (src_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001960 src_type = src_set->GetDescriptorFromBinding(update->srcBinding, update->srcArrayElement)->active_descriptor_type;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001961 }
1962 if (dst_type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06001963 dst_type = dst_set->GetDescriptorFromBinding(update->dstBinding, update->dstArrayElement)->active_descriptor_type;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06001964 }
1965
1966 // Update parameters all look good and descriptor updated so verify update contents
1967 if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, dst_set, dst_type, dst_start_idx, func_name, error_code,
1968 error_msg)) {
1969 return false;
1970 }
1971
1972 // All checks passed so update is good
1973 return true;
1974}
1975
1976// Validate given sampler. Currently this only checks to make sure it exists in the samplerMap
1977bool CoreChecks::ValidateSampler(const VkSampler sampler) const { return Get<SAMPLER_STATE>(sampler).get() != nullptr; }
1978
1979bool CoreChecks::ValidateImageUpdate(VkImageView image_view, VkImageLayout image_layout, VkDescriptorType type,
1980 const char *func_name, std::string *error_code, std::string *error_msg) const {
1981 auto iv_state = Get<IMAGE_VIEW_STATE>(image_view);
1982 assert(iv_state);
1983
1984 // Note that when an imageview is created, we validated that memory is bound so no need to re-check here
1985 // Validate that imageLayout is compatible with aspect_mask and image format
1986 // and validate that image usage bits are correct for given usage
1987 VkImageAspectFlags aspect_mask = iv_state->normalized_subresource_range.aspectMask;
1988 VkImage image = iv_state->create_info.image;
1989 VkFormat format = VK_FORMAT_MAX_ENUM;
1990 VkImageUsageFlags usage = 0;
1991 auto *image_node = iv_state->image_state.get();
1992 assert(image_node);
1993
1994 format = image_node->createInfo.format;
1995 const auto image_view_usage_info = LvlFindInChain<VkImageViewUsageCreateInfo>(iv_state->create_info.pNext);
1996 const auto stencil_usage_info = LvlFindInChain<VkImageStencilUsageCreateInfo>(image_node->createInfo.pNext);
1997 if (image_view_usage_info) {
1998 usage = image_view_usage_info->usage;
1999 } else {
2000 usage = image_node->createInfo.usage;
2001 }
2002 if (stencil_usage_info) {
2003 bool stencil_aspect = (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) > 0;
2004 bool depth_aspect = (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) > 0;
2005 if (stencil_aspect && !depth_aspect) {
2006 usage = stencil_usage_info->stencilUsage;
2007 } else if (stencil_aspect && depth_aspect) {
2008 usage &= stencil_usage_info->stencilUsage;
2009 }
2010 }
2011
2012 // Validate that memory is bound to image
2013 if (ValidateMemoryIsBoundToImage(image_node, func_name, kVUID_Core_Bound_Resource_FreedMemoryAccess)) {
2014 *error_code = kVUID_Core_Bound_Resource_FreedMemoryAccess;
2015 *error_msg = "No memory bound to image.";
2016 return false;
2017 }
2018
2019 // KHR_maintenance1 allows rendering into 2D or 2DArray views which slice a 3D image,
2020 // but not binding them to descriptor sets.
2021 if (iv_state->IsDepthSliced()) {
2022 if (!device_extensions.vk_ext_image_2d_view_of_3d) {
2023 if (iv_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_2D) {
2024 *error_code = "VUID-VkDescriptorImageInfo-imageView-06711";
2025 *error_msg = "ImageView must not be a 2D view of a 3D image";
2026 return false;
2027 }
2028 } else if (iv_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
2029 *error_code = "VUID-VkDescriptorImageInfo-imageView-06712";
2030 *error_msg = "ImageView must not be a 2DArray view of a 3D image";
2031 return false;
2032 }
2033 }
2034
2035 // TODO : The various image aspect and format checks here are based on general spec language in 11.5 Image Views section under
2036 // vkCreateImageView(). What's the best way to create unique id for these cases?
2037 *error_code = kVUID_Core_DrawState_InvalidImageView;
2038 bool ds = FormatIsDepthOrStencil(format);
2039 switch (image_layout) {
2040 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
2041 // Only Color bit must be set
2042 if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
2043 std::stringstream error_str;
2044 error_str
2045 << "ImageView (" << report_data->FormatHandle(image_view)
2046 << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but does not have VK_IMAGE_ASPECT_COLOR_BIT set.";
2047 *error_msg = error_str.str();
2048 return false;
2049 }
2050 // format must NOT be DS
2051 if (ds) {
2052 std::stringstream error_str;
2053 error_str << "ImageView (" << report_data->FormatHandle(image_view)
2054 << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but the image format is "
2055 << string_VkFormat(format) << " which is not a color format.";
2056 *error_msg = error_str.str();
2057 return false;
2058 }
2059 break;
2060 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
2061 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
2062 // Depth or stencil bit must be set, but both must NOT be set
2063 if (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
2064 if (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
2065 // both must NOT be set
2066 std::stringstream error_str;
2067 error_str << "ImageView (" << report_data->FormatHandle(image_view)
2068 << ") has both STENCIL and DEPTH aspects set";
2069 *error_msg = error_str.str();
2070 return false;
2071 }
2072 } else if (!(aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
2073 // Neither were set
2074 std::stringstream error_str;
2075 error_str << "ImageView (" << report_data->FormatHandle(image_view) << ") has layout "
2076 << string_VkImageLayout(image_layout) << " but does not have STENCIL or DEPTH aspects set";
2077 *error_msg = error_str.str();
2078 return false;
2079 }
2080 // format must be DS
2081 if (!ds) {
2082 std::stringstream error_str;
2083 error_str << "ImageView (" << report_data->FormatHandle(image_view) << ") has layout "
2084 << string_VkImageLayout(image_layout) << " but the image format is " << string_VkFormat(format)
2085 << " which is not a depth/stencil format.";
2086 *error_msg = error_str.str();
2087 return false;
2088 }
2089 break;
2090 default:
2091 // For other layouts if the source is depth/stencil image, both aspect bits must not be set
2092 if (ds) {
2093 if (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
2094 if (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
2095 // both must NOT be set
2096 std::stringstream error_str;
2097 error_str << "ImageView (" << report_data->FormatHandle(image_view) << ") has layout "
2098 << string_VkImageLayout(image_layout) << " and is using depth/stencil image of format "
2099 << string_VkFormat(format)
2100 << " but it has both STENCIL and DEPTH aspects set, which is illegal. When using a depth/stencil "
2101 "image in a descriptor set, please only set either VK_IMAGE_ASPECT_DEPTH_BIT or "
2102 "VK_IMAGE_ASPECT_STENCIL_BIT depending on whether it will be used for depth reads or stencil "
2103 "reads respectively.";
2104 *error_code = "VUID-VkDescriptorImageInfo-imageView-01976";
2105 *error_msg = error_str.str();
2106 return false;
2107 }
2108 }
2109 }
2110 break;
2111 }
2112 // Now validate that usage flags are correctly set for given type of update
2113 // As we're switching per-type, if any type has specific layout requirements, check those here as well
2114 // TODO : The various image usage bit requirements are in general spec language for VkImageUsageFlags bit block in 11.3 Images
2115 // under vkCreateImage()
2116 const char *error_usage_bit = nullptr;
2117 switch (type) {
2118 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2119 if (iv_state->samplerConversion != VK_NULL_HANDLE) {
2120 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-01946";
2121 std::stringstream error_str;
2122 error_str << "ImageView (" << report_data->FormatHandle(image_view) << ")"
2123 << "used as a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE can't be created with VkSamplerYcbcrConversion";
2124 *error_msg = error_str.str();
2125 return false;
2126 }
2127 // drop through
2128 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
2129 if (!(usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
2130 error_usage_bit = "VK_IMAGE_USAGE_SAMPLED_BIT";
2131 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00337";
2132 }
2133 break;
2134 }
2135 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
2136 if (!(usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
2137 error_usage_bit = "VK_IMAGE_USAGE_STORAGE_BIT";
2138 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00339";
2139 } else if ((VK_IMAGE_LAYOUT_GENERAL != image_layout) &&
2140 (!IsExtEnabled(device_extensions.vk_khr_shared_presentable_image) ||
2141 (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != image_layout))) {
2142 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-04152";
2143 std::stringstream error_str;
2144 error_str << "Descriptor update with descriptorType VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
2145 << " is being updated with invalid imageLayout " << string_VkImageLayout(image_layout) << " for image "
2146 << report_data->FormatHandle(image) << " in imageView " << report_data->FormatHandle(image_view)
2147 << ". Allowed layouts are: VK_IMAGE_LAYOUT_GENERAL";
2148 if (IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)) {
2149 error_str << " or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR";
2150 }
2151 *error_msg = error_str.str();
2152 return false;
2153 }
2154 break;
2155 }
2156 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
2157 if (!(usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) {
2158 error_usage_bit = "VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT";
2159 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00338";
2160 }
2161 break;
2162 }
2163 default:
2164 break;
2165 }
2166 if (error_usage_bit) {
2167 std::stringstream error_str;
2168 error_str << "ImageView (" << report_data->FormatHandle(image_view) << ") with usage mask " << std::hex << std::showbase
2169 << usage << " being used for a descriptor update of type " << string_VkDescriptorType(type) << " does not have "
2170 << error_usage_bit << " set.";
2171 *error_msg = error_str.str();
2172 return false;
2173 }
2174
2175 // All the following types share the same image layouts
2176 // checkf or Storage Images above
2177 if ((type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) || (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
2178 (type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
2179 // Test that the layout is compatible with the descriptorType for the two sampled image types
2180 const static std::array<VkImageLayout, 3> valid_layouts = {
2181 {VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL}};
2182
2183 struct ExtensionLayout {
2184 VkImageLayout layout;
2185 ExtEnabled DeviceExtensions::*extension;
2186 };
2187 const static std::array<ExtensionLayout, 7> extended_layouts{{
2188 // Note double brace req'd for aggregate initialization
2189 {VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, &DeviceExtensions::vk_khr_shared_presentable_image},
2190 {VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, &DeviceExtensions::vk_khr_maintenance2},
2191 {VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, &DeviceExtensions::vk_khr_maintenance2},
2192 {VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR, &DeviceExtensions::vk_khr_synchronization2},
2193 {VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR, &DeviceExtensions::vk_khr_synchronization2},
2194 {VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, &DeviceExtensions::vk_khr_separate_depth_stencil_layouts},
2195 {VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, &DeviceExtensions::vk_khr_separate_depth_stencil_layouts},
2196 }};
2197 auto is_layout = [image_layout, this](const ExtensionLayout &ext_layout) {
2198 return IsExtEnabled(device_extensions.*(ext_layout.extension)) && (ext_layout.layout == image_layout);
2199 };
2200
2201 bool valid_layout = (std::find(valid_layouts.cbegin(), valid_layouts.cend(), image_layout) != valid_layouts.cend()) ||
2202 std::any_of(extended_layouts.cbegin(), extended_layouts.cend(), is_layout);
2203
2204 if (!valid_layout) {
2205 // The following works as currently all 3 descriptor types share the same set of valid layouts
2206 switch (type) {
2207 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2208 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-04149";
2209 break;
2210 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2211 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-04150";
2212 break;
2213 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2214 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-04151";
2215 break;
2216 default:
2217 break;
2218 }
2219 std::stringstream error_str;
2220 error_str << "Descriptor update with descriptorType " << string_VkDescriptorType(type)
2221 << " is being updated with invalid imageLayout " << string_VkImageLayout(image_layout) << " for image "
2222 << report_data->FormatHandle(image) << " in imageView " << report_data->FormatHandle(image_view)
2223 << ". Allowed layouts are: VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "
2224 << "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL";
2225 for (auto &ext_layout : extended_layouts) {
2226 if (IsExtEnabled(device_extensions.*(ext_layout.extension))) {
2227 error_str << ", " << string_VkImageLayout(ext_layout.layout);
2228 }
2229 }
2230 *error_msg = error_str.str();
2231 return false;
2232 }
2233 }
2234
2235 if ((type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) || (type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
2236 const VkComponentMapping components = iv_state->create_info.components;
2237 if (IsIdentitySwizzle(components) == false) {
2238 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00336";
2239 std::stringstream error_str;
2240 error_str << "ImageView (" << report_data->FormatHandle(image_view) << ") has a non-identiy swizzle component, "
2241 << " r swizzle = " << string_VkComponentSwizzle(components.r) << ","
2242 << " g swizzle = " << string_VkComponentSwizzle(components.g) << ","
2243 << " b swizzle = " << string_VkComponentSwizzle(components.b) << ","
2244 << " a swizzle = " << string_VkComponentSwizzle(components.a) << ".";
2245 *error_msg = error_str.str();
2246 return false;
2247 }
2248 }
2249
2250 if ((type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) && (iv_state->min_lod != 0.0f)) {
2251 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-06450";
2252 std::stringstream error_str;
2253 error_str << "ImageView (" << report_data->FormatHandle(image_view)
2254 << ") , written to a descriptor of type VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT with a minLod (" << iv_state->min_lod
2255 << ") that is not 0.0";
2256 *error_msg = error_str.str();
2257 return false;
2258 }
2259
2260 if (device_extensions.vk_ext_image_2d_view_of_3d && iv_state->create_info.viewType == VK_IMAGE_VIEW_TYPE_2D &&
2261 image_node->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2262 if ((type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) || (type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
2263 (type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
2264 if (!(image_node->createInfo.flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT)) {
2265 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-06710";
2266 std::stringstream error_str;
2267 error_str << "ImageView (" << report_data->FormatHandle(image_view)
2268 << ") , is a 2D image view created from 3D image (" << report_data->FormatHandle(image)
2269 << ") , written to a descriptor of type " << string_VkDescriptorType(type)
2270 << " but the image used to create the image view was not created with "
2271 "VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT set";
2272 *error_msg = error_str.str();
2273 return false;
2274 }
2275 if (type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && !enabled_features.image_2d_view_of_3d_features.image2DViewOf3D) {
2276 *error_code = "VUID-VkDescriptorImageInfo-descriptorType-06713";
2277 std::stringstream error_str;
2278 error_str << "ImageView (" << report_data->FormatHandle(image_view)
2279 << ") , is a 2D image view created from 3D image (" << report_data->FormatHandle(image)
2280 << ") , written to a descriptor of type VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
2281 << " and the image2DViewOf3D feature is not enabled";
2282 *error_msg = error_str.str();
2283 return false;
2284 }
2285 if ((type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
2286 !enabled_features.image_2d_view_of_3d_features.sampler2DViewOf3D) {
2287 *error_code = "VUID-VkDescriptorImageInfo-descriptorType-06714";
2288 std::stringstream error_str;
2289 error_str << "ImageView (" << report_data->FormatHandle(image_view)
2290 << ") , is a 2D image view created from 3D image (" << report_data->FormatHandle(image)
2291 << ") , written to a descriptor of type " << string_VkDescriptorType(type)
2292 << " and the image2DViewOf3D feature is not enabled";
2293 *error_msg = error_str.str();
2294 return false;
2295 }
2296 }
2297 }
2298
2299 return true;
2300}
2301
2302// This is a helper function that iterates over a set of Write and Copy updates, pulls the DescriptorSet* for updated
2303// sets, and then calls their respective Validate[Write|Copy]Update functions.
2304// If the update hits an issue for which the callback returns "true", meaning that the call down the chain should
2305// be skipped, then true is returned.
2306// If there is no issue with the update, then false is returned.
2307bool CoreChecks::ValidateUpdateDescriptorSets(uint32_t write_count, const VkWriteDescriptorSet *p_wds, uint32_t copy_count,
2308 const VkCopyDescriptorSet *p_cds, const char *func_name) const {
2309 bool skip = false;
2310 // Validate Write updates
2311 for (uint32_t i = 0; i < write_count; i++) {
2312 auto dest_set = p_wds[i].dstSet;
2313 auto set_node = Get<cvdescriptorset::DescriptorSet>(dest_set);
2314 if (!set_node) {
2315 skip |= LogError(dest_set, kVUID_Core_DrawState_InvalidDescriptorSet,
2316 "Cannot call %s on %s that has not been allocated in pDescriptorWrites[%u].", func_name,
2317 report_data->FormatHandle(dest_set).c_str(), i);
2318 } else {
2319 std::string error_code;
2320 std::string error_str;
2321 if (!ValidateWriteUpdate(set_node.get(), &p_wds[i], func_name, &error_code, &error_str, false)) {
2322 skip |=
2323 LogError(dest_set, error_code, "%s pDescriptorWrites[%u] failed write update validation for %s with error: %s.",
2324 func_name, i, report_data->FormatHandle(dest_set).c_str(), error_str.c_str());
2325 }
2326 }
2327 if (p_wds[i].pNext) {
2328 const auto *pnext_struct = LvlFindInChain<VkWriteDescriptorSetAccelerationStructureKHR>(p_wds[i].pNext);
2329 if (pnext_struct) {
2330 for (uint32_t j = 0; j < pnext_struct->accelerationStructureCount; ++j) {
2331 auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pnext_struct->pAccelerationStructures[j]);
2332 if (as_state && (as_state->create_infoKHR.sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR &&
2333 (as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR &&
2334 as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR))) {
2335 skip |=
2336 LogError(dest_set, "VUID-VkWriteDescriptorSetAccelerationStructureKHR-pAccelerationStructures-03579",
2337 "%s: For pDescriptorWrites[%u] acceleration structure in pAccelerationStructures[%u] must "
2338 "have been created with "
2339 "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.",
2340 func_name, i, j);
2341 }
2342 }
2343 }
2344 const auto *pnext_struct_nv = LvlFindInChain<VkWriteDescriptorSetAccelerationStructureNV>(p_wds[i].pNext);
2345 if (pnext_struct_nv) {
2346 for (uint32_t j = 0; j < pnext_struct_nv->accelerationStructureCount; ++j) {
2347 auto as_state = Get<ACCELERATION_STRUCTURE_STATE>(pnext_struct_nv->pAccelerationStructures[j]);
2348 if (as_state && (as_state->create_infoNV.sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV &&
2349 as_state->create_infoNV.info.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV)) {
2350 skip |= LogError(dest_set, "VUID-VkWriteDescriptorSetAccelerationStructureNV-pAccelerationStructures-03748",
2351 "%s: For pDescriptorWrites[%u] acceleration structure in pAccelerationStructures[%u] must "
2352 "have been created with"
2353 " VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV.",
2354 func_name, i, j);
2355 }
2356 }
2357 }
2358 }
2359 }
2360 // Now validate copy updates
2361 for (uint32_t i = 0; i < copy_count; ++i) {
2362 auto dst_set = p_cds[i].dstSet;
2363 auto src_set = p_cds[i].srcSet;
2364 auto src_node = Get<cvdescriptorset::DescriptorSet>(src_set);
2365 auto dst_node = Get<cvdescriptorset::DescriptorSet>(dst_set);
2366 // Object_tracker verifies that src & dest descriptor set are valid
2367 assert(src_node);
2368 assert(dst_node);
2369 std::string error_code;
2370 std::string error_str;
2371 if (!ValidateCopyUpdate(&p_cds[i], dst_node.get(), src_node.get(), func_name, &error_code, &error_str)) {
2372 LogObjectList objlist(dst_set);
2373 objlist.add(src_set);
2374 skip |= LogError(objlist, error_code, "%s pDescriptorCopies[%u] failed copy update from %s to %s with error: %s.",
2375 func_name, i, report_data->FormatHandle(src_set).c_str(), report_data->FormatHandle(dst_set).c_str(),
2376 error_str.c_str());
2377 }
2378 }
2379 return skip;
2380}
2381
2382cvdescriptorset::DecodedTemplateUpdate::DecodedTemplateUpdate(const ValidationStateTracker *device_data,
2383 VkDescriptorSet descriptorSet,
2384 const UPDATE_TEMPLATE_STATE *template_state, const void *pData,
2385 VkDescriptorSetLayout push_layout) {
2386 auto const &create_info = template_state->create_info;
2387 inline_infos.resize(create_info.descriptorUpdateEntryCount); // Make sure we have one if we need it
2388 inline_infos_khr.resize(create_info.descriptorUpdateEntryCount);
2389 inline_infos_nv.resize(create_info.descriptorUpdateEntryCount);
2390 desc_writes.reserve(create_info.descriptorUpdateEntryCount); // emplaced, so reserved without initialization
2391 VkDescriptorSetLayout effective_dsl = create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
2392 ? create_info.descriptorSetLayout
2393 : push_layout;
2394 auto layout_obj = device_data->Get<cvdescriptorset::DescriptorSetLayout>(effective_dsl);
2395
2396 // Create a WriteDescriptorSet struct for each template update entry
2397 for (uint32_t i = 0; i < create_info.descriptorUpdateEntryCount; i++) {
2398 auto binding_count = layout_obj->GetDescriptorCountFromBinding(create_info.pDescriptorUpdateEntries[i].dstBinding);
2399 auto binding_being_updated = create_info.pDescriptorUpdateEntries[i].dstBinding;
2400 auto dst_array_element = create_info.pDescriptorUpdateEntries[i].dstArrayElement;
2401
2402 desc_writes.reserve(desc_writes.size() + create_info.pDescriptorUpdateEntries[i].descriptorCount);
2403 for (uint32_t j = 0; j < create_info.pDescriptorUpdateEntries[i].descriptorCount; j++) {
2404 desc_writes.emplace_back();
2405 auto &write_entry = desc_writes.back();
2406
2407 size_t offset = create_info.pDescriptorUpdateEntries[i].offset + j * create_info.pDescriptorUpdateEntries[i].stride;
2408 char *update_entry = (char *)(pData) + offset;
2409
2410 if (dst_array_element >= binding_count) {
2411 dst_array_element = 0;
2412 binding_being_updated = layout_obj->GetNextValidBinding(binding_being_updated);
2413 }
2414
2415 write_entry.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
2416 write_entry.pNext = NULL;
2417 write_entry.dstSet = descriptorSet;
2418 write_entry.dstBinding = binding_being_updated;
2419 write_entry.dstArrayElement = dst_array_element;
2420 write_entry.descriptorCount = 1;
2421 write_entry.descriptorType = create_info.pDescriptorUpdateEntries[i].descriptorType;
2422
2423 switch (create_info.pDescriptorUpdateEntries[i].descriptorType) {
2424 case VK_DESCRIPTOR_TYPE_SAMPLER:
2425 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2426 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2427 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
2428 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2429 write_entry.pImageInfo = reinterpret_cast<VkDescriptorImageInfo *>(update_entry);
2430 break;
2431
2432 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2433 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2434 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
2435 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
2436 write_entry.pBufferInfo = reinterpret_cast<VkDescriptorBufferInfo *>(update_entry);
2437 break;
2438
2439 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2440 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2441 write_entry.pTexelBufferView = reinterpret_cast<VkBufferView *>(update_entry);
2442 break;
2443 case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: {
2444 VkWriteDescriptorSetInlineUniformBlockEXT *inline_info = &inline_infos[i];
2445 inline_info->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT;
2446 inline_info->pNext = nullptr;
2447 inline_info->dataSize = create_info.pDescriptorUpdateEntries[i].descriptorCount;
2448 inline_info->pData = update_entry;
2449 write_entry.pNext = inline_info;
2450 // descriptorCount must match the dataSize member of the VkWriteDescriptorSetInlineUniformBlockEXT structure
2451 write_entry.descriptorCount = inline_info->dataSize;
2452 // skip the rest of the array, they just represent bytes in the update
2453 j = create_info.pDescriptorUpdateEntries[i].descriptorCount;
2454 break;
2455 }
2456 case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
2457 VkWriteDescriptorSetAccelerationStructureKHR *inline_info_khr = &inline_infos_khr[i];
2458 inline_info_khr->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
2459 inline_info_khr->pNext = nullptr;
2460 inline_info_khr->accelerationStructureCount = create_info.pDescriptorUpdateEntries[i].descriptorCount;
2461 inline_info_khr->pAccelerationStructures = reinterpret_cast<VkAccelerationStructureKHR *>(update_entry);
2462 write_entry.pNext = inline_info_khr;
2463 break;
2464 }
2465 case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV: {
2466 VkWriteDescriptorSetAccelerationStructureNV *inline_info_nv = &inline_infos_nv[i];
2467 inline_info_nv->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV;
2468 inline_info_nv->pNext = nullptr;
2469 inline_info_nv->accelerationStructureCount = create_info.pDescriptorUpdateEntries[i].descriptorCount;
2470 inline_info_nv->pAccelerationStructures = reinterpret_cast<VkAccelerationStructureNV *>(update_entry);
2471 write_entry.pNext = inline_info_nv;
2472 break;
2473 }
2474 default:
2475 assert(0);
2476 break;
2477 }
2478 dst_array_element++;
2479 }
2480 }
2481}
2482// These helper functions carry out the validate and record descriptor updates peformed via update templates. They decode
2483// the templatized data and leverage the non-template UpdateDescriptor helper functions.
2484bool CoreChecks::ValidateUpdateDescriptorSetsWithTemplateKHR(VkDescriptorSet descriptorSet,
2485 const UPDATE_TEMPLATE_STATE *template_state, const void *pData) const {
2486 // Translate the templated update into a normal update for validation...
2487 cvdescriptorset::DecodedTemplateUpdate decoded_update(this, descriptorSet, template_state, pData);
2488 return ValidateUpdateDescriptorSets(static_cast<uint32_t>(decoded_update.desc_writes.size()), decoded_update.desc_writes.data(),
2489 0, NULL, "vkUpdateDescriptorSetWithTemplate()");
2490}
2491
2492std::string cvdescriptorset::DescriptorSet::StringifySetAndLayout() const {
2493 std::string out;
2494 auto layout_handle = layout_->GetDescriptorSetLayout();
2495 if (IsPushDescriptor()) {
2496 std::ostringstream str;
2497 str << "Push Descriptors defined with " << state_data_->report_data->FormatHandle(layout_handle);
2498 out = str.str();
2499 } else {
2500 std::ostringstream str;
2501 str << state_data_->report_data->FormatHandle(GetSet()) << " allocated with "
2502 << state_data_->report_data->FormatHandle(layout_handle);
2503 out = str.str();
2504 }
2505 return out;
2506};
2507
2508// Loop through the write updates to validate for a push descriptor set, ignoring dstSet
2509bool CoreChecks::ValidatePushDescriptorsUpdate(const DescriptorSet *push_set, uint32_t write_count,
2510 const VkWriteDescriptorSet *p_wds, const char *func_name) const {
2511 assert(push_set->IsPushDescriptor());
2512 bool skip = false;
2513 for (uint32_t i = 0; i < write_count; i++) {
2514 std::string error_code;
2515 std::string error_str;
2516 if (!ValidateWriteUpdate(push_set, &p_wds[i], func_name, &error_code, &error_str, true)) {
2517 skip |= LogError(push_set->GetDescriptorSetLayout(), error_code,
2518 "%s VkWriteDescriptorSet[%u] failed update validation: %s.", func_name, i, error_str.c_str());
2519 }
2520 }
2521 return skip;
2522}
2523
2524// For the given buffer, verify that its creation parameters are appropriate for the given type
2525// If there's an error, update the error_msg string with details and return false, else return true
Jeremy Gebben567a5be2022-05-12 09:14:47 -06002526static bool ValidateBufferUsage(debug_report_data *report_data, BUFFER_STATE const *buffer_node, VkDescriptorType type,
2527 std::string *error_code, std::string *error_msg) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002528 // Verify that usage bits set correctly for given type
2529 auto usage = buffer_node->createInfo.usage;
2530 const char *error_usage_bit = nullptr;
2531 switch (type) {
2532 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2533 if (!(usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) {
2534 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00334";
2535 error_usage_bit = "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT";
2536 }
2537 break;
2538 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2539 if (!(usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
2540 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00335";
2541 error_usage_bit = "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT";
2542 }
2543 break;
2544 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2545 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
2546 if (!(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) {
2547 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00330";
2548 error_usage_bit = "VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT";
2549 }
2550 break;
2551 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2552 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
2553 if (!(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) {
2554 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00331";
2555 error_usage_bit = "VK_BUFFER_USAGE_STORAGE_BUFFER_BIT";
2556 }
2557 break;
2558 default:
2559 break;
2560 }
2561 if (error_usage_bit) {
2562 std::stringstream error_str;
2563 error_str << "Buffer (" << report_data->FormatHandle(buffer_node->buffer()) << ") with usage mask " << std::hex
2564 << std::showbase << usage << " being used for a descriptor update of type " << string_VkDescriptorType(type)
2565 << " does not have " << error_usage_bit << " set.";
2566 *error_msg = error_str.str();
2567 return false;
2568 }
2569 return true;
2570}
2571
2572// For buffer descriptor updates, verify the buffer usage and VkDescriptorBufferInfo struct which includes:
2573// 1. buffer is valid
2574// 2. buffer was created with correct usage flags
2575// 3. offset is less than buffer size
2576// 4. range is either VK_WHOLE_SIZE or falls in (0, (buffer size - offset)]
2577// 5. range and offset are within the device's limits
2578// If there's an error, update the error_msg string with details and return false, else return true
2579bool CoreChecks::ValidateBufferUpdate(VkDescriptorBufferInfo const *buffer_info, VkDescriptorType type, const char *func_name,
2580 std::string *error_code, std::string *error_msg) const {
2581 // First make sure that buffer is valid
2582 auto buffer_node = Get<BUFFER_STATE>(buffer_info->buffer);
2583 // Any invalid buffer should already be caught by object_tracker
2584 assert(buffer_node);
2585 if (ValidateMemoryIsBoundToBuffer(buffer_node.get(), func_name, "VUID-VkWriteDescriptorSet-descriptorType-00329")) {
2586 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00329";
2587 *error_msg = "No memory bound to buffer.";
2588 return false;
2589 }
2590 // Verify usage bits
Jeremy Gebben567a5be2022-05-12 09:14:47 -06002591 if (!ValidateBufferUsage(report_data, buffer_node.get(), type, error_code, error_msg)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002592 // error_msg will have been updated by ValidateBufferUsage()
2593 return false;
2594 }
2595 // offset must be less than buffer size
2596 if (buffer_info->offset >= buffer_node->createInfo.size) {
2597 *error_code = "VUID-VkDescriptorBufferInfo-offset-00340";
2598 std::stringstream error_str;
2599 error_str << "VkDescriptorBufferInfo offset of " << buffer_info->offset << " is greater than or equal to buffer "
2600 << report_data->FormatHandle(buffer_node->buffer()) << " size of " << buffer_node->createInfo.size;
2601 *error_msg = error_str.str();
2602 return false;
2603 }
2604 if (buffer_info->range != VK_WHOLE_SIZE) {
2605 // Range must be VK_WHOLE_SIZE or > 0
2606 if (!buffer_info->range) {
2607 *error_code = "VUID-VkDescriptorBufferInfo-range-00341";
2608 std::stringstream error_str;
2609 error_str << "For buffer " << report_data->FormatHandle(buffer_node->buffer())
2610 << " VkDescriptorBufferInfo range is not VK_WHOLE_SIZE and is zero, which is not allowed.";
2611 *error_msg = error_str.str();
2612 return false;
2613 }
2614 // Range must be VK_WHOLE_SIZE or <= (buffer size - offset)
2615 if (buffer_info->range > (buffer_node->createInfo.size - buffer_info->offset)) {
2616 *error_code = "VUID-VkDescriptorBufferInfo-range-00342";
2617 std::stringstream error_str;
2618 error_str << "For buffer " << report_data->FormatHandle(buffer_node->buffer()) << " VkDescriptorBufferInfo range is "
2619 << buffer_info->range << " which is greater than buffer size (" << buffer_node->createInfo.size
2620 << ") minus requested offset of " << buffer_info->offset;
2621 *error_msg = error_str.str();
2622 return false;
2623 }
2624 }
2625 // Check buffer update sizes against device limits
2626 const auto &limits = phys_dev_props.limits;
2627 if (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER == type || VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == type) {
2628 auto max_ub_range = limits.maxUniformBufferRange;
2629 if (buffer_info->range != VK_WHOLE_SIZE && buffer_info->range > max_ub_range) {
2630 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00332";
2631 std::stringstream error_str;
2632 error_str << "For buffer " << report_data->FormatHandle(buffer_node->buffer()) << " VkDescriptorBufferInfo range is "
2633 << buffer_info->range << " which is greater than this device's maxUniformBufferRange (" << max_ub_range
2634 << ")";
2635 *error_msg = error_str.str();
2636 return false;
2637 } else if (buffer_info->range == VK_WHOLE_SIZE && (buffer_node->createInfo.size - buffer_info->offset) > max_ub_range) {
2638 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00332";
2639 std::stringstream error_str;
2640 error_str << "For buffer " << report_data->FormatHandle(buffer_node->buffer())
2641 << " VkDescriptorBufferInfo range is VK_WHOLE_SIZE but effective range "
2642 << "(" << (buffer_node->createInfo.size - buffer_info->offset) << ") is greater than this device's "
2643 << "maxUniformBufferRange (" << max_ub_range << ")";
2644 *error_msg = error_str.str();
2645 return false;
2646 }
2647 } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == type || VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == type) {
2648 auto max_sb_range = limits.maxStorageBufferRange;
2649 if (buffer_info->range != VK_WHOLE_SIZE && buffer_info->range > max_sb_range) {
2650 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00333";
2651 std::stringstream error_str;
2652 error_str << "For buffer " << report_data->FormatHandle(buffer_node->buffer()) << " VkDescriptorBufferInfo range is "
2653 << buffer_info->range << " which is greater than this device's maxStorageBufferRange (" << max_sb_range
2654 << ")";
2655 *error_msg = error_str.str();
2656 return false;
2657 } else if (buffer_info->range == VK_WHOLE_SIZE && (buffer_node->createInfo.size - buffer_info->offset) > max_sb_range) {
2658 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00333";
2659 std::stringstream error_str;
2660 error_str << "For buffer " << report_data->FormatHandle(buffer_node->buffer())
2661 << " VkDescriptorBufferInfo range is VK_WHOLE_SIZE but effective range "
2662 << "(" << (buffer_node->createInfo.size - buffer_info->offset) << ") is greater than this device's "
2663 << "maxStorageBufferRange (" << max_sb_range << ")";
2664 *error_msg = error_str.str();
2665 return false;
2666 }
2667 }
2668 return true;
2669}
2670
2671template <typename T>
2672bool CoreChecks::ValidateAccelerationStructureUpdate(T acc_node, const char *func_name, std::string *error_code,
2673 std::string *error_msg) const {
2674 // nullDescriptor feature allows this to be VK_NULL_HANDLE
2675 if (acc_node) {
2676 if (ValidateMemoryIsBoundToAccelerationStructure(acc_node, func_name, kVUIDUndefined)) {
2677 *error_code = kVUIDUndefined;
2678 *error_msg = "No memory bound to acceleration structure.";
2679 return false;
2680 }
2681 }
2682 return true;
2683}
2684
2685// Verify that the contents of the update are ok, but don't perform actual update
2686bool CoreChecks::VerifyCopyUpdateContents(const VkCopyDescriptorSet *update, const DescriptorSet *src_set,
2687 VkDescriptorType src_type, uint32_t src_index, const DescriptorSet *dst_set,
2688 VkDescriptorType dst_type, uint32_t dst_index, const char *func_name,
2689 std::string *error_code, std::string *error_msg) const {
2690 // Note : Repurposing some Write update error codes here as specific details aren't called out for copy updates like they are
2691 // for write updates
2692 using DescriptorClass = cvdescriptorset::DescriptorClass;
2693 using BufferDescriptor = cvdescriptorset::BufferDescriptor;
2694 using ImageDescriptor = cvdescriptorset::ImageDescriptor;
2695 using ImageSamplerDescriptor = cvdescriptorset::ImageSamplerDescriptor;
2696 using SamplerDescriptor = cvdescriptorset::SamplerDescriptor;
2697 using TexelDescriptor = cvdescriptorset::TexelDescriptor;
2698
2699 auto device_data = this;
2700
2701 if (dst_type == VK_DESCRIPTOR_TYPE_SAMPLER) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002702 auto dst_iter = dst_set->FindDescriptor(update->dstBinding, update->dstArrayElement);
2703 for (uint32_t di = 0; di < update->descriptorCount; ++di, ++dst_iter) {
2704 if (dst_iter->updated && dst_iter->IsImmutableSampler()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002705 *error_code = "VUID-VkCopyDescriptorSet-dstBinding-02753";
2706 std::stringstream error_str;
2707 error_str << "Attempted copy update to an immutable sampler descriptor.";
2708 *error_msg = error_str.str();
2709 return false;
2710 }
2711 }
2712 }
2713
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002714 switch (src_set->GetBinding(update->srcBinding)->descriptor_class) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002715 case DescriptorClass::PlainSampler: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002716 auto src_iter = src_set->FindDescriptor(update->srcBinding, update->srcArrayElement);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002717 for (uint32_t di = 0; di < update->descriptorCount; ++di) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002718 if (src_iter->updated) {
2719 if (!src_iter->IsImmutableSampler()) {
2720 auto update_sampler = static_cast<const SamplerDescriptor &>(*src_iter).GetSampler();
2721 if (!ValidateSampler(update_sampler)) {
2722 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00325";
2723 std::stringstream error_str;
2724 error_str << "Attempted copy update to sampler descriptor with invalid sampler: "
2725 << report_data->FormatHandle(update_sampler) << ".";
2726 *error_msg = error_str.str();
2727 return false;
2728 }
2729 } else {
2730 // TODO : Warn here
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002731 }
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002732 }
2733 }
2734 break;
2735 }
2736 case DescriptorClass::ImageSampler: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002737 auto src_iter = src_set->FindDescriptor(update->srcBinding, update->srcArrayElement);
2738 for (uint32_t di = 0; di < update->descriptorCount; ++di, ++src_iter) {
2739 if (!src_iter->updated) continue;
2740 auto img_samp_desc = static_cast<const ImageSamplerDescriptor &>(*src_iter);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002741 // First validate sampler
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002742 if (!img_samp_desc.IsImmutableSampler()) {
2743 auto update_sampler = img_samp_desc.GetSampler();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002744 if (!ValidateSampler(update_sampler)) {
2745 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00325";
2746 std::stringstream error_str;
2747 error_str << "Attempted copy update to sampler descriptor with invalid sampler: "
2748 << report_data->FormatHandle(update_sampler) << ".";
2749 *error_msg = error_str.str();
2750 return false;
2751 }
2752 } else {
2753 // TODO : Warn here
2754 }
2755 // Validate image
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002756 auto image_view = img_samp_desc.GetImageView();
2757 auto image_layout = img_samp_desc.GetImageLayout();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002758 if (image_view) {
2759 if (!ValidateImageUpdate(image_view, image_layout, src_type, func_name, error_code, error_msg)) {
2760 std::stringstream error_str;
2761 error_str << "Attempted copy update to combined image sampler descriptor failed due to: "
2762 << error_msg->c_str();
2763 *error_msg = error_str.str();
2764 return false;
2765 }
2766 }
2767 }
2768 break;
2769 }
2770 case DescriptorClass::Image: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002771 auto src_iter = src_set->FindDescriptor(update->srcBinding, update->srcArrayElement);
2772 for (uint32_t di = 0; di < update->descriptorCount; ++di, ++src_iter) {
2773 if (!src_iter->updated) continue;
2774 auto img_desc = static_cast<const ImageDescriptor &>(*src_iter);
2775 auto image_view = img_desc.GetImageView();
2776 auto image_layout = img_desc.GetImageLayout();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002777 if (image_view) {
2778 if (!ValidateImageUpdate(image_view, image_layout, src_type, func_name, error_code, error_msg)) {
2779 std::stringstream error_str;
2780 error_str << "Attempted copy update to image descriptor failed due to: " << error_msg->c_str();
2781 *error_msg = error_str.str();
2782 return false;
2783 }
2784 }
2785 }
2786 break;
2787 }
2788 case DescriptorClass::TexelBuffer: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002789 auto src_iter = src_set->FindDescriptor(update->srcBinding, update->srcArrayElement);
2790 for (uint32_t di = 0; di < update->descriptorCount; ++di, ++src_iter) {
2791 if (!src_iter->updated) continue;
2792 auto buffer_view = static_cast<const TexelDescriptor &>(*src_iter).GetBufferView();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002793 if (buffer_view) {
2794 auto bv_state = device_data->Get<BUFFER_VIEW_STATE>(buffer_view);
2795 if (!bv_state) {
2796 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02994";
2797 std::stringstream error_str;
2798 error_str << "Attempted copy update to texel buffer descriptor with invalid buffer view: "
2799 << report_data->FormatHandle(buffer_view);
2800 *error_msg = error_str.str();
2801 return false;
2802 }
2803 auto buffer = bv_state->create_info.buffer;
2804 auto buffer_state = Get<BUFFER_STATE>(buffer);
Jeremy Gebben567a5be2022-05-12 09:14:47 -06002805 if (!ValidateBufferUsage(report_data, buffer_state.get(), src_type, error_code, error_msg)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002806 std::stringstream error_str;
2807 error_str << "Attempted copy update to texel buffer descriptor failed due to: " << error_msg->c_str();
2808 *error_msg = error_str.str();
2809 return false;
2810 }
2811 }
2812 }
2813 break;
2814 }
2815 case DescriptorClass::GeneralBuffer: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002816 auto src_iter = src_set->FindDescriptor(update->srcBinding, update->srcArrayElement);
2817 for (uint32_t di = 0; di < update->descriptorCount; ++di, ++src_iter) {
2818 if (!src_iter->updated) continue;
2819 auto buffer_state = static_cast<const BufferDescriptor &>(*src_iter).GetBufferState();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002820 if (buffer_state) {
Jeremy Gebben567a5be2022-05-12 09:14:47 -06002821 if (!ValidateBufferUsage(report_data, buffer_state, src_type, error_code, error_msg)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002822 std::stringstream error_str;
2823 error_str << "Attempted copy update to buffer descriptor failed due to: " << error_msg->c_str();
2824 *error_msg = error_str.str();
2825 return false;
2826 }
2827 }
2828 }
2829 break;
2830 }
2831 case DescriptorClass::InlineUniform:
2832 case DescriptorClass::AccelerationStructure:
2833 case DescriptorClass::Mutable:
2834 break;
2835 default:
2836 assert(0); // We've already verified update type so should never get here
2837 break;
2838 }
2839 // All checks passed so update contents are good
2840 return true;
2841}
2842
2843// Verify that the state at allocate time is correct, but don't actually allocate the sets yet
2844bool CoreChecks::ValidateAllocateDescriptorSets(const VkDescriptorSetAllocateInfo *p_alloc_info,
2845 const cvdescriptorset::AllocateDescriptorSetsData *ds_data) const {
2846 bool skip = false;
2847 auto pool_state = Get<DESCRIPTOR_POOL_STATE>(p_alloc_info->descriptorPool);
2848
2849 for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
2850 auto layout = Get<cvdescriptorset::DescriptorSetLayout>(p_alloc_info->pSetLayouts[i]);
2851 if (layout) { // nullptr layout indicates no valid layout handle for this device, validated/logged in object_tracker
2852 if (layout->IsPushDescriptor()) {
2853 skip |= LogError(p_alloc_info->pSetLayouts[i], "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-00308",
2854 "%s specified at pSetLayouts[%" PRIu32
2855 "] in vkAllocateDescriptorSets() was created with invalid flag %s set.",
2856 report_data->FormatHandle(p_alloc_info->pSetLayouts[i]).c_str(), i,
2857 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR");
2858 }
2859 if (layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT &&
2860 !(pool_state->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT)) {
2861 skip |= LogError(
2862 device, "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-03044",
2863 "vkAllocateDescriptorSets(): Descriptor set layout create flags and pool create flags mismatch for index (%d)",
2864 i);
2865 }
2866 if (layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE &&
2867 !(pool_state->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE)) {
2868 skip |= LogError(device, "VUID-VkDescriptorSetAllocateInfo-pSetLayouts-04610",
2869 "vkAllocateDescriptorSets(): pSetLayouts[%d].flags contain "
2870 "VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE bit, but the pool was not created "
2871 "with the VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE bit.",
2872 i);
2873 }
2874 }
2875 }
2876 if (!IsExtEnabled(device_extensions.vk_khr_maintenance1)) {
2877 // Track number of descriptorSets allowable in this pool
2878 if (pool_state->GetAvailableSets() < p_alloc_info->descriptorSetCount) {
2879 skip |= LogError(pool_state->Handle(), "VUID-VkDescriptorSetAllocateInfo-descriptorSetCount-00306",
2880 "vkAllocateDescriptorSets(): Unable to allocate %u descriptorSets from %s"
2881 ". This pool only has %d descriptorSets remaining.",
2882 p_alloc_info->descriptorSetCount, report_data->FormatHandle(pool_state->Handle()).c_str(),
2883 pool_state->GetAvailableSets());
2884 }
2885 // Determine whether descriptor counts are satisfiable
2886 for (auto it = ds_data->required_descriptors_by_type.begin(); it != ds_data->required_descriptors_by_type.end(); ++it) {
2887 auto available_count = pool_state->GetAvailableCount(it->first);
2888
2889 if (ds_data->required_descriptors_by_type.at(it->first) > available_count) {
2890 skip |= LogError(pool_state->Handle(), "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307",
2891 "vkAllocateDescriptorSets(): Unable to allocate %u descriptors of type %s from %s"
2892 ". This pool only has %d descriptors of this type remaining.",
2893 ds_data->required_descriptors_by_type.at(it->first),
2894 string_VkDescriptorType(VkDescriptorType(it->first)),
2895 report_data->FormatHandle(pool_state->Handle()).c_str(), available_count);
2896 }
2897 }
2898 }
2899
2900 const auto *count_allocate_info = LvlFindInChain<VkDescriptorSetVariableDescriptorCountAllocateInfo>(p_alloc_info->pNext);
2901
2902 if (count_allocate_info) {
2903 if (count_allocate_info->descriptorSetCount != 0 &&
2904 count_allocate_info->descriptorSetCount != p_alloc_info->descriptorSetCount) {
2905 skip |= LogError(device, "VUID-VkDescriptorSetVariableDescriptorCountAllocateInfo-descriptorSetCount-03045",
2906 "vkAllocateDescriptorSets(): VkDescriptorSetAllocateInfo::descriptorSetCount (%d) != "
2907 "VkDescriptorSetVariableDescriptorCountAllocateInfo::descriptorSetCount (%d)",
2908 p_alloc_info->descriptorSetCount, count_allocate_info->descriptorSetCount);
2909 }
2910 if (count_allocate_info->descriptorSetCount == p_alloc_info->descriptorSetCount) {
2911 for (uint32_t i = 0; i < p_alloc_info->descriptorSetCount; i++) {
2912 auto layout = Get<cvdescriptorset::DescriptorSetLayout>(p_alloc_info->pSetLayouts[i]);
2913 if (count_allocate_info->pDescriptorCounts[i] > layout->GetDescriptorCountFromBinding(layout->GetMaxBinding())) {
2914 skip |= LogError(device, "VUID-VkDescriptorSetVariableDescriptorCountAllocateInfo-pSetLayouts-03046",
2915 "vkAllocateDescriptorSets(): pDescriptorCounts[%d] = (%d), binding's descriptorCount = (%d)",
2916 i, count_allocate_info->pDescriptorCounts[i],
2917 layout->GetDescriptorCountFromBinding(layout->GetMaxBinding()));
2918 }
2919 }
2920 }
2921 }
2922
2923 return skip;
2924}
2925
2926// Validate the state for a given write update but don't actually perform the update
2927// If an error would occur for this update, return false and fill in details in error_msg string
2928bool CoreChecks::ValidateWriteUpdate(const DescriptorSet *dest_set, const VkWriteDescriptorSet *update, const char *func_name,
2929 std::string *error_code, std::string *error_msg, bool push) const {
2930 const auto *dest_layout = dest_set->GetLayout().get();
2931
2932 // Verify dst layout still valid
2933 if (dest_layout->Destroyed()) {
2934 *error_code = "VUID-VkWriteDescriptorSet-dstSet-00320";
2935 std::ostringstream str;
2936 str << "Cannot call " << func_name << " to perform write update on " << dest_set->StringifySetAndLayout()
2937 << " which has been destroyed";
2938 *error_msg = str.str();
2939 return false;
2940 }
2941 // Verify dst binding exists
2942 if (!dest_layout->HasBinding(update->dstBinding)) {
2943 *error_code = "VUID-VkWriteDescriptorSet-dstBinding-00315";
2944 std::stringstream error_str;
2945 error_str << dest_set->StringifySetAndLayout() << " does not have binding " << update->dstBinding;
2946 *error_msg = error_str.str();
2947 return false;
2948 }
2949
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002950 auto dest = dest_set->GetBinding(update->dstBinding);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002951 // Make sure binding isn't empty
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002952 if (0 == dest->count) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002953 *error_code = "VUID-VkWriteDescriptorSet-dstBinding-00316";
2954 std::stringstream error_str;
2955 error_str << dest_set->StringifySetAndLayout() << " cannot updated binding " << update->dstBinding
2956 << " that has 0 descriptors";
2957 *error_msg = error_str.str();
2958 return false;
2959 }
2960
2961 // Verify idle ds
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002962 if (dest_set->InUse() && !(dest->IsBindless())) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002963 *error_code = "VUID-vkUpdateDescriptorSets-None-03047";
2964 std::stringstream error_str;
2965 error_str << "Cannot call " << func_name << " to perform write update on " << dest_set->StringifySetAndLayout()
2966 << " that is in use by a command buffer";
2967 *error_msg = error_str.str();
2968 return false;
2969 }
2970 // We know that binding is valid, verify update and do update on each descriptor
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002971 if ((dest->type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) && (dest->type != update->descriptorType)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002972 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00319";
2973 std::stringstream error_str;
2974 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002975 << " with type " << string_VkDescriptorType(dest->type) << " but update type is "
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002976 << string_VkDescriptorType(update->descriptorType);
2977 *error_msg = error_str.str();
2978 return false;
2979 }
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06002980 if (dest->type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06002981 if ((update->dstArrayElement % 4) != 0) {
2982 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02219";
2983 std::stringstream error_str;
2984 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2985 << " with "
2986 << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
2987 *error_msg = error_str.str();
2988 return false;
2989 }
2990 if ((update->descriptorCount % 4) != 0) {
2991 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02220";
2992 std::stringstream error_str;
2993 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
2994 << " with "
2995 << "descriptorCount " << update->descriptorCount << " not a multiple of 4";
2996 *error_msg = error_str.str();
2997 return false;
2998 }
2999 const auto *write_inline_info = LvlFindInChain<VkWriteDescriptorSetInlineUniformBlockEXT>(update->pNext);
3000 if (!write_inline_info || write_inline_info->dataSize != update->descriptorCount) {
3001 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02221";
3002 std::stringstream error_str;
3003 if (!write_inline_info) {
3004 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #"
3005 << update->dstBinding << " with "
3006 << "VkWriteDescriptorSetInlineUniformBlock missing";
3007 } else {
3008 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #"
3009 << update->dstBinding << " with "
3010 << "VkWriteDescriptorSetInlineUniformBlock dataSize " << write_inline_info->dataSize << " not equal to "
3011 << "VkWriteDescriptorSet descriptorCount " << update->descriptorCount;
3012 }
3013 *error_msg = error_str.str();
3014 return false;
3015 }
3016 // This error is probably unreachable due to the previous two errors
3017 if (write_inline_info && (write_inline_info->dataSize % 4) != 0) {
3018 *error_code = "VUID-VkWriteDescriptorSetInlineUniformBlock-dataSize-02222";
3019 std::stringstream error_str;
3020 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
3021 << " with "
3022 << "VkWriteDescriptorSetInlineUniformBlock dataSize " << write_inline_info->dataSize
3023 << " not a multiple of 4";
3024 *error_msg = error_str.str();
3025 return false;
3026 }
3027 }
3028 // Verify all bindings update share identical properties across all items
3029 if (update->descriptorCount > 0) {
3030 // Save first binding information and error if something different is found
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003031 auto current_iter = dest_set->FindBinding(update->dstBinding);
3032 VkShaderStageFlags stage_flags = (*current_iter)->stage_flags;
3033 VkDescriptorType descriptor_type = (*current_iter)->type;
3034 bool immutable_samplers = (*current_iter)->has_immutable_samplers;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003035 uint32_t dst_array_element = update->dstArrayElement;
3036
3037 for (uint32_t i = 0; i < update->descriptorCount;) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003038 if (current_iter == dest_set->end()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003039 break; // prevents setting error here if bindings don't exist
3040 }
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003041 auto current_binding = current_iter->get();
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003042
3043 // All consecutive bindings updated, except those with a descriptorCount of zero, must have identical descType and
3044 // stageFlags
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003045 if (current_binding->count > 0) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003046 // Check for consistent stageFlags and descriptorType
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003047 if ((current_binding->stage_flags != stage_flags) || (current_binding->type != descriptor_type)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003048 *error_code = "VUID-VkWriteDescriptorSet-descriptorCount-00317";
3049 std::stringstream error_str;
3050 error_str
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003051 << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding #"
3052 << current_binding->binding << " (" << i << " from dstBinding offset)"
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003053 << " with a different stageFlag and/or descriptorType from previous bindings."
3054 << " All bindings must have consecutive stageFlag and/or descriptorType across a VkWriteDescriptorSet";
3055 *error_msg = error_str.str();
3056 return false;
3057 }
3058 // Check if all immutableSamplers or not
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003059 if (current_binding->has_immutable_samplers != immutable_samplers) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003060 *error_code = "VUID-VkWriteDescriptorSet-descriptorCount-00318";
3061 std::stringstream error_str;
3062 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding index #"
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003063 << current_binding->binding << " (" << i << " from dstBinding offset)"
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003064 << " with a different usage of immutable samplers from previous bindings."
3065 << " All bindings must have all or none usage of immutable samplers across a VkWriteDescriptorSet";
3066 *error_msg = error_str.str();
3067 return false;
3068 }
3069 }
3070
3071 // Skip the remaining descriptors for this binding, and move to the next binding
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003072 i += (current_binding->count - dst_array_element);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003073 dst_array_element = 0;
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003074 ++current_iter;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003075 }
3076 }
3077
3078 // Verify consecutive bindings match (if needed)
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003079 if (!VerifyUpdateConsistency(report_data, *dest_set, update->dstBinding, update->dstArrayElement, update->descriptorCount,
3080 "write update to", error_msg)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003081 *error_code = "VUID-VkWriteDescriptorSet-dstArrayElement-00321";
3082 return false;
3083 }
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003084 const auto orig_binding = dest_set->GetBinding(update->dstBinding);
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003085 // Verify write to variable descriptor
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003086 if (orig_binding && orig_binding->IsVariableCount()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003087 if ((update->dstArrayElement + update->descriptorCount) > dest_set->GetVariableDescriptorCount()) {
3088 std::stringstream error_str;
3089 *error_code = "VUID-VkWriteDescriptorSet-dstArrayElement-00321";
3090 error_str << "Attempting write update to " << dest_set->StringifySetAndLayout() << " binding index #"
3091 << update->dstBinding << " array element " << update->dstArrayElement << " with " << update->descriptorCount
3092 << " writes but variable descriptor size is " << dest_set->GetVariableDescriptorCount();
3093 *error_msg = error_str.str();
3094 return false;
3095 }
3096 }
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003097 auto start_idx = dest_set->GetGlobalIndexRangeFromBinding(update->dstBinding).start + update->dstArrayElement;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003098 // Update is within bounds and consistent so last step is to validate update contents
3099 if (!VerifyWriteUpdateContents(dest_set, update, start_idx, func_name, error_code, error_msg, push)) {
3100 std::stringstream error_str;
3101 error_str << "Write update to " << dest_set->StringifySetAndLayout() << " binding #" << update->dstBinding
3102 << " failed with error message: " << error_msg->c_str();
3103 *error_msg = error_str.str();
3104 return false;
3105 }
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003106 if (orig_binding != nullptr && orig_binding->type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003107 // Check if the new descriptor descriptor type is in the list of allowed mutable types for this binding
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003108 if (!dest_set->Layout().IsTypeMutable(update->descriptorType, update->dstBinding)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003109 *error_code = "VUID-VkWriteDescriptorSet-dstSet-04611";
3110 std::stringstream error_str;
3111 error_str << "Write update type is " << string_VkDescriptorType(update->descriptorType)
3112 << ", but descriptor set layout binding was created with type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE and used type "
3113 "is not in VkMutableDescriptorTypeListVALVE::pDescriptorTypes for this binding.";
3114 *error_msg = error_str.str();
3115 return false;
3116 }
3117 }
3118 // All checks passed, update is clean
3119 return true;
3120}
3121
3122// Verify that the contents of the update are ok, but don't perform actual update
3123bool CoreChecks::VerifyWriteUpdateContents(const DescriptorSet *dest_set, const VkWriteDescriptorSet *update, const uint32_t index,
3124 const char *func_name, std::string *error_code, std::string *error_msg,
3125 bool push) const {
3126 using ImageSamplerDescriptor = cvdescriptorset::ImageSamplerDescriptor;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003127
3128 switch (update->descriptorType) {
3129 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003130 auto iter = dest_set->FindDescriptor(update->dstBinding, update->dstArrayElement);
3131 for (uint32_t di = 0; di < update->descriptorCount && !iter.AtEnd(); ++di, ++iter) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003132 // Validate image
3133 auto image_view = update->pImageInfo[di].imageView;
3134 auto image_layout = update->pImageInfo[di].imageLayout;
3135 auto sampler = update->pImageInfo[di].sampler;
3136 auto iv_state = Get<IMAGE_VIEW_STATE>(image_view);
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003137 const ImageSamplerDescriptor &desc = (const ImageSamplerDescriptor &)*iter;
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003138 if (image_view) {
3139 const auto *image_state = iv_state->image_state.get();
3140 if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, func_name, error_code, error_msg)) {
3141 std::stringstream error_str;
3142 error_str << "Attempted write update to combined image sampler descriptor failed due to: "
3143 << error_msg->c_str();
3144 *error_msg = error_str.str();
3145 return false;
3146 }
3147 if (IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)) {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003148 if (desc.IsImmutableSampler()) {
3149 auto sampler_state = Get<SAMPLER_STATE>(desc.GetSampler());
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003150 if (iv_state && sampler_state) {
3151 if (iv_state->samplerConversion != sampler_state->samplerConversion) {
3152 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-01948";
3153 std::stringstream error_str;
3154 error_str
3155 << "Attempted write update to combined image sampler and image view and sampler ycbcr "
3156 "conversions are not identical, sampler: "
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003157 << report_data->FormatHandle(desc.GetSampler())
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003158 << " image view: " << report_data->FormatHandle(iv_state->image_view()) << ".";
3159 *error_msg = error_str.str();
3160 return false;
3161 }
3162 }
3163 } else {
3164 if (iv_state && (iv_state->samplerConversion != VK_NULL_HANDLE)) {
3165 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02738";
3166 std::stringstream error_str;
3167 error_str << "Because dstSet (" << report_data->FormatHandle(update->dstSet)
3168 << ") is bound to image view (" << report_data->FormatHandle(iv_state->image_view())
3169 << ") that includes a YCBCR conversion, it must have been allocated with a layout that "
3170 "includes an immutable sampler.";
3171 *error_msg = error_str.str();
3172 return false;
3173 }
3174 }
3175 }
3176 // If there is an immutable sampler then |sampler| isn't used, so the following VU does not apply.
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003177 if (sampler && !desc.IsImmutableSampler() && FormatIsMultiplane(image_state->createInfo.format)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003178 // multiplane formats must be created with mutable format bit
3179 if (0 == (image_state->createInfo.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) {
3180 *error_code = "VUID-VkDescriptorImageInfo-sampler-01564";
3181 std::stringstream error_str;
3182 error_str << "image " << report_data->FormatHandle(image_state->image())
3183 << " combined image sampler is a multi-planar "
3184 << "format and was not was not created with the VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT";
3185 *error_msg = error_str.str();
3186 return false;
3187 }
3188 // image view need aspect mask for only the planes supported of format
3189 VkImageAspectFlags legal_aspect_flags = (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
3190 legal_aspect_flags |=
3191 (FormatPlaneCount(image_state->createInfo.format) == 3) ? VK_IMAGE_ASPECT_PLANE_2_BIT : 0;
3192 if (0 != (iv_state->create_info.subresourceRange.aspectMask & (~legal_aspect_flags))) {
3193 *error_code = "VUID-VkDescriptorImageInfo-sampler-01564";
3194 std::stringstream error_str;
3195 error_str << "image " << report_data->FormatHandle(image_state->image())
3196 << " combined image sampler is a multi-planar "
3197 << "format and " << report_data->FormatHandle(iv_state->image_view())
3198 << " aspectMask must only include " << string_VkImageAspectFlags(legal_aspect_flags);
3199 *error_msg = error_str.str();
3200 return false;
3201 }
3202 }
3203
3204 // Verify portability
3205 auto sampler_state = Get<SAMPLER_STATE>(sampler);
3206 if (sampler_state) {
3207 if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
3208 if ((VK_FALSE == enabled_features.portability_subset_features.mutableComparisonSamplers) &&
3209 (VK_FALSE != sampler_state->createInfo.compareEnable)) {
3210 LogError(device, "VUID-VkDescriptorImageInfo-mutableComparisonSamplers-04450",
3211 "%s (portability error): sampler comparison not available.", func_name);
3212 }
3213 }
3214 }
3215 }
3216 }
3217 }
3218 // Fall through
3219 case VK_DESCRIPTOR_TYPE_SAMPLER: {
Jeremy Gebben1b9fdb82022-06-15 15:31:32 -06003220 auto iter = dest_set->FindDescriptor(update->dstBinding, update->dstArrayElement);
3221 for (uint32_t di = 0; di < update->descriptorCount && !iter.AtEnd(); ++di, ++iter) {
3222 const auto &desc = *iter;
3223 if (!desc.IsImmutableSampler()) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003224 if (!ValidateSampler(update->pImageInfo[di].sampler)) {
3225 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-00325";
3226 std::stringstream error_str;
3227 error_str << "Attempted write update to sampler descriptor with invalid sampler: "
3228 << report_data->FormatHandle(update->pImageInfo[di].sampler) << ".";
3229 *error_msg = error_str.str();
3230 return false;
3231 }
3232 } else if (update->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER && !push) {
3233 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02752";
3234 std::stringstream error_str;
3235 error_str << "Attempted write update to an immutable sampler descriptor.";
3236 *error_msg = error_str.str();
3237 return false;
3238 }
3239 }
3240 break;
3241 }
3242 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3243 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
3244 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
3245 for (uint32_t di = 0; di < update->descriptorCount; ++di) {
3246 auto image_view = update->pImageInfo[di].imageView;
3247 auto image_layout = update->pImageInfo[di].imageLayout;
3248 if (image_view) {
3249 if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, func_name, error_code, error_msg)) {
3250 std::stringstream error_str;
3251 error_str << "Attempted write update to image descriptor failed due to: " << error_msg->c_str();
3252 *error_msg = error_str.str();
3253 return false;
3254 }
3255 }
3256 }
3257 break;
3258 }
3259 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
3260 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
3261 for (uint32_t di = 0; di < update->descriptorCount; ++di) {
3262 auto buffer_view = update->pTexelBufferView[di];
3263 if (buffer_view) {
3264 auto bv_state = Get<BUFFER_VIEW_STATE>(buffer_view);
3265 if (!bv_state) {
3266 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02994";
3267 std::stringstream error_str;
3268 error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: "
3269 << report_data->FormatHandle(buffer_view);
3270 *error_msg = error_str.str();
3271 return false;
3272 }
3273 auto buffer = bv_state->create_info.buffer;
3274 auto buffer_state = Get<BUFFER_STATE>(buffer);
3275 // Verify that buffer underlying the view hasn't been destroyed prematurely
3276 if (!buffer_state) {
3277 *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02994";
3278 std::stringstream error_str;
3279 error_str << "Attempted write update to texel buffer descriptor failed because underlying buffer ("
3280 << report_data->FormatHandle(buffer) << ") has been destroyed: " << error_msg->c_str();
3281 *error_msg = error_str.str();
3282 return false;
Jeremy Gebben567a5be2022-05-12 09:14:47 -06003283 } else if (!ValidateBufferUsage(report_data, buffer_state.get(), update->descriptorType, error_code,
3284 error_msg)) {
Jeremy Gebbenbb718a32022-05-12 08:51:10 -06003285 std::stringstream error_str;
3286 error_str << "Attempted write update to texel buffer descriptor failed due to: " << error_msg->c_str();
3287 *error_msg = error_str.str();
3288 return false;
3289 }
3290 }
3291 }
3292 break;
3293 }
3294 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3295 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
3296 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3297 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
3298 for (uint32_t di = 0; di < update->descriptorCount; ++di) {
3299 if (update->pBufferInfo[di].buffer) {
3300 if (!ValidateBufferUpdate(update->pBufferInfo + di, update->descriptorType, func_name, error_code, error_msg)) {
3301 std::stringstream error_str;
3302 error_str << "Attempted write update to buffer descriptor failed due to: " << error_msg->c_str();
3303 *error_msg = error_str.str();
3304 return false;
3305 }
3306 }
3307 }
3308 break;
3309 }
3310 case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
3311 break;
3312 case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV: {
3313 const auto *acc_info = LvlFindInChain<VkWriteDescriptorSetAccelerationStructureNV>(update->pNext);
3314 for (uint32_t di = 0; di < update->descriptorCount; ++di) {
3315 auto as_state = Get<ACCELERATION_STRUCTURE_STATE>(acc_info->pAccelerationStructures[di]);
3316 if (!ValidateAccelerationStructureUpdate(as_state.get(), func_name, error_code, error_msg)) {
3317 std::stringstream error_str;
3318 error_str << "Attempted write update to acceleration structure descriptor failed due to: "
3319 << error_msg->c_str();
3320 *error_msg = error_str.str();
3321 return false;
3322 }
3323 }
3324
3325 } break;
3326 // KHR acceleration structures don't require memory to be bound manually to them.
3327 case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
3328 break;
3329 default:
3330 assert(0); // We've already verified update type so should never get here
3331 break;
3332 }
3333 // All checks passed so update contents are good
3334 return true;
3335}