1 /* Copyright (c) 2015-2021 The Khronos Group Inc.
2  * Copyright (c) 2015-2021 Valve Corporation
3  * Copyright (c) 2015-2021 LunarG, Inc.
4  * Copyright (C) 2015-2021 Google Inc.
5  * Modifications Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * Author: Cody Northrop <cnorthrop@google.com>
20  * Author: Michael Lentine <mlentine@google.com>
21  * Author: Tobin Ehlis <tobine@google.com>
22  * Author: Chia-I Wu <olv@google.com>
23  * Author: Chris Forbes <chrisf@ijw.co.nz>
24  * Author: Mark Lobodzinski <mark@lunarg.com>
25  * Author: Ian Elliott <ianelliott@google.com>
26  * Author: Dave Houlton <daveh@lunarg.com>
27  * Author: Dustin Graves <dustin@lunarg.com>
28  * Author: Jeremy Hayes <jeremy@lunarg.com>
29  * Author: Jon Ashburn <jon@lunarg.com>
30  * Author: Karl Schultz <karl@lunarg.com>
31  * Author: Mark Young <marky@lunarg.com>
32  * Author: Mike Schuchardt <mikes@lunarg.com>
33  * Author: Mike Weiblen <mikew@lunarg.com>
34  * Author: Tony Barbour <tony@LunarG.com>
35  * Author: John Zulauf <jzulauf@lunarg.com>
36  * Author: Shannon McPherson <shannon@lunarg.com>
37  * Author: Jeremy Kniager <jeremyk@lunarg.com>
38  * Author: Tobias Hector <tobias.hector@amd.com>
39  * Author: Jeremy Gebben <jeremyg@lunarg.com>
40  */
41 
42 #include <algorithm>
43 #include <array>
44 #include <assert.h>
45 #include <cmath>
46 #include <fstream>
47 #include <iostream>
48 #include <list>
49 #include <map>
50 #include <memory>
51 #include <mutex>
52 #include <set>
53 #include <sstream>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <string>
58 #include <valarray>
59 
60 #if defined(__linux__) || defined(__FreeBSD__)
61 
62 #include <unistd.h>
63 #include <sys/types.h>
64 #endif
65 
66 #include "vk_loader_platform.h"
67 #include "vk_enum_string_helper.h"
68 #include "chassis.h"
69 #include "convert_to_renderpass2.h"
70 #include "core_validation.h"
71 #include "buffer_validation.h"
72 #include "shader_validation.h"
73 #include "vk_layer_utils.h"
74 #include "sync_utils.h"
75 #include "sync_vuid_maps.h"
76 
77 // these templates are defined in buffer_validation.cpp so we need to pull in the explicit instantiations from there
78 extern template void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t barrier_count,
79                                                         const VkImageMemoryBarrier *barrier);
80 extern template void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t barrier_count,
81                                                         const VkImageMemoryBarrier2KHR *barrier);
82 extern template bool CoreChecks::ValidateImageBarrierAttachment(const Location &loc, CMD_BUFFER_STATE const *cb_state,
83                                                                 const FRAMEBUFFER_STATE *framebuffer, uint32_t active_subpass,
84                                                                 const safe_VkSubpassDescription2 &sub_desc,
85                                                                 const VkRenderPass rp_handle,
86                                                                 const VkImageMemoryBarrier &img_barrier,
87                                                                 const CMD_BUFFER_STATE *primary_cb_state) const;
88 extern template bool CoreChecks::ValidateImageBarrierAttachment(const Location &loc, CMD_BUFFER_STATE const *cb_state,
89                                                                 const FRAMEBUFFER_STATE *framebuffer, uint32_t active_subpass,
90                                                                 const safe_VkSubpassDescription2 &sub_desc,
91                                                                 const VkRenderPass rp_handle,
92                                                                 const VkImageMemoryBarrier2KHR &img_barrier,
93                                                                 const CMD_BUFFER_STATE *primary_cb_state) const;
94 
95 using std::max;
96 using std::string;
97 using std::stringstream;
98 using std::unique_ptr;
99 using std::vector;
100 
AddInitialLayoutintoImageLayoutMap(const IMAGE_STATE & image_state,GlobalImageLayoutMap & image_layout_map)101 void CoreChecks::AddInitialLayoutintoImageLayoutMap(const IMAGE_STATE &image_state, GlobalImageLayoutMap &image_layout_map) {
102     auto *range_map = GetLayoutRangeMap(image_layout_map, image_state);
103     auto range_gen = subresource_adapter::RangeGenerator(image_state.subresource_encoder);
104     for (; range_gen->non_empty(); ++range_gen) {
105         range_map->insert(range_map->end(), std::make_pair(*range_gen, image_state.createInfo.initialLayout));
106     }
107 }
108 
109 // Override base class, we have some extra work to do here
InitDeviceValidationObject(bool add_obj,ValidationObject * inst_obj,ValidationObject * dev_obj)110 void CoreChecks::InitDeviceValidationObject(bool add_obj, ValidationObject *inst_obj, ValidationObject *dev_obj) {
111     if (add_obj) {
112         ValidationStateTracker::InitDeviceValidationObject(add_obj, inst_obj, dev_obj);
113     }
114 }
115 
116 // For given mem object, verify that it is not null or UNBOUND, if it is, report error. Return skip value.
117 template <typename T1>
VerifyBoundMemoryIsValid(const DEVICE_MEMORY_STATE * mem_state,const T1 object,const VulkanTypedHandle & typed_handle,const char * api_name,const char * error_code) const118 bool CoreChecks::VerifyBoundMemoryIsValid(const DEVICE_MEMORY_STATE *mem_state, const T1 object,
119                                           const VulkanTypedHandle &typed_handle, const char *api_name,
120                                           const char *error_code) const {
121     return VerifyBoundMemoryIsValid<T1, SimpleErrorLocation>(mem_state, object, typed_handle, {api_name, error_code});
122 }
123 
124 template <typename T1, typename LocType>
VerifyBoundMemoryIsValid(const DEVICE_MEMORY_STATE * mem_state,const T1 object,const VulkanTypedHandle & typed_handle,const LocType & location) const125 bool CoreChecks::VerifyBoundMemoryIsValid(const DEVICE_MEMORY_STATE *mem_state, const T1 object,
126                                           const VulkanTypedHandle &typed_handle, const LocType &location) const {
127     bool result = false;
128     auto type_name = object_string[typed_handle.type];
129     if (!mem_state) {
130         result |= LogError(object, location.Vuid(),
131                            "%s: %s used with no memory bound. Memory should be bound by calling vkBind%sMemory().",
132                            location.FuncName(), report_data->FormatHandle(typed_handle).c_str(), type_name + 2);
133     } else if (mem_state->Destroyed()) {
134         result |= LogError(object, location.Vuid(),
135                            "%s: %s used with no memory bound and previously bound memory was freed. Memory must not be freed "
136                            "prior to this operation.",
137                            location.FuncName(), report_data->FormatHandle(typed_handle).c_str());
138     }
139     return result;
140 }
141 
142 // Check to see if memory was ever bound to this image
143 
ValidateMemoryIsBoundToImage(const IMAGE_STATE * image_state,const Location & loc) const144 bool CoreChecks::ValidateMemoryIsBoundToImage(const IMAGE_STATE *image_state, const Location &loc) const {
145     using LocationAdapter = core_error::LocationVuidAdapter<sync_vuid_maps::GetImageBarrierVUIDFunctor>;
146     return ValidateMemoryIsBoundToImage<LocationAdapter>(image_state, LocationAdapter(loc, sync_vuid_maps::ImageError::kNoMemory));
147 }
148 
ValidateMemoryIsBoundToImage(const IMAGE_STATE * image_state,const char * api_name,const char * error_code) const149 bool CoreChecks::ValidateMemoryIsBoundToImage(const IMAGE_STATE *image_state, const char *api_name, const char *error_code) const {
150     return ValidateMemoryIsBoundToImage<SimpleErrorLocation>(image_state, SimpleErrorLocation(api_name, error_code));
151 }
152 
153 template <typename LocType>
ValidateMemoryIsBoundToImage(const IMAGE_STATE * image_state,const LocType & location) const154 bool CoreChecks::ValidateMemoryIsBoundToImage(const IMAGE_STATE *image_state, const LocType &location) const {
155     bool result = false;
156     if (image_state->create_from_swapchain != VK_NULL_HANDLE) {
157         if (!image_state->bind_swapchain) {
158             LogObjectList objlist(image_state->image());
159             objlist.add(image_state->create_from_swapchain);
160             result |= LogError(
161                 objlist, location.Vuid(),
162                 "%s: %s is created by %s, and the image should be bound by calling vkBindImageMemory2(), and the pNext chain "
163                 "includes VkBindImageMemorySwapchainInfoKHR.",
164                 location.FuncName(), report_data->FormatHandle(image_state->image()).c_str(),
165                 report_data->FormatHandle(image_state->create_from_swapchain).c_str());
166         } else if (image_state->create_from_swapchain != image_state->bind_swapchain->swapchain()) {
167             LogObjectList objlist(image_state->image());
168             objlist.add(image_state->create_from_swapchain);
169             objlist.add(image_state->bind_swapchain->Handle());
170             result |=
171                 LogError(objlist, location.Vuid(),
172                          "%s: %s is created by %s, but the image is bound by %s. The image should be created and bound by the same "
173                          "swapchain",
174                          location.FuncName(), report_data->FormatHandle(image_state->image()).c_str(),
175                          report_data->FormatHandle(image_state->create_from_swapchain).c_str(),
176                          report_data->FormatHandle(image_state->bind_swapchain->Handle()).c_str());
177         }
178     } else if (image_state->IsExternalAHB()) {
179         // TODO look into how to properly check for a valid bound memory for an external AHB
180     } else if (0 == (static_cast<uint32_t>(image_state->createInfo.flags) & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
181         result |= VerifyBoundMemoryIsValid(image_state->MemState(), image_state->image(), image_state->Handle(), location);
182     }
183     return result;
184 }
185 
186 // Check to see if memory was bound to this buffer
ValidateMemoryIsBoundToBuffer(const BUFFER_STATE * buffer_state,const char * api_name,const char * error_code) const187 bool CoreChecks::ValidateMemoryIsBoundToBuffer(const BUFFER_STATE *buffer_state, const char *api_name,
188                                                const char *error_code) const {
189     bool result = false;
190     if (0 == (static_cast<uint32_t>(buffer_state->createInfo.flags) & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
191         result |= VerifyBoundMemoryIsValid(buffer_state->MemState(), buffer_state->buffer(), buffer_state->Handle(), api_name,
192                                            error_code);
193     }
194     return result;
195 }
196 
197 // Check to see if memory was bound to this acceleration structure
ValidateMemoryIsBoundToAccelerationStructure(const ACCELERATION_STRUCTURE_STATE * as_state,const char * api_name,const char * error_code) const198 bool CoreChecks::ValidateMemoryIsBoundToAccelerationStructure(const ACCELERATION_STRUCTURE_STATE *as_state, const char *api_name,
199                                                               const char *error_code) const {
200     return VerifyBoundMemoryIsValid(as_state->MemState(), as_state->acceleration_structure(), as_state->Handle(), api_name,
201                                     error_code);
202 }
203 
204 // Check to see if memory was bound to this acceleration structure
ValidateMemoryIsBoundToAccelerationStructure(const ACCELERATION_STRUCTURE_STATE_KHR * as_state,const char * api_name,const char * error_code) const205 bool CoreChecks::ValidateMemoryIsBoundToAccelerationStructure(const ACCELERATION_STRUCTURE_STATE_KHR *as_state,
206                                                               const char *api_name, const char *error_code) const {
207     return VerifyBoundMemoryIsValid(as_state->MemState(), as_state->acceleration_structure(), as_state->Handle(), api_name,
208                                     error_code);
209 }
210 
211 // Valid usage checks for a call to SetMemBinding().
212 // For NULL mem case, output warning
213 // Make sure given object is in global object map
214 //  IF a previous binding existed, output validation error
215 //  Otherwise, add reference from objectInfo to memoryInfo
216 //  Add reference off of objInfo
217 // TODO: We may need to refactor or pass in multiple valid usage statements to handle multiple valid usage conditions.
ValidateSetMemBinding(VkDeviceMemory mem,const BINDABLE & mem_binding,const char * apiName) const218 bool CoreChecks::ValidateSetMemBinding(VkDeviceMemory mem, const BINDABLE &mem_binding, const char *apiName) const {
219     bool skip = false;
220     // It's an error to bind an object to NULL memory
221     if (mem != VK_NULL_HANDLE) {
222         auto typed_handle = mem_binding.Handle();
223         if (mem_binding.sparse) {
224             const char *error_code = nullptr;
225             const char *handle_type = nullptr;
226             if (typed_handle.type == kVulkanObjectTypeBuffer) {
227                 handle_type = "BUFFER";
228                 if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
229                     error_code = "VUID-vkBindBufferMemory-buffer-01030";
230                 } else {
231                     error_code = "VUID-VkBindBufferMemoryInfo-buffer-01030";
232                 }
233             } else if (typed_handle.type == kVulkanObjectTypeImage) {
234                 handle_type = "IMAGE";
235                 if (strcmp(apiName, "vkBindImageMemory()") == 0) {
236                     error_code = "VUID-vkBindImageMemory-image-01045";
237                 } else {
238                     error_code = "VUID-VkBindImageMemoryInfo-image-01045";
239                 }
240             } else {
241                 // Unsupported object type
242                 assert(false);
243             }
244 
245             LogObjectList objlist(mem);
246             objlist.add(typed_handle);
247             skip |= LogError(objlist, error_code,
248                              "In %s, attempting to bind %s to %s which was created with sparse memory flags "
249                              "(VK_%s_CREATE_SPARSE_*_BIT).",
250                              apiName, report_data->FormatHandle(mem).c_str(), report_data->FormatHandle(typed_handle).c_str(),
251                              handle_type);
252         }
253         const auto mem_info = Get<DEVICE_MEMORY_STATE>(mem);
254         if (mem_info) {
255             const auto *prev_binding = mem_binding.MemState();
256             if (prev_binding) {
257                 if (!prev_binding->Destroyed()) {
258                     const char *error_code = nullptr;
259                     if (typed_handle.type == kVulkanObjectTypeBuffer) {
260                         if (strcmp(apiName, "vkBindBufferMemory()") == 0) {
261                             error_code = "VUID-vkBindBufferMemory-buffer-01029";
262                         } else {
263                             error_code = "VUID-VkBindBufferMemoryInfo-buffer-01029";
264                         }
265                     } else if (typed_handle.type == kVulkanObjectTypeImage) {
266                         if (strcmp(apiName, "vkBindImageMemory()") == 0) {
267                             error_code = "VUID-vkBindImageMemory-image-01044";
268                         } else {
269                             error_code = "VUID-VkBindImageMemoryInfo-image-01044";
270                         }
271                     } else {
272                         // Unsupported object type
273                         assert(false);
274                     }
275 
276                     LogObjectList objlist(mem);
277                     objlist.add(typed_handle);
278                     objlist.add(prev_binding->mem());
279                     skip |=
280                         LogError(objlist, error_code, "In %s, attempting to bind %s to %s which has already been bound to %s.",
281                                  apiName, report_data->FormatHandle(mem).c_str(), report_data->FormatHandle(typed_handle).c_str(),
282                                  report_data->FormatHandle(prev_binding->mem()).c_str());
283                 } else {
284                     LogObjectList objlist(mem);
285                     objlist.add(typed_handle);
286                     skip |=
287                         LogError(objlist, kVUID_Core_MemTrack_RebindObject,
288                                  "In %s, attempting to bind %s to %s which was previous bound to memory that has "
289                                  "since been freed. Memory bindings are immutable in "
290                                  "Vulkan so this attempt to bind to new memory is not allowed.",
291                                  apiName, report_data->FormatHandle(mem).c_str(), report_data->FormatHandle(typed_handle).c_str());
292                 }
293             }
294         }
295     }
296     return skip;
297 }
298 
ValidateDeviceQueueFamily(uint32_t queue_family,const char * cmd_name,const char * parameter_name,const char * error_code,bool optional=false) const299 bool CoreChecks::ValidateDeviceQueueFamily(uint32_t queue_family, const char *cmd_name, const char *parameter_name,
300                                            const char *error_code, bool optional = false) const {
301     bool skip = false;
302     if (!optional && queue_family == VK_QUEUE_FAMILY_IGNORED) {
303         skip |= LogError(device, error_code,
304                          "%s: %s is VK_QUEUE_FAMILY_IGNORED, but it is required to provide a valid queue family index value.",
305                          cmd_name, parameter_name);
306     } else if (queue_family_index_set.find(queue_family) == queue_family_index_set.end()) {
307         skip |=
308             LogError(device, error_code,
309                      "%s: %s (= %" PRIu32
310                      ") is not one of the queue families given via VkDeviceQueueCreateInfo structures when the device was created.",
311                      cmd_name, parameter_name, queue_family);
312     }
313 
314     return skip;
315 }
316 
317 // Validate the specified queue families against the families supported by the physical device that owns this device
ValidatePhysicalDeviceQueueFamilies(uint32_t queue_family_count,const uint32_t * queue_families,const char * cmd_name,const char * array_parameter_name,const char * vuid) const318 bool CoreChecks::ValidatePhysicalDeviceQueueFamilies(uint32_t queue_family_count, const uint32_t *queue_families,
319                                                      const char *cmd_name, const char *array_parameter_name,
320                                                      const char *vuid) const {
321     bool skip = false;
322     if (queue_families) {
323         layer_data::unordered_set<uint32_t> set;
324         for (uint32_t i = 0; i < queue_family_count; ++i) {
325             std::string parameter_name = std::string(array_parameter_name) + "[" + std::to_string(i) + "]";
326 
327             if (set.count(queue_families[i])) {
328                 skip |= LogError(device, vuid, "%s: %s (=%" PRIu32 ") is not unique within %s array.", cmd_name,
329                                  parameter_name.c_str(), queue_families[i], array_parameter_name);
330             } else {
331                 set.insert(queue_families[i]);
332                 if (queue_families[i] == VK_QUEUE_FAMILY_IGNORED) {
333                     skip |= LogError(
334                         device, vuid,
335                         "%s: %s is VK_QUEUE_FAMILY_IGNORED, but it is required to provide a valid queue family index value.",
336                         cmd_name, parameter_name.c_str());
337                 } else if (queue_families[i] >= physical_device_state->queue_family_known_count) {
338                     LogObjectList obj_list(physical_device);
339                     obj_list.add(device);
340                     skip |=
341                         LogError(obj_list, vuid,
342                                  "%s: %s (= %" PRIu32
343                                  ") is not one of the queue families supported by the parent PhysicalDevice %s of this device %s.",
344                                  cmd_name, parameter_name.c_str(), queue_families[i],
345                                  report_data->FormatHandle(physical_device).c_str(), report_data->FormatHandle(device).c_str());
346                 }
347             }
348         }
349     }
350     return skip;
351 }
352 
353 // Check object status for selected flag state
ValidateStatus(const CMD_BUFFER_STATE * pNode,CBStatusFlags status_mask,const char * fail_msg,const char * msg_code) const354 bool CoreChecks::ValidateStatus(const CMD_BUFFER_STATE *pNode, CBStatusFlags status_mask, const char *fail_msg,
355                                 const char *msg_code) const {
356     if (!(pNode->status & status_mask)) {
357         return LogError(pNode->commandBuffer(), msg_code, "%s: %s.", report_data->FormatHandle(pNode->commandBuffer()).c_str(),
358                         fail_msg);
359     }
360     return false;
361 }
362 
363 // Return true if for a given PSO, the given state enum is dynamic, else return false
IsDynamic(const PIPELINE_STATE * pPipeline,const VkDynamicState state) const364 bool CoreChecks::IsDynamic(const PIPELINE_STATE *pPipeline, const VkDynamicState state) const {
365     if (pPipeline && (pPipeline->GetPipelineType() == VK_PIPELINE_BIND_POINT_GRAPHICS) &&
366         pPipeline->create_info.graphics.pDynamicState) {
367         for (uint32_t i = 0; i < pPipeline->create_info.graphics.pDynamicState->dynamicStateCount; i++) {
368             if (state == pPipeline->create_info.graphics.pDynamicState->pDynamicStates[i]) return true;
369         }
370     }
371     return false;
372 }
373 
374 // Validate state stored as flags at time of draw call
ValidateDrawStateFlags(const CMD_BUFFER_STATE * pCB,const PIPELINE_STATE * pPipe,bool indexed,const char * msg_code) const375 bool CoreChecks::ValidateDrawStateFlags(const CMD_BUFFER_STATE *pCB, const PIPELINE_STATE *pPipe, bool indexed,
376                                         const char *msg_code) const {
377     bool result = false;
378     if (pPipe->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_LINE_LIST ||
379         pPipe->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP) {
380         result |=
381             ValidateStatus(pCB, CBSTATUS_LINE_WIDTH_SET, "Dynamic line width state not set for this command buffer", msg_code);
382     }
383     const auto &create_info = pPipe->create_info.graphics;
384     if (create_info.pRasterizationState && (create_info.pRasterizationState->depthBiasEnable == VK_TRUE)) {
385         result |=
386             ValidateStatus(pCB, CBSTATUS_DEPTH_BIAS_SET, "Dynamic depth bias state not set for this command buffer", msg_code);
387     }
388     if (pPipe->blend_constants_enabled) {
389         result |= ValidateStatus(pCB, CBSTATUS_BLEND_CONSTANTS_SET, "Dynamic blend constants state not set for this command buffer",
390                                  msg_code);
391     }
392     if (create_info.pDepthStencilState && (create_info.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
393         result |=
394             ValidateStatus(pCB, CBSTATUS_DEPTH_BOUNDS_SET, "Dynamic depth bounds state not set for this command buffer", msg_code);
395     }
396     if (create_info.pDepthStencilState && (create_info.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
397         result |= ValidateStatus(pCB, CBSTATUS_STENCIL_READ_MASK_SET,
398                                  "Dynamic stencil read mask state not set for this command buffer", msg_code);
399         result |= ValidateStatus(pCB, CBSTATUS_STENCIL_WRITE_MASK_SET,
400                                  "Dynamic stencil write mask state not set for this command buffer", msg_code);
401         result |= ValidateStatus(pCB, CBSTATUS_STENCIL_REFERENCE_SET,
402                                  "Dynamic stencil reference state not set for this command buffer", msg_code);
403     }
404     if (indexed) {
405         result |= ValidateStatus(pCB, CBSTATUS_INDEX_BUFFER_BOUND,
406                                  "Index buffer object not bound to this command buffer when Indexed Draw attempted", msg_code);
407     }
408     if (pPipe->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_LINE_LIST ||
409         pPipe->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP) {
410         const auto *line_state =
411             LvlFindInChain<VkPipelineRasterizationLineStateCreateInfoEXT>(create_info.pRasterizationState->pNext);
412         if (line_state && line_state->stippledLineEnable) {
413             result |= ValidateStatus(pCB, CBSTATUS_LINE_STIPPLE_SET, "Dynamic line stipple state not set for this command buffer",
414                                      msg_code);
415         }
416     }
417 
418     return result;
419 }
420 
LogInvalidAttachmentMessage(const char * type1_string,const RENDER_PASS_STATE * rp1_state,const char * type2_string,const RENDER_PASS_STATE * rp2_state,uint32_t primary_attach,uint32_t secondary_attach,const char * msg,const char * caller,const char * error_code) const421 bool CoreChecks::LogInvalidAttachmentMessage(const char *type1_string, const RENDER_PASS_STATE *rp1_state, const char *type2_string,
422                                              const RENDER_PASS_STATE *rp2_state, uint32_t primary_attach, uint32_t secondary_attach,
423                                              const char *msg, const char *caller, const char *error_code) const {
424     LogObjectList objlist(rp1_state->renderPass());
425     objlist.add(rp2_state->renderPass());
426     return LogError(objlist, error_code,
427                     "%s: RenderPasses incompatible between %s w/ %s and %s w/ %s Attachment %u is not "
428                     "compatible with %u: %s.",
429                     caller, type1_string, report_data->FormatHandle(rp1_state->renderPass()).c_str(), type2_string,
430                     report_data->FormatHandle(rp2_state->renderPass()).c_str(), primary_attach, secondary_attach, msg);
431 }
432 
ValidateAttachmentCompatibility(const char * type1_string,const RENDER_PASS_STATE * rp1_state,const char * type2_string,const RENDER_PASS_STATE * rp2_state,uint32_t primary_attach,uint32_t secondary_attach,const char * caller,const char * error_code) const433 bool CoreChecks::ValidateAttachmentCompatibility(const char *type1_string, const RENDER_PASS_STATE *rp1_state,
434                                                  const char *type2_string, const RENDER_PASS_STATE *rp2_state,
435                                                  uint32_t primary_attach, uint32_t secondary_attach, const char *caller,
436                                                  const char *error_code) const {
437     bool skip = false;
438     const auto &primary_pass_ci = rp1_state->createInfo;
439     const auto &secondary_pass_ci = rp2_state->createInfo;
440     if (primary_pass_ci.attachmentCount <= primary_attach) {
441         primary_attach = VK_ATTACHMENT_UNUSED;
442     }
443     if (secondary_pass_ci.attachmentCount <= secondary_attach) {
444         secondary_attach = VK_ATTACHMENT_UNUSED;
445     }
446     if (primary_attach == VK_ATTACHMENT_UNUSED && secondary_attach == VK_ATTACHMENT_UNUSED) {
447         return skip;
448     }
449     if (primary_attach == VK_ATTACHMENT_UNUSED) {
450         skip |= LogInvalidAttachmentMessage(type1_string, rp1_state, type2_string, rp2_state, primary_attach, secondary_attach,
451                                             "The first is unused while the second is not.", caller, error_code);
452         return skip;
453     }
454     if (secondary_attach == VK_ATTACHMENT_UNUSED) {
455         skip |= LogInvalidAttachmentMessage(type1_string, rp1_state, type2_string, rp2_state, primary_attach, secondary_attach,
456                                             "The second is unused while the first is not.", caller, error_code);
457         return skip;
458     }
459     if (primary_pass_ci.pAttachments[primary_attach].format != secondary_pass_ci.pAttachments[secondary_attach].format) {
460         skip |= LogInvalidAttachmentMessage(type1_string, rp1_state, type2_string, rp2_state, primary_attach, secondary_attach,
461                                             "They have different formats.", caller, error_code);
462     }
463     if (primary_pass_ci.pAttachments[primary_attach].samples != secondary_pass_ci.pAttachments[secondary_attach].samples) {
464         skip |= LogInvalidAttachmentMessage(type1_string, rp1_state, type2_string, rp2_state, primary_attach, secondary_attach,
465                                             "They have different samples.", caller, error_code);
466     }
467     if (primary_pass_ci.pAttachments[primary_attach].flags != secondary_pass_ci.pAttachments[secondary_attach].flags) {
468         skip |= LogInvalidAttachmentMessage(type1_string, rp1_state, type2_string, rp2_state, primary_attach, secondary_attach,
469                                             "They have different flags.", caller, error_code);
470     }
471 
472     return skip;
473 }
474 
ValidateSubpassCompatibility(const char * type1_string,const RENDER_PASS_STATE * rp1_state,const char * type2_string,const RENDER_PASS_STATE * rp2_state,const int subpass,const char * caller,const char * error_code) const475 bool CoreChecks::ValidateSubpassCompatibility(const char *type1_string, const RENDER_PASS_STATE *rp1_state,
476                                               const char *type2_string, const RENDER_PASS_STATE *rp2_state, const int subpass,
477                                               const char *caller, const char *error_code) const {
478     bool skip = false;
479     const auto &primary_desc = rp1_state->createInfo.pSubpasses[subpass];
480     const auto &secondary_desc = rp2_state->createInfo.pSubpasses[subpass];
481     uint32_t max_input_attachment_count = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
482     for (uint32_t i = 0; i < max_input_attachment_count; ++i) {
483         uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
484         if (i < primary_desc.inputAttachmentCount) {
485             primary_input_attach = primary_desc.pInputAttachments[i].attachment;
486         }
487         if (i < secondary_desc.inputAttachmentCount) {
488             secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
489         }
490         skip |= ValidateAttachmentCompatibility(type1_string, rp1_state, type2_string, rp2_state, primary_input_attach,
491                                                 secondary_input_attach, caller, error_code);
492     }
493     uint32_t max_color_attachment_count = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
494     for (uint32_t i = 0; i < max_color_attachment_count; ++i) {
495         uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
496         if (i < primary_desc.colorAttachmentCount) {
497             primary_color_attach = primary_desc.pColorAttachments[i].attachment;
498         }
499         if (i < secondary_desc.colorAttachmentCount) {
500             secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
501         }
502         skip |= ValidateAttachmentCompatibility(type1_string, rp1_state, type2_string, rp2_state, primary_color_attach,
503                                                 secondary_color_attach, caller, error_code);
504         if (rp1_state->createInfo.subpassCount > 1) {
505             uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
506             if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
507                 primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
508             }
509             if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
510                 secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
511             }
512             skip |= ValidateAttachmentCompatibility(type1_string, rp1_state, type2_string, rp2_state, primary_resolve_attach,
513                                                     secondary_resolve_attach, caller, error_code);
514         }
515     }
516     uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
517     if (primary_desc.pDepthStencilAttachment) {
518         primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
519     }
520     if (secondary_desc.pDepthStencilAttachment) {
521         secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
522     }
523     skip |= ValidateAttachmentCompatibility(type1_string, rp1_state, type2_string, rp2_state, primary_depthstencil_attach,
524                                             secondary_depthstencil_attach, caller, error_code);
525 
526     // Both renderpasses must agree on Multiview usage
527     if (primary_desc.viewMask && secondary_desc.viewMask) {
528         if (primary_desc.viewMask != secondary_desc.viewMask) {
529             std::stringstream ss;
530             ss << "For subpass " << subpass << ", they have a different viewMask. The first has view mask " << primary_desc.viewMask
531                << " while the second has view mask " << secondary_desc.viewMask << ".";
532             skip |= LogInvalidPnextMessage(type1_string, rp1_state, type2_string, rp2_state, ss.str().c_str(), caller, error_code);
533         }
534     } else if (primary_desc.viewMask) {
535         skip |= LogInvalidPnextMessage(type1_string, rp1_state, type2_string, rp2_state,
536                                        "The first uses Multiview (has non-zero viewMasks) while the second one does not.", caller,
537                                        error_code);
538     } else if (secondary_desc.viewMask) {
539         skip |= LogInvalidPnextMessage(type1_string, rp1_state, type2_string, rp2_state,
540                                        "The second uses Multiview (has non-zero viewMasks) while the first one does not.", caller,
541                                        error_code);
542     }
543 
544     return skip;
545 }
546 
LogInvalidPnextMessage(const char * type1_string,const RENDER_PASS_STATE * rp1_state,const char * type2_string,const RENDER_PASS_STATE * rp2_state,const char * msg,const char * caller,const char * error_code) const547 bool CoreChecks::LogInvalidPnextMessage(const char *type1_string, const RENDER_PASS_STATE *rp1_state, const char *type2_string,
548                                         const RENDER_PASS_STATE *rp2_state, const char *msg, const char *caller,
549                                         const char *error_code) const {
550     LogObjectList objlist(rp1_state->renderPass());
551     objlist.add(rp2_state->renderPass());
552     return LogError(objlist, error_code, "%s: RenderPasses incompatible between %s w/ %s and %s w/ %s: %s", caller, type1_string,
553                     report_data->FormatHandle(rp1_state->renderPass()).c_str(), type2_string,
554                     report_data->FormatHandle(rp2_state->renderPass()).c_str(), msg);
555 }
556 
557 // Verify that given renderPass CreateInfo for primary and secondary command buffers are compatible.
558 //  This function deals directly with the CreateInfo, there are overloaded versions below that can take the renderPass handle and
559 //  will then feed into this function
ValidateRenderPassCompatibility(const char * type1_string,const RENDER_PASS_STATE * rp1_state,const char * type2_string,const RENDER_PASS_STATE * rp2_state,const char * caller,const char * error_code) const560 bool CoreChecks::ValidateRenderPassCompatibility(const char *type1_string, const RENDER_PASS_STATE *rp1_state,
561                                                  const char *type2_string, const RENDER_PASS_STATE *rp2_state, const char *caller,
562                                                  const char *error_code) const {
563     bool skip = false;
564 
565     // createInfo flags must be identical for the renderpasses to be compatible.
566     if (rp1_state->createInfo.flags != rp2_state->createInfo.flags) {
567         LogObjectList objlist(rp1_state->renderPass());
568         objlist.add(rp2_state->renderPass());
569         skip |=
570             LogError(objlist, error_code,
571                      "%s: RenderPasses incompatible between %s w/ %s with flags of %u and %s w/ "
572                      "%s with a flags of %u.",
573                      caller, type1_string, report_data->FormatHandle(rp1_state->renderPass()).c_str(), rp1_state->createInfo.flags,
574                      type2_string, report_data->FormatHandle(rp2_state->renderPass()).c_str(), rp2_state->createInfo.flags);
575     }
576 
577     if (rp1_state->createInfo.subpassCount != rp2_state->createInfo.subpassCount) {
578         LogObjectList objlist(rp1_state->renderPass());
579         objlist.add(rp2_state->renderPass());
580         skip |= LogError(objlist, error_code,
581                          "%s: RenderPasses incompatible between %s w/ %s with a subpassCount of %u and %s w/ "
582                          "%s with a subpassCount of %u.",
583                          caller, type1_string, report_data->FormatHandle(rp1_state->renderPass()).c_str(),
584                          rp1_state->createInfo.subpassCount, type2_string, report_data->FormatHandle(rp2_state->renderPass()).c_str(),
585                          rp2_state->createInfo.subpassCount);
586     } else {
587         for (uint32_t i = 0; i < rp1_state->createInfo.subpassCount; ++i) {
588             skip |= ValidateSubpassCompatibility(type1_string, rp1_state, type2_string, rp2_state, i, caller, error_code);
589         }
590     }
591 
592     // Find an entry of the Fragment Density Map type in the pNext chain, if it exists
593     const auto fdm1 = LvlFindInChain<VkRenderPassFragmentDensityMapCreateInfoEXT>(rp1_state->createInfo.pNext);
594     const auto fdm2 = LvlFindInChain<VkRenderPassFragmentDensityMapCreateInfoEXT>(rp2_state->createInfo.pNext);
595 
596     // Both renderpasses must agree on usage of a Fragment Density Map type
597     if (fdm1 && fdm2) {
598         uint32_t primary_input_attach = fdm1->fragmentDensityMapAttachment.attachment;
599         uint32_t secondary_input_attach = fdm2->fragmentDensityMapAttachment.attachment;
600         skip |= ValidateAttachmentCompatibility(type1_string, rp1_state, type2_string, rp2_state, primary_input_attach,
601                                                 secondary_input_attach, caller, error_code);
602     } else if (fdm1) {
603         skip |= LogInvalidPnextMessage(type1_string, rp1_state, type2_string, rp2_state,
604                                        "The first uses a Fragment Density Map while the second one does not.", caller, error_code);
605     } else if (fdm2) {
606         skip |= LogInvalidPnextMessage(type1_string, rp1_state, type2_string, rp2_state,
607                                        "The second uses a Fragment Density Map while the first one does not.", caller, error_code);
608     }
609 
610     return skip;
611 }
612 
613 // For given pipeline, return number of MSAA samples, or one if MSAA disabled
GetNumSamples(PIPELINE_STATE const * pipe)614 static VkSampleCountFlagBits GetNumSamples(PIPELINE_STATE const *pipe) {
615     if (pipe->create_info.graphics.pMultisampleState != NULL &&
616         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pipe->create_info.graphics.pMultisampleState->sType) {
617         return pipe->create_info.graphics.pMultisampleState->rasterizationSamples;
618     }
619     return VK_SAMPLE_COUNT_1_BIT;
620 }
621 
ListBits(std::ostream & s,uint32_t bits)622 static void ListBits(std::ostream &s, uint32_t bits) {
623     for (int i = 0; i < 32 && bits; i++) {
624         if (bits & (1 << i)) {
625             s << i;
626             bits &= ~(1 << i);
627             if (bits) {
628                 s << ",";
629             }
630         }
631     }
632 }
633 
DynamicStateString(CBStatusFlags input_value)634 std::string DynamicStateString(CBStatusFlags input_value) {
635     std::string ret;
636     int index = 0;
637     while (input_value) {
638         if (input_value & 1) {
639             if (!ret.empty()) ret.append("|");
640             ret.append(string_VkDynamicState(ConvertToDynamicState(static_cast<CBStatusFlagBits>(1llu << index))));
641         }
642         ++index;
643         input_value >>= 1;
644     }
645     if (ret.empty()) ret.append(string_VkDynamicState(ConvertToDynamicState(static_cast<CBStatusFlagBits>(0))));
646     return ret;
647 }
648 
649 // Validate draw-time state related to the PSO
ValidatePipelineDrawtimeState(const LAST_BOUND_STATE & state,const CMD_BUFFER_STATE * pCB,CMD_TYPE cmd_type,const PIPELINE_STATE * pPipeline) const650 bool CoreChecks::ValidatePipelineDrawtimeState(const LAST_BOUND_STATE &state, const CMD_BUFFER_STATE *pCB, CMD_TYPE cmd_type,
651                                                const PIPELINE_STATE *pPipeline) const {
652     bool skip = false;
653     const auto &current_vtx_bfr_binding_info = pCB->current_vertex_buffer_binding_info.vertex_buffer_bindings;
654     const DrawDispatchVuid vuid = GetDrawDispatchVuid(cmd_type);
655     const char *caller = CommandTypeString(cmd_type);
656 
657     if (pCB->activeRenderPass->use_dynamic_rendering) {
658         if (pPipeline->rp_state->dynamic_rendering_pipeline_create_info.viewMask !=
659             pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.viewMask) {
660                 skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_view_mask,
661                     "%s: Currently bound pipeline %s viewMask ([%" PRIu32 ") must be equal to pBeginRendering->viewMask ([%" PRIu32 ")",
662                     caller, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(),
663                     pPipeline->rp_state->dynamic_rendering_pipeline_create_info.viewMask,
664                     pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.viewMask);
665         }
666 
667         if (pPipeline->rp_state->dynamic_rendering_pipeline_create_info.colorAttachmentCount !=
668             pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount) {
669             skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_color_count,
670                              "%s: Currently bound pipeline %s colorAttachmentCount ([%" PRIu32
671                              ") must be equal to pBeginRendering->colorAttachmentCount ([%" PRIu32 ")",
672                              caller, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(),
673                              pPipeline->rp_state->dynamic_rendering_pipeline_create_info.colorAttachmentCount,
674                              pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount);
675         }
676 
677         if (pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount > 0) {
678             for (uint32_t i = 0; i < pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount; ++i) {
679                 if (pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pColorAttachments[i].imageView != VK_NULL_HANDLE) {
680                     auto view_state = Get<IMAGE_VIEW_STATE>(
681                         pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pColorAttachments[i].imageView);
682                     if (view_state->create_info.format != pPipeline->rp_state->dynamic_rendering_pipeline_create_info.pColorAttachmentFormats[i]) {
683                         skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_color_formats,
684                             "%s: Color attachment ([%" PRIu32 ") imageView format (%s) must match corresponding format in pipeline (%s)",
685                             caller, i, string_VkFormat(view_state->create_info.format),
686                                        string_VkFormat(pPipeline->rp_state->dynamic_rendering_pipeline_create_info.pColorAttachmentFormats[i]));
687                     }
688                 }
689             }
690         }
691 
692         auto rendering_fragment_shading_rate_attachment_info = LvlFindInChain<VkRenderingFragmentShadingRateAttachmentInfoKHR>(
693             pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pNext);
694         if (rendering_fragment_shading_rate_attachment_info && (rendering_fragment_shading_rate_attachment_info->imageView != VK_NULL_HANDLE)) {
695             if (!(pPipeline->rp_state->createInfo.flags & VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR)) {
696                 skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_fsr,
697                     "%s: Currently bound graphics pipeline %s must have been created with VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR",
698                     caller, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str());
699             }
700         }
701 
702         auto rendering_fragment_shading_rate_density_map = LvlFindInChain<VkRenderingFragmentDensityMapAttachmentInfoEXT>(
703             pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pNext);
704         if (rendering_fragment_shading_rate_density_map && (rendering_fragment_shading_rate_density_map->imageView != VK_NULL_HANDLE)) {
705             if (!(pPipeline->rp_state->createInfo.flags & VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT)) {
706                 skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_fdm,
707                     "%s: Currently bound graphics pipeline %s must have been created with VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT",
708                     caller, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str());
709             }
710         }
711 
712         auto p_attachment_sample_count_info_amd = LvlFindInChain<VkAttachmentSampleCountInfoAMD>(pPipeline->create_info.graphics.pNext);
713         auto p_attachment_sample_count_info_nv = LvlFindInChain<VkAttachmentSampleCountInfoNV>(pPipeline->create_info.graphics.pNext);
714         if ((p_attachment_sample_count_info_amd || p_attachment_sample_count_info_nv) &&
715             (pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount > 0)) {
716             for (uint32_t i = 0; i < pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount; ++i) {
717                 if (pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pColorAttachments[i].imageView != VK_NULL_HANDLE) {
718                     auto color_view_state = Get<IMAGE_VIEW_STATE>(
719                         pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pColorAttachments[i].imageView);
720                     auto color_image_samples = Get<IMAGE_STATE>(color_view_state->create_info.image)->createInfo.samples;
721 
722                     if (p_attachment_sample_count_info_amd) {
723                         if (color_image_samples != p_attachment_sample_count_info_amd->pColorAttachmentSamples[i]) {
724                             skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_color_sample,
725                                 "%s: Color attachment (%" PRIu32 ") sample count (%s) must match corresponding VkAttachmentSampleCountInfoAMD sample count (%s)",
726                                 caller, i, string_VkSampleCountFlagBits(color_image_samples),
727                                 string_VkSampleCountFlagBits(p_attachment_sample_count_info_amd->pColorAttachmentSamples[i]));
728                         }
729                     }
730 
731                     if (p_attachment_sample_count_info_nv) {
732                         if (color_image_samples != p_attachment_sample_count_info_nv->pColorAttachmentSamples[i]) {
733                             skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_color_sample,
734                                 "%s: Color attachment (%" PRIu32 ") sample count (%s) must match corresponding VkAttachmentSampleCountInfoNV sample count (%s)",
735                                 caller, i, string_VkSampleCountFlagBits(color_image_samples),
736                                 string_VkSampleCountFlagBits(p_attachment_sample_count_info_nv->pColorAttachmentSamples[i]));
737                         }
738                     }
739 
740                     if (color_image_samples != pPipeline->create_info.graphics.pMultisampleState->rasterizationSamples) {
741                         skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_multi_sample,
742                             "%s: Color attachment (%" PRIu32 ") sample count (%s) must match corresponding VkPipelineMultisampleStateCreateInfo sample count (%s)",
743                             caller, i, string_VkSampleCountFlagBits(color_image_samples),
744                             string_VkSampleCountFlagBits(pPipeline->create_info.graphics.pMultisampleState->rasterizationSamples));
745                     }
746                 }
747             }
748 
749             auto depth_view_state =
750                 Get<IMAGE_VIEW_STATE>(pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pDepthAttachment->imageView);
751             auto depth_image_samples = Get<IMAGE_STATE>(depth_view_state->create_info.image)->createInfo.samples;
752 
753             if (p_attachment_sample_count_info_amd) {
754                 if (depth_image_samples != p_attachment_sample_count_info_amd->depthStencilAttachmentSamples) {
755                     skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_depth_sample,
756                         "%s: Depth attachment sample count (%s) must match corresponding VkAttachmentSampleCountInfoAMD sample count (%s)",
757                         caller, string_VkSampleCountFlagBits(depth_image_samples),
758                         string_VkSampleCountFlagBits(p_attachment_sample_count_info_amd->depthStencilAttachmentSamples));
759                 }
760             }
761 
762             if (p_attachment_sample_count_info_nv) {
763                 if (depth_image_samples != p_attachment_sample_count_info_nv->depthStencilAttachmentSamples) {
764                     skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_depth_sample,
765                         "%s: Depth attachment sample count (%s) must match corresponding VkAttachmentSampleCountInfoNV sample count (%s)",
766                         caller, string_VkSampleCountFlagBits(depth_image_samples),
767                         string_VkSampleCountFlagBits(p_attachment_sample_count_info_nv->depthStencilAttachmentSamples));
768                 }
769             }
770 
771             auto stencil_view_state =
772                 Get<IMAGE_VIEW_STATE>(pCB->activeRenderPass->dynamic_rendering_begin_rendering_info.pDepthAttachment->imageView);
773             auto stencil_image_samples = Get<IMAGE_STATE>(stencil_view_state->create_info.image)->createInfo.samples;
774 
775             if (p_attachment_sample_count_info_amd) {
776                 if (stencil_image_samples != p_attachment_sample_count_info_amd->depthStencilAttachmentSamples) {
777                     skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_stencil_sample,
778                         "%s: Stencil attachment sample count (%s) must match corresponding VkAttachmentSampleCountInfoAMD sample count (%s)",
779                         caller, string_VkSampleCountFlagBits(stencil_image_samples),
780                         string_VkSampleCountFlagBits(p_attachment_sample_count_info_amd->depthStencilAttachmentSamples));
781                 }
782             }
783 
784             if (p_attachment_sample_count_info_nv) {
785                 if (stencil_image_samples != p_attachment_sample_count_info_nv->depthStencilAttachmentSamples) {
786                     skip |= LogError(pCB->commandBuffer(), vuid.dynamic_rendering_stencil_sample,
787                         "%s: Stencil attachment sample count (%s) must match corresponding VkAttachmentSampleCountInfoNV sample count (%s)",
788                         caller, string_VkSampleCountFlagBits(stencil_image_samples),
789                         string_VkSampleCountFlagBits(p_attachment_sample_count_info_nv->depthStencilAttachmentSamples));
790                 }
791             }
792         }
793     }
794 
795     // Verify vertex & index buffer for unprotected command buffer.
796     // Because vertex & index buffer is read only, it doesn't need to care protected command buffer case.
797     if (enabled_features.core11.protectedMemory == VK_TRUE) {
798         for (const auto &buffer_binding : current_vtx_bfr_binding_info) {
799             if (buffer_binding.buffer_state && !buffer_binding.buffer_state->Destroyed()) {
800                 skip |= ValidateProtectedBuffer(pCB, buffer_binding.buffer_state.get(), caller, vuid.unprotected_command_buffer,
801                                                 "Buffer is vertex buffer");
802             }
803         }
804         if (pCB->index_buffer_binding.buffer_state && !pCB->index_buffer_binding.buffer_state->Destroyed()) {
805             skip |= ValidateProtectedBuffer(pCB, pCB->index_buffer_binding.buffer_state.get(), caller,
806                                             vuid.unprotected_command_buffer, "Buffer is index buffer");
807         }
808     }
809 
810     // Verify if using dynamic state setting commands that it doesn't set up in pipeline
811     CBStatusFlags invalid_status = CBSTATUS_ALL_STATE_SET & ~(pCB->dynamic_status | pCB->static_status);
812     if (invalid_status) {
813         std::string dynamic_states = DynamicStateString(invalid_status);
814         LogObjectList objlist(pCB->commandBuffer());
815         objlist.add(pPipeline->pipeline());
816         skip |= LogError(objlist, vuid.dynamic_state_setting_commands,
817                          "%s: %s doesn't set up %s, but it calls the related dynamic state setting commands", caller,
818                          report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(), dynamic_states.c_str());
819     }
820 
821     // Verify vertex binding
822     if (pPipeline->vertex_binding_descriptions_.size() > 0) {
823         for (size_t i = 0; i < pPipeline->vertex_binding_descriptions_.size(); i++) {
824             const auto vertex_binding = pPipeline->vertex_binding_descriptions_[i].binding;
825             if (current_vtx_bfr_binding_info.size() < (vertex_binding + 1)) {
826                 skip |= LogError(pCB->commandBuffer(), vuid.vertex_binding,
827                                  "%s: %s expects that this Command Buffer's vertex binding Index %u should be set via "
828                                  "vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at "
829                                  "index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
830                                  caller, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(), vertex_binding, i,
831                                  vertex_binding);
832             } else if ((current_vtx_bfr_binding_info[vertex_binding].buffer_state == nullptr) &&
833                        !enabled_features.robustness2_features.nullDescriptor) {
834                 skip |= LogError(pCB->commandBuffer(), vuid.vertex_binding_null,
835                                  "%s: Vertex binding %d must not be VK_NULL_HANDLE %s expects that this Command Buffer's vertex "
836                                  "binding Index %u should be set via "
837                                  "vkCmdBindVertexBuffers. This is because VkVertexInputBindingDescription struct at "
838                                  "index " PRINTF_SIZE_T_SPECIFIER " of pVertexBindingDescriptions has a binding value of %u.",
839                                  caller, vertex_binding, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(),
840                                  vertex_binding, i, vertex_binding);
841             }
842         }
843 
844         // Verify vertex attribute address alignment
845         for (size_t i = 0; i < pPipeline->vertex_attribute_descriptions_.size(); i++) {
846             const auto &attribute_description = pPipeline->vertex_attribute_descriptions_[i];
847             const auto vertex_binding = attribute_description.binding;
848             const auto attribute_offset = attribute_description.offset;
849 
850             const auto &vertex_binding_map_it = pPipeline->vertex_binding_to_index_map_.find(vertex_binding);
851             if ((vertex_binding_map_it != pPipeline->vertex_binding_to_index_map_.cend()) &&
852                 (vertex_binding < current_vtx_bfr_binding_info.size()) &&
853                 ((current_vtx_bfr_binding_info[vertex_binding].buffer_state) ||
854                  enabled_features.robustness2_features.nullDescriptor)) {
855                 auto vertex_buffer_stride = pPipeline->vertex_binding_descriptions_[vertex_binding_map_it->second].stride;
856                 if (IsDynamic(pPipeline, VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT)) {
857                     vertex_buffer_stride = static_cast<uint32_t>(current_vtx_bfr_binding_info[vertex_binding].stride);
858                     uint32_t attribute_binding_extent =
859                         attribute_description.offset + FormatElementSize(attribute_description.format);
860                     if (vertex_buffer_stride != 0 && vertex_buffer_stride < attribute_binding_extent) {
861                         skip |= LogError(pCB->commandBuffer(), "VUID-vkCmdBindVertexBuffers2EXT-pStrides-06209",
862                                          "The pStrides[%u] (%u) parameter in the last call to vkCmdBindVertexBuffers2EXT is not 0 "
863                                          "and less than the extent of the binding for attribute %zu (%u).",
864                                          vertex_binding, vertex_buffer_stride, i, attribute_binding_extent);
865                     }
866                 }
867                 const auto vertex_buffer_offset = current_vtx_bfr_binding_info[vertex_binding].offset;
868 
869                 // Use 1 as vertex/instance index to use buffer stride as well
870                 const auto attrib_address = vertex_buffer_offset + vertex_buffer_stride + attribute_offset;
871 
872                 VkDeviceSize vtx_attrib_req_alignment = pPipeline->vertex_attribute_alignments_[i];
873 
874                 if (SafeModulo(attrib_address, vtx_attrib_req_alignment) != 0) {
875                     LogObjectList objlist(current_vtx_bfr_binding_info[vertex_binding].buffer_state->buffer());
876                     objlist.add(state.pipeline_state->pipeline());
877                     skip |= LogError(
878                         objlist, vuid.vertex_binding_attribute,
879                         "%s: Invalid attribAddress alignment for vertex attribute " PRINTF_SIZE_T_SPECIFIER
880                         ", %s,from of %s and vertex %s.",
881                         caller, i, string_VkFormat(attribute_description.format),
882                         report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(),
883                         report_data->FormatHandle(current_vtx_bfr_binding_info[vertex_binding].buffer_state->buffer()).c_str());
884                 }
885             } else {
886                 LogObjectList objlist(pCB->commandBuffer());
887                 objlist.add(state.pipeline_state->pipeline());
888                 skip |= LogError(objlist, vuid.vertex_binding_attribute,
889                                  "%s: binding #%" PRIu32
890                                  " in pVertexAttributeDescriptions of %s is invalid in vkCmdBindVertexBuffers of %s.",
891                                  caller, vertex_binding, report_data->FormatHandle(state.pipeline_state->pipeline()).c_str(),
892                                  report_data->FormatHandle(pCB->commandBuffer()).c_str());
893             }
894         }
895     }
896 
897     // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
898     // Skip check if rasterization is disabled, if there is no viewport, or if viewport/scissors are being inherited.
899     bool dyn_viewport = IsDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
900     const auto &create_info = pPipeline->create_info.graphics;
901     if ((!create_info.pRasterizationState || (create_info.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
902         create_info.pViewportState && pCB->inheritedViewportDepths.size() == 0) {
903         bool dyn_scissor = IsDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
904 
905         // NB (akeley98): Current validation layers do not detect the error where vkCmdSetViewport (or scissor) was called, but
906         // the dynamic state set is overwritten by binding a graphics pipeline with static viewport (scissor) state.
907         // This condition be detected by checking trashedViewportMask & viewportMask (trashedScissorMask & scissorMask) is
908         // nonzero in the range of bits needed by the pipeline.
909         if (dyn_viewport) {
910             const auto required_viewports_mask = (1 << create_info.pViewportState->viewportCount) - 1;
911             const auto missing_viewport_mask = ~pCB->viewportMask & required_viewports_mask;
912             if (missing_viewport_mask) {
913                 std::stringstream ss;
914                 ss << caller << ": Dynamic viewport(s) ";
915                 ListBits(ss, missing_viewport_mask);
916                 ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewport().";
917                 skip |= LogError(device, vuid.dynamic_state, "%s", ss.str().c_str());
918             }
919         }
920 
921         if (dyn_scissor) {
922             const auto required_scissor_mask = (1 << create_info.pViewportState->scissorCount) - 1;
923             const auto missing_scissor_mask = ~pCB->scissorMask & required_scissor_mask;
924             if (missing_scissor_mask) {
925                 std::stringstream ss;
926                 ss << caller << ": Dynamic scissor(s) ";
927                 ListBits(ss, missing_scissor_mask);
928                 ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissor().";
929                 skip |= LogError(device, vuid.dynamic_state, "%s", ss.str().c_str());
930             }
931         }
932 
933         bool dyn_viewport_count = IsDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
934         bool dyn_scissor_count = IsDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
935 
936         // VUID {refpage}-viewportCount-03417
937         if (dyn_viewport_count && !dyn_scissor_count) {
938             const auto required_viewport_mask = (1 << create_info.pViewportState->scissorCount) - 1;
939             const auto missing_viewport_mask = ~pCB->viewportWithCountMask & required_viewport_mask;
940             if (missing_viewport_mask) {
941                 std::stringstream ss;
942                 ss << caller << ": Dynamic viewport with count ";
943                 ListBits(ss, missing_viewport_mask);
944                 ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetViewportWithCountEXT().";
945                 skip |= LogError(device, vuid.viewport_count, "%s", ss.str().c_str());
946             }
947         }
948 
949         // VUID {refpage}-scissorCount-03418
950         if (dyn_scissor_count && !dyn_viewport_count) {
951             const auto required_scissor_mask = (1 << create_info.pViewportState->viewportCount) - 1;
952             const auto missing_scissor_mask = ~pCB->scissorWithCountMask & required_scissor_mask;
953             if (missing_scissor_mask) {
954                 std::stringstream ss;
955                 ss << caller << ": Dynamic scissor with count ";
956                 ListBits(ss, missing_scissor_mask);
957                 ss << " are used by pipeline state object, but were not provided via calls to vkCmdSetScissorWithCountEXT().";
958                 skip |= LogError(device, vuid.scissor_count, "%s", ss.str().c_str());
959             }
960         }
961 
962         // VUID {refpage}-viewportCount-03419
963         if (dyn_scissor_count && dyn_viewport_count) {
964             if (pCB->viewportWithCountMask != pCB->scissorWithCountMask) {
965                 std::stringstream ss;
966                 ss << caller << ": Dynamic viewport and scissor with count ";
967                 ListBits(ss, pCB->viewportWithCountMask ^ pCB->scissorWithCountMask);
968                 ss << " are used by pipeline state object, but were not provided via matching calls to "
969                       "vkCmdSetViewportWithCountEXT and vkCmdSetScissorWithCountEXT().";
970                 skip |= LogError(device, vuid.viewport_scissor_count, "%s", ss.str().c_str());
971             }
972         }
973     }
974 
975     // If inheriting viewports, verify that not using more than inherited.
976     if (pCB->inheritedViewportDepths.size() != 0 && dyn_viewport) {
977         uint32_t viewport_count = create_info.pViewportState->viewportCount;
978         uint32_t max_inherited  = uint32_t(pCB->inheritedViewportDepths.size());
979         if (viewport_count > max_inherited) {
980             skip |= LogError(device, vuid.dynamic_state,
981                 "Pipeline requires more viewports (%u) than inherited (viewportDepthCount=%u).",
982                 unsigned(viewport_count), unsigned(max_inherited));
983         }
984     }
985 
986     // Verify that any MSAA request in PSO matches sample# in bound FB
987     // Verify that blend is enabled only if supported by subpasses image views format features
988     // Skip the check if rasterization is disabled.
989     if (!create_info.pRasterizationState || (create_info.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
990         VkSampleCountFlagBits pso_num_samples = GetNumSamples(pPipeline);
991         if (pCB->activeRenderPass) {
992             if (pCB->activeRenderPass->use_dynamic_rendering || pCB->activeRenderPass->use_dynamic_rendering_inherited) {
993                 // TODO: Mirror the below VUs but using dynamic rendering
994                 const auto dynamic_rendering_info = pCB->activeRenderPass->dynamic_rendering_begin_rendering_info;
995             } else {
996                 const auto render_pass_info = pCB->activeRenderPass->createInfo.ptr();
997                 const VkSubpassDescription2 *subpass_desc = &render_pass_info->pSubpasses[pCB->activeSubpass];
998                 uint32_t i;
999                 unsigned subpass_num_samples = 0;
1000 
1001                 for (i = 0; i < subpass_desc->colorAttachmentCount; i++) {
1002                     const auto attachment = subpass_desc->pColorAttachments[i].attachment;
1003                     if (attachment != VK_ATTACHMENT_UNUSED) {
1004                         subpass_num_samples |= static_cast<unsigned>(render_pass_info->pAttachments[attachment].samples);
1005 
1006                         const auto *imageview_state = pCB->GetActiveAttachmentImageViewState(attachment);
1007                         if (imageview_state != nullptr &&
1008                             attachment < pPipeline->create_info.graphics.pColorBlendState->attachmentCount) {
1009                             if ((imageview_state->format_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) == 0 &&
1010                                 pPipeline->create_info.graphics.pColorBlendState->pAttachments[i].blendEnable != VK_FALSE) {
1011                                 skip |=
1012                                     LogError(pPipeline->pipeline(), vuid.blend_enable,
1013                                              "%s: Image view's format features of the color attachment (%" PRIu32
1014                                              ") of the active subpass do not contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT "
1015                                              "bit, but active pipeline's pAttachments[%" PRIu32 "].blendEnable is not VK_FALSE.",
1016                                              caller, attachment, attachment);
1017                             }
1018                         }
1019                     }
1020                 }
1021 
1022                 if (subpass_desc->pDepthStencilAttachment &&
1023                     subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
1024                     const auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
1025                     subpass_num_samples |= static_cast<unsigned>(render_pass_info->pAttachments[attachment].samples);
1026                 }
1027 
1028                 if (!(IsExtEnabled(device_extensions.vk_amd_mixed_attachment_samples) ||
1029                       IsExtEnabled(device_extensions.vk_nv_framebuffer_mixed_samples)) &&
1030                     ((subpass_num_samples & static_cast<unsigned>(pso_num_samples)) != subpass_num_samples)) {
1031                     LogObjectList objlist(pPipeline->pipeline());
1032                     objlist.add(pCB->activeRenderPass->renderPass());
1033                 skip |=
1034                     LogError(objlist, vuid.rasterization_samples,
1035                              "%s: In %s the sample count is %s while the current %s has %s and they need to be the same.", caller,
1036                              report_data->FormatHandle(pPipeline->pipeline()).c_str(), string_VkSampleCountFlagBits(pso_num_samples),
1037                                      report_data->FormatHandle(pCB->activeRenderPass->renderPass()).c_str(),
1038                                      string_VkSampleCountFlags(static_cast<VkSampleCountFlags>(subpass_num_samples)).c_str());
1039                 }
1040             }
1041         } else {
1042             skip |= LogError(pPipeline->pipeline(), kVUID_Core_DrawState_NoActiveRenderpass,
1043                              "%s: No active render pass found at draw-time in %s!", caller,
1044                              report_data->FormatHandle(pPipeline->pipeline()).c_str());
1045         }
1046     }
1047     // Verify that PSO creation renderPass is compatible with active renderPass
1048     if (pCB->activeRenderPass && !pCB->activeRenderPass->use_dynamic_rendering) {
1049         // TODO: AMD extension codes are included here, but actual function entrypoints are not yet intercepted
1050         if (pCB->activeRenderPass->renderPass() != pPipeline->rp_state->renderPass()) {
1051             // renderPass that PSO was created with must be compatible with active renderPass that PSO is being used with
1052             skip |= ValidateRenderPassCompatibility("active render pass", pCB->activeRenderPass.get(), "pipeline state object",
1053                                                     pPipeline->rp_state.get(), caller, vuid.render_pass_compatible);
1054         }
1055         if (pPipeline->create_info.graphics.subpass != pCB->activeSubpass) {
1056             skip |=
1057                 LogError(pPipeline->pipeline(), vuid.subpass_index, "%s: Pipeline was built for subpass %u but used in subpass %u.",
1058                          caller, pPipeline->create_info.graphics.subpass, pCB->activeSubpass);
1059         }
1060         // Check if depth stencil attachment was created with sample location compatible bit
1061         if (pPipeline->sample_location_enabled == VK_TRUE) {
1062             const safe_VkAttachmentReference2 *ds_attachment =
1063                 pCB->activeRenderPass->createInfo.pSubpasses[pCB->activeSubpass].pDepthStencilAttachment;
1064             const FRAMEBUFFER_STATE *fb_state = pCB->activeFramebuffer.get();
1065             if ((ds_attachment != nullptr) && (fb_state != nullptr)) {
1066                 const uint32_t attachment = ds_attachment->attachment;
1067                 if (attachment != VK_ATTACHMENT_UNUSED) {
1068                     const auto *imageview_state = pCB->GetActiveAttachmentImageViewState(attachment);
1069                     if (imageview_state != nullptr) {
1070                         const auto *image_state = imageview_state->image_state.get();
1071                         if (image_state != nullptr) {
1072                             if ((image_state->createInfo.flags & VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT) == 0) {
1073                                 skip |= LogError(pPipeline->pipeline(), vuid.sample_location,
1074                                                  "%s: sampleLocationsEnable is true for the pipeline, but the subpass (%u) depth "
1075                                                  "stencil attachment's VkImage was not created with "
1076                                                  "VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT.",
1077                                                  caller, pCB->activeSubpass);
1078                             }
1079                         }
1080                     }
1081                 }
1082             }
1083         }
1084     }
1085 
1086     skip |= ValidateStatus(pCB, CBSTATUS_PATCH_CONTROL_POINTS_SET, "Dynamic patch control points not set for this command buffer",
1087                            vuid.patch_control_points);
1088     skip |= ValidateStatus(pCB, CBSTATUS_RASTERIZER_DISCARD_ENABLE_SET,
1089                            "Dynamic rasterizer discard enable not set for this command buffer", vuid.rasterizer_discard_enable);
1090     skip |= ValidateStatus(pCB, CBSTATUS_DEPTH_BIAS_ENABLE_SET, "Dynamic depth bias enable not set for this command buffer",
1091                            vuid.depth_bias_enable);
1092     skip |= ValidateStatus(pCB, CBSTATUS_LOGIC_OP_SET, "Dynamic state logicOp not set for this command buffer", vuid.logic_op);
1093     skip |= ValidateStatus(pCB, CBSTATUS_PRIMITIVE_RESTART_ENABLE_SET,
1094                            "Dynamic primitive restart enable not set for this command buffer", vuid.primitive_restart_enable);
1095     skip |= ValidateStatus(pCB, CBSTATUS_VERTEX_INPUT_BINDING_STRIDE_SET,
1096                            "Dynamic vertex input binding stride not set for this command buffer", vuid.vertex_input_binding_stride);
1097     skip |=
1098         ValidateStatus(pCB, CBSTATUS_VERTEX_INPUT_SET, "Dynamic vertex input not set for this command buffer", vuid.vertex_input);
1099 
1100     // VUID {refpage}-primitiveTopology-03420
1101     skip |= ValidateStatus(pCB, CBSTATUS_PRIMITIVE_TOPOLOGY_SET, "Dynamic primitive topology state not set for this command buffer",
1102                            vuid.primitive_topology);
1103     if (IsDynamic(pPipeline, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT)) {
1104         bool compatible_topology = false;
1105         switch (create_info.pInputAssemblyState->topology) {
1106             case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1107                 switch (pCB->primitiveTopology) {
1108                     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1109                         compatible_topology = true;
1110                         break;
1111                     default:
1112                         break;
1113                 }
1114                 break;
1115             case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1116             case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
1117             case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1118             case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
1119                 switch (pCB->primitiveTopology) {
1120                     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1121                     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
1122                     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1123                     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
1124                         compatible_topology = true;
1125                         break;
1126                     default:
1127                         break;
1128                 }
1129                 break;
1130             case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1131             case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1132             case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
1133             case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1134             case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1135                 switch (pCB->primitiveTopology) {
1136                     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1137                     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1138                     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
1139                     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1140                     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1141                         compatible_topology = true;
1142                         break;
1143                     default:
1144                         break;
1145                 }
1146                 break;
1147             case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1148                 switch (pCB->primitiveTopology) {
1149                     case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1150                         compatible_topology = true;
1151                         break;
1152                     default:
1153                         break;
1154                 }
1155                 break;
1156             default:
1157                 break;
1158         }
1159         if (!compatible_topology) {
1160             skip |= LogError(pPipeline->pipeline(), vuid.primitive_topology,
1161                              "%s: the last primitive topology %s state set by vkCmdSetPrimitiveTopologyEXT is "
1162                              "not compatible with the pipeline topology %s.",
1163                              caller, string_VkPrimitiveTopology(pCB->primitiveTopology),
1164                              string_VkPrimitiveTopology(pPipeline->create_info.graphics.pInputAssemblyState->topology));
1165         }
1166     }
1167 
1168     if (enabled_features.fragment_shading_rate_features.primitiveFragmentShadingRate) {
1169         skip |= ValidateGraphicsPipelineShaderDynamicState(pPipeline, pCB, caller, vuid);
1170     }
1171 
1172     return skip;
1173 }
1174 
1175 // For given cvdescriptorset::DescriptorSet, verify that its Set is compatible w/ the setLayout corresponding to
1176 // pipelineLayout[layoutIndex]
VerifySetLayoutCompatibility(const debug_report_data * report_data,const cvdescriptorset::DescriptorSet * descriptor_set,PIPELINE_LAYOUT_STATE const * pipeline_layout,const uint32_t layoutIndex,string & errorMsg)1177 static bool VerifySetLayoutCompatibility(const debug_report_data *report_data, const cvdescriptorset::DescriptorSet *descriptor_set,
1178                                          PIPELINE_LAYOUT_STATE const *pipeline_layout, const uint32_t layoutIndex,
1179                                          string &errorMsg) {
1180     auto num_sets = pipeline_layout->set_layouts.size();
1181     if (layoutIndex >= num_sets) {
1182         stringstream error_str;
1183         error_str << report_data->FormatHandle(pipeline_layout->layout()) << ") only contains " << num_sets
1184                   << " setLayouts corresponding to sets 0-" << num_sets - 1 << ", but you're attempting to bind set to index "
1185                   << layoutIndex;
1186         errorMsg = error_str.str();
1187         return false;
1188     }
1189     if (descriptor_set->IsPushDescriptor()) return true;
1190     auto layout_node = pipeline_layout->set_layouts[layoutIndex].get();
1191     return cvdescriptorset::VerifySetLayoutCompatibility(report_data, layout_node, descriptor_set->GetLayout().get(), &errorMsg);
1192 }
1193 
1194 // Validate overall state at the time of a draw call
ValidateCmdBufDrawState(const CMD_BUFFER_STATE * cb_node,CMD_TYPE cmd_type,const bool indexed,const VkPipelineBindPoint bind_point) const1195 bool CoreChecks::ValidateCmdBufDrawState(const CMD_BUFFER_STATE *cb_node, CMD_TYPE cmd_type, const bool indexed,
1196                                          const VkPipelineBindPoint bind_point) const {
1197     const DrawDispatchVuid vuid = GetDrawDispatchVuid(cmd_type);
1198     const char *function = CommandTypeString(cmd_type);
1199     const auto lv_bind_point = ConvertToLvlBindPoint(bind_point);
1200     const auto &state = cb_node->lastBound[lv_bind_point];
1201     const auto *pipe = state.pipeline_state;
1202 
1203     if (nullptr == pipe) {
1204         return LogError(cb_node->commandBuffer(), vuid.pipeline_bound,
1205                         "Must not call %s on this command buffer while there is no %s pipeline bound.", function,
1206                         bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR
1207                             ? "RayTracing"
1208                             : bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS ? "Graphics" : "Compute");
1209     }
1210 
1211     bool result = false;
1212 
1213     if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) {
1214         // First check flag states
1215         result |= ValidateDrawStateFlags(cb_node, pipe, indexed, vuid.dynamic_state);
1216 
1217         if (cb_node->activeRenderPass && cb_node->activeFramebuffer) {
1218             // Verify attachments for unprotected/protected command buffer.
1219             if (enabled_features.core11.protectedMemory == VK_TRUE && cb_node->active_attachments) {
1220                 uint32_t i = 0;
1221                 for (const auto &view_state : *cb_node->active_attachments.get()) {
1222                     const auto &subpass = cb_node->active_subpasses->at(i);
1223                     if (subpass.used && view_state && !view_state->Destroyed()) {
1224                         std::string image_desc = "Image is ";
1225                         image_desc.append(string_VkImageUsageFlagBits(subpass.usage));
1226                         // Because inputAttachment is read only, it doesn't need to care protected command buffer case.
1227                         // Some CMD_TYPE could not be protected. See VUID 02711.
1228                         if (subpass.usage != VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT &&
1229                             vuid.protected_command_buffer != kVUIDUndefined) {
1230                             result |= ValidateUnprotectedImage(cb_node, view_state->image_state.get(), function,
1231                                                                vuid.protected_command_buffer, image_desc.c_str());
1232                         }
1233                         result |= ValidateProtectedImage(cb_node, view_state->image_state.get(), function,
1234                                                          vuid.unprotected_command_buffer, image_desc.c_str());
1235                     }
1236                     ++i;
1237                 }
1238             }
1239         }
1240     }
1241     // Now complete other state checks
1242     string error_string;
1243     auto const &pipeline_layout = pipe->pipeline_layout.get();
1244 
1245     // Check if the current pipeline is compatible for the maximum used set with the bound sets.
1246     if (pipe->active_slots.size() > 0 && !CompatForSet(pipe->max_active_slot, state, pipeline_layout->compat_for_set)) {
1247         LogObjectList objlist(pipe->pipeline());
1248         objlist.add(pipeline_layout->layout());
1249         objlist.add(state.pipeline_layout);
1250         result |= LogError(objlist, vuid.compatible_pipeline,
1251                            "%s(): %s defined with %s is not compatible for maximum set statically used %" PRIu32
1252                            " with bound descriptor sets, last bound with %s",
1253                            CommandTypeString(cmd_type), report_data->FormatHandle(pipe->pipeline()).c_str(),
1254                            report_data->FormatHandle(pipeline_layout->layout()).c_str(), pipe->max_active_slot,
1255                            report_data->FormatHandle(state.pipeline_layout).c_str());
1256     }
1257 
1258     for (const auto &set_binding_pair : pipe->active_slots) {
1259         uint32_t set_index = set_binding_pair.first;
1260         // If valid set is not bound throw an error
1261         if ((state.per_set.size() <= set_index) || (!state.per_set[set_index].bound_descriptor_set)) {
1262             result |= LogError(cb_node->commandBuffer(), kVUID_Core_DrawState_DescriptorSetNotBound,
1263                                "%s(): %s uses set #%u but that set is not bound.", CommandTypeString(cmd_type),
1264                                report_data->FormatHandle(pipe->pipeline()).c_str(), set_index);
1265         } else if (!VerifySetLayoutCompatibility(report_data, state.per_set[set_index].bound_descriptor_set, pipeline_layout,
1266                                                  set_index, error_string)) {
1267             // Set is bound but not compatible w/ overlapping pipeline_layout from PSO
1268             VkDescriptorSet set_handle = state.per_set[set_index].bound_descriptor_set->GetSet();
1269             LogObjectList objlist(set_handle);
1270             objlist.add(pipeline_layout->layout());
1271             result |= LogError(objlist, kVUID_Core_DrawState_PipelineLayoutsIncompatible,
1272                                "%s(): %s bound as set #%u is not compatible with overlapping %s due to: %s",
1273                                CommandTypeString(cmd_type), report_data->FormatHandle(set_handle).c_str(), set_index,
1274                                report_data->FormatHandle(pipeline_layout->layout()).c_str(), error_string.c_str());
1275         } else {  // Valid set is bound and layout compatible, validate that it's updated
1276             // Pull the set node
1277             const cvdescriptorset::DescriptorSet *descriptor_set = state.per_set[set_index].bound_descriptor_set;
1278             // Validate the draw-time state for this descriptor set
1279             std::string err_str;
1280             // For the "bindless" style resource usage with many descriptors, need to optimize command <-> descriptor
1281             // binding validation. Take the requested binding set and prefilter it to eliminate redundant validation checks.
1282             // Here, the currently bound pipeline determines whether an image validation check is redundant...
1283             // for images are the "req" portion of the binding_req is indirectly (but tightly) coupled to the pipeline.
1284             cvdescriptorset::PrefilterBindRequestMap reduced_map(*descriptor_set, set_binding_pair.second);
1285             const auto &binding_req_map = reduced_map.FilteredMap(*cb_node, *pipe);
1286 
1287             // We can skip validating the descriptor set if "nothing" has changed since the last validation.
1288             // Same set, no image layout changes, and same "pipeline state" (binding_req_map). If there are
1289             // any dynamic descriptors, always revalidate rather than caching the values. We currently only
1290             // apply this optimization if IsManyDescriptors is true, to avoid the overhead of copying the
1291             // binding_req_map which could potentially be expensive.
1292             bool descriptor_set_changed =
1293                 !reduced_map.IsManyDescriptors() ||
1294                 // Revalidate each time if the set has dynamic offsets
1295                 state.per_set[set_index].dynamicOffsets.size() > 0 ||
1296                 // Revalidate if descriptor set (or contents) has changed
1297                 state.per_set[set_index].validated_set != descriptor_set ||
1298                 state.per_set[set_index].validated_set_change_count != descriptor_set->GetChangeCount() ||
1299                 (!disabled[image_layout_validation] &&
1300                  state.per_set[set_index].validated_set_image_layout_change_count != cb_node->image_layout_change_count);
1301             bool need_validate = descriptor_set_changed ||
1302                                  // Revalidate if previous bindingReqMap doesn't include new bindingReqMap
1303                                  !std::includes(state.per_set[set_index].validated_set_binding_req_map.begin(),
1304                                                 state.per_set[set_index].validated_set_binding_req_map.end(),
1305                                                 binding_req_map.begin(), binding_req_map.end());
1306 
1307             if (need_validate) {
1308                 if (!descriptor_set_changed && reduced_map.IsManyDescriptors()) {
1309                     // Only validate the bindings that haven't already been validated
1310                     BindingReqMap delta_reqs;
1311                     std::set_difference(binding_req_map.begin(), binding_req_map.end(),
1312                                         state.per_set[set_index].validated_set_binding_req_map.begin(),
1313                                         state.per_set[set_index].validated_set_binding_req_map.end(),
1314                                         layer_data::insert_iterator<BindingReqMap>(delta_reqs, delta_reqs.begin()));
1315                     result |=
1316                         ValidateDrawState(descriptor_set, delta_reqs, state.per_set[set_index].dynamicOffsets, cb_node,
1317                                           cb_node->active_attachments.get(), cb_node->active_subpasses.get(), function, vuid);
1318                 } else {
1319                     result |=
1320                         ValidateDrawState(descriptor_set, binding_req_map, state.per_set[set_index].dynamicOffsets, cb_node,
1321                                           cb_node->active_attachments.get(), cb_node->active_subpasses.get(), function, vuid);
1322                 }
1323             }
1324         }
1325     }
1326 
1327     // Check general pipeline state that needs to be validated at drawtime
1328     if (VK_PIPELINE_BIND_POINT_GRAPHICS == bind_point) {
1329         result |= ValidatePipelineDrawtimeState(state, cb_node, cmd_type, pipe);
1330     }
1331 
1332     // Verify if push constants have been set
1333     // NOTE: Currently not checking whether active push constants are compatible with the active pipeline, nor whether the
1334     //       "life times" of push constants are correct.
1335     //       Discussion on validity of these checks can be found at https://gitlab.khronos.org/vulkan/vulkan/-/issues/2602.
1336     if (!cb_node->push_constant_data_ranges || (pipeline_layout->push_constant_ranges == cb_node->push_constant_data_ranges)) {
1337         for (const auto &stage : pipe->stage_state) {
1338             const auto *entrypoint = stage.module->FindEntrypointStruct(stage.create_info->pName, stage.create_info->stage);
1339             if (!entrypoint || !entrypoint->push_constant_used_in_shader.IsUsed()) {
1340                 continue;
1341             }
1342 
1343             // Edge case where if the shader is using push constants statically and there never was a vkCmdPushConstants
1344             if (!cb_node->push_constant_data_ranges && !enabled_features.maintenance4_features.maintenance4) {
1345                 LogObjectList objlist(cb_node->commandBuffer());
1346                 objlist.add(pipeline_layout->layout());
1347                 objlist.add(pipe->pipeline());
1348                 result |= LogError(objlist, vuid.push_constants_set,
1349                                    "%s(): Shader in %s uses push-constant statically but vkCmdPushConstants was not called yet for "
1350                                    "pipeline layout %s.",
1351                                    CommandTypeString(cmd_type), string_VkShaderStageFlags(stage.stage_flag).c_str(),
1352                                    report_data->FormatHandle(pipeline_layout->layout()).c_str());
1353             }
1354 
1355             const auto it = cb_node->push_constant_data_update.find(stage.stage_flag);
1356             if (it == cb_node->push_constant_data_update.end()) {
1357                 // This error has been printed in ValidatePushConstantUsage.
1358                 break;
1359             }
1360         }
1361     }
1362     return result;
1363 }
1364 
ValidateCmdRayQueryState(const CMD_BUFFER_STATE * cb_state,CMD_TYPE cmd_type,const VkPipelineBindPoint bind_point) const1365 bool CoreChecks::ValidateCmdRayQueryState(const CMD_BUFFER_STATE *cb_state, CMD_TYPE cmd_type,
1366                                           const VkPipelineBindPoint bind_point) const {
1367     bool skip = false;
1368     const DrawDispatchVuid vuid = GetDrawDispatchVuid(cmd_type);
1369     const auto lv_bind_point = ConvertToLvlBindPoint(bind_point);
1370     const auto &state = cb_state->lastBound[lv_bind_point];
1371     const auto *pipe = state.pipeline_state;
1372 
1373     bool ray_query_shader = false;
1374     if (nullptr != pipe) {
1375         if (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
1376             ray_query_shader = true;
1377         } else {
1378             // TODO - Loop through shader for RayQueryKHR for draw/dispatch commands
1379         }
1380     }
1381 
1382     if (cb_state->unprotected == false && ray_query_shader) {
1383         skip |= LogError(cb_state->commandBuffer(), vuid.ray_query_protected_cb,
1384                          "%s(): can't use in protected command buffers for RayQuery operations.", CommandTypeString(cmd_type));
1385     }
1386 
1387     return skip;
1388 }
1389 
ValidateGraphicsPipelineBlendEnable(const PIPELINE_STATE * pPipeline) const1390 bool CoreChecks::ValidateGraphicsPipelineBlendEnable(const PIPELINE_STATE *pPipeline) const {
1391     bool skip = false;
1392     const auto& create_info = pPipeline->create_info.graphics;
1393     if (create_info.pColorBlendState) {
1394         const auto *subpass_desc = &pPipeline->rp_state->createInfo.pSubpasses[create_info.subpass];
1395 
1396         uint32_t numberColorAttachments = (pPipeline->rp_state->use_dynamic_rendering)
1397                                               ? pPipeline->rp_state->dynamic_rendering_pipeline_create_info.colorAttachmentCount
1398                                               : subpass_desc->colorAttachmentCount;
1399 
1400         for (uint32_t i = 0; i < pPipeline->attachments.size() && i < numberColorAttachments; ++i) {
1401             VkFormatFeatureFlags format_features;
1402 
1403             if (pPipeline->rp_state->use_dynamic_rendering) {
1404                 format_features = GetPotentialFormatFeatures(
1405                     pPipeline->rp_state->dynamic_rendering_pipeline_create_info.pColorAttachmentFormats[i]);
1406             } else {
1407                 const auto attachment = subpass_desc->pColorAttachments[i].attachment;
1408                 if (attachment == VK_ATTACHMENT_UNUSED) continue;
1409 
1410                 const auto attachment_desc = pPipeline->rp_state->createInfo.pAttachments[attachment];
1411                 format_features = GetPotentialFormatFeatures(attachment_desc.format);
1412 
1413                 if (create_info.pRasterizationState && !create_info.pRasterizationState->rasterizerDiscardEnable &&
1414                     pPipeline->attachments[i].blendEnable && !(format_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)) {
1415                 skip |=
1416                     LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06041",
1417                         "vkCreateGraphicsPipelines(): pipeline.pColorBlendState.pAttachments[%" PRIu32
1418                         "].blendEnable is VK_TRUE but format %s of the corresponding attachment description (subpass %" PRIu32
1419                         ", attachment %" PRIu32 ") does not support VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT.",
1420                         i, string_VkFormat(attachment_desc.format), create_info.subpass, attachment);
1421                 }
1422             }
1423         }
1424     }
1425 
1426     return skip;
1427 }
1428 
ValidatePipelineLocked(std::vector<std::shared_ptr<PIPELINE_STATE>> const & pPipelines,int pipelineIndex) const1429 bool CoreChecks::ValidatePipelineLocked(std::vector<std::shared_ptr<PIPELINE_STATE>> const &pPipelines, int pipelineIndex) const {
1430     bool skip = false;
1431 
1432     const auto pipeline = pPipelines[pipelineIndex].get();
1433     const auto &create_info = pipeline->create_info.graphics;
1434     // If create derivative bit is set, check that we've specified a base
1435     // pipeline correctly, and that the base pipeline was created to allow
1436     // derivatives.
1437     if (create_info.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
1438         std::shared_ptr<const PIPELINE_STATE> base_pipeline;
1439         if (!((create_info.basePipelineHandle != VK_NULL_HANDLE) ^ (create_info.basePipelineIndex != -1))) {
1440             // TODO: This check is a superset of VUID-VkGraphicsPipelineCreateInfo-flags-00724 and
1441             // TODO: VUID-VkGraphicsPipelineCreateInfo-flags-00725
1442             skip |= LogError(device, kVUID_Core_DrawState_InvalidPipelineCreateState,
1443                              "Invalid Pipeline CreateInfo[%d]: exactly one of base pipeline index and handle must be specified",
1444                              pipelineIndex);
1445         } else if (create_info.basePipelineIndex != -1) {
1446             if (create_info.basePipelineIndex >= pipelineIndex) {
1447                 skip |=
1448                     LogError(device, "VUID-vkCreateGraphicsPipelines-flags-00720",
1449                              "Invalid Pipeline CreateInfo[%d]: base pipeline must occur earlier in array than derivative pipeline.",
1450                              pipelineIndex);
1451             } else {
1452                 base_pipeline = pPipelines[create_info.basePipelineIndex];
1453             }
1454         } else if (create_info.basePipelineHandle != VK_NULL_HANDLE) {
1455             base_pipeline = Get<PIPELINE_STATE>(create_info.basePipelineHandle);
1456         }
1457 
1458         if (base_pipeline && !(base_pipeline->create_info.graphics.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
1459             skip |= LogError(device, "VUID-vkCreateGraphicsPipelines-flags-00721",
1460                              "Invalid Pipeline CreateInfo[%d]: base pipeline does not allow derivatives.", pipelineIndex);
1461         }
1462     }
1463 
1464     // Check for portability errors
1465     if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
1466         if ((VK_FALSE == enabled_features.portability_subset_features.triangleFans) &&
1467             (VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN == pipeline->topology_at_rasterizer)) {
1468             skip |=
1469                 LogError(device, "VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452",
1470                          "Invalid Pipeline CreateInfo[%d] (portability error): VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN is not supported",
1471                          pipelineIndex);
1472         }
1473 
1474         // Validate vertex inputs
1475         for (const auto &desc : pipeline->vertex_binding_descriptions_) {
1476             const auto min_alignment = phys_dev_ext_props.portability_props.minVertexInputBindingStrideAlignment;
1477             if ((desc.stride < min_alignment) || (min_alignment == 0) || ((desc.stride % min_alignment) != 0)) {
1478                 skip |= LogError(
1479                     device, "VUID-VkVertexInputBindingDescription-stride-04456",
1480                     "Invalid Pipeline CreateInfo[%d] (portability error): Vertex input stride must be at least as large as and a "
1481                     "multiple of VkPhysicalDevicePortabilitySubsetPropertiesKHR::minVertexInputBindingStrideAlignment.",
1482                     pipelineIndex);
1483             }
1484         }
1485 
1486         // Validate vertex attributes
1487         if (VK_FALSE == enabled_features.portability_subset_features.vertexAttributeAccessBeyondStride) {
1488             for (const auto &attrib : pipeline->vertex_attribute_descriptions_) {
1489                 const auto vertex_binding_map_it = pipeline->vertex_binding_to_index_map_.find(attrib.binding);
1490                 if (vertex_binding_map_it != pipeline->vertex_binding_to_index_map_.cend()) {
1491                     const auto& desc = pipeline->vertex_binding_descriptions_[vertex_binding_map_it->second];
1492                     if ((attrib.offset + FormatElementSize(attrib.format)) > desc.stride) {
1493                         skip |= LogError(device, "VUID-VkVertexInputAttributeDescription-vertexAttributeAccessBeyondStride-04457",
1494                                          "Invalid Pipeline CreateInfo[%d] (portability error): (attribute.offset + "
1495                                          "sizeof(vertex_description.format)) is larger than the vertex stride",
1496                                          pipelineIndex);
1497                     }
1498                 }
1499             }
1500         }
1501 
1502         // Validate polygon mode
1503         auto raster_state_ci = create_info.pRasterizationState;
1504         if ((VK_FALSE == enabled_features.portability_subset_features.pointPolygons) && raster_state_ci &&
1505             (VK_FALSE == raster_state_ci->rasterizerDiscardEnable) && (VK_POLYGON_MODE_POINT == raster_state_ci->polygonMode)) {
1506             skip |=
1507                 LogError(device, "VUID-VkPipelineRasterizationStateCreateInfo-pointPolygons-04458",
1508                          "Invalid Pipeline CreateInfo[%d] (portability error): point polygons are not supported", pipelineIndex);
1509         }
1510     }
1511 
1512     return skip;
1513 }
1514 
1515 // UNLOCKED pipeline validation. DO NOT lookup objects in the CoreChecks->* maps in this function.
ValidatePipelineUnlocked(const PIPELINE_STATE * pPipeline,uint32_t pipelineIndex) const1516 bool CoreChecks::ValidatePipelineUnlocked(const PIPELINE_STATE *pPipeline, uint32_t pipelineIndex) const {
1517     bool skip = false;
1518     const auto &create_info = pPipeline->create_info.graphics;
1519 
1520     safe_VkSubpassDescription2 *subpass_desc = nullptr;
1521 
1522     if (!pPipeline->rp_state->use_dynamic_rendering) {
1523         // Ensure the subpass index is valid. If not, then ValidateGraphicsPipelineShaderState
1524         // produces nonsense errors that confuse users. Other layers should already
1525         // emit errors for renderpass being invalid.
1526         subpass_desc = &pPipeline->rp_state->createInfo.pSubpasses[create_info.subpass];
1527         if (create_info.subpass >= pPipeline->rp_state->createInfo.subpassCount) {
1528             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06046",
1529                              "Invalid Pipeline CreateInfo[%" PRIu32
1530                              "] State: Subpass index %u is out of range for this renderpass (0..%u).",
1531                              pipelineIndex, create_info.subpass, pPipeline->rp_state->createInfo.subpassCount - 1);
1532             subpass_desc = nullptr;
1533         }
1534     }
1535 
1536     if (create_info.pColorBlendState != NULL) {
1537         const safe_VkPipelineColorBlendStateCreateInfo *color_blend_state = create_info.pColorBlendState;
1538         if (subpass_desc && color_blend_state->attachmentCount != subpass_desc->colorAttachmentCount) {
1539             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06042",
1540                              "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1541                              "]: %s subpass %u has colorAttachmentCount of %u which doesn't "
1542                              "match the pColorBlendState->attachmentCount of %u.",
1543                              pipelineIndex, report_data->FormatHandle(pPipeline->rp_state->renderPass()).c_str(),
1544                              create_info.subpass, subpass_desc->colorAttachmentCount, color_blend_state->attachmentCount);
1545         }
1546         if (!enabled_features.core.independentBlend) {
1547             if (pPipeline->attachments.size() > 1) {
1548                 const VkPipelineColorBlendAttachmentState *const attachments = &pPipeline->attachments[0];
1549                 for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
1550                     // Quoting the spec: "If [the independent blend] feature is not enabled, the VkPipelineColorBlendAttachmentState
1551                     // settings for all color attachments must be identical." VkPipelineColorBlendAttachmentState contains
1552                     // only attachment state, so memcmp is best suited for the comparison
1553                     if (memcmp(static_cast<const void *>(attachments), static_cast<const void *>(&attachments[i]),
1554                                sizeof(attachments[0]))) {
1555                         skip |= LogError(device, "VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605",
1556                                          "Invalid Pipeline CreateInfo[%" PRIu32
1557                                          "]: If independent blend feature not enabled, all elements of "
1558                                          "pAttachments must be identical.",
1559                                          pipelineIndex);
1560                         break;
1561                     }
1562                 }
1563             }
1564         }
1565         if (!enabled_features.core.logicOp && (create_info.pColorBlendState->logicOpEnable != VK_FALSE)) {
1566             skip |= LogError(device, "VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00606",
1567                              "Invalid Pipeline CreateInfo[%" PRIu32
1568                              "]: If logic operations feature not enabled, logicOpEnable must be VK_FALSE.",
1569                              pipelineIndex);
1570         }
1571         for (size_t i = 0; i < pPipeline->attachments.size(); i++) {
1572             if ((pPipeline->attachments[i].srcColorBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
1573                 (pPipeline->attachments[i].srcColorBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
1574                 (pPipeline->attachments[i].srcColorBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
1575                 (pPipeline->attachments[i].srcColorBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
1576                 if (!enabled_features.core.dualSrcBlend) {
1577                     skip |= LogError(device, "VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-00608",
1578                                      "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1579                                      "].pColorBlendState.pAttachments[" PRINTF_SIZE_T_SPECIFIER
1580                                      "].srcColorBlendFactor uses a dual-source blend factor (%d), but this device feature is not "
1581                                      "enabled.",
1582                                      pipelineIndex, i, pPipeline->attachments[i].srcColorBlendFactor);
1583                 }
1584             }
1585             if ((pPipeline->attachments[i].dstColorBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
1586                 (pPipeline->attachments[i].dstColorBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
1587                 (pPipeline->attachments[i].dstColorBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
1588                 (pPipeline->attachments[i].dstColorBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
1589                 if (!enabled_features.core.dualSrcBlend) {
1590                     skip |= LogError(device, "VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-00609",
1591                                      "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1592                                      "].pColorBlendState.pAttachments[" PRINTF_SIZE_T_SPECIFIER
1593                                      "].dstColorBlendFactor uses a dual-source blend factor (%d), but this device feature is not "
1594                                      "enabled.",
1595                                      pipelineIndex, i, pPipeline->attachments[i].dstColorBlendFactor);
1596                 }
1597             }
1598             if ((pPipeline->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
1599                 (pPipeline->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
1600                 (pPipeline->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
1601                 (pPipeline->attachments[i].srcAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
1602                 if (!enabled_features.core.dualSrcBlend) {
1603                     skip |= LogError(device, "VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-00610",
1604                                      "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1605                                      "].pColorBlendState.pAttachments[" PRINTF_SIZE_T_SPECIFIER
1606                                      "].srcAlphaBlendFactor uses a dual-source blend factor (%d), but this device feature is not "
1607                                      "enabled.",
1608                                      pipelineIndex, i, pPipeline->attachments[i].srcAlphaBlendFactor);
1609                 }
1610             }
1611             if ((pPipeline->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_COLOR) ||
1612                 (pPipeline->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR) ||
1613                 (pPipeline->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_SRC1_ALPHA) ||
1614                 (pPipeline->attachments[i].dstAlphaBlendFactor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA)) {
1615                 if (!enabled_features.core.dualSrcBlend) {
1616                     skip |= LogError(device, "VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-00611",
1617                                      "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1618                                      "].pColorBlendState.pAttachments[" PRINTF_SIZE_T_SPECIFIER
1619                                      "].dstAlphaBlendFactor uses a dual-source blend factor (%d), but this device feature is not "
1620                                      "enabled.",
1621                                      pipelineIndex, i, pPipeline->attachments[i].dstAlphaBlendFactor);
1622                 }
1623             }
1624         }
1625         auto color_write = lvl_find_in_chain<VkPipelineColorWriteCreateInfoEXT>(create_info.pColorBlendState->pNext);
1626         if (color_write) {
1627             if (color_write->attachmentCount != color_blend_state->attachmentCount) {
1628                 skip |= LogError(
1629                     device, "VUID-VkPipelineColorWriteCreateInfoEXT-attachmentCount-04802",
1630                     "vkCreateGraphicsPipelines(): VkPipelineColorWriteCreateInfoEXT in the pNext chain of pPipelines[%" PRIu32
1631                     "].pColorBlendState has different attachmentCount (%" PRIu32 ") than pColorBlendState.attachmentCount (%" PRIu32
1632                     ").",
1633                     pipelineIndex, color_write->attachmentCount, color_blend_state->attachmentCount);
1634             }
1635             if (!enabled_features.color_write_features.colorWriteEnable) {
1636                 for (uint32_t i = 0; i < color_write->attachmentCount; ++i) {
1637                     if (color_write->pColorWriteEnables[i] != VK_TRUE) {
1638                         skip |= LogError(device, "VUID-VkPipelineColorWriteCreateInfoEXT-pAttachments-04801",
1639                                          "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1640                                          "].pColorBlendState pNext chain includes VkPipelineColorWriteCreateInfoEXT with "
1641                                          "pColorWriteEnables[%" PRIu32 "] = VK_FALSE, but colorWriteEnable is not enabled.",
1642                                          pipelineIndex, i);
1643                     }
1644                 }
1645             }
1646         }
1647         const auto *color_blend_advanced =
1648             LvlFindInChain<VkPipelineColorBlendAdvancedStateCreateInfoEXT>(create_info.pColorBlendState->pNext);
1649         if (color_blend_advanced) {
1650             if (!phys_dev_ext_props.blend_operation_advanced_props.advancedBlendCorrelatedOverlap &&
1651                 color_blend_advanced->blendOverlap != VK_BLEND_OVERLAP_UNCORRELATED_EXT) {
1652                 skip |= LogError(
1653                     device, "VUID-VkPipelineColorBlendAdvancedStateCreateInfoEXT-blendOverlap-01426",
1654                     "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1655                     "].pColorBlendState pNext chain contains VkPipelineColorBlendAdvancedStateCreateInfoEXT structure with "
1656                     "blendOverlap equal to %s, but "
1657                     "VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT::advancedBlendCorrelatedOverlap is not supported.",
1658                     pipelineIndex, string_VkBlendOverlapEXT(color_blend_advanced->blendOverlap));
1659             }
1660             if (!phys_dev_ext_props.blend_operation_advanced_props.advancedBlendNonPremultipliedDstColor &&
1661                 color_blend_advanced->dstPremultiplied != VK_TRUE) {
1662                 skip |= LogError(
1663                     device, "VUID-VkPipelineColorBlendAdvancedStateCreateInfoEXT-dstPremultiplied-01425",
1664                     "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1665                     "].pColorBlendState pNext chain contains VkPipelineColorBlendAdvancedStateCreateInfoEXT structure with "
1666                     "dstPremultiplied equal to VK_FALSE, but "
1667                     "VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT::advancedBlendNonPremultipliedDstColor is not supported.",
1668                     pipelineIndex);
1669             }
1670             if (!phys_dev_ext_props.blend_operation_advanced_props.advancedBlendNonPremultipliedSrcColor &&
1671                 color_blend_advanced->srcPremultiplied != VK_TRUE) {
1672                 skip |= LogError(
1673                     device, "VUID-VkPipelineColorBlendAdvancedStateCreateInfoEXT-srcPremultiplied-01424",
1674                     "vkCreateGraphicsPipelines(): pPipelines[%" PRIu32
1675                     "].pColorBlendState pNext chain contains VkPipelineColorBlendAdvancedStateCreateInfoEXT structure with "
1676                     "srcPremultiplied equal to VK_FALSE, but "
1677                     "VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT::advancedBlendNonPremultipliedSrcColor is not supported.",
1678                     pipelineIndex);
1679             }
1680         }
1681     }
1682 
1683     if (ValidateGraphicsPipelineShaderState(pPipeline)) {
1684         skip = true;
1685     }
1686     skip |= ValidateGraphicsPipelineBlendEnable(pPipeline);
1687     // Each shader's stage must be unique
1688     for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
1689         if (pPipeline->active_shaders & stage) {
1690             const auto &states = pPipeline->stage_state;
1691             if (std::count_if(states.begin(), states.end(),
1692                               [stage](const PipelineStageState &pss) { return stage == pss.stage_flag; }) > 1) {
1693                 skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-stage-00726",
1694                                  "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Multiple shaders provided for stage %s",
1695                                  pipelineIndex, string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
1696             }
1697         }
1698     }
1699     if (!enabled_features.core.geometryShader && (pPipeline->active_shaders & VK_SHADER_STAGE_GEOMETRY_BIT)) {
1700         skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-stage-00704",
1701                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Geometry Shader not supported.", pipelineIndex);
1702     }
1703     if (!enabled_features.core.tessellationShader && (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
1704                                                       pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
1705         skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-stage-00705",
1706                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Tessellation Shader not supported.", pipelineIndex);
1707     }
1708     if (IsExtEnabled(device_extensions.vk_nv_mesh_shader)) {
1709         // VS or mesh is required
1710         if (!(pPipeline->active_shaders & (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_MESH_BIT_NV))) {
1711             skip |=
1712                 LogError(device, "VUID-VkGraphicsPipelineCreateInfo-stage-02096",
1713                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Vertex Shader or Mesh Shader required.", pipelineIndex);
1714         }
1715         // Can't mix mesh and VTG
1716         if ((pPipeline->active_shaders & (VK_SHADER_STAGE_MESH_BIT_NV | VK_SHADER_STAGE_TASK_BIT_NV)) &&
1717             (pPipeline->active_shaders &
1718              (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT |
1719               VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))) {
1720             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pStages-02095",
1721                              "Invalid Pipeline CreateInfo[%" PRIu32
1722                              "] State: Geometric shader stages must either be all mesh (mesh | task) "
1723                              "or all VTG (vertex, tess control, tess eval, geom).",
1724                              pipelineIndex);
1725         }
1726     } else {
1727         // VS is required
1728         if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
1729             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-stage-00727",
1730                              "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Vertex Shader required.", pipelineIndex);
1731         }
1732     }
1733 
1734     if (!enabled_features.mesh_shader_features.meshShader && (pPipeline->active_shaders & VK_SHADER_STAGE_MESH_BIT_NV)) {
1735         skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-stage-02091",
1736                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Mesh Shader not supported.", pipelineIndex);
1737     }
1738 
1739     if (!enabled_features.mesh_shader_features.taskShader && (pPipeline->active_shaders & VK_SHADER_STAGE_TASK_BIT_NV)) {
1740         skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-stage-02092",
1741                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Task Shader not supported.", pipelineIndex);
1742     }
1743 
1744     // Either both or neither TC/TE shaders should be defined
1745     bool has_control = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0;
1746     bool has_eval = (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0;
1747     if (has_control && !has_eval) {
1748         skip |=
1749             LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pStages-00729",
1750                      "Invalid Pipeline CreateInfo[%" PRIu32 "] State: TE and TC shaders must be included or excluded as a pair.",
1751                      pipelineIndex);
1752     }
1753     if (!has_control && has_eval) {
1754         skip |=
1755             LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pStages-00730",
1756                      "Invalid Pipeline CreateInfo[%" PRIu32 "] State: TE and TC shaders must be included or excluded as a pair.",
1757                      pipelineIndex);
1758     }
1759     // Compute shaders should be specified independent of Gfx shaders
1760     if (pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) {
1761         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-stage-00728",
1762                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Do not specify Compute Shader for Gfx Pipeline.",
1763                          pipelineIndex);
1764     }
1765 
1766     if ((pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT) && !create_info.pInputAssemblyState) {
1767         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pStages-02098",
1768                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Missing pInputAssemblyState.", pipelineIndex);
1769     }
1770 
1771     // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
1772     // Mismatching primitive topology and tessellation fails graphics pipeline creation.
1773     if (has_control && has_eval &&
1774         (!create_info.pInputAssemblyState || create_info.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
1775         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pStages-00736",
1776                          "Invalid Pipeline CreateInfo[%" PRIu32
1777                          "] State: VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA topology for "
1778                          "tessellation pipelines.",
1779                          pipelineIndex);
1780     }
1781     if (create_info.pInputAssemblyState) {
1782         if (create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
1783             if (!has_control || !has_eval) {
1784                 skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-topology-00737",
1785                                  "Invalid Pipeline CreateInfo[%" PRIu32
1786                                  "] State: VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid "
1787                                  "for tessellation pipelines.",
1788                                  pipelineIndex);
1789             }
1790         }
1791 
1792         if ((create_info.pInputAssemblyState->primitiveRestartEnable == VK_TRUE) &&
1793             (create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ||
1794              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST ||
1795              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ||
1796              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
1797              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
1798              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
1799             if (IsExtEnabled(device_extensions.vk_ext_primitive_topology_list_restart)) {
1800                 if (create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
1801                     if (!enabled_features.primitive_topology_list_restart_features.primitiveTopologyPatchListRestart) {
1802                         skip |= LogError(device, "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06253",
1803                                          "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1804                                          "]: topology is %s and primitiveRestartEnable is VK_TRUE and the "
1805                                          "primitiveTopologyPatchListRestart feature is not enabled.",
1806                                          pipelineIndex,
1807                                          string_VkPrimitiveTopology(create_info.pInputAssemblyState->topology));
1808                     }
1809                 } else if (!enabled_features.primitive_topology_list_restart_features.primitiveTopologyListRestart) {
1810                     skip |= LogError(
1811                         device, "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06252",
1812                         "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1813                         "]: topology is %s and primitiveRestartEnable is VK_TRUE and the primitiveTopologyListRestart feature "
1814                         "is not enabled.",
1815                         pipelineIndex, string_VkPrimitiveTopology(create_info.pInputAssemblyState->topology));
1816                 }
1817             } else {
1818                 skip |= LogError(device, "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00428",
1819                                  "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1820                                  "]: topology is %s and primitiveRestartEnable is VK_TRUE. It is invalid.",
1821                                  pipelineIndex,
1822                                  string_VkPrimitiveTopology(create_info.pInputAssemblyState->topology));
1823             }
1824         }
1825         if ((enabled_features.core.geometryShader == VK_FALSE) &&
1826             (create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
1827              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
1828              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
1829              create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY)) {
1830             skip |= LogError(device, "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429",
1831                              "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1832                              "]: topology is %s and geometry shaders feature is not enabled. "
1833                              "It is invalid.",
1834                              pipelineIndex, string_VkPrimitiveTopology(create_info.pInputAssemblyState->topology));
1835         }
1836         if ((enabled_features.core.tessellationShader == VK_FALSE) &&
1837             (create_info.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
1838             skip |= LogError(device, "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430",
1839                              "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1840                              "]: topology is %s and tessellation shaders feature is not "
1841                              "enabled. It is invalid.",
1842                              pipelineIndex, string_VkPrimitiveTopology(create_info.pInputAssemblyState->topology));
1843         }
1844     }
1845 
1846     // If a rasterization state is provided...
1847     if (create_info.pRasterizationState) {
1848         if ((create_info.pRasterizationState->depthClampEnable == VK_TRUE) && (!enabled_features.core.depthClamp)) {
1849             skip |= LogError(device, "VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782",
1850                              "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1851                              "]: the depthClamp device feature is disabled: the "
1852                              "depthClampEnable member "
1853                              "of the VkPipelineRasterizationStateCreateInfo structure must be set to VK_FALSE.",
1854                              pipelineIndex);
1855         }
1856 
1857         if (!IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS) && (create_info.pRasterizationState->depthBiasClamp != 0.0) &&
1858             (!enabled_features.core.depthBiasClamp)) {
1859             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754",
1860                              "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1861                              "]: the depthBiasClamp device feature is disabled: the "
1862                              "depthBiasClamp member "
1863                              "of the VkPipelineRasterizationStateCreateInfo structure must be set to 0.0 unless the "
1864                              "VK_DYNAMIC_STATE_DEPTH_BIAS dynamic state is enabled",
1865                              pipelineIndex);
1866         }
1867 
1868         // If rasterization is enabled...
1869         if (create_info.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) {
1870             if ((create_info.pMultisampleState->alphaToOneEnable == VK_TRUE) && (!enabled_features.core.alphaToOne)) {
1871                 skip |= LogError(device, "VUID-VkPipelineMultisampleStateCreateInfo-alphaToOneEnable-00785",
1872                                  "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1873                                  "]: the alphaToOne device feature is disabled: the alphaToOneEnable "
1874                                  "member of the VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE.",
1875                                  pipelineIndex);
1876             }
1877 
1878             // If subpass uses a depth/stencil attachment, pDepthStencilState must be a pointer to a valid structure
1879             if (subpass_desc && subpass_desc->pDepthStencilAttachment &&
1880                 subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
1881                 if (!create_info.pDepthStencilState) {
1882                     skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06043",
1883                                      "Invalid Pipeline CreateInfo[%" PRIu32
1884                                      "] State: pDepthStencilState is NULL when rasterization is enabled "
1885                                      "and subpass uses a depth/stencil attachment.",
1886                                      pipelineIndex);
1887 
1888                 } else if (create_info.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) {
1889                     if (!enabled_features.core.depthBounds) {
1890                         skip |=
1891                             LogError(device, "VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598",
1892                                      "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1893                                      "]: the depthBounds device feature is disabled: the "
1894                                      "depthBoundsTestEnable member of the VkPipelineDepthStencilStateCreateInfo structure must be "
1895                                      "set to VK_FALSE.",
1896                                      pipelineIndex);
1897                     }
1898 
1899                     // The extension was not created with a feature bit whichs prevents displaying the 2 variations of the VUIDs
1900                     if (!IsExtEnabled(device_extensions.vk_ext_depth_range_unrestricted) &&
1901                         !IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BOUNDS)) {
1902                         const float minDepthBounds = create_info.pDepthStencilState->minDepthBounds;
1903                         const float maxDepthBounds = create_info.pDepthStencilState->maxDepthBounds;
1904                         // Also VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00755
1905                         if (!(minDepthBounds >= 0.0) || !(minDepthBounds <= 1.0)) {
1906                             skip |=
1907                                 LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510",
1908                                          "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1909                                          "]: VK_EXT_depth_range_unrestricted extension "
1910                                          "is not enabled, VK_DYNAMIC_STATE_DEPTH_BOUNDS is not used, depthBoundsTestEnable is "
1911                                          "true, and pDepthStencilState::minDepthBounds (=%f) is not within the [0.0, 1.0] range.",
1912                                          pipelineIndex, minDepthBounds);
1913                         }
1914                         if (!(maxDepthBounds >= 0.0) || !(maxDepthBounds <= 1.0)) {
1915                             skip |=
1916                                 LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510",
1917                                          "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
1918                                          "]: VK_EXT_depth_range_unrestricted extension "
1919                                          "is not enabled, VK_DYNAMIC_STATE_DEPTH_BOUNDS is not used, depthBoundsTestEnable is "
1920                                          "true, and pDepthStencilState::maxDepthBounds (=%f) is not within the [0.0, 1.0] range.",
1921                                          pipelineIndex, maxDepthBounds);
1922                         }
1923                     }
1924                 }
1925             }
1926 
1927             // If subpass uses color attachments, pColorBlendState must be valid pointer
1928             if (subpass_desc) {
1929                 uint32_t color_attachment_count = 0;
1930                 for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
1931                     if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
1932                         ++color_attachment_count;
1933                     }
1934                 }
1935                 if (color_attachment_count > 0 && create_info.pColorBlendState == nullptr) {
1936                     skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06044",
1937                                      "Invalid Pipeline CreateInfo[%" PRIu32
1938                                      "] State: pColorBlendState is NULL when rasterization is enabled and "
1939                                      "subpass uses color attachments.",
1940                                      pipelineIndex);
1941                 }
1942 
1943                 constexpr int num_bits = sizeof(subpass_desc->viewMask) * CHAR_BIT;
1944                 std::bitset<num_bits> view_bits(subpass_desc->viewMask);
1945                 uint32_t view_bits_count = static_cast<uint32_t>(view_bits.count());
1946                 if (view_bits_count > 1) {
1947                     if (!enabled_features.multiview_features.multiviewTessellationShader &&
1948                         (pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
1949                          pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
1950                         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06047",
1951                                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: subpass has %" PRIu32
1952                                          " bits set in viewMask and pStages includes tessellation shaders, but the "
1953                                          "VkPhysicalDeviceMultiviewFeatures::multiviewTessellationShader features is not enabled.",
1954                                          pipelineIndex, view_bits_count);
1955                     }
1956                     if (!enabled_features.multiview_features.multiviewGeometryShader &&
1957                         pPipeline->active_shaders & VK_SHADER_STAGE_GEOMETRY_BIT) {
1958                         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-renderPass-06048",
1959                                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: subpass has %" PRIu32
1960                                          " bits set in viewMask and pStages includes geometry shader, but the "
1961                                          "VkPhysicalDeviceMultiviewFeatures::multiviewGeometryShader features is not enabled.",
1962                                          pipelineIndex, view_bits_count);
1963                     }
1964                 }
1965             }
1966         }
1967 
1968         auto provoking_vertex_state_ci =
1969             lvl_find_in_chain<VkPipelineRasterizationProvokingVertexStateCreateInfoEXT>(create_info.pRasterizationState->pNext);
1970         if (provoking_vertex_state_ci &&
1971             provoking_vertex_state_ci->provokingVertexMode == VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT &&
1972             !enabled_features.provoking_vertex_features.provokingVertexLast) {
1973             skip |= LogError(
1974                 device, "VUID-VkPipelineRasterizationProvokingVertexStateCreateInfoEXT-provokingVertexMode-04883",
1975                 "provokingVertexLast feature is not enabled.");
1976         }
1977 
1978         const auto rasterization_state_stream_ci = LvlFindInChain<VkPipelineRasterizationStateStreamCreateInfoEXT>(
1979             pPipeline->create_info.graphics.pRasterizationState->pNext);
1980         if (rasterization_state_stream_ci) {
1981             if (!enabled_features.transform_feedback_features.geometryStreams) {
1982                 skip |= LogError(device, "VUID-VkPipelineRasterizationStateStreamCreateInfoEXT-geometryStreams-02324",
1983                                  "pCreateInfos[%" PRIu32
1984                                  "].pRasterizationState pNext chain includes VkPipelineRasterizationStateStreamCreateInfoEXT, but "
1985                                  "geometryStreams feature is not enabled.",
1986                                  pipelineIndex);
1987             } else if (phys_dev_ext_props.transform_feedback_props.transformFeedbackRasterizationStreamSelect == VK_FALSE &&
1988                 rasterization_state_stream_ci->rasterizationStream != 0) {
1989                 skip |= LogError(device, "VUID-VkPipelineRasterizationStateStreamCreateInfoEXT-rasterizationStream-02326",
1990                                  "VkPhysicalDeviceTransformFeedbackPropertiesEXT::transformFeedbackRasterizationStreamSelect is "
1991                                  "VK_FALSE, but pCreateInfos[%" PRIu32
1992                                  "].pRasterizationState pNext chain includes VkPipelineRasterizationStateStreamCreateInfoEXT with "
1993                                  "rasterizationStream (%" PRIu32 ") not equal to 0.",
1994                                  pipelineIndex, rasterization_state_stream_ci->rasterizationStream);
1995             } else if (rasterization_state_stream_ci->rasterizationStream >=
1996                        phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams) {
1997                 skip |= LogError(
1998                     device, "VUID-VkPipelineRasterizationStateStreamCreateInfoEXT-rasterizationStream-02325",
1999                     "pCreateInfos[%" PRIu32
2000                     "].pRasterizationState pNext chain includes VkPipelineRasterizationStateStreamCreateInfoEXT with "
2001                     "rasterizationStream (%" PRIu32
2002                     ") not less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams (%" PRIu32 ").",
2003                     pipelineIndex, rasterization_state_stream_ci->rasterizationStream,
2004                     phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
2005             }
2006         }
2007 
2008         const auto rasterization_conservative_state_ci =
2009             LvlFindInChain<VkPipelineRasterizationConservativeStateCreateInfoEXT>(create_info.pRasterizationState->pNext);
2010         if (rasterization_conservative_state_ci) {
2011             if (rasterization_conservative_state_ci->extraPrimitiveOverestimationSize < 0.0f ||
2012                 rasterization_conservative_state_ci->extraPrimitiveOverestimationSize >
2013                     phys_dev_ext_props.conservative_rasterization_props.maxExtraPrimitiveOverestimationSize) {
2014                 skip |= LogError(
2015                     device, "VUID-VkPipelineRasterizationConservativeStateCreateInfoEXT-extraPrimitiveOverestimationSize-01769",
2016                     "pCreateInfos[%" PRIu32
2017                     "].pRasterizationState pNext chain includes VkPipelineRasterizationConservativeStateCreateInfoEXT with "
2018                     "extraPrimitiveOverestimationSize (%f), which is not between 0.0 and "
2019                     "VkPipelineRasterizationConservativeStateCreateInfoEXT::maxExtraPrimitiveOverestimationSize (%f).",
2020                     pipelineIndex, rasterization_conservative_state_ci->extraPrimitiveOverestimationSize,
2021                     phys_dev_ext_props.conservative_rasterization_props.maxExtraPrimitiveOverestimationSize);
2022             }
2023         }
2024     }
2025 
2026     if ((pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT) && !create_info.pVertexInputState &&
2027         !IsDynamic(pPipeline, VK_DYNAMIC_STATE_VERTEX_INPUT_EXT)) {
2028         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pStages-02097",
2029                          "Invalid Pipeline CreateInfo[%" PRIu32 "] State: Missing pVertexInputState.", pipelineIndex);
2030     }
2031 
2032     auto vi = create_info.pVertexInputState;
2033     if (vi != NULL) {
2034         for (uint32_t j = 0; j < vi->vertexAttributeDescriptionCount; j++) {
2035             VkFormat format = vi->pVertexAttributeDescriptions[j].format;
2036             // Internal call to get format info.  Still goes through layers, could potentially go directly to ICD.
2037             VkFormatProperties properties;
2038             DispatchGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
2039             if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
2040                 skip |= LogError(device, "VUID-VkVertexInputAttributeDescription-format-00623",
2041                                  "vkCreateGraphicsPipelines: pCreateInfo[%" PRIu32
2042                                  "].pVertexInputState->vertexAttributeDescriptions[%d].format "
2043                                  "(%s) is not a supported vertex buffer format.",
2044                                  pipelineIndex, j, string_VkFormat(format));
2045             }
2046         }
2047     }
2048 
2049     if (subpass_desc && create_info.pMultisampleState) {
2050         const safe_VkPipelineMultisampleStateCreateInfo *multisample_state = create_info.pMultisampleState;
2051         auto accum_color_samples = [subpass_desc, pPipeline](uint32_t &samples) {
2052             for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; i++) {
2053                 const auto attachment = subpass_desc->pColorAttachments[i].attachment;
2054                 if (attachment != VK_ATTACHMENT_UNUSED) {
2055                     samples |= static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
2056                 }
2057             }
2058         };
2059 
2060         if (!(IsExtEnabled(device_extensions.vk_amd_mixed_attachment_samples) ||
2061               IsExtEnabled(device_extensions.vk_nv_framebuffer_mixed_samples))) {
2062             uint32_t raster_samples = static_cast<uint32_t>(GetNumSamples(pPipeline));
2063             uint32_t subpass_num_samples = 0;
2064 
2065             accum_color_samples(subpass_num_samples);
2066 
2067             if (subpass_desc->pDepthStencilAttachment &&
2068                 subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
2069                 const auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
2070                 subpass_num_samples |= static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
2071             }
2072 
2073             // subpass_num_samples is 0 when the subpass has no attachments or if all attachments are VK_ATTACHMENT_UNUSED.
2074             // Only validate the value of subpass_num_samples if the subpass has attachments that are not VK_ATTACHMENT_UNUSED.
2075             if (subpass_num_samples && (!IsPowerOfTwo(subpass_num_samples) || (subpass_num_samples != raster_samples))) {
2076                 skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-subpass-00757",
2077                                  "vkCreateGraphicsPipelines: pCreateInfo[%" PRIu32
2078                                  "].pMultisampleState->rasterizationSamples (%u) "
2079                                  "does not match the number of samples of the RenderPass color and/or depth attachment.",
2080                                  pipelineIndex, raster_samples);
2081             }
2082         }
2083 
2084         if (IsExtEnabled(device_extensions.vk_amd_mixed_attachment_samples)) {
2085             VkSampleCountFlagBits max_sample_count = static_cast<VkSampleCountFlagBits>(0);
2086             for (uint32_t i = 0; i < subpass_desc->colorAttachmentCount; ++i) {
2087                 if (subpass_desc->pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
2088                     max_sample_count = std::max(
2089                         max_sample_count,
2090                         pPipeline->rp_state->createInfo.pAttachments[subpass_desc->pColorAttachments[i].attachment].samples);
2091                 }
2092             }
2093             if (subpass_desc->pDepthStencilAttachment &&
2094                 subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
2095                 max_sample_count = std::max(
2096                     max_sample_count,
2097                     pPipeline->rp_state->createInfo.pAttachments[subpass_desc->pDepthStencilAttachment->attachment].samples);
2098             }
2099             if ((create_info.pRasterizationState->rasterizerDiscardEnable == VK_FALSE) &&
2100                 (max_sample_count != static_cast<VkSampleCountFlagBits>(0)) &&
2101                 (multisample_state->rasterizationSamples != max_sample_count)) {
2102                 skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-subpass-01505",
2103                                  "vkCreateGraphicsPipelines: pCreateInfo[%" PRIu32
2104                                  "].pMultisampleState->rasterizationSamples (%s) != max "
2105                                  "attachment samples (%s) used in subpass %u.",
2106                                  pipelineIndex, string_VkSampleCountFlagBits(multisample_state->rasterizationSamples),
2107                                  string_VkSampleCountFlagBits(max_sample_count), create_info.subpass);
2108             }
2109         }
2110 
2111         if (IsExtEnabled(device_extensions.vk_nv_framebuffer_mixed_samples)) {
2112             uint32_t raster_samples = static_cast<uint32_t>(GetNumSamples(pPipeline));
2113             uint32_t subpass_color_samples = 0;
2114 
2115             accum_color_samples(subpass_color_samples);
2116 
2117             if (subpass_desc->pDepthStencilAttachment &&
2118                 subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
2119                 const auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
2120                 const uint32_t subpass_depth_samples =
2121                     static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
2122 
2123                 if (create_info.pDepthStencilState) {
2124                     const bool ds_test_enabled = (create_info.pDepthStencilState->depthTestEnable == VK_TRUE) ||
2125                                                  (create_info.pDepthStencilState->depthBoundsTestEnable == VK_TRUE) ||
2126                                                  (create_info.pDepthStencilState->stencilTestEnable == VK_TRUE);
2127 
2128                     if (ds_test_enabled && (!IsPowerOfTwo(subpass_depth_samples) || (raster_samples != subpass_depth_samples))) {
2129                         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-subpass-01411",
2130                                          "vkCreateGraphicsPipelines: pCreateInfo[%" PRIu32
2131                                          "].pMultisampleState->rasterizationSamples (%u) "
2132                                          "does not match the number of samples of the RenderPass depth attachment (%u).",
2133                                          pipelineIndex, raster_samples, subpass_depth_samples);
2134                     }
2135                 }
2136             }
2137 
2138             if (IsPowerOfTwo(subpass_color_samples)) {
2139                 if (raster_samples < subpass_color_samples) {
2140                     skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-subpass-01412",
2141                                      "vkCreateGraphicsPipelines: pCreateInfo[%" PRIu32
2142                                      "].pMultisampleState->rasterizationSamples (%u) "
2143                                      "is not greater or equal to the number of samples of the RenderPass color attachment (%u).",
2144                                      pipelineIndex, raster_samples, subpass_color_samples);
2145                 }
2146 
2147                 if (multisample_state) {
2148                     if ((raster_samples > subpass_color_samples) && (multisample_state->sampleShadingEnable == VK_TRUE)) {
2149                         skip |= LogError(device, "VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-01415",
2150                                          "vkCreateGraphicsPipelines: pCreateInfo[%" PRIu32
2151                                          "].pMultisampleState->sampleShadingEnable must be "
2152                                          "VK_FALSE when "
2153                                          "pCreateInfo[%" PRIu32
2154                                          "].pMultisampleState->rasterizationSamples (%u) is greater than the number of "
2155                                          "samples of the "
2156                                          "subpass color attachment (%u).",
2157                                          pipelineIndex, pipelineIndex, raster_samples, subpass_color_samples);
2158                     }
2159 
2160                     const auto *coverage_modulation_state =
2161                         LvlFindInChain<VkPipelineCoverageModulationStateCreateInfoNV>(multisample_state->pNext);
2162 
2163                     if (coverage_modulation_state && (coverage_modulation_state->coverageModulationTableEnable == VK_TRUE)) {
2164                         if (coverage_modulation_state->coverageModulationTableCount != (raster_samples / subpass_color_samples)) {
2165                             skip |= LogError(
2166                                 device, "VUID-VkPipelineCoverageModulationStateCreateInfoNV-coverageModulationTableEnable-01405",
2167                                 "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
2168                                 "] VkPipelineCoverageModulationStateCreateInfoNV "
2169                                 "coverageModulationTableCount of %u is invalid.",
2170                                 pipelineIndex, coverage_modulation_state->coverageModulationTableCount);
2171                         }
2172                     }
2173                 }
2174             }
2175         }
2176 
2177         if (IsExtEnabled(device_extensions.vk_nv_coverage_reduction_mode)) {
2178             uint32_t raster_samples = static_cast<uint32_t>(GetNumSamples(pPipeline));
2179             uint32_t subpass_color_samples = 0;
2180             uint32_t subpass_depth_samples = 0;
2181 
2182             accum_color_samples(subpass_color_samples);
2183 
2184             if (subpass_desc->pDepthStencilAttachment &&
2185                 subpass_desc->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
2186                 const auto attachment = subpass_desc->pDepthStencilAttachment->attachment;
2187                 subpass_depth_samples = static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
2188             }
2189 
2190             if (multisample_state && IsPowerOfTwo(subpass_color_samples) &&
2191                 (subpass_depth_samples == 0 || IsPowerOfTwo(subpass_depth_samples))) {
2192                 const auto *coverage_reduction_state =
2193                     LvlFindInChain<VkPipelineCoverageReductionStateCreateInfoNV>(multisample_state->pNext);
2194 
2195                 if (coverage_reduction_state) {
2196                     const VkCoverageReductionModeNV coverage_reduction_mode = coverage_reduction_state->coverageReductionMode;
2197                     uint32_t combination_count = 0;
2198                     std::vector<VkFramebufferMixedSamplesCombinationNV> combinations;
2199                     DispatchGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(physical_device, &combination_count,
2200                                                                                             nullptr);
2201                     combinations.resize(combination_count);
2202                     DispatchGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(physical_device, &combination_count,
2203                                                                                             &combinations[0]);
2204 
2205                     bool combination_found = false;
2206                     for (const auto &combination : combinations) {
2207                         if (coverage_reduction_mode == combination.coverageReductionMode &&
2208                             raster_samples == combination.rasterizationSamples &&
2209                             subpass_depth_samples == combination.depthStencilSamples &&
2210                             subpass_color_samples == combination.colorSamples) {
2211                             combination_found = true;
2212                             break;
2213                         }
2214                     }
2215 
2216                     if (!combination_found) {
2217                         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-coverageReductionMode-02722",
2218                                          "vkCreateGraphicsPipelines: pCreateInfos[%" PRIu32
2219                                          "] the specified combination of coverage "
2220                                          "reduction mode (%s), pMultisampleState->rasterizationSamples (%u), sample counts for "
2221                                          "the subpass color and depth/stencil attachments is not a valid combination returned by "
2222                                          "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV.",
2223                                          pipelineIndex, string_VkCoverageReductionModeNV(coverage_reduction_mode), raster_samples);
2224                     }
2225                 }
2226             }
2227         }
2228 
2229         if (IsExtEnabled(device_extensions.vk_nv_fragment_coverage_to_color)) {
2230             const auto coverage_to_color_state = LvlFindInChain<VkPipelineCoverageToColorStateCreateInfoNV>(multisample_state);
2231 
2232             if (coverage_to_color_state && coverage_to_color_state->coverageToColorEnable == VK_TRUE) {
2233                 bool attachment_is_valid = false;
2234                 std::string error_detail;
2235 
2236                 if (coverage_to_color_state->coverageToColorLocation < subpass_desc->colorAttachmentCount) {
2237                     const auto& color_attachment_ref =
2238                         subpass_desc->pColorAttachments[coverage_to_color_state->coverageToColorLocation];
2239                     if (color_attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
2240                         const auto& color_attachment = pPipeline->rp_state->createInfo.pAttachments[color_attachment_ref.attachment];
2241 
2242                         switch (color_attachment.format) {
2243                             case VK_FORMAT_R8_UINT:
2244                             case VK_FORMAT_R8_SINT:
2245                             case VK_FORMAT_R16_UINT:
2246                             case VK_FORMAT_R16_SINT:
2247                             case VK_FORMAT_R32_UINT:
2248                             case VK_FORMAT_R32_SINT:
2249                                 attachment_is_valid = true;
2250                                 break;
2251                             default:
2252                                 std::ostringstream str;
2253                                 str << "references an attachment with an invalid format ("
2254                                     << string_VkFormat(color_attachment.format) << ").";
2255                                 error_detail = str.str();
2256                                 break;
2257                         }
2258                     } else {
2259                         std::ostringstream str;
2260                         str << "references an invalid attachment. The subpass pColorAttachments["
2261                             << coverage_to_color_state->coverageToColorLocation
2262                             << "].attachment has the value VK_ATTACHMENT_UNUSED.";
2263                         error_detail = str.str();
2264                     }
2265                 } else {
2266                     std::ostringstream str;
2267                     str << "references an non-existing attachment since the subpass colorAttachmentCount is "
2268                         << subpass_desc->colorAttachmentCount << ".";
2269                     error_detail = str.str();
2270                 }
2271 
2272                 if (!attachment_is_valid) {
2273                     skip |= LogError(device, "VUID-VkPipelineCoverageToColorStateCreateInfoNV-coverageToColorEnable-01404",
2274                                      "vkCreateGraphicsPipelines: pCreateInfos[%" PRId32
2275                                      "].pMultisampleState VkPipelineCoverageToColorStateCreateInfoNV "
2276                                      "coverageToColorLocation = %" PRIu32 " %s",
2277                                      pipelineIndex, coverage_to_color_state->coverageToColorLocation, error_detail.c_str());
2278                 }
2279             }
2280         }
2281 
2282         if (IsExtEnabled(device_extensions.vk_ext_sample_locations)) {
2283             const VkPipelineSampleLocationsStateCreateInfoEXT *sample_location_state =
2284                 LvlFindInChain<VkPipelineSampleLocationsStateCreateInfoEXT>(multisample_state->pNext);
2285 
2286             if (sample_location_state != nullptr) {
2287                 if ((sample_location_state->sampleLocationsEnable == VK_TRUE) &&
2288                     (IsDynamic(pPipeline, VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT) == false)) {
2289                     const VkSampleLocationsInfoEXT sample_location_info = sample_location_state->sampleLocationsInfo;
2290                     skip |= ValidateSampleLocationsInfo(&sample_location_info, "vkCreateGraphicsPipelines");
2291                     const VkExtent2D grid_size = sample_location_info.sampleLocationGridSize;
2292 
2293                     auto multisample_prop = LvlInitStruct<VkMultisamplePropertiesEXT>();
2294                     DispatchGetPhysicalDeviceMultisamplePropertiesEXT(physical_device, multisample_state->rasterizationSamples,
2295                                                                       &multisample_prop);
2296                     const VkExtent2D max_grid_size = multisample_prop.maxSampleLocationGridSize;
2297 
2298                     // Note order or "divide" in "sampleLocationsInfo must evenly divide VkMultisamplePropertiesEXT"
2299                     if (SafeModulo(max_grid_size.width, grid_size.width) != 0) {
2300                         skip |= LogError(
2301                             device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01521",
2302                             "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
2303                             "]: Because there is no dynamic state for Sample Location "
2304                             "and sampleLocationEnable is true, the "
2305                             "VkPipelineSampleLocationsStateCreateInfoEXT::sampleLocationsInfo::sampleLocationGridSize.width (%u) "
2306                             "must be evenly divided by VkMultisamplePropertiesEXT::sampleLocationGridSize.width (%u).",
2307                             pipelineIndex, grid_size.width, max_grid_size.width);
2308                     }
2309                     if (SafeModulo(max_grid_size.height, grid_size.height) != 0) {
2310                         skip |= LogError(
2311                             device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01522",
2312                             "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
2313                             "]: Because there is no dynamic state for Sample Location "
2314                             "and sampleLocationEnable is true, the "
2315                             "VkPipelineSampleLocationsStateCreateInfoEXT::sampleLocationsInfo::sampleLocationGridSize.height (%u) "
2316                             "must be evenly divided by VkMultisamplePropertiesEXT::sampleLocationGridSize.height (%u).",
2317                             pipelineIndex, grid_size.height, max_grid_size.height);
2318                     }
2319                     if (sample_location_info.sampleLocationsPerPixel != multisample_state->rasterizationSamples) {
2320                         skip |= LogError(
2321                             device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-01523",
2322                             "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
2323                             "]: Because there is no dynamic state for Sample Location "
2324                             "and sampleLocationEnable is true, the "
2325                             "VkPipelineSampleLocationsStateCreateInfoEXT::sampleLocationsInfo::sampleLocationsPerPixel (%s) must "
2326                             "be the same as the VkPipelineMultisampleStateCreateInfo::rasterizationSamples (%s).",
2327                             pipelineIndex, string_VkSampleCountFlagBits(sample_location_info.sampleLocationsPerPixel),
2328                             string_VkSampleCountFlagBits(multisample_state->rasterizationSamples));
2329                     }
2330                 }
2331             }
2332         }
2333 
2334         if (IsExtEnabled(device_extensions.vk_qcom_render_pass_shader_resolve)) {
2335             uint32_t raster_samples = static_cast<uint32_t>(GetNumSamples(pPipeline));
2336             uint32_t subpass_input_attachment_samples = 0;
2337 
2338             for (uint32_t i = 0; i < subpass_desc->inputAttachmentCount; i++) {
2339                 const auto attachment = subpass_desc->pInputAttachments[i].attachment;
2340                 if (attachment != VK_ATTACHMENT_UNUSED) {
2341                     subpass_input_attachment_samples |=
2342                         static_cast<uint32_t>(pPipeline->rp_state->createInfo.pAttachments[attachment].samples);
2343                 }
2344             }
2345 
2346             if ((subpass_desc->flags & VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM) != 0) {
2347                 if (raster_samples != subpass_input_attachment_samples) {
2348                     skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-rasterizationSamples-04899",
2349                                      "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
2350                                      "]: The subpass includes "
2351                                      "VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM "
2352                                      "but the input attachment VkSampleCountFlagBits (%u) does not match the "
2353                                      "VkPipelineMultisampleStateCreateInfo::rasterizationSamples (%u) VkSampleCountFlagBits.",
2354                                      pipelineIndex, subpass_input_attachment_samples, multisample_state->rasterizationSamples);
2355                 }
2356                 if (multisample_state->sampleShadingEnable == VK_TRUE) {
2357                     skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-sampleShadingEnable-04900",
2358                                      "vkCreateGraphicsPipelines() pCreateInfo[%" PRIu32
2359                                      "]: The subpass includes "
2360                                      "VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM "
2361                                      "which requires sample shading is disabled, but "
2362                                      "VkPipelineMultisampleStateCreateInfo::sampleShadingEnable is true. ",
2363                                      pipelineIndex);
2364                 }
2365             }
2366         }
2367     }
2368 
2369     skip |= ValidatePipelineCacheControlFlags(create_info.flags, pipelineIndex, "vkCreateGraphicsPipelines",
2370                                               "VUID-VkGraphicsPipelineCreateInfo-pipelineCreationCacheControl-02878");
2371 
2372     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03378
2373     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState &&
2374         (IsDynamic(pPipeline, VK_DYNAMIC_STATE_CULL_MODE_EXT) || IsDynamic(pPipeline, VK_DYNAMIC_STATE_FRONT_FACE_EXT) ||
2375          IsDynamic(pPipeline, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT) ||
2376          IsDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT) ||
2377          IsDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT) ||
2378          IsDynamic(pPipeline, VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT) ||
2379          IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT) ||
2380          IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT) ||
2381          IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT) ||
2382          IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT) ||
2383          IsDynamic(pPipeline, VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT) || IsDynamic(pPipeline, VK_DYNAMIC_STATE_STENCIL_OP_EXT))) {
2384         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03378",
2385                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2386                          "]: Extended dynamic state used by the extendedDynamicState "
2387                          "feature is not enabled",
2388                          pipelineIndex);
2389     }
2390 
2391     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04868
2392     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2 &&
2393         (IsDynamic(pPipeline, VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT) ||
2394          IsDynamic(pPipeline, VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT) ||
2395          IsDynamic(pPipeline, VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT))) {
2396         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04868",
2397                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2398                          "]: Extended dynamic state used by the extendedDynamicState2 "
2399                          "feature is not enabled",
2400                          pipelineIndex);
2401     }
2402 
2403     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869
2404     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2LogicOp &&
2405         IsDynamic(pPipeline, VK_DYNAMIC_STATE_LOGIC_OP_EXT)) {
2406         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869",
2407                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2408                          "]: Extended dynamic state used by the "
2409                          "extendedDynamicState2LogicOp feature is not enabled",
2410                          pipelineIndex);
2411     }
2412 
2413     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04870
2414     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2PatchControlPoints &&
2415         IsDynamic(pPipeline, VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT)) {
2416         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04870",
2417                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2418                          "]: Extended dynamic state used by the "
2419                          "extendedDynamicState2PatchControlPoints "
2420                          "feature is not enabled",
2421                          pipelineIndex);
2422     }
2423 
2424     const VkPipelineFragmentShadingRateStateCreateInfoKHR *fragment_shading_rate_state =
2425         LvlFindInChain<VkPipelineFragmentShadingRateStateCreateInfoKHR>(create_info.pNext);
2426 
2427     if (fragment_shading_rate_state && !IsDynamic(pPipeline, VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR)) {
2428         const char *struct_name = "VkPipelineFragmentShadingRateStateCreateInfoKHR";
2429 
2430         if (fragment_shading_rate_state->fragmentSize.width == 0) {
2431             skip |=
2432                 LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04494",
2433                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32 "]: Fragment width of %u has been specified in %s.",
2434                          pipelineIndex, fragment_shading_rate_state->fragmentSize.width, struct_name);
2435         }
2436 
2437         if (fragment_shading_rate_state->fragmentSize.height == 0) {
2438             skip |=
2439                 LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04495",
2440                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32 "]: Fragment height of %u has been specified in %s.",
2441                          pipelineIndex, fragment_shading_rate_state->fragmentSize.height, struct_name);
2442         }
2443 
2444         if (fragment_shading_rate_state->fragmentSize.width != 0 &&
2445             !IsPowerOfTwo(fragment_shading_rate_state->fragmentSize.width)) {
2446             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04496",
2447                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2448                              "]: Non-power-of-two fragment width of %u has been specified in %s.",
2449                              pipelineIndex, fragment_shading_rate_state->fragmentSize.width, struct_name);
2450         }
2451 
2452         if (fragment_shading_rate_state->fragmentSize.height != 0 &&
2453             !IsPowerOfTwo(fragment_shading_rate_state->fragmentSize.height)) {
2454             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04497",
2455                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2456                              "]: Non-power-of-two fragment height of %u has been specified in %s.",
2457                              pipelineIndex, fragment_shading_rate_state->fragmentSize.height, struct_name);
2458         }
2459 
2460         if (fragment_shading_rate_state->fragmentSize.width > 4) {
2461             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04498",
2462                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2463                              "]: Fragment width of %u specified in %s is too large.",
2464                              pipelineIndex, fragment_shading_rate_state->fragmentSize.width, struct_name);
2465         }
2466 
2467         if (fragment_shading_rate_state->fragmentSize.height > 4) {
2468             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04499",
2469                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2470                              "]: Fragment height of %u specified in %s is too large",
2471                              pipelineIndex, fragment_shading_rate_state->fragmentSize.height, struct_name);
2472         }
2473 
2474         if (!enabled_features.fragment_shading_rate_features.pipelineFragmentShadingRate &&
2475             fragment_shading_rate_state->fragmentSize.width != 1) {
2476             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04500",
2477                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2478                              "]: Pipeline fragment width of %u has been specified in %s, but "
2479                              "pipelineFragmentShadingRate is not enabled",
2480                              pipelineIndex, fragment_shading_rate_state->fragmentSize.width, struct_name);
2481         }
2482 
2483         if (!enabled_features.fragment_shading_rate_features.pipelineFragmentShadingRate &&
2484             fragment_shading_rate_state->fragmentSize.height != 1) {
2485             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04500",
2486                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2487                              "]: Pipeline fragment height of %u has been specified in %s, but "
2488                              "pipelineFragmentShadingRate is not enabled",
2489                              pipelineIndex, fragment_shading_rate_state->fragmentSize.height, struct_name);
2490         }
2491 
2492         if (!enabled_features.fragment_shading_rate_features.primitiveFragmentShadingRate &&
2493             fragment_shading_rate_state->combinerOps[0] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR) {
2494             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04501",
2495                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2496                              "]: First combiner operation of %s has been specified in %s, but "
2497                              "primitiveFragmentShadingRate is not enabled",
2498                              pipelineIndex, string_VkFragmentShadingRateCombinerOpKHR(fragment_shading_rate_state->combinerOps[0]),
2499                              struct_name);
2500         }
2501 
2502         if (!enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate &&
2503             fragment_shading_rate_state->combinerOps[1] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR) {
2504             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicState-04502",
2505                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2506                              "]: Second combiner operation of %s has been specified in %s, but "
2507                              "attachmentFragmentShadingRate is not enabled",
2508                              pipelineIndex, string_VkFragmentShadingRateCombinerOpKHR(fragment_shading_rate_state->combinerOps[1]),
2509                              struct_name);
2510         }
2511 
2512         if (!phys_dev_ext_props.fragment_shading_rate_props.fragmentShadingRateNonTrivialCombinerOps &&
2513             (fragment_shading_rate_state->combinerOps[0] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR &&
2514              fragment_shading_rate_state->combinerOps[0] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR)) {
2515             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-fragmentShadingRateNonTrivialCombinerOps-04506",
2516                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2517                              "]: First combiner operation of %s has been specified in %s, but "
2518                              "fragmentShadingRateNonTrivialCombinerOps is not supported",
2519                              pipelineIndex, string_VkFragmentShadingRateCombinerOpKHR(fragment_shading_rate_state->combinerOps[0]),
2520                              struct_name);
2521         }
2522 
2523         if (!phys_dev_ext_props.fragment_shading_rate_props.fragmentShadingRateNonTrivialCombinerOps &&
2524             (fragment_shading_rate_state->combinerOps[1] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR &&
2525              fragment_shading_rate_state->combinerOps[1] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR)) {
2526             skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-fragmentShadingRateNonTrivialCombinerOps-04506",
2527                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2528                              "]: Second combiner operation of %s has been specified in %s, but "
2529                              "fragmentShadingRateNonTrivialCombinerOps is not supported",
2530                              pipelineIndex, string_VkFragmentShadingRateCombinerOpKHR(fragment_shading_rate_state->combinerOps[1]),
2531                              struct_name);
2532         }
2533     }
2534 
2535     const auto *discard_rectangle_state = LvlFindInChain<VkPipelineDiscardRectangleStateCreateInfoEXT>(create_info.pNext);
2536     if (discard_rectangle_state) {
2537         if (discard_rectangle_state->discardRectangleCount > phys_dev_ext_props.discard_rectangle_props.maxDiscardRectangles) {
2538             skip |= LogError(
2539                 device, "VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleCount-00582",
2540                 "vkCreateGraphicsPipelines(): VkPipelineDiscardRectangleStateCreateInfoEXT::discardRectangleCount (%" PRIu32
2541                 ") in pNext chain of pCreateInfo[%" PRIu32
2542                 "] is not less than VkPhysicalDeviceDiscardRectanglePropertiesEXT::maxDiscardRectangles (%" PRIu32 ".",
2543                 discard_rectangle_state->discardRectangleCount, pipelineIndex,
2544                 phys_dev_ext_props.discard_rectangle_props.maxDiscardRectangles);
2545         }
2546     }
2547 
2548     // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04807
2549     if (!enabled_features.vertex_input_dynamic_state_features.vertexInputDynamicState &&
2550         IsDynamic(pPipeline, VK_DYNAMIC_STATE_VERTEX_INPUT_EXT)) {
2551         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04807",
2552                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2553                          "]: The vertexInputDynamicState feature must be enabled to use "
2554                          "the VK_DYNAMIC_STATE_VERTEX_INPUT_EXT dynamic state",
2555                          pipelineIndex);
2556     }
2557 
2558     if (!enabled_features.color_write_features.colorWriteEnable && IsDynamic(pPipeline, VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT)) {
2559         skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04800",
2560                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2561                          "]: The colorWriteEnable feature must be enabled to use the "
2562                          "VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT dynamic state",
2563                          pipelineIndex);
2564     }
2565 
2566     const auto rendering_struct = LvlFindInChain<VkPipelineRenderingCreateInfoKHR>(create_info.pNext);
2567     if (rendering_struct) {
2568         for (uint32_t color_index = 0; color_index < rendering_struct->colorAttachmentCount; color_index++) {
2569             const VkFormat color_format = rendering_struct->pColorAttachmentFormats[color_index];
2570             if (color_format != VK_FORMAT_UNDEFINED) {
2571                 VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(color_format);
2572                 if ((format_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) {
2573                     skip |= LogError(device, "VUID-VkPipelineRenderingCreateInfoKHR-pColorAttachmentFormats-06064",
2574                                      "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2575                                      "]: color_format (%s) must be a format with potential format features that include "
2576                                      "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT",
2577                                      pipelineIndex, string_VkFormat(color_format));
2578                 }
2579             }
2580         }
2581 
2582         if (rendering_struct->depthAttachmentFormat != VK_FORMAT_UNDEFINED) {
2583             VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(rendering_struct->depthAttachmentFormat);
2584             if ((format_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
2585                 skip |= LogError(device, "VUID-VkPipelineRenderingCreateInfoKHR-depthAttachmentFormat-06065",
2586                                  "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2587                                  "]: depthAttachmentFormat (%s) must be a format with potential format features that include "
2588                                  "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT",
2589                                  pipelineIndex, string_VkFormat(rendering_struct->depthAttachmentFormat));
2590             }
2591         }
2592 
2593         if (rendering_struct->stencilAttachmentFormat != VK_FORMAT_UNDEFINED) {
2594             VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(rendering_struct->stencilAttachmentFormat);
2595             if ((format_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
2596                 skip |= LogError(device, "VUID-VkPipelineRenderingCreateInfoKHR-stencilAttachmentFormat-06164",
2597                                  "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2598                                  "]: stencilAttachmentFormat (%s) must be a format with potential format features that include "
2599                                  "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT",
2600                                  pipelineIndex, string_VkFormat(rendering_struct->stencilAttachmentFormat));
2601             }
2602         }
2603 
2604         if ((rendering_struct->depthAttachmentFormat != VK_FORMAT_UNDEFINED) &&
2605             (rendering_struct->stencilAttachmentFormat != VK_FORMAT_UNDEFINED) &&
2606             (rendering_struct->depthAttachmentFormat != rendering_struct->stencilAttachmentFormat)) {
2607             skip |= LogError(device, "VUID-VkPipelineRenderingCreateInfoKHR-depthAttachmentFormat-06165",
2608                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2609                              "]: depthAttachmentFormat is not VK_FORMAT_UNDEFINED and stencilAttachmentFormat is not "
2610                              "VK_FORMAT_UNDEFINED, but depthAttachmentFormat (%s) does not equal stencilAttachmentFormat (%s)",
2611                              pipelineIndex, string_VkFormat(rendering_struct->depthAttachmentFormat),
2612                              string_VkFormat(rendering_struct->stencilAttachmentFormat));
2613         }
2614 
2615         if ((enabled_features.core11.multiview == VK_FALSE) && (rendering_struct->viewMask != 0)) {
2616             skip |=
2617                 LogError(device, "VUID-VkPipelineRenderingCreateInfoKHR-multiview-06066",
2618                          "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32 "]: multiview is not enabled but viewMask is (%u).",
2619                          pipelineIndex, rendering_struct->viewMask);
2620         }
2621 
2622         if (MostSignificantBit(rendering_struct->viewMask) >= phys_dev_props_core11.maxMultiviewViewCount) {
2623             skip |= LogError(device, "VUID-VkPipelineRenderingCreateInfoKHR-viewMask-06067",
2624                              "vkCreateGraphicsPipelines() pCreateInfos[%" PRIu32
2625                              "]: Most significant bit in "
2626                              "VkPipelineRenderingCreateInfoKHR->viewMask(%u) must be less maxMultiviewViewCount(%u)",
2627                              pipelineIndex, rendering_struct->viewMask, phys_dev_props_core11.maxMultiviewViewCount);
2628         }
2629     }
2630 
2631     return skip;
2632 }
2633 
2634 // Block of code at start here specifically for managing/tracking DSs
2635 
2636 // Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
2637 // func_str is the name of the calling function
2638 // Return false if no errors occur
2639 // Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
ValidateIdleDescriptorSet(VkDescriptorSet set,const char * func_str) const2640 bool CoreChecks::ValidateIdleDescriptorSet(VkDescriptorSet set, const char *func_str) const {
2641     if (disabled[object_in_use]) return false;
2642     bool skip = false;
2643     auto set_node = Get<cvdescriptorset::DescriptorSet>(set);
2644     if (set_node) {
2645         // TODO : This covers various error cases so should pass error enum into this function and use passed in enum here
2646         if (set_node->InUse()) {
2647             skip |= LogError(set, "VUID-vkFreeDescriptorSets-pDescriptorSets-00309",
2648                              "Cannot call %s() on %s that is in use by a command buffer.", func_str,
2649                              report_data->FormatHandle(set).c_str());
2650         }
2651     }
2652     return skip;
2653 }
2654 
2655 // If a renderpass is active, verify that the given command type is appropriate for current subpass state
ValidateCmdSubpassState(const CMD_BUFFER_STATE * pCB,const CMD_TYPE cmd_type) const2656 bool CoreChecks::ValidateCmdSubpassState(const CMD_BUFFER_STATE *pCB, const CMD_TYPE cmd_type) const {
2657     if (!pCB->activeRenderPass) return false;
2658     bool skip = false;
2659     if (pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY &&
2660         pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS &&
2661         (cmd_type != CMD_EXECUTECOMMANDS && cmd_type != CMD_NEXTSUBPASS && cmd_type != CMD_ENDRENDERPASS &&
2662          cmd_type != CMD_NEXTSUBPASS2 && cmd_type != CMD_NEXTSUBPASS2KHR && cmd_type != CMD_ENDRENDERPASS2 &&
2663          cmd_type != CMD_ENDRENDERPASS2KHR)) {
2664         skip |= LogError(pCB->commandBuffer(), kVUID_Core_DrawState_InvalidCommandBuffer,
2665                          "%s() cannot be called in a subpass using secondary command buffers.",
2666                           kGeneratedCommandNameList[cmd_type]);
2667     }
2668     return skip;
2669 }
2670 
ValidateCmdQueueFlags(const CMD_BUFFER_STATE * cb_node,const char * caller_name,VkQueueFlags required_flags,const char * error_code) const2671 bool CoreChecks::ValidateCmdQueueFlags(const CMD_BUFFER_STATE *cb_node, const char *caller_name, VkQueueFlags required_flags,
2672                                        const char *error_code) const {
2673     auto pool = cb_node->command_pool;
2674     if (pool) {
2675         const uint32_t queue_family_index = pool->queueFamilyIndex;
2676         const VkQueueFlags queue_flags = physical_device_state->queue_family_properties[queue_family_index].queueFlags;
2677         if (!(required_flags & queue_flags)) {
2678             string required_flags_string;
2679             for (auto flag : {VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT, VK_QUEUE_SPARSE_BINDING_BIT,
2680                               VK_QUEUE_PROTECTED_BIT}) {
2681                 if (flag & required_flags) {
2682                     if (required_flags_string.size()) {
2683                         required_flags_string += " or ";
2684                     }
2685                     required_flags_string += string_VkQueueFlagBits(flag);
2686                 }
2687             }
2688             return LogError(cb_node->commandBuffer(), error_code,
2689                             "%s(): Called in command buffer %s which was allocated from the command pool %s which was created with "
2690                             "queueFamilyIndex %u which doesn't contain the required %s capability flags.",
2691                             caller_name, report_data->FormatHandle(cb_node->commandBuffer()).c_str(),
2692                             report_data->FormatHandle(pool->commandPool()).c_str(), queue_family_index,
2693                             required_flags_string.c_str());
2694         }
2695     }
2696     return false;
2697 }
2698 
ValidateSampleLocationsInfo(const VkSampleLocationsInfoEXT * pSampleLocationsInfo,const char * apiName) const2699 bool CoreChecks::ValidateSampleLocationsInfo(const VkSampleLocationsInfoEXT *pSampleLocationsInfo, const char *apiName) const {
2700     bool skip = false;
2701     const VkSampleCountFlagBits sample_count = pSampleLocationsInfo->sampleLocationsPerPixel;
2702     const uint32_t sample_total_size = pSampleLocationsInfo->sampleLocationGridSize.width *
2703                                        pSampleLocationsInfo->sampleLocationGridSize.height * SampleCountSize(sample_count);
2704     if (pSampleLocationsInfo->sampleLocationsCount != sample_total_size) {
2705         skip |= LogError(device, "VUID-VkSampleLocationsInfoEXT-sampleLocationsCount-01527",
2706                          "%s: VkSampleLocationsInfoEXT::sampleLocationsCount (%u) must equal grid width * grid height * pixel "
2707                          "sample rate which currently is (%u * %u * %u).",
2708                          apiName, pSampleLocationsInfo->sampleLocationsCount, pSampleLocationsInfo->sampleLocationGridSize.width,
2709                          pSampleLocationsInfo->sampleLocationGridSize.height, SampleCountSize(sample_count));
2710     }
2711     if ((phys_dev_ext_props.sample_locations_props.sampleLocationSampleCounts & sample_count) == 0) {
2712         skip |= LogError(device, "VUID-VkSampleLocationsInfoEXT-sampleLocationsPerPixel-01526",
2713                          "%s: VkSampleLocationsInfoEXT::sampleLocationsPerPixel of %s is not supported by the device, please check "
2714                          "VkPhysicalDeviceSampleLocationsPropertiesEXT::sampleLocationSampleCounts for valid sample counts.",
2715                          apiName, string_VkSampleCountFlagBits(sample_count));
2716     }
2717 
2718     return skip;
2719 }
2720 
MatchSampleLocationsInfo(const VkSampleLocationsInfoEXT * pSampleLocationsInfo1,const VkSampleLocationsInfoEXT * pSampleLocationsInfo2) const2721 bool CoreChecks::MatchSampleLocationsInfo(const VkSampleLocationsInfoEXT *pSampleLocationsInfo1,
2722                                           const VkSampleLocationsInfoEXT *pSampleLocationsInfo2) const {
2723     if (pSampleLocationsInfo1->sampleLocationsPerPixel != pSampleLocationsInfo2->sampleLocationsPerPixel ||
2724         pSampleLocationsInfo1->sampleLocationGridSize.width != pSampleLocationsInfo2->sampleLocationGridSize.width ||
2725         pSampleLocationsInfo1->sampleLocationGridSize.height != pSampleLocationsInfo2->sampleLocationGridSize.height ||
2726         pSampleLocationsInfo1->sampleLocationsCount != pSampleLocationsInfo2->sampleLocationsCount) {
2727         return false;
2728     }
2729     for (uint32_t i = 0; i < pSampleLocationsInfo1->sampleLocationsCount; ++i) {
2730         if (pSampleLocationsInfo1->pSampleLocations[i].x != pSampleLocationsInfo2->pSampleLocations[i].x ||
2731             pSampleLocationsInfo1->pSampleLocations[i].y != pSampleLocationsInfo2->pSampleLocations[i].y) {
2732             return false;
2733         }
2734     }
2735     return true;
2736 }
2737 
GetCauseStr(VulkanTypedHandle obj)2738 static char const *GetCauseStr(VulkanTypedHandle obj) {
2739     if (obj.type == kVulkanObjectTypeDescriptorSet) return "destroyed or updated";
2740     if (obj.type == kVulkanObjectTypeCommandBuffer) return "destroyed or rerecorded";
2741     return "destroyed";
2742 }
2743 
ReportInvalidCommandBuffer(const CMD_BUFFER_STATE * cb_state,const char * call_source) const2744 bool CoreChecks::ReportInvalidCommandBuffer(const CMD_BUFFER_STATE *cb_state, const char *call_source) const {
2745     bool skip = false;
2746     for (const auto& entry: cb_state->broken_bindings) {
2747         const auto& obj = entry.first;
2748         const char *cause_str = GetCauseStr(obj);
2749         string vuid;
2750         std::ostringstream str;
2751         str << kVUID_Core_DrawState_InvalidCommandBuffer << "-" << object_string[obj.type];
2752         vuid = str.str();
2753         auto objlist = entry.second; //intentional copy
2754         objlist.add(cb_state->commandBuffer());
2755         skip |=
2756             LogError(objlist, vuid, "You are adding %s to %s that is invalid because bound %s was %s.", call_source,
2757                      report_data->FormatHandle(cb_state->commandBuffer()).c_str(), report_data->FormatHandle(obj).c_str(), cause_str);
2758     }
2759     return skip;
2760 }
2761 
ValidateIndirectCmd(const CMD_BUFFER_STATE & cb_state,const BUFFER_STATE & buffer_state,CMD_TYPE cmd_type) const2762 bool CoreChecks::ValidateIndirectCmd(const CMD_BUFFER_STATE &cb_state, const BUFFER_STATE &buffer_state, CMD_TYPE cmd_type) const {
2763     bool skip = false;
2764     const DrawDispatchVuid vuid = GetDrawDispatchVuid(cmd_type);
2765     const char *caller_name = CommandTypeString(cmd_type);
2766 
2767     skip |= ValidateMemoryIsBoundToBuffer(&buffer_state, caller_name, vuid.indirect_contiguous_memory);
2768     skip |= ValidateBufferUsageFlags(&buffer_state, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, true, vuid.indirect_buffer_bit,
2769                                      caller_name, "VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT");
2770     if (cb_state.unprotected == false) {
2771         skip |= LogError(cb_state.Handle(), vuid.indirect_protected_cb,
2772                          "%s: Indirect commands can't be used in protected command buffers.", caller_name);
2773     }
2774     return skip;
2775 }
2776 
2777 template <typename T1>
ValidateDeviceMaskToPhysicalDeviceCount(uint32_t deviceMask,const T1 object,const char * VUID) const2778 bool CoreChecks::ValidateDeviceMaskToPhysicalDeviceCount(uint32_t deviceMask, const T1 object, const char *VUID) const {
2779     bool skip = false;
2780     uint32_t count = 1 << physical_device_count;
2781     if (count <= deviceMask) {
2782         skip |= LogError(object, VUID, "deviceMask(0x%" PRIx32 ") is invalid. Physical device count is %" PRIu32 ".", deviceMask,
2783                          physical_device_count);
2784     }
2785     return skip;
2786 }
2787 
2788 template <typename T1>
ValidateDeviceMaskToZero(uint32_t deviceMask,const T1 object,const char * VUID) const2789 bool CoreChecks::ValidateDeviceMaskToZero(uint32_t deviceMask, const T1 object, const char *VUID) const {
2790     bool skip = false;
2791     if (deviceMask == 0) {
2792         skip |= LogError(object, VUID, "deviceMask(0x%" PRIx32 ") must be non-zero.", deviceMask);
2793     }
2794     return skip;
2795 }
2796 
2797 template <typename T1>
ValidateDeviceMaskToCommandBuffer(const CMD_BUFFER_STATE * pCB,uint32_t deviceMask,const T1 object,const char * VUID) const2798 bool CoreChecks::ValidateDeviceMaskToCommandBuffer(const CMD_BUFFER_STATE *pCB, uint32_t deviceMask, const T1 object,
2799                                                    const char *VUID) const {
2800     bool skip = false;
2801     if ((deviceMask & pCB->initial_device_mask) != deviceMask) {
2802         skip |= LogError(object, VUID, "deviceMask(0x%" PRIx32 ") is not a subset of %s initial device mask(0x%" PRIx32 ").",
2803                          deviceMask, report_data->FormatHandle(pCB->commandBuffer()).c_str(), pCB->initial_device_mask);
2804     }
2805     return skip;
2806 }
2807 
ValidateDeviceMaskToRenderPass(const CMD_BUFFER_STATE * pCB,uint32_t deviceMask,const char * VUID) const2808 bool CoreChecks::ValidateDeviceMaskToRenderPass(const CMD_BUFFER_STATE *pCB, uint32_t deviceMask, const char *VUID) const {
2809     bool skip = false;
2810     if ((deviceMask & pCB->active_render_pass_device_mask) != deviceMask) {
2811         skip |= LogError(pCB->commandBuffer(), VUID, "deviceMask(0x%" PRIx32 ") is not a subset of %s device mask(0x%" PRIx32 ").",
2812                          deviceMask, report_data->FormatHandle(pCB->activeRenderPass->renderPass()).c_str(),
2813                          pCB->active_render_pass_device_mask);
2814     }
2815     return skip;
2816 }
2817 
2818 // Flags validation error if the associated call is made inside a render pass. The apiName routine should ONLY be called outside a
2819 // render pass.
InsideRenderPass(const CMD_BUFFER_STATE * pCB,const char * apiName,const char * msgCode) const2820 bool CoreChecks::InsideRenderPass(const CMD_BUFFER_STATE *pCB, const char *apiName, const char *msgCode) const {
2821     bool inside = false;
2822     if (pCB->activeRenderPass) {
2823         inside = LogError(pCB->commandBuffer(), msgCode, "%s: It is invalid to issue this call inside an active %s.", apiName,
2824                           report_data->FormatHandle(pCB->activeRenderPass->renderPass()).c_str());
2825     }
2826     return inside;
2827 }
2828 
2829 // Flags validation error if the associated call is made outside a render pass. The apiName
2830 // routine should ONLY be called inside a render pass.
OutsideRenderPass(const CMD_BUFFER_STATE * pCB,const char * apiName,const char * msgCode) const2831 bool CoreChecks::OutsideRenderPass(const CMD_BUFFER_STATE *pCB, const char *apiName, const char *msgCode) const {
2832     bool outside = false;
2833     if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
2834         ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
2835          !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
2836         outside = LogError(pCB->commandBuffer(), msgCode, "%s: This call must be issued inside an active render pass.", apiName);
2837     }
2838     return outside;
2839 }
2840 
ValidateQueueFamilyIndex(const PHYSICAL_DEVICE_STATE * pd_state,uint32_t requested_queue_family,const char * err_code,const char * cmd_name,const char * queue_family_var_name) const2841 bool CoreChecks::ValidateQueueFamilyIndex(const PHYSICAL_DEVICE_STATE *pd_state, uint32_t requested_queue_family,
2842                                           const char *err_code, const char *cmd_name, const char *queue_family_var_name) const {
2843     bool skip = false;
2844 
2845     if (requested_queue_family >= pd_state->queue_family_known_count) {
2846         const char *conditional_ext_cmd =
2847             instance_extensions.vk_khr_get_physical_device_properties2 ? " or vkGetPhysicalDeviceQueueFamilyProperties2[KHR]" : "";
2848 
2849         skip |= LogError(pd_state->Handle(), err_code,
2850                          "%s: %s (= %" PRIu32
2851                          ") is not less than any previously obtained pQueueFamilyPropertyCount from "
2852                          "vkGetPhysicalDeviceQueueFamilyProperties%s (i.e. is not less than %s).",
2853                          cmd_name, queue_family_var_name, requested_queue_family, conditional_ext_cmd,
2854                          std::to_string(pd_state->queue_family_known_count).c_str());
2855     }
2856     return skip;
2857 }
2858 
2859 // Verify VkDeviceQueueCreateInfos
ValidateDeviceQueueCreateInfos(const PHYSICAL_DEVICE_STATE * pd_state,uint32_t info_count,const VkDeviceQueueCreateInfo * infos) const2860 bool CoreChecks::ValidateDeviceQueueCreateInfos(const PHYSICAL_DEVICE_STATE *pd_state, uint32_t info_count,
2861                                                 const VkDeviceQueueCreateInfo *infos) const {
2862     bool skip = false;
2863 
2864     const uint32_t not_used = std::numeric_limits<uint32_t>::max();
2865     struct create_flags {
2866         // uint32_t is to represent the queue family index to allow for better error messages
2867         uint32_t unprocted_index;
2868         uint32_t protected_index;
2869         create_flags(uint32_t a, uint32_t b) : unprocted_index(a), protected_index(b) {}
2870     };
2871     layer_data::unordered_map<uint32_t, create_flags> queue_family_map;
2872 
2873     for (uint32_t i = 0; i < info_count; ++i) {
2874         const auto requested_queue_family = infos[i].queueFamilyIndex;
2875         const bool protected_create_bit = (infos[i].flags & VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT) != 0;
2876 
2877         std::string queue_family_var_name = "pCreateInfo->pQueueCreateInfos[" + std::to_string(i) + "].queueFamilyIndex";
2878         skip |= ValidateQueueFamilyIndex(pd_state, requested_queue_family, "VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381",
2879                                          "vkCreateDevice", queue_family_var_name.c_str());
2880 
2881         if (api_version == VK_API_VERSION_1_0) {
2882             // Vulkan 1.0 didn't have protected memory so always needed unique info
2883             create_flags flags = {requested_queue_family, not_used};
2884             if (queue_family_map.emplace(requested_queue_family, flags).second == false) {
2885                 skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-queueFamilyIndex-00372",
2886                                  "CreateDevice(): %s (=%" PRIu32
2887                                  ") is not unique and was also used in pCreateInfo->pQueueCreateInfos[%d].",
2888                                  queue_family_var_name.c_str(), requested_queue_family,
2889                                  queue_family_map.at(requested_queue_family).unprocted_index);
2890             }
2891         } else {
2892             // Vulkan 1.1 and up can have 2 queues be same family index if one is protected and one isn't
2893             auto it = queue_family_map.find(requested_queue_family);
2894             if (it == queue_family_map.end()) {
2895                 // Add first time seeing queue family index and what the create flags were
2896                 create_flags new_flags = {not_used, not_used};
2897                 if (protected_create_bit) {
2898                     new_flags.protected_index = requested_queue_family;
2899                 } else {
2900                     new_flags.unprocted_index = requested_queue_family;
2901                 }
2902                 queue_family_map.emplace(requested_queue_family, new_flags);
2903             } else {
2904                 // The queue family was seen, so now need to make sure the flags were different
2905                 if (protected_create_bit) {
2906                     if (it->second.protected_index != not_used) {
2907                         skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-queueFamilyIndex-02802",
2908                                          "CreateDevice(): %s (=%" PRIu32
2909                                          ") is not unique and was also used in pCreateInfo->pQueueCreateInfos[%d] which both have "
2910                                          "VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT.",
2911                                          queue_family_var_name.c_str(), requested_queue_family,
2912                                          queue_family_map.at(requested_queue_family).protected_index);
2913                     } else {
2914                         it->second.protected_index = requested_queue_family;
2915                     }
2916                 } else {
2917                     if (it->second.unprocted_index != not_used) {
2918                         skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-queueFamilyIndex-02802",
2919                                          "CreateDevice(): %s (=%" PRIu32
2920                                          ") is not unique and was also used in pCreateInfo->pQueueCreateInfos[%d].",
2921                                          queue_family_var_name.c_str(), requested_queue_family,
2922                                          queue_family_map.at(requested_queue_family).unprocted_index);
2923                     } else {
2924                         it->second.unprocted_index = requested_queue_family;
2925                     }
2926                 }
2927             }
2928         }
2929 
2930         const VkQueueFamilyProperties requested_queue_family_props = pd_state->queue_family_properties[requested_queue_family];
2931 
2932         // if using protected flag, make sure queue supports it
2933         if (protected_create_bit && ((requested_queue_family_props.queueFlags & VK_QUEUE_PROTECTED_BIT) == 0)) {
2934             skip |= LogError(
2935                 pd_state->Handle(), "VUID-VkDeviceQueueCreateInfo-flags-06449",
2936                 "CreateDevice(): %s (=%" PRIu32
2937                 ") does not have VK_QUEUE_PROTECTED_BIT supported, but VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT is being used.",
2938                 queue_family_var_name.c_str(), requested_queue_family);
2939         }
2940 
2941         // Verify that requested queue count of queue family is known to be valid at this point in time
2942         if (requested_queue_family < pd_state->queue_family_known_count) {
2943             const auto requested_queue_count = infos[i].queueCount;
2944             const bool queue_family_has_props = requested_queue_family < pd_state->queue_family_properties.size();
2945             // spec guarantees at least one queue for each queue family
2946             const uint32_t available_queue_count = queue_family_has_props ? requested_queue_family_props.queueCount : 1;
2947             const char *conditional_ext_cmd = instance_extensions.vk_khr_get_physical_device_properties2
2948                                                   ? " or vkGetPhysicalDeviceQueueFamilyProperties2[KHR]"
2949                                                   : "";
2950 
2951             if (requested_queue_count > available_queue_count) {
2952                 const std::string count_note =
2953                     queue_family_has_props
2954                         ? "i.e. is not less than or equal to " + std::to_string(requested_queue_family_props.queueCount)
2955                         : "the pQueueFamilyProperties[" + std::to_string(requested_queue_family) + "] was never obtained";
2956 
2957                 skip |= LogError(
2958                     pd_state->Handle(), "VUID-VkDeviceQueueCreateInfo-queueCount-00382",
2959                     "vkCreateDevice: pCreateInfo->pQueueCreateInfos[%" PRIu32 "].queueCount (=%" PRIu32
2960                     ") is not less than or equal to available queue count for this pCreateInfo->pQueueCreateInfos[%" PRIu32
2961                     "].queueFamilyIndex} (=%" PRIu32 ") obtained previously from vkGetPhysicalDeviceQueueFamilyProperties%s (%s).",
2962                     i, requested_queue_count, i, requested_queue_family, conditional_ext_cmd, count_note.c_str());
2963             }
2964         }
2965 
2966         const VkQueueFlags queue_flags = pd_state->queue_family_properties[requested_queue_family].queueFlags;
2967         if ((infos[i].flags == VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT) && ((queue_flags & VK_QUEUE_PROTECTED_BIT) == VK_FALSE)) {
2968             skip |= LogError(pd_state->Handle(), "VUID-VkDeviceQueueCreateInfo-flags-06449",
2969                 "vkCreateDevice: pCreateInfo->flags set to VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT on a queue that doesn't include VK_QUEUE_PROTECTED_BIT capability");
2970         }
2971     }
2972 
2973     return skip;
2974 }
2975 
PreCallValidateCreateDevice(VkPhysicalDevice gpu,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice) const2976 bool CoreChecks::PreCallValidateCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
2977                                              const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) const {
2978     bool skip = false;
2979     auto pd_state = Get<PHYSICAL_DEVICE_STATE>(gpu);
2980 
2981     // TODO: object_tracker should perhaps do this instead
2982     //       and it does not seem to currently work anyway -- the loader just crashes before this point
2983     if (!pd_state) {
2984         skip |= LogError(device, kVUID_Core_DevLimit_MustQueryCount,
2985                          "Invalid call to vkCreateDevice() w/o first calling vkEnumeratePhysicalDevices().");
2986     } else {
2987         skip |= ValidateDeviceQueueCreateInfos(pd_state.get(), pCreateInfo->queueCreateInfoCount, pCreateInfo->pQueueCreateInfos);
2988 
2989         const VkPhysicalDeviceFragmentShadingRateFeaturesKHR *fragment_shading_rate_features =
2990             LvlFindInChain<VkPhysicalDeviceFragmentShadingRateFeaturesKHR>(pCreateInfo->pNext);
2991 
2992         if (fragment_shading_rate_features) {
2993             const VkPhysicalDeviceShadingRateImageFeaturesNV *shading_rate_image_features =
2994                 LvlFindInChain<VkPhysicalDeviceShadingRateImageFeaturesNV>(pCreateInfo->pNext);
2995 
2996             if (shading_rate_image_features && shading_rate_image_features->shadingRateImage) {
2997                 if (fragment_shading_rate_features->pipelineFragmentShadingRate) {
2998                     skip |= LogError(
2999                         pd_state->Handle(), "VUID-VkDeviceCreateInfo-shadingRateImage-04478",
3000                         "vkCreateDevice: Cannot enable shadingRateImage and pipelineFragmentShadingRate features simultaneously.");
3001                 }
3002                 if (fragment_shading_rate_features->primitiveFragmentShadingRate) {
3003                     skip |= LogError(
3004                         pd_state->Handle(), "VUID-VkDeviceCreateInfo-shadingRateImage-04479",
3005                         "vkCreateDevice: Cannot enable shadingRateImage and primitiveFragmentShadingRate features simultaneously.");
3006                 }
3007                 if (fragment_shading_rate_features->attachmentFragmentShadingRate) {
3008                     skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-shadingRateImage-04480",
3009                                      "vkCreateDevice: Cannot enable shadingRateImage and attachmentFragmentShadingRate features "
3010                                      "simultaneously.");
3011                 }
3012             }
3013 
3014             const VkPhysicalDeviceFragmentDensityMapFeaturesEXT *fragment_density_map_features =
3015                 LvlFindInChain<VkPhysicalDeviceFragmentDensityMapFeaturesEXT>(pCreateInfo->pNext);
3016 
3017             if (fragment_density_map_features && fragment_density_map_features->fragmentDensityMap) {
3018                 if (fragment_shading_rate_features->pipelineFragmentShadingRate) {
3019                     skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-fragmentDensityMap-04481",
3020                                      "vkCreateDevice: Cannot enable fragmentDensityMap and pipelineFragmentShadingRate features "
3021                                      "simultaneously.");
3022                 }
3023                 if (fragment_shading_rate_features->primitiveFragmentShadingRate) {
3024                     skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-fragmentDensityMap-04482",
3025                                      "vkCreateDevice: Cannot enable fragmentDensityMap and primitiveFragmentShadingRate features "
3026                                      "simultaneously.");
3027                 }
3028                 if (fragment_shading_rate_features->attachmentFragmentShadingRate) {
3029                     skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-fragmentDensityMap-04483",
3030                                      "vkCreateDevice: Cannot enable fragmentDensityMap and attachmentFragmentShadingRate features "
3031                                      "simultaneously.");
3032                 }
3033             }
3034         }
3035 
3036         const auto *shader_image_atomic_int64_features =
3037             LvlFindInChain<VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT>(pCreateInfo->pNext);
3038         if (shader_image_atomic_int64_features) {
3039             if (shader_image_atomic_int64_features->sparseImageInt64Atomics &&
3040                 !shader_image_atomic_int64_features->shaderImageInt64Atomics) {
3041                 skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-None-04896",
3042                                  "vkCreateDevice: if shaderImageInt64Atomics feature is enabled then sparseImageInt64Atomics "
3043                                  "feature must also be enabled.");
3044             }
3045         }
3046         const auto *shader_atomic_float_features = LvlFindInChain<VkPhysicalDeviceShaderAtomicFloatFeaturesEXT>(pCreateInfo->pNext);
3047         if (shader_atomic_float_features) {
3048             if (shader_atomic_float_features->sparseImageFloat32Atomics &&
3049                 !shader_atomic_float_features->shaderImageFloat32Atomics) {
3050                 skip |= LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-None-04897",
3051                                  "vkCreateDevice: if sparseImageFloat32Atomics feature is enabled then shaderImageFloat32Atomics "
3052                                  "feature must also be enabled.");
3053             }
3054             if (shader_atomic_float_features->sparseImageFloat32AtomicAdd &&
3055                 !shader_atomic_float_features->shaderImageFloat32AtomicAdd) {
3056                 skip |=
3057                     LogError(pd_state->Handle(), "VUID-VkDeviceCreateInfo-None-04898",
3058                              "vkCreateDevice: if sparseImageFloat32AtomicAdd feature is enabled then shaderImageFloat32AtomicAdd "
3059                              "feature must also be enabled.");
3060             }
3061         }
3062         const auto *shader_atomic_float2_features =
3063             LvlFindInChain<VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT>(pCreateInfo->pNext);
3064         if (shader_atomic_float2_features) {
3065             if (shader_atomic_float2_features->sparseImageFloat32AtomicMinMax &&
3066                 !shader_atomic_float2_features->shaderImageFloat32AtomicMinMax) {
3067                 skip |= LogError(
3068                     pd_state->Handle(), "VUID-VkDeviceCreateInfo-sparseImageFloat32AtomicMinMax-04975",
3069                     "vkCreateDevice: if sparseImageFloat32AtomicMinMax feature is enabled then shaderImageFloat32AtomicMinMax "
3070                     "feature must also be enabled.");
3071             }
3072         }
3073         const auto *device_group_ci = LvlFindInChain<VkDeviceGroupDeviceCreateInfo>(pCreateInfo->pNext);
3074         if (device_group_ci) {
3075             for (uint32_t i = 0; i < device_group_ci->physicalDeviceCount - 1; ++i) {
3076                 for (uint32_t j = i + 1; j < device_group_ci->physicalDeviceCount; ++j) {
3077                     if (device_group_ci->pPhysicalDevices[i] == device_group_ci->pPhysicalDevices[j]) {
3078                         skip |= LogError(pd_state->Handle(), "VUID-VkDeviceGroupDeviceCreateInfo-pPhysicalDevices-00375",
3079                                          "vkCreateDevice: VkDeviceGroupDeviceCreateInfo has a duplicated physical device "
3080                                          "in pPhysicalDevices [%" PRIu32 "] and [%" PRIu32 "].",
3081                                          i, j);
3082                     }
3083                 }
3084             }
3085         }
3086     }
3087     return skip;
3088 }
3089 
PostCallRecordCreateDevice(VkPhysicalDevice gpu,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice,VkResult result)3090 void CoreChecks::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
3091                                             const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
3092     // The state tracker sets up the device state
3093     StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
3094 
3095     // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker refactor
3096     // would be messier without.
3097     // TODO: Find a good way to do this hooklessly.
3098     ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
3099     ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeCoreValidation);
3100     CoreChecks *core_checks = static_cast<CoreChecks *>(validation_data);
3101     core_checks->SetSetImageViewInitialLayoutCallback(
3102         [](CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_STATE &iv_state, VkImageLayout layout) -> void {
3103             cb_node->SetImageViewInitialLayout(iv_state, layout);
3104         });
3105 
3106     // Allocate shader validation cache
3107     if (!disabled[shader_validation_caching] && !disabled[shader_validation] && !core_checks->core_validation_cache) {
3108         std::string validation_cache_path;
3109         auto tmp_path = GetEnvironment("TMPDIR");
3110         if (!tmp_path.size()) tmp_path = GetEnvironment("TMP");
3111         if (!tmp_path.size()) tmp_path = GetEnvironment("TEMP");
3112         if (!tmp_path.size()) tmp_path = "//tmp";
3113         core_checks->validation_cache_path = tmp_path + "//shader_validation_cache";
3114 #if defined(__linux__) || defined(__FreeBSD__)
3115         core_checks->validation_cache_path += "-" + std::to_string(getuid());
3116 #endif
3117         core_checks->validation_cache_path += ".bin";
3118 
3119         std::vector<char> validation_cache_data;
3120         std::ifstream read_file(core_checks->validation_cache_path.c_str(), std::ios::in | std::ios::binary);
3121 
3122         if (read_file) {
3123             std::copy(std::istreambuf_iterator<char>(read_file), {}, std::back_inserter(validation_cache_data));
3124             read_file.close();
3125         } else {
3126             LogInfo(core_checks->device, "VUID-NONE",
3127                     "Cannot open shader validation cache at %s for reading (it may not exist yet)",
3128                     core_checks->validation_cache_path.c_str());
3129         }
3130 
3131         VkValidationCacheCreateInfoEXT cacheCreateInfo = {};
3132         cacheCreateInfo.sType = VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT;
3133         cacheCreateInfo.pNext = NULL;
3134         cacheCreateInfo.initialDataSize = validation_cache_data.size();
3135         cacheCreateInfo.pInitialData = validation_cache_data.data();
3136         cacheCreateInfo.flags = 0;
3137         CoreLayerCreateValidationCacheEXT(*pDevice, &cacheCreateInfo, nullptr, &core_checks->core_validation_cache);
3138     }
3139 }
3140 
PreCallRecordDestroyDevice(VkDevice device,const VkAllocationCallbacks * pAllocator)3141 void CoreChecks::PreCallRecordDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
3142     if (!device) return;
3143     imageLayoutMap.clear();
3144 
3145     StateTracker::PreCallRecordDestroyDevice(device, pAllocator);
3146 
3147     if (core_validation_cache) {
3148         size_t validation_cache_size = 0;
3149         void *validation_cache_data = nullptr;
3150 
3151         CoreLayerGetValidationCacheDataEXT(device, core_validation_cache, &validation_cache_size, nullptr);
3152 
3153         validation_cache_data = (char *)malloc(sizeof(char) * validation_cache_size);
3154         if (!validation_cache_data) {
3155             LogInfo(device, "VUID-NONE", "Validation Cache Memory Error");
3156             return;
3157         }
3158 
3159         VkResult result =
3160             CoreLayerGetValidationCacheDataEXT(device, core_validation_cache, &validation_cache_size, validation_cache_data);
3161 
3162         if (result != VK_SUCCESS) {
3163             LogInfo(device, "VUID-NONE", "Validation Cache Retrieval Error");
3164             return;
3165         }
3166 
3167         FILE *write_file = fopen(validation_cache_path.c_str(), "wb");
3168         if (write_file) {
3169             fwrite(validation_cache_data, sizeof(char), validation_cache_size, write_file);
3170             fclose(write_file);
3171         } else {
3172             LogInfo(device, "VUID-NONE", "Cannot open shader validation cache at %s for writing", validation_cache_path.c_str());
3173         }
3174         free(validation_cache_data);
3175         CoreLayerDestroyValidationCacheEXT(device, core_validation_cache, NULL);
3176     }
3177 }
3178 
ValidateStageMaskHost(const Location & loc,VkPipelineStageFlags2KHR stageMask) const3179 bool CoreChecks::ValidateStageMaskHost(const Location &loc, VkPipelineStageFlags2KHR stageMask) const {
3180     bool skip = false;
3181     if ((stageMask & VK_PIPELINE_STAGE_HOST_BIT) != 0) {
3182         const auto &vuid = sync_vuid_maps::GetQueueSubmitVUID(loc, sync_vuid_maps::SubmitError::kHostStageMask);
3183         skip |= LogError(
3184             device, vuid,
3185             "%s stage mask must not include VK_PIPELINE_STAGE_HOST_BIT as the stage can't be invoked inside a command buffer.",
3186             loc.Message().c_str());
3187     }
3188     return skip;
3189 }
3190 
3191 // Note: This function assumes that the global lock is held by the calling thread.
3192 // For the given queue, verify the queue state up to the given seq number.
3193 // Currently the only check is to make sure that if there are events to be waited on prior to
3194 //  a QueryReset, make sure that all such events have been signalled.
VerifyQueueStateToSeq(const QUEUE_STATE * initial_queue,uint64_t initial_seq) const3195 bool CoreChecks::VerifyQueueStateToSeq(const QUEUE_STATE *initial_queue, uint64_t initial_seq) const {
3196     bool skip = false;
3197 
3198     // sequence number we want to validate up to, per queue
3199     layer_data::unordered_map<const QUEUE_STATE *, uint64_t> target_seqs{{initial_queue, initial_seq}};
3200     // sequence number we've completed validation for, per queue
3201     layer_data::unordered_map<const QUEUE_STATE *, uint64_t> done_seqs;
3202     std::vector<const QUEUE_STATE *> worklist{initial_queue};
3203 
3204     while (worklist.size()) {
3205         auto queue = worklist.back();
3206         worklist.pop_back();
3207 
3208         auto target_seq = target_seqs[queue];
3209         auto seq = std::max(done_seqs[queue], queue->seq);
3210         auto sub_it = queue->submissions.begin() + int(seq - queue->seq);  // seq >= queue->seq
3211 
3212         for (; seq < target_seq; ++sub_it, ++seq) {
3213             for (const auto &wait : sub_it->wait_semaphores) {
3214                 auto other_queue = wait.semaphore->signaler.queue;
3215 
3216                 if (!other_queue || other_queue == queue) continue;  // semaphores /always/ point backwards, so no point here.
3217 
3218                 auto other_target_seq = std::max(target_seqs[other_queue], wait.semaphore->signaler.seq);
3219                 auto other_done_seq = std::max(done_seqs[other_queue], other_queue->seq);
3220 
3221                 // if this wait is for another queue, and covers new sequence
3222                 // numbers beyond what we've already validated, mark the new
3223                 // target seq and (possibly-re)add the queue to the worklist.
3224                 if (other_done_seq < other_target_seq) {
3225                     target_seqs[other_queue] = other_target_seq;
3226                     worklist.push_back(other_queue);
3227                 }
3228             }
3229         }
3230 
3231         // finally mark the point we've now validated this queue to.
3232         done_seqs[queue] = seq;
3233     }
3234 
3235     return skip;
3236 }
3237 
3238 // When the given fence is retired, verify outstanding queue operations through the point of the fence
VerifyQueueStateToFence(VkFence fence) const3239 bool CoreChecks::VerifyQueueStateToFence(VkFence fence) const {
3240     auto fence_state = Get<FENCE_STATE>(fence);
3241     if (fence_state && fence_state->scope == kSyncScopeInternal && nullptr != fence_state->signaler.queue) {
3242         return VerifyQueueStateToSeq(fence_state->signaler.queue, fence_state->signaler.seq);
3243     }
3244     return false;
3245 }
3246 
ValidateCommandBufferSimultaneousUse(const Location & loc,const CMD_BUFFER_STATE * pCB,int current_submit_count) const3247 bool CoreChecks::ValidateCommandBufferSimultaneousUse(const Location &loc, const CMD_BUFFER_STATE *pCB,
3248                                                       int current_submit_count) const {
3249     using sync_vuid_maps::GetQueueSubmitVUID;
3250     using sync_vuid_maps::SubmitError;
3251 
3252     bool skip = false;
3253     if ((pCB->InUse() || current_submit_count > 1) &&
3254         !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
3255         const auto &vuid = sync_vuid_maps::GetQueueSubmitVUID(loc, SubmitError::kCmdNotSimultaneous);
3256 
3257         skip |= LogError(device, vuid, "%s %s is already in use and is not marked for simultaneous use.", loc.Message().c_str(),
3258                          report_data->FormatHandle(pCB->commandBuffer()).c_str());
3259     }
3260     return skip;
3261 }
3262 
ValidateCommandBufferState(const CMD_BUFFER_STATE * cb_state,const char * call_source,int current_submit_count,const char * vu_id) const3263 bool CoreChecks::ValidateCommandBufferState(const CMD_BUFFER_STATE *cb_state, const char *call_source, int current_submit_count,
3264                                             const char *vu_id) const {
3265     bool skip = false;
3266     if (disabled[command_buffer_state]) return skip;
3267     // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
3268     if ((cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
3269         (cb_state->submitCount + current_submit_count > 1)) {
3270         skip |= LogError(cb_state->commandBuffer(), kVUID_Core_DrawState_CommandBufferSingleSubmitViolation,
3271                          "%s was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set, but has been submitted 0x%" PRIxLEAST64
3272                          "times.",
3273                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(), cb_state->submitCount + current_submit_count);
3274     }
3275 
3276     // Validate that cmd buffers have been updated
3277     switch (cb_state->state) {
3278         case CB_INVALID_INCOMPLETE:
3279         case CB_INVALID_COMPLETE:
3280             skip |= ReportInvalidCommandBuffer(cb_state, call_source);
3281             break;
3282 
3283         case CB_NEW:
3284             skip |= LogError(cb_state->commandBuffer(), vu_id, "%s used in the call to %s is unrecorded and contains no commands.",
3285                              report_data->FormatHandle(cb_state->commandBuffer()).c_str(), call_source);
3286             break;
3287 
3288         case CB_RECORDING:
3289             skip |= LogError(cb_state->commandBuffer(), kVUID_Core_DrawState_NoEndCommandBuffer,
3290                              "You must call vkEndCommandBuffer() on %s before this call to %s!",
3291                              report_data->FormatHandle(cb_state->commandBuffer()).c_str(), call_source);
3292             break;
3293 
3294         default: /* recorded */
3295             break;
3296     }
3297     return skip;
3298 }
3299 
3300 // Check that the queue family index of 'queue' matches one of the entries in pQueueFamilyIndices
ValidImageBufferQueue(const CMD_BUFFER_STATE * cb_node,const VulkanTypedHandle & object,uint32_t queueFamilyIndex,uint32_t count,const uint32_t * indices) const3301 bool CoreChecks::ValidImageBufferQueue(const CMD_BUFFER_STATE *cb_node, const VulkanTypedHandle &object, uint32_t queueFamilyIndex,
3302                                        uint32_t count, const uint32_t *indices) const {
3303     bool found = false;
3304     bool skip = false;
3305     for (uint32_t i = 0; i < count; i++) {
3306         if (indices[i] == queueFamilyIndex) {
3307             found = true;
3308             break;
3309         }
3310     }
3311 
3312     if (!found) {
3313         LogObjectList objlist(cb_node->commandBuffer());
3314         objlist.add(object);
3315         skip = LogError(objlist, "VUID-vkQueueSubmit-pSubmits-04626",
3316                         "vkQueueSubmit: %s contains %s which was not created allowing concurrent access to "
3317                         "this queue family %d.",
3318                         report_data->FormatHandle(cb_node->commandBuffer()).c_str(), report_data->FormatHandle(object).c_str(),
3319                         queueFamilyIndex);
3320     }
3321     return skip;
3322 }
3323 
3324 // Validate that queueFamilyIndices of primary command buffers match this queue
3325 // Secondary command buffers were previously validated in vkCmdExecuteCommands().
ValidateQueueFamilyIndices(const Location & loc,const CMD_BUFFER_STATE * pCB,VkQueue queue) const3326 bool CoreChecks::ValidateQueueFamilyIndices(const Location &loc, const CMD_BUFFER_STATE *pCB, VkQueue queue) const {
3327     using sync_vuid_maps::GetQueueSubmitVUID;
3328     using sync_vuid_maps::SubmitError;
3329     bool skip = false;
3330     auto pool = pCB->command_pool;
3331     auto queue_state = Get<QUEUE_STATE>(queue);
3332 
3333     if (pool && queue_state) {
3334         if (pool->queueFamilyIndex != queue_state->queueFamilyIndex) {
3335             LogObjectList objlist(pCB->commandBuffer());
3336             objlist.add(queue);
3337             const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kCmdWrongQueueFamily);
3338             skip |= LogError(objlist, vuid,
3339                              "%s Primary %s created in queue family %d is being submitted on %s "
3340                              "from queue family %d.",
3341                              loc.Message().c_str(), report_data->FormatHandle(pCB->commandBuffer()).c_str(), pool->queueFamilyIndex,
3342                              report_data->FormatHandle(queue).c_str(), queue_state->queueFamilyIndex);
3343         }
3344 
3345         // Ensure that any bound images or buffers created with SHARING_MODE_CONCURRENT have access to the current queue family
3346         for (const auto *base_node : pCB->object_bindings) {
3347             switch (base_node->Type()) {
3348                 case kVulkanObjectTypeImage: {
3349                     auto image_state = static_cast<const IMAGE_STATE *>(base_node);
3350                     if (image_state && image_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
3351                         skip |= ValidImageBufferQueue(pCB, image_state->Handle(), queue_state->queueFamilyIndex,
3352                                                       image_state->createInfo.queueFamilyIndexCount,
3353                                                       image_state->createInfo.pQueueFamilyIndices);
3354                     }
3355                     break;
3356                 }
3357                 case kVulkanObjectTypeBuffer: {
3358                     auto buffer_state = static_cast<const BUFFER_STATE *>(base_node);
3359                     if (buffer_state && buffer_state->createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
3360                         skip |= ValidImageBufferQueue(pCB, buffer_state->Handle(), queue_state->queueFamilyIndex,
3361                                                       buffer_state->createInfo.queueFamilyIndexCount,
3362                                                       buffer_state->createInfo.pQueueFamilyIndices);
3363                     }
3364                     break;
3365                 }
3366                 default:
3367                     break;
3368             }
3369         }
3370     }
3371 
3372     return skip;
3373 }
3374 
ValidatePrimaryCommandBufferState(const Location & loc,const CMD_BUFFER_STATE * pCB,int current_submit_count,QFOTransferCBScoreboards<QFOImageTransferBarrier> * qfo_image_scoreboards,QFOTransferCBScoreboards<QFOBufferTransferBarrier> * qfo_buffer_scoreboards) const3375 bool CoreChecks::ValidatePrimaryCommandBufferState(
3376     const Location &loc, const CMD_BUFFER_STATE *pCB, int current_submit_count,
3377     QFOTransferCBScoreboards<QFOImageTransferBarrier> *qfo_image_scoreboards,
3378     QFOTransferCBScoreboards<QFOBufferTransferBarrier> *qfo_buffer_scoreboards) const {
3379     using sync_vuid_maps::GetQueueSubmitVUID;
3380     using sync_vuid_maps::SubmitError;
3381 
3382     // Track in-use for resources off of primary and any secondary CBs
3383     bool skip = false;
3384 
3385     if (pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
3386         const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kSecondaryCmdInSubmit);
3387         skip |= LogError(pCB->commandBuffer(), vuid, "%s Command buffer %s must be allocated with VK_COMMAND_BUFFER_LEVEL_PRIMARY.",
3388                          loc.Message().c_str(), report_data->FormatHandle(pCB->commandBuffer()).c_str());
3389     } else {
3390         for (const auto *sub_cb : pCB->linkedCommandBuffers) {
3391             skip |= ValidateQueuedQFOTransfers(sub_cb, qfo_image_scoreboards, qfo_buffer_scoreboards);
3392             // TODO: replace with InvalidateCommandBuffers() at recording.
3393             if ((sub_cb->primaryCommandBuffer != pCB->commandBuffer()) &&
3394                 !(sub_cb->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
3395                 LogObjectList objlist(device);
3396                 objlist.add(pCB->commandBuffer());
3397                 objlist.add(sub_cb->commandBuffer());
3398                 objlist.add(sub_cb->primaryCommandBuffer);
3399                 const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kSecondaryCmdNotSimultaneous);
3400                 skip |= LogError(objlist, vuid,
3401                                  "%s %s was submitted with secondary %s but that buffer has subsequently been bound to "
3402                                  "primary %s and it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
3403                                  loc.Message().c_str(), report_data->FormatHandle(pCB->commandBuffer()).c_str(),
3404                                  report_data->FormatHandle(sub_cb->commandBuffer()).c_str(),
3405                                  report_data->FormatHandle(sub_cb->primaryCommandBuffer).c_str());
3406             }
3407         }
3408     }
3409 
3410     // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing on device
3411     skip |= ValidateCommandBufferSimultaneousUse(loc, pCB, current_submit_count);
3412 
3413     skip |= ValidateQueuedQFOTransfers(pCB, qfo_image_scoreboards, qfo_buffer_scoreboards);
3414 
3415     const char *vuid = loc.function == Func::vkQueueSubmit ? "VUID-vkQueueSubmit-pCommandBuffers-00072"
3416                                                            : "VUID-vkQueueSubmit2KHR-commandBuffer-03876";
3417     skip |= ValidateCommandBufferState(pCB, loc.StringFunc().c_str(), current_submit_count, vuid);
3418     return skip;
3419 }
3420 
ValidateFenceForSubmit(const FENCE_STATE * pFence,const char * inflight_vuid,const char * retired_vuid,const char * func_name) const3421 bool CoreChecks::ValidateFenceForSubmit(const FENCE_STATE *pFence, const char *inflight_vuid, const char *retired_vuid,
3422                                         const char *func_name) const {
3423     bool skip = false;
3424 
3425     if (pFence && pFence->scope == kSyncScopeInternal) {
3426         if (pFence->state == FENCE_INFLIGHT) {
3427             skip |= LogError(pFence->fence(), inflight_vuid, "%s: %s is already in use by another submission.", func_name,
3428                              report_data->FormatHandle(pFence->fence()).c_str());
3429         }
3430 
3431         else if (pFence->state == FENCE_RETIRED) {
3432             skip |= LogError(pFence->fence(), retired_vuid,
3433                              "%s: %s submitted in SIGNALED state.  Fences must be reset before being submitted", func_name,
3434                              report_data->FormatHandle(pFence->fence()).c_str());
3435         }
3436     }
3437 
3438     return skip;
3439 }
3440 
PostCallRecordQueueSubmit(VkQueue queue,uint32_t submitCount,const VkSubmitInfo * pSubmits,VkFence fence,VkResult result)3441 void CoreChecks::PostCallRecordQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence,
3442                                            VkResult result) {
3443     StateTracker::PostCallRecordQueueSubmit(queue, submitCount, pSubmits, fence, result);
3444 
3445     if (result != VK_SUCCESS) return;
3446     // The triply nested for duplicates that in the StateTracker, but avoids the need for two additional callbacks.
3447     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
3448         const VkSubmitInfo *submit = &pSubmits[submit_idx];
3449         for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
3450             auto cb_node = Get<CMD_BUFFER_STATE>(submit->pCommandBuffers[i]);
3451             if (cb_node) {
3452                 for (auto *secondary_cmd_buffer : cb_node->linkedCommandBuffers) {
3453                     UpdateCmdBufImageLayouts(secondary_cmd_buffer);
3454                     RecordQueuedQFOTransfers(secondary_cmd_buffer);
3455                 }
3456                 UpdateCmdBufImageLayouts(cb_node.get());
3457                 RecordQueuedQFOTransfers(cb_node.get());
3458             }
3459         }
3460     }
3461 }
3462 
PostCallRecordQueueSubmit2KHR(VkQueue queue,uint32_t submitCount,const VkSubmitInfo2KHR * pSubmits,VkFence fence,VkResult result)3463 void CoreChecks::PostCallRecordQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2KHR *pSubmits, VkFence fence,
3464                                                VkResult result) {
3465     StateTracker::PostCallRecordQueueSubmit2KHR(queue, submitCount, pSubmits, fence, result);
3466 
3467     if (result != VK_SUCCESS) return;
3468     // The triply nested for duplicates that in the StateTracker, but avoids the need for two additional callbacks.
3469     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
3470         const VkSubmitInfo2KHR *submit = &pSubmits[submit_idx];
3471         for (uint32_t i = 0; i < submit->commandBufferInfoCount; i++) {
3472             auto cb_node = Get<CMD_BUFFER_STATE>(submit->pCommandBufferInfos[i].commandBuffer);
3473             if (cb_node) {
3474                 for (auto *secondaryCmdBuffer : cb_node->linkedCommandBuffers) {
3475                     UpdateCmdBufImageLayouts(secondaryCmdBuffer);
3476                     RecordQueuedQFOTransfers(secondaryCmdBuffer);
3477                 }
3478                 UpdateCmdBufImageLayouts(cb_node.get());
3479                 RecordQueuedQFOTransfers(cb_node.get());
3480             }
3481         }
3482     }
3483 }
3484 
SemaphoreWasSignaled(VkSemaphore semaphore) const3485 bool CoreChecks::SemaphoreWasSignaled(VkSemaphore semaphore) const {
3486     return AnyOf<QUEUE_STATE>([semaphore](const QUEUE_STATE &queue_state) {
3487         for (const auto &submission : queue_state.submissions) {
3488             for (const auto &signal_semaphore : submission.signal_semaphores) {
3489                 if (signal_semaphore.semaphore->semaphore() == semaphore) {
3490                     return true;
3491                 }
3492             }
3493         }
3494         return false;
3495     });
3496 }
3497 
3498 struct SemaphoreSubmitState {
3499     const CoreChecks *core;
3500     VkQueueFlags queue_flags;
3501     layer_data::unordered_set<VkSemaphore> signaled_semaphores;
3502     layer_data::unordered_set<VkSemaphore> unsignaled_semaphores;
3503     layer_data::unordered_set<VkSemaphore> internal_semaphores;
3504 
SemaphoreSubmitStateSemaphoreSubmitState3505     SemaphoreSubmitState(const CoreChecks *core_, VkQueueFlags queue_flags_) : core(core_), queue_flags(queue_flags_) {}
3506 
ValidateWaitSemaphoreSemaphoreSubmitState3507     bool ValidateWaitSemaphore(const core_error::Location &loc, VkQueue queue, VkSemaphore semaphore, uint64_t value,
3508                                uint32_t device_Index) {
3509         using sync_vuid_maps::GetQueueSubmitVUID;
3510         using sync_vuid_maps::SubmitError;
3511         bool skip = false;
3512 
3513         const auto pSemaphore = core->Get<SEMAPHORE_STATE>(semaphore);
3514         if (pSemaphore && pSemaphore->type == VK_SEMAPHORE_TYPE_BINARY_KHR &&
3515             (pSemaphore->scope == kSyncScopeInternal || internal_semaphores.count(semaphore))) {
3516             if (unsignaled_semaphores.count(semaphore) ||
3517                 (!(signaled_semaphores.count(semaphore)) && !(pSemaphore->signaled) && !core->SemaphoreWasSignaled(semaphore))) {
3518                 auto error = IsExtEnabled(core->device_extensions.vk_khr_timeline_semaphore)
3519                                  ? SubmitError::kTimelineCannotBeSignalled
3520                                  : SubmitError::kBinaryCannotBeSignalled;
3521                 const auto &vuid = GetQueueSubmitVUID(loc, error);
3522                 LogObjectList objlist(semaphore);
3523                 objlist.add(queue);
3524                 skip |= core->LogError(
3525                     objlist, pSemaphore->scope == kSyncScopeInternal ? vuid : kVUID_Core_DrawState_QueueForwardProgress,
3526                     "%s Queue %s is waiting on semaphore (%s) that has no way to be signaled.", loc.Message().c_str(),
3527                     core->report_data->FormatHandle(queue).c_str(), core->report_data->FormatHandle(semaphore).c_str());
3528             } else {
3529                 signaled_semaphores.erase(semaphore);
3530                 unsignaled_semaphores.insert(semaphore);
3531             }
3532         }
3533         if (pSemaphore && pSemaphore->type == VK_SEMAPHORE_TYPE_BINARY_KHR && pSemaphore->scope == kSyncScopeExternalTemporary) {
3534             internal_semaphores.insert(semaphore);
3535         }
3536         if (pSemaphore && pSemaphore->type == VK_SEMAPHORE_TYPE_BINARY_KHR) {
3537             core->ForEach<QUEUE_STATE>([loc, queue, semaphore, &skip, this](const QUEUE_STATE &q) {
3538                 if (q.Queue() != queue) {
3539                     for (const auto &cb : q.submissions) {
3540                         for (const auto &wait_semaphore : cb.wait_semaphores) {
3541                             if (wait_semaphore.semaphore->semaphore() == semaphore) {
3542                                 const char *vuid = loc.function == core_error::Func::vkQueueSubmit
3543                                                        ? "VUID-vkQueueSubmit-pWaitSemaphores-00068"
3544                                                        : "VUID-vkQueueSubmit2KHR-semaphore-03871";
3545                                 LogObjectList objlist(semaphore);
3546                                 objlist.add(queue);
3547                                 skip |= core->LogError(objlist, vuid, "%s Queue %s is already waiting on semaphore (%s).",
3548                                                        loc.Message().c_str(), core->report_data->FormatHandle(q.Handle()).c_str(),
3549                                                        core->report_data->FormatHandle(semaphore).c_str());
3550                             }
3551                         }
3552                     }
3553                 }
3554             });
3555         }
3556         return skip;
3557     }
3558 
ValidateSignalSemaphoreSemaphoreSubmitState3559     bool ValidateSignalSemaphore(const core_error::Location &loc, VkQueue queue, VkSemaphore semaphore, uint64_t value,
3560                                  uint32_t deviceIndex) {
3561         using sync_vuid_maps::GetQueueSubmitVUID;
3562         using sync_vuid_maps::SubmitError;
3563         bool skip = false;
3564         LogObjectList objlist(semaphore);
3565         objlist.add(queue);
3566 
3567         const auto pSemaphore = core->Get<SEMAPHORE_STATE>(semaphore);
3568         if (pSemaphore && pSemaphore->type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && value <= pSemaphore->payload) {
3569             const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kTimelineSemSmallValue);
3570             skip |= core->LogError(objlist, vuid,
3571                                    "%s signal value (0x%" PRIx64
3572                                    ") in %s must be greater than current timeline semaphore %s value (0x%" PRIx64 ")",
3573                                    loc.Message().c_str(), pSemaphore->payload, core->report_data->FormatHandle(queue).c_str(),
3574                                    core->report_data->FormatHandle(semaphore).c_str(), value);
3575         }
3576         if (pSemaphore && pSemaphore->type == VK_SEMAPHORE_TYPE_BINARY_KHR &&
3577             (pSemaphore->scope == kSyncScopeInternal || internal_semaphores.count(semaphore))) {
3578             if (signaled_semaphores.count(semaphore) || (!(unsignaled_semaphores.count(semaphore)) && pSemaphore->signaled)) {
3579                 objlist.add(pSemaphore->signaler.queue->Handle());
3580                 skip |= core->LogError(objlist, kVUID_Core_DrawState_QueueForwardProgress,
3581                                        "%s is signaling %s (%s) that was previously "
3582                                        "signaled by %s but has not since been waited on by any queue.",
3583                                        loc.Message().c_str(), core->report_data->FormatHandle(queue).c_str(),
3584                                        core->report_data->FormatHandle(semaphore).c_str(),
3585                                        core->report_data->FormatHandle(pSemaphore->signaler.queue->Handle()).c_str());
3586             } else {
3587                 unsignaled_semaphores.erase(semaphore);
3588                 signaled_semaphores.insert(semaphore);
3589             }
3590         }
3591         return skip;
3592     }
3593 };
3594 
ValidateSemaphoresForSubmit(SemaphoreSubmitState & state,VkQueue queue,const VkSubmitInfo * submit,const Location & outer_loc) const3595 bool CoreChecks::ValidateSemaphoresForSubmit(SemaphoreSubmitState &state, VkQueue queue, const VkSubmitInfo *submit,
3596                                              const Location &outer_loc) const {
3597     bool skip = false;
3598     auto *timeline_semaphore_submit_info = LvlFindInChain<VkTimelineSemaphoreSubmitInfo>(submit->pNext);
3599     for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
3600         uint64_t value = 0;
3601         uint32_t device_index = 0;  // TODO:
3602         VkSemaphore semaphore = submit->pWaitSemaphores[i];
3603 
3604         LogObjectList objlist(semaphore);
3605         objlist.add(queue);
3606         if (submit->pWaitDstStageMask) {
3607             auto loc = outer_loc.dot(Field::pWaitDstStageMask, i);
3608             skip |= ValidatePipelineStage(objlist, loc, state.queue_flags, submit->pWaitDstStageMask[i]);
3609             skip |= ValidateStageMaskHost(loc, submit->pWaitDstStageMask[i]);
3610         }
3611         const auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
3612         if (!semaphore_state) {
3613             continue;
3614         }
3615         auto loc = outer_loc.dot(Field::pWaitSemaphores, i);
3616         if (semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE) {
3617             if (timeline_semaphore_submit_info == nullptr) {
3618                 skip |= LogError(semaphore, "VUID-VkSubmitInfo-pWaitSemaphores-03239",
3619                                  "%s (%s) is a timeline semaphore, but VkSubmitInfo does "
3620                                  "not include an instance of VkTimelineSemaphoreSubmitInfo",
3621                                  loc.Message().c_str(), report_data->FormatHandle(semaphore).c_str());
3622                 continue;
3623             } else if (submit->waitSemaphoreCount != timeline_semaphore_submit_info->waitSemaphoreValueCount) {
3624                 skip |= LogError(semaphore, "VUID-VkSubmitInfo-pNext-03240",
3625                                  "%s (%s) is a timeline semaphore, it contains an "
3626                                  "instance of VkTimelineSemaphoreSubmitInfo, but waitSemaphoreValueCount (%u) is different than "
3627                                  "waitSemaphoreCount (%u)",
3628                                  loc.Message().c_str(), report_data->FormatHandle(semaphore).c_str(),
3629                                  timeline_semaphore_submit_info->waitSemaphoreValueCount, submit->waitSemaphoreCount);
3630                 continue;
3631             }
3632             value = timeline_semaphore_submit_info->pWaitSemaphoreValues[i];
3633         }
3634         skip |= state.ValidateWaitSemaphore(outer_loc.dot(Field::pWaitSemaphores, i), queue, semaphore, value, device_index);
3635     }
3636     for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
3637         VkSemaphore semaphore = submit->pSignalSemaphores[i];
3638         uint64_t value = 0;
3639         uint32_t device_index = 0;
3640         const auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
3641         if (!semaphore_state) {
3642             continue;
3643         }
3644         auto loc = outer_loc.dot(Field::pSignalSemaphores, i);
3645         if (semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE) {
3646             if (timeline_semaphore_submit_info == nullptr) {
3647                 skip |= LogError(semaphore, "VUID-VkSubmitInfo-pWaitSemaphores-03239",
3648                                  "%s (%s) is a timeline semaphore, but VkSubmitInfo"
3649                                  "does not include an instance of VkTimelineSemaphoreSubmitInfo",
3650                                  loc.Message().c_str(), report_data->FormatHandle(semaphore).c_str());
3651                 continue;
3652             } else if (submit->signalSemaphoreCount != timeline_semaphore_submit_info->signalSemaphoreValueCount) {
3653                 skip |= LogError(semaphore, "VUID-VkSubmitInfo-pNext-03241",
3654                                  "%s (%s) is a timeline semaphore, it contains an "
3655                                  "instance of VkTimelineSemaphoreSubmitInfo, but signalSemaphoreValueCount (%u) is different than "
3656                                  "signalSemaphoreCount (%u)",
3657                                  loc.Message().c_str(), report_data->FormatHandle(semaphore).c_str(),
3658                                  timeline_semaphore_submit_info->signalSemaphoreValueCount, submit->signalSemaphoreCount);
3659                 continue;
3660             }
3661             value = timeline_semaphore_submit_info->pSignalSemaphoreValues[i];
3662         }
3663         skip |= state.ValidateSignalSemaphore(loc, queue, semaphore, value, device_index);
3664     }
3665     return skip;
3666 }
ValidateSemaphoresForSubmit(SemaphoreSubmitState & state,VkQueue queue,const VkSubmitInfo2KHR * submit,const Location & outer_loc) const3667 bool CoreChecks::ValidateSemaphoresForSubmit(SemaphoreSubmitState &state, VkQueue queue, const VkSubmitInfo2KHR *submit,
3668                                              const Location &outer_loc) const {
3669     bool skip = false;
3670     for (uint32_t i = 0; i < submit->waitSemaphoreInfoCount; ++i) {
3671         const auto &sem_info = submit->pWaitSemaphoreInfos[i];
3672         Location loc = outer_loc.dot(Field::pWaitSemaphoreInfos, i);
3673         skip |= ValidatePipelineStage(LogObjectList(sem_info.semaphore), loc.dot(Field::stageMask), state.queue_flags,
3674                                       sem_info.stageMask);
3675         skip |= ValidateStageMaskHost(loc.dot(Field::stageMask), sem_info.stageMask);
3676         skip |= state.ValidateWaitSemaphore(loc, queue, sem_info.semaphore, sem_info.value, sem_info.deviceIndex);
3677     }
3678     for (uint32_t i = 0; i < submit->signalSemaphoreInfoCount; ++i) {
3679         const auto &sem_info = submit->pSignalSemaphoreInfos[i];
3680         auto loc = outer_loc.dot(Field::pSignalSemaphoreInfos, i);
3681         skip |= ValidatePipelineStage(LogObjectList(sem_info.semaphore), loc.dot(Field::stageMask), state.queue_flags,
3682                                       sem_info.stageMask);
3683         skip |= ValidateStageMaskHost(loc.dot(Field::stageMask), sem_info.stageMask);
3684         skip |= state.ValidateSignalSemaphore(loc, queue, sem_info.semaphore, sem_info.value, sem_info.deviceIndex);
3685     }
3686     return skip;
3687 }
3688 
ValidateMaxTimelineSemaphoreValueDifference(const Location & loc,VkSemaphore semaphore,uint64_t value) const3689 bool CoreChecks::ValidateMaxTimelineSemaphoreValueDifference(const Location &loc, VkSemaphore semaphore, uint64_t value) const {
3690     using sync_vuid_maps::GetQueueSubmitVUID;
3691     using sync_vuid_maps::SubmitError;
3692     bool skip = false;
3693     const auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
3694 
3695     if (semaphore_state->type != VK_SEMAPHORE_TYPE_TIMELINE) return false;
3696 
3697     uint64_t diff = value > semaphore_state->payload ? value - semaphore_state->payload : semaphore_state->payload - value;
3698 
3699     if (diff > phys_dev_props_core12.maxTimelineSemaphoreValueDifference) {
3700         const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kTimelineSemMaxDiff);
3701         skip |= LogError(semaphore, vuid, "%s value exceeds limit regarding current semaphore %s payload", loc.Message().c_str(),
3702                          report_data->FormatHandle(semaphore).c_str());
3703     }
3704 
3705     ForEach<QUEUE_STATE>([&skip, loc, value, semaphore, this](const QUEUE_STATE &queue_state) {
3706         for (const auto &submission : queue_state.submissions) {
3707             for (const auto &signal_semaphore : submission.signal_semaphores) {
3708                 if (signal_semaphore.semaphore->semaphore() == semaphore) {
3709                     uint64_t diff =
3710                         value > signal_semaphore.payload ? value - signal_semaphore.payload : signal_semaphore.payload - value;
3711                     if (diff > phys_dev_props_core12.maxTimelineSemaphoreValueDifference) {
3712                         const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kTimelineSemMaxDiff);
3713                         skip |= LogError(semaphore, vuid, "%s value exceeds limit regarding pending semaphore %s signal value",
3714                                          loc.Message().c_str(), report_data->FormatHandle(semaphore).c_str());
3715                     }
3716                 }
3717             }
3718             for (const auto &wait_semaphore : submission.wait_semaphores) {
3719                 if (wait_semaphore.semaphore->semaphore() == semaphore) {
3720                     uint64_t diff =
3721                         value > wait_semaphore.payload ? value - wait_semaphore.payload : wait_semaphore.payload - value;
3722                     if (diff > phys_dev_props_core12.maxTimelineSemaphoreValueDifference) {
3723                         const auto &vuid = GetQueueSubmitVUID(loc, SubmitError::kTimelineSemMaxDiff);
3724                         skip |= LogError(semaphore, vuid, "%s value exceeds limit regarding pending semaphore %s wait value",
3725                                          loc.Message().c_str(), report_data->FormatHandle(semaphore).c_str());
3726                     }
3727                 }
3728             }
3729         }
3730     });
3731 
3732     return skip;
3733 }
3734 
3735 struct CommandBufferSubmitState {
3736     const CoreChecks *core;
3737     const QUEUE_STATE *queue_state;
3738     QFOTransferCBScoreboards<QFOImageTransferBarrier> qfo_image_scoreboards;
3739     QFOTransferCBScoreboards<QFOBufferTransferBarrier> qfo_buffer_scoreboards;
3740     vector<VkCommandBuffer> current_cmds;
3741     GlobalImageLayoutMap overlay_image_layout_map;
3742     QueryMap local_query_to_state_map;
3743     EventToStageMap local_event_to_stage_map;
3744 
CommandBufferSubmitStateCommandBufferSubmitState3745     CommandBufferSubmitState(const CoreChecks *c, const char *func, const QUEUE_STATE *q) : core(c), queue_state(q) {}
3746 
ValidateCommandBufferSubmitState3747     bool Validate(const core_error::Location &loc, const CMD_BUFFER_STATE &cb_node, uint32_t perf_pass) {
3748         bool skip = false;
3749         skip |= core->ValidateCmdBufImageLayouts(loc, &cb_node, core->imageLayoutMap, overlay_image_layout_map);
3750         auto cmd = cb_node.commandBuffer();
3751         current_cmds.push_back(cmd);
3752         skip |= core->ValidatePrimaryCommandBufferState(loc, &cb_node,
3753                                                         static_cast<int>(std::count(current_cmds.begin(), current_cmds.end(), cmd)),
3754                                                         &qfo_image_scoreboards, &qfo_buffer_scoreboards);
3755         skip |= core->ValidateQueueFamilyIndices(loc, &cb_node, queue_state->Queue());
3756 
3757         for (const auto &descriptor_set : cb_node.validate_descriptorsets_in_queuesubmit) {
3758             const auto set_node = core->Get<cvdescriptorset::DescriptorSet>(descriptor_set.first);
3759             if (!set_node) {
3760                 continue;
3761             }
3762             for (const auto &cmd_info : descriptor_set.second) {
3763                 std::string function = loc.StringFunc();
3764                 function += ", ";
3765                 function += CommandTypeString(cmd_info.cmd_type);
3766                 for (const auto &binding_info : cmd_info.binding_infos) {
3767                     std::string error;
3768                     std::vector<uint32_t> dynamic_offsets;
3769                     // dynamic data isn't allowed in UPDATE_AFTER_BIND, so dynamicOffsets is always empty.
3770                     // This submit time not record time...
3771                     const bool record_time_validate = false;
3772                     layer_data::optional<layer_data::unordered_map<VkImageView, VkImageLayout>> checked_layouts;
3773                     if (set_node->GetTotalDescriptorCount() > cvdescriptorset::PrefilterBindRequestMap::kManyDescriptors_) {
3774                         checked_layouts.emplace();
3775                     }
3776                     skip |= core->ValidateDescriptorSetBindingData(&cb_node, set_node.get(), dynamic_offsets, binding_info,
3777                                                                    cmd_info.framebuffer, cmd_info.attachments.get(),
3778                                                                    cmd_info.subpasses.get(), record_time_validate, function.c_str(),
3779                                                                    core->GetDrawDispatchVuid(cmd_info.cmd_type), checked_layouts);
3780                 }
3781             }
3782         }
3783 
3784         // Potential early exit here as bad object state may crash in delayed function calls
3785         if (skip) {
3786             return true;
3787         }
3788 
3789         // Call submit-time functions to validate or update local mirrors of state (to preserve const-ness at validate time)
3790         for (auto &function : cb_node.queue_submit_functions) {
3791             skip |= function(*core, *queue_state, cb_node);
3792         }
3793         for (auto &function : cb_node.eventUpdates) {
3794             skip |= function(core, /*do_validate*/ true, &local_event_to_stage_map);
3795         }
3796         VkQueryPool first_perf_query_pool = VK_NULL_HANDLE;
3797         for (auto &function : cb_node.queryUpdates) {
3798             skip |= function(core, /*do_validate*/ true, first_perf_query_pool, perf_pass, &local_query_to_state_map);
3799         }
3800         return skip;
3801     }
3802 };
3803 
PreCallValidateQueueSubmit(VkQueue queue,uint32_t submitCount,const VkSubmitInfo * pSubmits,VkFence fence) const3804 bool CoreChecks::PreCallValidateQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
3805                                             VkFence fence) const {
3806     const auto fence_state = Get<FENCE_STATE>(fence);
3807     bool skip = ValidateFenceForSubmit(fence_state.get(), "VUID-vkQueueSubmit-fence-00064", "VUID-vkQueueSubmit-fence-00063",
3808                                        "vkQueueSubmit()");
3809     if (skip) {
3810         return true;
3811     }
3812     const auto queue_state = Get<QUEUE_STATE>(queue);
3813     CommandBufferSubmitState cb_submit_state(this, "vkQueueSubmit()", queue_state.get());
3814     SemaphoreSubmitState sem_submit_state(this,
3815                                           physical_device_state->queue_family_properties[queue_state->queueFamilyIndex].queueFlags);
3816 
3817     // Now verify each individual submit
3818     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
3819         const VkSubmitInfo *submit = &pSubmits[submit_idx];
3820         const auto perf_submit = LvlFindInChain<VkPerformanceQuerySubmitInfoKHR>(submit->pNext);
3821         uint32_t perf_pass = perf_submit ? perf_submit->counterPassIndex : 0;
3822 
3823         Location loc(Func::vkQueueSubmit, Struct::VkSubmitInfo, Field::pSubmits, submit_idx);
3824         for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
3825             const auto cb_state = Get<CMD_BUFFER_STATE>(submit->pCommandBuffers[i]);
3826             skip |= cb_submit_state.Validate(loc.dot(Field::pCommandBuffers, i), *cb_state, perf_pass);
3827         }
3828         skip |= ValidateSemaphoresForSubmit(sem_submit_state, queue, submit, loc);
3829 
3830         auto chained_device_group_struct = LvlFindInChain<VkDeviceGroupSubmitInfo>(submit->pNext);
3831         if (chained_device_group_struct && chained_device_group_struct->commandBufferCount > 0) {
3832             for (uint32_t i = 0; i < chained_device_group_struct->commandBufferCount; ++i) {
3833                 skip |= ValidateDeviceMaskToPhysicalDeviceCount(chained_device_group_struct->pCommandBufferDeviceMasks[i], queue,
3834                                                                 "VUID-VkDeviceGroupSubmitInfo-pCommandBufferDeviceMasks-00086");
3835             }
3836             if (chained_device_group_struct->signalSemaphoreCount != submit->signalSemaphoreCount) {
3837                 skip |= LogError(queue, "VUID-VkDeviceGroupSubmitInfo-signalSemaphoreCount-00084",
3838                                  "pSubmits[%" PRIu32 "] signalSemaphoreCount (%" PRIu32
3839                                  ") is different than signalSemaphoreCount (%" PRIu32
3840                                  ") of the VkDeviceGroupSubmitInfo in its pNext chain",
3841                                  submit_idx, submit->signalSemaphoreCount, chained_device_group_struct->signalSemaphoreCount);
3842             }
3843             if (chained_device_group_struct->waitSemaphoreCount != submit->waitSemaphoreCount) {
3844                 skip |=
3845                     LogError(queue, "VUID-VkDeviceGroupSubmitInfo-waitSemaphoreCount-00082",
3846                              "pSubmits[%" PRIu32 "] waitSemaphoreCount (%" PRIu32 ") is different than waitSemaphoreCount (%" PRIu32
3847                              ") of the VkDeviceGroupSubmitInfo in its pNext chain",
3848                              submit_idx, submit->waitSemaphoreCount, chained_device_group_struct->waitSemaphoreCount);
3849             }
3850             if (chained_device_group_struct->commandBufferCount != submit->commandBufferCount) {
3851                 skip |=
3852                     LogError(queue, "VUID-VkDeviceGroupSubmitInfo-commandBufferCount-00083",
3853                              "pSubmits[%" PRIu32 "] commandBufferCount (%" PRIu32 ") is different than commandBufferCount (%" PRIu32
3854                              ") of the VkDeviceGroupSubmitInfo in its pNext chain",
3855                              submit_idx, submit->commandBufferCount, chained_device_group_struct->commandBufferCount);
3856             }
3857         }
3858 
3859         auto protected_submit_info = LvlFindInChain<VkProtectedSubmitInfo>(submit->pNext);
3860         if (protected_submit_info) {
3861             const bool protected_submit = protected_submit_info->protectedSubmit == VK_TRUE;
3862             if ((protected_submit == true) && ((queue_state->flags & VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT) == 0)) {
3863                 skip |= LogError(queue, "VUID-vkQueueSubmit-queue-06448",
3864                                  "vkQueueSubmit(): pSubmits[%u] contains a protected submission to %s which was not created with "
3865                                  "VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT",
3866                                  submit_idx, report_data->FormatHandle(queue).c_str());
3867             }
3868 
3869             // Make sure command buffers are all protected or unprotected
3870             for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
3871                 const auto cb_state = Get<CMD_BUFFER_STATE>(submit->pCommandBuffers[i]);
3872                 if (cb_state) {
3873                     if ((cb_state->unprotected == true) && (protected_submit == true)) {
3874                         LogObjectList objlist(cb_state->commandBuffer());
3875                         objlist.add(queue);
3876                         skip |= LogError(objlist, "VUID-VkSubmitInfo-pNext-04148",
3877                                          "vkQueueSubmit(): command buffer %s is unprotected while queue %s pSubmits[%u] has "
3878                                          "VkProtectedSubmitInfo:protectedSubmit set to VK_TRUE",
3879                                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
3880                                          report_data->FormatHandle(queue).c_str(), submit_idx);
3881                     }
3882                     if ((cb_state->unprotected == false) && (protected_submit == false)) {
3883                         LogObjectList objlist(cb_state->commandBuffer());
3884                         objlist.add(queue);
3885                         skip |= LogError(objlist, "VUID-VkSubmitInfo-pNext-04120",
3886                                          "vkQueueSubmit(): command buffer %s is protected while queue %s pSubmits[%u] has "
3887                                          "VkProtectedSubmitInfo:protectedSubmit set to VK_FALSE",
3888                                          report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
3889                                          report_data->FormatHandle(queue).c_str(), submit_idx);
3890                     }
3891                 }
3892             }
3893         }
3894     }
3895 
3896     if (skip) return skip;
3897 
3898     // Now verify maxTimelineSemaphoreValueDifference
3899     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
3900         Location loc(Func::vkQueueSubmit, Struct::VkSubmitInfo, Field::pSubmits, submit_idx);
3901         const VkSubmitInfo *submit = &pSubmits[submit_idx];
3902         auto *info = LvlFindInChain<VkTimelineSemaphoreSubmitInfo>(submit->pNext);
3903         if (info) {
3904             // If there are any timeline semaphores, this condition gets checked before the early return above
3905             if (info->waitSemaphoreValueCount) {
3906                 for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
3907                     VkSemaphore semaphore = submit->pWaitSemaphores[i];
3908                     skip |= ValidateMaxTimelineSemaphoreValueDifference(loc.dot(Field::pWaitSemaphores, i), semaphore,
3909                                                                         info->pWaitSemaphoreValues[i]);
3910                 }
3911             }
3912             // If there are any timeline semaphores, this condition gets checked before the early return above
3913             if (info->signalSemaphoreValueCount) {
3914                 for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
3915                     VkSemaphore semaphore = submit->pSignalSemaphores[i];
3916                     skip |= ValidateMaxTimelineSemaphoreValueDifference(loc.dot(Field::pSignalSemaphores, i), semaphore,
3917                                                                         info->pSignalSemaphoreValues[i]);
3918                 }
3919             }
3920         }
3921     }
3922 
3923     return skip;
3924 }
3925 
PreCallValidateQueueSubmit2KHR(VkQueue queue,uint32_t submitCount,const VkSubmitInfo2KHR * pSubmits,VkFence fence) const3926 bool CoreChecks::PreCallValidateQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2KHR *pSubmits,
3927                                                 VkFence fence) const {
3928     const auto pFence = Get<FENCE_STATE>(fence);
3929     bool skip = ValidateFenceForSubmit(pFence.get(), "VUID-vkQueueSubmit2KHR-fence-04895", "VUID-vkQueueSubmit2KHR-fence-04894",
3930                                        "vkQueueSubmit2KHR()");
3931     if (skip) {
3932         return true;
3933     }
3934 
3935     if (!enabled_features.synchronization2_features.synchronization2) {
3936         skip |= LogError(queue, "VUID-vkQueueSubmit2KHR-synchronization2-03866",
3937                          "vkQueueSubmit2KHR(): Synchronization2 feature is not enabled");
3938     }
3939 
3940     const auto queue_state = Get<QUEUE_STATE>(queue);
3941     CommandBufferSubmitState cb_submit_state(this, "vkQueueSubmit2KHR()", queue_state.get());
3942     SemaphoreSubmitState sem_submit_state(this,
3943                                           physical_device_state->queue_family_properties[queue_state->queueFamilyIndex].queueFlags);
3944 
3945     // Now verify each individual submit
3946     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
3947         const VkSubmitInfo2KHR *submit = &pSubmits[submit_idx];
3948         const auto perf_submit = LvlFindInChain<VkPerformanceQuerySubmitInfoKHR>(submit->pNext);
3949         uint32_t perf_pass = perf_submit ? perf_submit->counterPassIndex : 0;
3950         Location loc(Func::vkQueueSubmit2KHR, Struct::VkSubmitInfo2KHR, Field::pSubmits, submit_idx);
3951 
3952         skip |= ValidateSemaphoresForSubmit(sem_submit_state, queue, submit, loc);
3953 
3954         bool protected_submit = (submit->flags & VK_SUBMIT_PROTECTED_BIT_KHR) != 0;
3955         if ((protected_submit == true) && ((queue_state->flags & VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT)) == 0) {
3956             skip |= LogError(queue, "VUID-vkQueueSubmit2KHR-queue-06447",
3957                              "vkQueueSubmit2KHR(): pSubmits[%u] contains a protected submission to %s which was not created with "
3958                              "VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT",
3959                              submit_idx, report_data->FormatHandle(queue).c_str());
3960         }
3961 
3962         for (uint32_t i = 0; i < submit->commandBufferInfoCount; i++) {
3963             auto info_loc = loc.dot(Field::pCommandBufferInfos, i);
3964             info_loc.structure = Struct::VkCommandBufferSubmitInfoKHR;
3965             const auto cb_state = Get<CMD_BUFFER_STATE>(submit->pCommandBufferInfos[i].commandBuffer);
3966             skip |= cb_submit_state.Validate(info_loc.dot(Field::commandBuffer), *cb_state, perf_pass);
3967 
3968             skip |= ValidateDeviceMaskToPhysicalDeviceCount(submit->pCommandBufferInfos[i].deviceMask, queue,
3969                                                             "VUID-VkCommandBufferSubmitInfoKHR-deviceMask-03891");
3970 
3971             // Make sure command buffers are all protected or unprotected
3972             if (cb_state != nullptr) {
3973                 if ((cb_state->unprotected == true) && (protected_submit == true)) {
3974                     LogObjectList objlist(cb_state->commandBuffer());
3975                     objlist.add(queue);
3976                     skip |= LogError(objlist, "VUID-VkSubmitInfo2KHR-flags-03886",
3977                                      "vkQueueSubmit2KHR(): command buffer %s is unprotected while queue %s pSubmits[%u] has "
3978                                      "VK_SUBMIT_PROTECTED_BIT_KHR set",
3979                                      report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
3980                                      report_data->FormatHandle(queue).c_str(), submit_idx);
3981                 }
3982                 if ((cb_state->unprotected == false) && (protected_submit == false)) {
3983                     LogObjectList objlist(cb_state->commandBuffer());
3984                     objlist.add(queue);
3985                     skip |= LogError(objlist, "VUID-VkSubmitInfo2KHR-flags-03887",
3986                                      "vkQueueSubmit2KHR(): command buffer %s is protected while queue %s pSubmitInfos[%u] has "
3987                                      "VK_SUBMIT_PROTECTED_BIT_KHR not set",
3988                                      report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
3989                                      report_data->FormatHandle(queue).c_str(), submit_idx);
3990                 }
3991             }
3992         }
3993     }
3994 
3995     if (skip) return skip;
3996 
3997     // Now verify maxTimelineSemaphoreValueDifference
3998     for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
3999         const VkSubmitInfo2KHR *submit = &pSubmits[submit_idx];
4000         Location outer_loc(Func::vkQueueSubmit2KHR, Struct::VkSubmitInfo2KHR, Field::pSubmits, submit_idx);
4001         // If there are any timeline semaphores, this condition gets checked before the early return above
4002         for (uint32_t i = 0; i < submit->waitSemaphoreInfoCount; ++i) {
4003             const auto *sem_info = &submit->pWaitSemaphoreInfos[i];
4004             auto loc = outer_loc.dot(Field::pWaitSemaphoreInfos, i);
4005             skip |= ValidateMaxTimelineSemaphoreValueDifference(loc.dot(Field::semaphore), sem_info->semaphore, sem_info->value);
4006         }
4007         // If there are any timeline semaphores, this condition gets checked before the early return above
4008         for (uint32_t i = 0; i < submit->signalSemaphoreInfoCount; ++i) {
4009             const auto *sem_info = &submit->pSignalSemaphoreInfos[i];
4010             auto loc = outer_loc.dot(Field::pSignalSemaphoreInfos, i);
4011             skip |= ValidateMaxTimelineSemaphoreValueDifference(loc.dot(Field::semaphore), sem_info->semaphore, sem_info->value);
4012         }
4013     }
4014 
4015     return skip;
4016 }
4017 
4018 #ifdef AHB_VALIDATION_SUPPORT
4019 // Android-specific validation that uses types defined only on Android and only for NDK versions
4020 // that support the VK_ANDROID_external_memory_android_hardware_buffer extension.
4021 // This chunk could move into a seperate core_validation_android.cpp file... ?
4022 
4023 // clang-format off
4024 
4025 // Map external format and usage flags to/from equivalent Vulkan flags
4026 // (Tables as of v1.1.92)
4027 
4028 // AHardwareBuffer Format                       Vulkan Format
4029 // ======================                       =============
4030 // AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM        VK_FORMAT_R8G8B8A8_UNORM
4031 // AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM        VK_FORMAT_R8G8B8A8_UNORM
4032 // AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM          VK_FORMAT_R8G8B8_UNORM
4033 // AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM          VK_FORMAT_R5G6B5_UNORM_PACK16
4034 // AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT    VK_FORMAT_R16G16B16A16_SFLOAT
4035 // AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM     VK_FORMAT_A2B10G10R10_UNORM_PACK32
4036 // AHARDWAREBUFFER_FORMAT_D16_UNORM             VK_FORMAT_D16_UNORM
4037 // AHARDWAREBUFFER_FORMAT_D24_UNORM             VK_FORMAT_X8_D24_UNORM_PACK32
4038 // AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT     VK_FORMAT_D24_UNORM_S8_UINT
4039 // AHARDWAREBUFFER_FORMAT_D32_FLOAT             VK_FORMAT_D32_SFLOAT
4040 // AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT     VK_FORMAT_D32_SFLOAT_S8_UINT
4041 // AHARDWAREBUFFER_FORMAT_S8_UINT               VK_FORMAT_S8_UINT
4042 
4043 // The AHARDWAREBUFFER_FORMAT_* are an enum in the NDK headers, but get passed in to Vulkan
4044 // as uint32_t. Casting the enums here avoids scattering casts around in the code.
4045 std::map<uint32_t, VkFormat> ahb_format_map_a2v = {
4046     { (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,        VK_FORMAT_R8G8B8A8_UNORM },
4047     { (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,        VK_FORMAT_R8G8B8A8_UNORM },
4048     { (uint32_t)AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM,          VK_FORMAT_R8G8B8_UNORM },
4049     { (uint32_t)AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,          VK_FORMAT_R5G6B5_UNORM_PACK16 },
4050     { (uint32_t)AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,    VK_FORMAT_R16G16B16A16_SFLOAT },
4051     { (uint32_t)AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,     VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
4052     { (uint32_t)AHARDWAREBUFFER_FORMAT_D16_UNORM,             VK_FORMAT_D16_UNORM },
4053     { (uint32_t)AHARDWAREBUFFER_FORMAT_D24_UNORM,             VK_FORMAT_X8_D24_UNORM_PACK32 },
4054     { (uint32_t)AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,     VK_FORMAT_D24_UNORM_S8_UINT },
4055     { (uint32_t)AHARDWAREBUFFER_FORMAT_D32_FLOAT,             VK_FORMAT_D32_SFLOAT },
4056     { (uint32_t)AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,     VK_FORMAT_D32_SFLOAT_S8_UINT },
4057     { (uint32_t)AHARDWAREBUFFER_FORMAT_S8_UINT,               VK_FORMAT_S8_UINT }
4058 };
4059 
4060 // AHardwareBuffer Usage                        Vulkan Usage or Creation Flag (Intermixed - Aargh!)
4061 // =====================                        ===================================================
4062 // None                                         VK_IMAGE_USAGE_TRANSFER_SRC_BIT
4063 // None                                         VK_IMAGE_USAGE_TRANSFER_DST_BIT
4064 // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      VK_IMAGE_USAGE_SAMPLED_BIT
4065 // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
4066 // AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
4067 // AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
4068 // AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP           VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
4069 // AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE    None
4070 // AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      VK_IMAGE_CREATE_PROTECTED_BIT
4071 // None                                         VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
4072 // None                                         VK_IMAGE_CREATE_EXTENDED_USAGE_BIT
4073 
4074 // Same casting rationale. De-mixing the table to prevent type confusion and aliasing
4075 std::map<uint64_t, VkImageUsageFlags> ahb_usage_map_a2v = {
4076     { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,    (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) },
4077     { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,     (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) },
4078     { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE,  0 },   // No equivalent
4079 };
4080 
4081 std::map<uint64_t, VkImageCreateFlags> ahb_create_map_a2v = {
4082     { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP,         VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT },
4083     { (uint64_t)AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT,    VK_IMAGE_CREATE_PROTECTED_BIT },
4084     { (uint64_t)AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE,  0 },   // No equivalent
4085 };
4086 
4087 std::map<VkImageUsageFlags, uint64_t> ahb_usage_map_v2a = {
4088     { VK_IMAGE_USAGE_SAMPLED_BIT,           (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE },
4089     { VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE },
4090     { VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER  },
4091     { VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER  },
4092 };
4093 
4094 std::map<VkImageCreateFlags, uint64_t> ahb_create_map_v2a = {
4095     { VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,  (uint64_t)AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP },
4096     { VK_IMAGE_CREATE_PROTECTED_BIT,        (uint64_t)AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT },
4097 };
4098 
4099 // clang-format on
4100 
4101 //
4102 // AHB-extension new APIs
4103 //
PreCallValidateGetAndroidHardwareBufferPropertiesANDROID(VkDevice device,const struct AHardwareBuffer * buffer,VkAndroidHardwareBufferPropertiesANDROID * pProperties) const4104 bool CoreChecks::PreCallValidateGetAndroidHardwareBufferPropertiesANDROID(
4105     VkDevice device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties) const {
4106     bool skip = false;
4107     //  buffer must be a valid Android hardware buffer object with at least one of the AHARDWAREBUFFER_USAGE_GPU_* usage flags.
4108     AHardwareBuffer_Desc ahb_desc;
4109     AHardwareBuffer_describe(buffer, &ahb_desc);
4110     uint32_t required_flags = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
4111                               AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
4112                               AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
4113     if (0 == (ahb_desc.usage & required_flags)) {
4114         skip |= LogError(device, "VUID-vkGetAndroidHardwareBufferPropertiesANDROID-buffer-01884",
4115                          "vkGetAndroidHardwareBufferPropertiesANDROID: The AHardwareBuffer's AHardwareBuffer_Desc.usage (0x%" PRIx64
4116                          ") does not have any AHARDWAREBUFFER_USAGE_GPU_* flags set.",
4117                          ahb_desc.usage);
4118     }
4119     return skip;
4120 }
4121 
PreCallValidateGetMemoryAndroidHardwareBufferANDROID(VkDevice device,const VkMemoryGetAndroidHardwareBufferInfoANDROID * pInfo,struct AHardwareBuffer ** pBuffer) const4122 bool CoreChecks::PreCallValidateGetMemoryAndroidHardwareBufferANDROID(VkDevice device,
4123                                                                       const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
4124                                                                       struct AHardwareBuffer **pBuffer) const {
4125     bool skip = false;
4126     const auto mem_info = Get<DEVICE_MEMORY_STATE>(pInfo->memory);
4127 
4128     // VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must have been included in
4129     // VkExportMemoryAllocateInfo::handleTypes when memory was created.
4130     if (!mem_info->IsExport() ||
4131         (0 == (mem_info->export_handle_type_flags & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))) {
4132         skip |= LogError(device, "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-handleTypes-01882",
4133                          "vkGetMemoryAndroidHardwareBufferANDROID: %s was not allocated for export, or the "
4134                          "export handleTypes (0x%" PRIx32
4135                          ") did not contain VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
4136                          report_data->FormatHandle(pInfo->memory).c_str(), mem_info->export_handle_type_flags);
4137     }
4138 
4139     // If the pNext chain of the VkMemoryAllocateInfo used to allocate memory included a VkMemoryDedicatedAllocateInfo
4140     // with non-NULL image member, then that image must already be bound to memory.
4141     if (mem_info->IsDedicatedImage()) {
4142         const auto image_state = Get<IMAGE_STATE>(mem_info->dedicated->handle.Cast<VkImage>());
4143         if ((nullptr == image_state) || (0 == (image_state->GetBoundMemory().count(mem_info->mem())))) {
4144             LogObjectList objlist(device);
4145             objlist.add(pInfo->memory);
4146             objlist.add(mem_info->dedicated->handle);
4147             skip |= LogError(objlist, "VUID-VkMemoryGetAndroidHardwareBufferInfoANDROID-pNext-01883",
4148                              "vkGetMemoryAndroidHardwareBufferANDROID: %s was allocated using a dedicated "
4149                              "%s, but that image is not bound to the VkDeviceMemory object.",
4150                              report_data->FormatHandle(pInfo->memory).c_str(),
4151                              report_data->FormatHandle(mem_info->dedicated->handle).c_str());
4152         }
4153     }
4154 
4155     return skip;
4156 }
4157 
4158 //
4159 // AHB-specific validation within non-AHB APIs
4160 //
ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo * alloc_info) const4161 bool CoreChecks::ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo *alloc_info) const {
4162     bool skip = false;
4163     auto import_ahb_info = LvlFindInChain<VkImportAndroidHardwareBufferInfoANDROID>(alloc_info->pNext);
4164     auto exp_mem_alloc_info = LvlFindInChain<VkExportMemoryAllocateInfo>(alloc_info->pNext);
4165     auto mem_ded_alloc_info = LvlFindInChain<VkMemoryDedicatedAllocateInfo>(alloc_info->pNext);
4166 
4167     if ((import_ahb_info) && (NULL != import_ahb_info->buffer)) {
4168         // This is an import with handleType of VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
4169         AHardwareBuffer_Desc ahb_desc = {};
4170         AHardwareBuffer_describe(import_ahb_info->buffer, &ahb_desc);
4171 
4172         //  Validate AHardwareBuffer_Desc::usage is a valid usage for imported AHB
4173         //
4174         //  BLOB & GPU_DATA_BUFFER combo specifically allowed
4175         if ((AHARDWAREBUFFER_FORMAT_BLOB != ahb_desc.format) || (0 == (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
4176             // Otherwise, must be a combination from the AHardwareBuffer Format and Usage Equivalence tables
4177             // Usage must have at least one bit from the table. It may have additional bits not in the table
4178             uint64_t ahb_equiv_usage_bits = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
4179                                             AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP | AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE |
4180                                             AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
4181             if (0 == (ahb_desc.usage & ahb_equiv_usage_bits)) {
4182                 skip |=
4183                     LogError(device, "VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01881",
4184                              "vkAllocateMemory: The AHardwareBuffer_Desc's usage (0x%" PRIx64 ") is not compatible with Vulkan.",
4185                              ahb_desc.usage);
4186             }
4187         }
4188 
4189         // Collect external buffer info
4190         auto pdebi = LvlInitStruct<VkPhysicalDeviceExternalBufferInfo>();
4191         pdebi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
4192         if (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE & ahb_desc.usage) {
4193             pdebi.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE];
4194         }
4195         if (AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER & ahb_desc.usage) {
4196             pdebi.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER];
4197         }
4198         auto ext_buf_props = LvlInitStruct<VkExternalBufferProperties>();
4199         DispatchGetPhysicalDeviceExternalBufferProperties(physical_device, &pdebi, &ext_buf_props);
4200 
4201         //  If buffer is not NULL, Android hardware buffers must be supported for import, as reported by
4202         //  VkExternalImageFormatProperties or VkExternalBufferProperties.
4203         if (0 == (ext_buf_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) {
4204             // Collect external format info
4205             auto pdeifi = LvlInitStruct<VkPhysicalDeviceExternalImageFormatInfo>();
4206             pdeifi.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
4207             auto pdifi2 = LvlInitStruct<VkPhysicalDeviceImageFormatInfo2>(&pdeifi);
4208             if (0 < ahb_format_map_a2v.count(ahb_desc.format)) pdifi2.format = ahb_format_map_a2v[ahb_desc.format];
4209             pdifi2.type = VK_IMAGE_TYPE_2D;           // Seems likely
4210             pdifi2.tiling = VK_IMAGE_TILING_OPTIMAL;  // Ditto
4211             if (AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE & ahb_desc.usage) {
4212                 pdifi2.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE];
4213             }
4214             if (AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER & ahb_desc.usage) {
4215                 pdifi2.usage |= ahb_usage_map_a2v[AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER];
4216             }
4217             if (AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP & ahb_desc.usage) {
4218                 pdifi2.flags |= ahb_create_map_a2v[AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP];
4219             }
4220             if (AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT & ahb_desc.usage) {
4221                 pdifi2.flags |= ahb_create_map_a2v[AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT];
4222             }
4223 
4224             auto ext_img_fmt_props = LvlInitStruct<VkExternalImageFormatProperties>();
4225             auto ifp2 = LvlInitStruct<VkImageFormatProperties2>(&ext_img_fmt_props);
4226 
4227             VkResult fmt_lookup_result = DispatchGetPhysicalDeviceImageFormatProperties2(physical_device, &pdifi2, &ifp2);
4228 
4229             if ((VK_SUCCESS != fmt_lookup_result) || (0 == (ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures &
4230                                                             VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT))) {
4231                 skip |= LogError(device, "VUID-VkImportAndroidHardwareBufferInfoANDROID-buffer-01880",
4232                                  "vkAllocateMemory: Neither the VkExternalImageFormatProperties nor the VkExternalBufferProperties "
4233                                  "structs for the AHardwareBuffer include the VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT flag.");
4234             }
4235         }
4236 
4237         // Retrieve buffer and format properties of the provided AHardwareBuffer
4238         auto ahb_format_props = LvlInitStruct<VkAndroidHardwareBufferFormatPropertiesANDROID>();
4239         auto ahb_props = LvlInitStruct<VkAndroidHardwareBufferPropertiesANDROID>(&ahb_format_props);
4240         DispatchGetAndroidHardwareBufferPropertiesANDROID(device, import_ahb_info->buffer, &ahb_props);
4241 
4242         // allocationSize must be the size returned by vkGetAndroidHardwareBufferPropertiesANDROID for the Android hardware buffer
4243         if (alloc_info->allocationSize != ahb_props.allocationSize) {
4244             skip |= LogError(device, "VUID-VkMemoryAllocateInfo-allocationSize-02383",
4245                              "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID "
4246                              "struct, allocationSize (%" PRId64
4247                              ") does not match the AHardwareBuffer's reported allocationSize (%" PRId64 ").",
4248                              alloc_info->allocationSize, ahb_props.allocationSize);
4249         }
4250 
4251         // memoryTypeIndex must be one of those returned by vkGetAndroidHardwareBufferPropertiesANDROID for the AHardwareBuffer
4252         // Note: memoryTypeIndex is an index, memoryTypeBits is a bitmask
4253         uint32_t mem_type_bitmask = 1 << alloc_info->memoryTypeIndex;
4254         if (0 == (mem_type_bitmask & ahb_props.memoryTypeBits)) {
4255             skip |= LogError(device, "VUID-VkMemoryAllocateInfo-memoryTypeIndex-02385",
4256                              "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID "
4257                              "struct, memoryTypeIndex (%" PRId32
4258                              ") does not correspond to a bit set in AHardwareBuffer's reported "
4259                              "memoryTypeBits bitmask (0x%" PRIx32 ").",
4260                              alloc_info->memoryTypeIndex, ahb_props.memoryTypeBits);
4261         }
4262 
4263         // Checks for allocations without a dedicated allocation requirement
4264         if ((nullptr == mem_ded_alloc_info) || (VK_NULL_HANDLE == mem_ded_alloc_info->image)) {
4265             // the Android hardware buffer must have a format of AHARDWAREBUFFER_FORMAT_BLOB and a usage that includes
4266             // AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER
4267             if (((uint64_t)AHARDWAREBUFFER_FORMAT_BLOB != ahb_desc.format) ||
4268                 (0 == (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER))) {
4269                 skip |= LogError(
4270                     device, "VUID-VkMemoryAllocateInfo-pNext-02384",
4271                     "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID "
4272                     "struct without a dedicated allocation requirement, while the AHardwareBuffer_Desc's format ( %u ) is not "
4273                     "AHARDWAREBUFFER_FORMAT_BLOB or usage (0x%" PRIx64 ") does not include AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER.",
4274                     ahb_desc.format, ahb_desc.usage);
4275             }
4276         } else {  // Checks specific to import with a dedicated allocation requirement
4277             auto image_state = Get<IMAGE_STATE>(mem_ded_alloc_info->image);
4278             const auto *ici = &image_state->createInfo;
4279 
4280             // The Android hardware buffer's usage must include at least one of AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER or
4281             // AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE
4282             if (0 == (ahb_desc.usage & (AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE))) {
4283                 skip |= LogError(
4284                     device, "VUID-VkMemoryAllocateInfo-pNext-02386",
4285                     "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID and a "
4286                     "dedicated allocation requirement, while the AHardwareBuffer's usage (0x%" PRIx64
4287                     ") contains neither AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER nor AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.",
4288                     ahb_desc.usage);
4289             }
4290 
4291             //  the format of image must be VK_FORMAT_UNDEFINED or the format returned by
4292             //  vkGetAndroidHardwareBufferPropertiesANDROID
4293             if ((ici->format != ahb_format_props.format) && (VK_FORMAT_UNDEFINED != ici->format)) {
4294                 skip |= LogError(device, "VUID-VkMemoryAllocateInfo-pNext-02387",
4295                                  "vkAllocateMemory: VkMemoryAllocateInfo struct with chained "
4296                                  "VkImportAndroidHardwareBufferInfoANDROID, the dedicated allocation image's "
4297                                  "format (%s) is not VK_FORMAT_UNDEFINED and does not match the AHardwareBuffer's format (%s).",
4298                                  string_VkFormat(ici->format), string_VkFormat(ahb_format_props.format));
4299             }
4300 
4301             // The width, height, and array layer dimensions of image and the Android hardwarebuffer must be identical
4302             if ((ici->extent.width != ahb_desc.width) || (ici->extent.height != ahb_desc.height) ||
4303                 (ici->arrayLayers != ahb_desc.layers)) {
4304                 skip |= LogError(device, "VUID-VkMemoryAllocateInfo-pNext-02388",
4305                                  "vkAllocateMemory: VkMemoryAllocateInfo struct with chained "
4306                                  "VkImportAndroidHardwareBufferInfoANDROID, the dedicated allocation image's "
4307                                  "width, height, and arrayLayers (%" PRId32 " %" PRId32 " %" PRId32
4308                                  ") do not match those of the AHardwareBuffer (%" PRId32 " %" PRId32 " %" PRId32 ").",
4309                                  ici->extent.width, ici->extent.height, ici->arrayLayers, ahb_desc.width, ahb_desc.height,
4310                                  ahb_desc.layers);
4311             }
4312 
4313             // If the Android hardware buffer's usage includes AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE, the image must
4314             // have either a full mipmap chain or exactly 1 mip level.
4315             //
4316             // NOTE! The language of this VUID contradicts the language in the spec (1.1.93), which says "The
4317             // AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE flag does not correspond to a Vulkan image usage or creation flag. Instead,
4318             // its presence indicates that the Android hardware buffer contains a complete mipmap chain, and its absence indicates
4319             // that the Android hardware buffer contains only a single mip level."
4320             //
4321             // TODO: This code implements the VUID's meaning, but it seems likely that the spec text is actually correct.
4322             // Clarification requested.
4323             if ((ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE) && (ici->mipLevels != 1) &&
4324                 (ici->mipLevels != FullMipChainLevels(ici->extent))) {
4325                 skip |=
4326                     LogError(device, "VUID-VkMemoryAllocateInfo-pNext-02389",
4327                              "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID, "
4328                              "usage includes AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE but mipLevels (%" PRId32
4329                              ") is neither 1 nor full mip "
4330                              "chain levels (%" PRId32 ").",
4331                              ici->mipLevels, FullMipChainLevels(ici->extent));
4332             }
4333 
4334             // each bit set in the usage of image must be listed in AHardwareBuffer Usage Equivalence, and if there is a
4335             // corresponding AHARDWAREBUFFER_USAGE bit listed that bit must be included in the Android hardware buffer's
4336             // AHardwareBuffer_Desc::usage
4337             if (ici->usage & ~(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
4338                                VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
4339                                VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
4340                 skip |=
4341                     LogError(device, "VUID-VkMemoryAllocateInfo-pNext-02390",
4342                              "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID, "
4343                              "dedicated image usage bits (0x%" PRIx32
4344                              ") include an issue not listed in the AHardwareBuffer Usage Equivalence table.",
4345                              ici->usage);
4346             }
4347 
4348             std::vector<VkImageUsageFlags> usages = {VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
4349                                                      VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
4350                                                      VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT};
4351             for (VkImageUsageFlags ubit : usages) {
4352                 if (ici->usage & ubit) {
4353                     uint64_t ahb_usage = ahb_usage_map_v2a[ubit];
4354                     if (0 == (ahb_usage & ahb_desc.usage)) {
4355                         skip |= LogError(
4356                             device, "VUID-VkMemoryAllocateInfo-pNext-02390",
4357                             "vkAllocateMemory: VkMemoryAllocateInfo struct with chained VkImportAndroidHardwareBufferInfoANDROID, "
4358                             "The dedicated image usage bit %s equivalent is not in AHardwareBuffer_Desc.usage (0x%" PRIx64 ") ",
4359                             string_VkImageUsageFlags(ubit).c_str(), ahb_desc.usage);
4360                     }
4361                 }
4362             }
4363         }
4364     } else {  // Not an import
4365         if ((exp_mem_alloc_info) && (mem_ded_alloc_info) &&
4366             (0 != (VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID & exp_mem_alloc_info->handleTypes)) &&
4367             (VK_NULL_HANDLE != mem_ded_alloc_info->image)) {
4368             // This is an Android HW Buffer export
4369             if (0 != alloc_info->allocationSize) {
4370                 skip |= LogError(device, "VUID-VkMemoryAllocateInfo-pNext-01874",
4371                                  "vkAllocateMemory: pNext chain indicates a dedicated Android Hardware Buffer export allocation, "
4372                                  "but allocationSize is non-zero.");
4373             }
4374         } else {
4375             if (0 == alloc_info->allocationSize) {
4376                 skip |= LogError(
4377                     device, "VUID-VkMemoryAllocateInfo-pNext-01874",
4378                     "vkAllocateMemory: pNext chain does not indicate a dedicated export allocation, but allocationSize is 0.");
4379             };
4380         }
4381     }
4382     return skip;
4383 }
4384 
ValidateGetImageMemoryRequirementsANDROID(const VkImage image,const char * func_name) const4385 bool CoreChecks::ValidateGetImageMemoryRequirementsANDROID(const VkImage image, const char *func_name) const {
4386     bool skip = false;
4387 
4388     const auto image_state = Get<IMAGE_STATE>(image);
4389     if (image_state != nullptr) {
4390         if (image_state->IsExternalAHB() && (0 == image_state->GetBoundMemory().size())) {
4391             const char *vuid = strcmp(func_name, "vkGetImageMemoryRequirements()") == 0
4392                                    ? "VUID-vkGetImageMemoryRequirements-image-04004"
4393                                    : "VUID-VkImageMemoryRequirementsInfo2-image-01897";
4394             skip |=
4395                 LogError(image, vuid,
4396                          "%s: Attempt get image memory requirements for an image created with a "
4397                          "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType, which has not yet been "
4398                          "bound to memory.",
4399                          func_name);
4400         }
4401     }
4402     return skip;
4403 }
4404 
ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,const VkImageFormatProperties2 * pImageFormatProperties) const4405 bool CoreChecks::ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(
4406     const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, const VkImageFormatProperties2 *pImageFormatProperties) const {
4407     bool skip = false;
4408     const VkAndroidHardwareBufferUsageANDROID *ahb_usage =
4409         LvlFindInChain<VkAndroidHardwareBufferUsageANDROID>(pImageFormatProperties->pNext);
4410     if (nullptr != ahb_usage) {
4411         const VkPhysicalDeviceExternalImageFormatInfo *pdeifi =
4412             LvlFindInChain<VkPhysicalDeviceExternalImageFormatInfo>(pImageFormatInfo->pNext);
4413         if ((nullptr == pdeifi) || (VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID != pdeifi->handleType)) {
4414             skip |= LogError(device, "VUID-vkGetPhysicalDeviceImageFormatProperties2-pNext-01868",
4415                              "vkGetPhysicalDeviceImageFormatProperties2: pImageFormatProperties includes a chained "
4416                              "VkAndroidHardwareBufferUsageANDROID struct, but pImageFormatInfo does not include a chained "
4417                              "VkPhysicalDeviceExternalImageFormatInfo struct with handleType "
4418                              "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.");
4419         }
4420     }
4421     return skip;
4422 }
4423 
ValidateBufferImportedHandleANDROID(const char * func_name,VkExternalMemoryHandleTypeFlags handleType,VkDeviceMemory memory,VkBuffer buffer) const4424 bool CoreChecks::ValidateBufferImportedHandleANDROID(const char *func_name, VkExternalMemoryHandleTypeFlags handleType,
4425                                                      VkDeviceMemory memory, VkBuffer buffer) const {
4426     bool skip = false;
4427     if ((handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) == 0) {
4428         const char *vuid = (strcmp(func_name, "vkBindBufferMemory()") == 0) ? "VUID-vkBindBufferMemory-memory-02986"
4429                                                                             : "VUID-VkBindBufferMemoryInfo-memory-02986";
4430         LogObjectList objlist(buffer);
4431         objlist.add(memory);
4432         skip |= LogError(objlist, vuid,
4433                          "%s: The VkDeviceMemory (%s) was created with an AHB import operation which is not set "
4434                          "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID in the VkBuffer (%s) "
4435                          "VkExternalMemoryBufferreateInfo::handleType (%s)",
4436                          func_name, report_data->FormatHandle(memory).c_str(), report_data->FormatHandle(buffer).c_str(),
4437                          string_VkExternalMemoryHandleTypeFlags(handleType).c_str());
4438     }
4439     return skip;
4440 }
4441 
ValidateImageImportedHandleANDROID(const char * func_name,VkExternalMemoryHandleTypeFlags handleType,VkDeviceMemory memory,VkImage image) const4442 bool CoreChecks::ValidateImageImportedHandleANDROID(const char *func_name, VkExternalMemoryHandleTypeFlags handleType,
4443                                                     VkDeviceMemory memory, VkImage image) const {
4444     bool skip = false;
4445     if ((handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) == 0) {
4446         const char *vuid = (strcmp(func_name, "vkBindImageMemory()") == 0) ? "VUID-vkBindImageMemory-memory-02990"
4447                                                                            : "VUID-VkBindImageMemoryInfo-memory-02990";
4448         LogObjectList objlist(image);
4449         objlist.add(memory);
4450         skip |= LogError(objlist, vuid,
4451                          "%s: The VkDeviceMemory (%s) was created with an AHB import operation which is not set "
4452                          "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID in the VkImage (%s) "
4453                          "VkExternalMemoryImageCreateInfo::handleType (%s)",
4454                          func_name, report_data->FormatHandle(memory).c_str(), report_data->FormatHandle(image).c_str(),
4455                          string_VkExternalMemoryHandleTypeFlags(handleType).c_str());
4456     }
4457     return skip;
4458 }
4459 
4460 #else  // !AHB_VALIDATION_SUPPORT
4461 
4462 // Case building for Android without AHB Validation
4463 #ifdef VK_USE_PLATFORM_ANDROID_KHR
PreCallValidateGetAndroidHardwareBufferPropertiesANDROID(VkDevice device,const struct AHardwareBuffer * buffer,VkAndroidHardwareBufferPropertiesANDROID * pProperties) const4464 bool CoreChecks::PreCallValidateGetAndroidHardwareBufferPropertiesANDROID(
4465     VkDevice device, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties) const {
4466     return false;
4467 }
PreCallValidateGetMemoryAndroidHardwareBufferANDROID(VkDevice device,const VkMemoryGetAndroidHardwareBufferInfoANDROID * pInfo,struct AHardwareBuffer ** pBuffer) const4468 bool CoreChecks::PreCallValidateGetMemoryAndroidHardwareBufferANDROID(VkDevice device,
4469                                                                       const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
4470                                                                       struct AHardwareBuffer **pBuffer) const {
4471     return false;
4472 }
4473 #endif  // VK_USE_PLATFORM_ANDROID_KHR
4474 
ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo * alloc_info) const4475 bool CoreChecks::ValidateAllocateMemoryANDROID(const VkMemoryAllocateInfo *alloc_info) const { return false; }
4476 
ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,const VkImageFormatProperties2 * pImageFormatProperties) const4477 bool CoreChecks::ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(
4478     const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, const VkImageFormatProperties2 *pImageFormatProperties) const {
4479     return false;
4480 }
4481 
ValidateGetImageMemoryRequirementsANDROID(const VkImage image,const char * func_name) const4482 bool CoreChecks::ValidateGetImageMemoryRequirementsANDROID(const VkImage image, const char *func_name) const { return false; }
4483 
ValidateBufferImportedHandleANDROID(const char * func_name,VkExternalMemoryHandleTypeFlags handleType,VkDeviceMemory memory,VkBuffer buffer) const4484 bool CoreChecks::ValidateBufferImportedHandleANDROID(const char *func_name, VkExternalMemoryHandleTypeFlags handleType,
4485                                                      VkDeviceMemory memory, VkBuffer buffer) const {
4486     return false;
4487 }
4488 
ValidateImageImportedHandleANDROID(const char * func_name,VkExternalMemoryHandleTypeFlags handleType,VkDeviceMemory memory,VkImage image) const4489 bool CoreChecks::ValidateImageImportedHandleANDROID(const char *func_name, VkExternalMemoryHandleTypeFlags handleType,
4490                                                     VkDeviceMemory memory, VkImage image) const {
4491     return false;
4492 }
4493 
4494 #endif  // AHB_VALIDATION_SUPPORT
4495 
PreCallValidateAllocateMemory(VkDevice device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMemory) const4496 bool CoreChecks::PreCallValidateAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
4497                                                const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) const {
4498     bool skip = false;
4499     if (Count<DEVICE_MEMORY_STATE>() >= phys_dev_props.limits.maxMemoryAllocationCount) {
4500         skip |= LogError(device, "VUID-vkAllocateMemory-maxMemoryAllocationCount-04101",
4501                          "vkAllocateMemory: Number of currently valid memory objects is not less than the maximum allowed (%u).",
4502                          phys_dev_props.limits.maxMemoryAllocationCount);
4503     }
4504 
4505     if (IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
4506         skip |= ValidateAllocateMemoryANDROID(pAllocateInfo);
4507     } else {
4508         if (0 == pAllocateInfo->allocationSize) {
4509             skip |= LogError(device, "VUID-VkMemoryAllocateInfo-allocationSize-00638", "vkAllocateMemory: allocationSize is 0.");
4510         };
4511     }
4512 
4513     auto chained_flags_struct = LvlFindInChain<VkMemoryAllocateFlagsInfo>(pAllocateInfo->pNext);
4514     if (chained_flags_struct && chained_flags_struct->flags == VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT) {
4515         skip |= ValidateDeviceMaskToPhysicalDeviceCount(chained_flags_struct->deviceMask, device,
4516                                                         "VUID-VkMemoryAllocateFlagsInfo-deviceMask-00675");
4517         skip |=
4518             ValidateDeviceMaskToZero(chained_flags_struct->deviceMask, device, "VUID-VkMemoryAllocateFlagsInfo-deviceMask-00676");
4519     }
4520 
4521     if (pAllocateInfo->memoryTypeIndex >= phys_dev_mem_props.memoryTypeCount) {
4522         skip |= LogError(device, "VUID-vkAllocateMemory-pAllocateInfo-01714",
4523                          "vkAllocateMemory: attempting to allocate memory type %u, which is not a valid index. Device only "
4524                          "advertises %u memory types.",
4525                          pAllocateInfo->memoryTypeIndex, phys_dev_mem_props.memoryTypeCount);
4526     } else {
4527         const VkMemoryType memory_type = phys_dev_mem_props.memoryTypes[pAllocateInfo->memoryTypeIndex];
4528         if (pAllocateInfo->allocationSize > phys_dev_mem_props.memoryHeaps[memory_type.heapIndex].size) {
4529             skip |= LogError(device, "VUID-vkAllocateMemory-pAllocateInfo-01713",
4530                              "vkAllocateMemory: attempting to allocate %" PRIu64
4531                              " bytes from heap %u,"
4532                              "but size of that heap is only %" PRIu64 " bytes.",
4533                              pAllocateInfo->allocationSize, memory_type.heapIndex,
4534                              phys_dev_mem_props.memoryHeaps[memory_type.heapIndex].size);
4535         }
4536 
4537         if (!enabled_features.device_coherent_memory_features.deviceCoherentMemory &&
4538             ((memory_type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD) != 0)) {
4539             skip |= LogError(device, "VUID-vkAllocateMemory-deviceCoherentMemory-02790",
4540                              "vkAllocateMemory: attempting to allocate memory type %u, which includes the "
4541                              "VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD memory property, but the deviceCoherentMemory feature "
4542                              "is not enabled.",
4543                              pAllocateInfo->memoryTypeIndex);
4544         }
4545 
4546         if ((enabled_features.core11.protectedMemory == VK_FALSE) &&
4547             ((memory_type.propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0)) {
4548             skip |= LogError(device, "VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872",
4549                              "vkAllocateMemory(): attempting to allocate memory type %u, which includes the "
4550                              "VK_MEMORY_PROPERTY_PROTECTED_BIT memory property, but the protectedMemory feature "
4551                              "is not enabled.",
4552                              pAllocateInfo->memoryTypeIndex);
4553         }
4554     }
4555 
4556     bool imported_ahb = false;
4557 #ifdef AHB_VALIDATION_SUPPORT
4558     //  "memory is not an imported Android Hardware Buffer" refers to VkImportAndroidHardwareBufferInfoANDROID with a non-NULL
4559     //  buffer value. Memory imported has another VUID to check size and allocationSize match up
4560     auto imported_ahb_info = LvlFindInChain<VkImportAndroidHardwareBufferInfoANDROID>(pAllocateInfo->pNext);
4561     if (imported_ahb_info != nullptr) {
4562         imported_ahb = imported_ahb_info->buffer != nullptr;
4563     }
4564 #endif  // AHB_VALIDATION_SUPPORT
4565     auto dedicated_allocate_info = LvlFindInChain<VkMemoryDedicatedAllocateInfo>(pAllocateInfo->pNext);
4566     if (dedicated_allocate_info) {
4567         if ((dedicated_allocate_info->buffer != VK_NULL_HANDLE) && (dedicated_allocate_info->image != VK_NULL_HANDLE)) {
4568             skip |= LogError(device, "VUID-VkMemoryDedicatedAllocateInfo-image-01432",
4569                              "vkAllocateMemory: Either buffer or image has to be VK_NULL_HANDLE in VkMemoryDedicatedAllocateInfo");
4570         } else if (dedicated_allocate_info->image != VK_NULL_HANDLE) {
4571             // Dedicated VkImage
4572             const auto image_state = Get<IMAGE_STATE>(dedicated_allocate_info->image);
4573             if (image_state->disjoint == true) {
4574                 skip |= LogError(
4575                     device, "VUID-VkMemoryDedicatedAllocateInfo-image-01797",
4576                     "vkAllocateMemory: VkImage %s can't be used in VkMemoryDedicatedAllocateInfo because it was created with "
4577                     "VK_IMAGE_CREATE_DISJOINT_BIT",
4578                     report_data->FormatHandle(dedicated_allocate_info->image).c_str());
4579             } else {
4580                 if ((pAllocateInfo->allocationSize != image_state->requirements[0].size) && (imported_ahb == false)) {
4581                     const char *vuid = IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)
4582                                            ? "VUID-VkMemoryDedicatedAllocateInfo-image-02964"
4583                                            : "VUID-VkMemoryDedicatedAllocateInfo-image-01433";
4584                     skip |=
4585                         LogError(device, vuid,
4586                                  "vkAllocateMemory: Allocation Size (%" PRIu64
4587                                  ") needs to be equal to VkImage %s VkMemoryRequirements::size (%" PRIu64 ")",
4588                                  pAllocateInfo->allocationSize, report_data->FormatHandle(dedicated_allocate_info->image).c_str(),
4589                                  image_state->requirements[0].size);
4590                 }
4591                 if ((image_state->createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != 0) {
4592                     skip |= LogError(
4593                         device, "VUID-VkMemoryDedicatedAllocateInfo-image-01434",
4594                         "vkAllocateMemory: VkImage %s can't be used in VkMemoryDedicatedAllocateInfo because it was created with "
4595                         "VK_IMAGE_CREATE_SPARSE_BINDING_BIT",
4596                         report_data->FormatHandle(dedicated_allocate_info->image).c_str());
4597                 }
4598             }
4599         } else if (dedicated_allocate_info->buffer != VK_NULL_HANDLE) {
4600             // Dedicated VkBuffer
4601             const auto buffer_state = Get<BUFFER_STATE>(dedicated_allocate_info->buffer);
4602             if ((pAllocateInfo->allocationSize != buffer_state->requirements.size) && (imported_ahb == false)) {
4603                 const char *vuid = IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)
4604                                        ? "VUID-VkMemoryDedicatedAllocateInfo-buffer-02965"
4605                                        : "VUID-VkMemoryDedicatedAllocateInfo-buffer-01435";
4606                 skip |= LogError(
4607                     device, vuid,
4608                     "vkAllocateMemory: Allocation Size (%" PRIu64 ") needs to be equal to VkBuffer %s VkMemoryRequirements::size (%" PRIu64 ")",
4609                     pAllocateInfo->allocationSize, report_data->FormatHandle(dedicated_allocate_info->buffer).c_str(),
4610                     buffer_state->requirements.size);
4611             }
4612             if ((buffer_state->createInfo.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0) {
4613                 skip |= LogError(
4614                     device, "VUID-VkMemoryDedicatedAllocateInfo-buffer-01436",
4615                     "vkAllocateMemory: VkBuffer %s can't be used in VkMemoryDedicatedAllocateInfo because it was created with "
4616                     "VK_BUFFER_CREATE_SPARSE_BINDING_BIT",
4617                     report_data->FormatHandle(dedicated_allocate_info->buffer).c_str());
4618             }
4619         }
4620     }
4621 
4622     // TODO: VUIDs ending in 00643, 00644, 00646, 00647, 01742, 01743, 01745, 00645, 00648, 01744
4623     return skip;
4624 }
4625 
4626 // For given obj node, if it is use, flag a validation error and return callback result, else return false
ValidateObjectNotInUse(const BASE_NODE * obj_node,const char * caller_name,const char * error_code) const4627 bool CoreChecks::ValidateObjectNotInUse(const BASE_NODE *obj_node, const char *caller_name, const char *error_code) const {
4628     if (disabled[object_in_use]) return false;
4629     auto obj_struct = obj_node->Handle();
4630     bool skip = false;
4631     if (obj_node->InUse()) {
4632         skip |= LogError(device, error_code, "Cannot call %s on %s that is currently in use by a command buffer.", caller_name,
4633                          report_data->FormatHandle(obj_struct).c_str());
4634     }
4635     return skip;
4636 }
4637 
PreCallValidateFreeMemory(VkDevice device,VkDeviceMemory mem,const VkAllocationCallbacks * pAllocator) const4638 bool CoreChecks::PreCallValidateFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) const {
4639     const auto mem_info = Get<DEVICE_MEMORY_STATE>(mem);
4640     bool skip = false;
4641     if (mem_info) {
4642         skip |= ValidateObjectNotInUse(mem_info.get(), "vkFreeMemory", "VUID-vkFreeMemory-memory-00677");
4643     }
4644     return skip;
4645 }
4646 
4647 // Validate that given Map memory range is valid. This means that the memory should not already be mapped,
4648 //  and that the size of the map range should be:
4649 //  1. Not zero
4650 //  2. Within the size of the memory allocation
ValidateMapMemRange(const DEVICE_MEMORY_STATE * mem_info,VkDeviceSize offset,VkDeviceSize size) const4651 bool CoreChecks::ValidateMapMemRange(const DEVICE_MEMORY_STATE *mem_info, VkDeviceSize offset, VkDeviceSize size) const {
4652     bool skip = false;
4653     assert(mem_info);
4654     const auto mem = mem_info->mem();
4655     if (size == 0) {
4656         skip = LogError(mem, "VUID-vkMapMemory-size-00680", "VkMapMemory: Attempting to map memory range of size zero");
4657     }
4658 
4659     // It is an application error to call VkMapMemory on an object that is already mapped
4660     if (mem_info->mapped_range.size != 0) {
4661         skip = LogError(mem, "VUID-vkMapMemory-memory-00678", "VkMapMemory: Attempting to map memory on an already-mapped %s.",
4662                         report_data->FormatHandle(mem).c_str());
4663     }
4664 
4665     // Validate offset is not over allocaiton size
4666     if (offset >= mem_info->alloc_info.allocationSize) {
4667         skip = LogError(mem, "VUID-vkMapMemory-offset-00679",
4668                         "VkMapMemory: Attempting to map memory with an offset of 0x%" PRIx64
4669                         " which is larger than the total array size 0x%" PRIx64,
4670                         offset, mem_info->alloc_info.allocationSize);
4671     }
4672     // Validate that offset + size is within object's allocationSize
4673     if (size != VK_WHOLE_SIZE) {
4674         if ((offset + size) > mem_info->alloc_info.allocationSize) {
4675             skip = LogError(mem, "VUID-vkMapMemory-size-00681",
4676                             "VkMapMemory: Mapping Memory from 0x%" PRIx64 " to 0x%" PRIx64 " oversteps total array size 0x%" PRIx64
4677                             ".",
4678                             offset, size + offset, mem_info->alloc_info.allocationSize);
4679         }
4680     }
4681     return skip;
4682 }
4683 
PreCallValidateWaitForFences(VkDevice device,uint32_t fenceCount,const VkFence * pFences,VkBool32 waitAll,uint64_t timeout) const4684 bool CoreChecks::PreCallValidateWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll,
4685                                               uint64_t timeout) const {
4686     // Verify fence status of submitted fences
4687     bool skip = false;
4688     for (uint32_t i = 0; i < fenceCount; i++) {
4689         skip |= VerifyQueueStateToFence(pFences[i]);
4690     }
4691     return skip;
4692 }
4693 
PreCallValidateGetDeviceQueue(VkDevice device,uint32_t queueFamilyIndex,uint32_t queueIndex,VkQueue * pQueue) const4694 bool CoreChecks::PreCallValidateGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
4695                                                VkQueue *pQueue) const {
4696     bool skip = false;
4697 
4698     skip |= ValidateDeviceQueueFamily(queueFamilyIndex, "vkGetDeviceQueue", "queueFamilyIndex",
4699                                       "VUID-vkGetDeviceQueue-queueFamilyIndex-00384");
4700 
4701     for (size_t i = 0; i < device_queue_info_list.size(); i++) {
4702         const auto device_queue_info = device_queue_info_list.at(i);
4703         if (device_queue_info.queue_family_index != queueFamilyIndex) {
4704             continue;
4705         }
4706 
4707         // flag must be zero
4708         if (device_queue_info.flags != 0) {
4709             skip |= LogError(
4710                 device, "VUID-vkGetDeviceQueue-flags-01841",
4711                 "vkGetDeviceQueue: queueIndex (=%" PRIu32
4712                 ") was created with a non-zero VkDeviceQueueCreateFlags in vkCreateDevice::pCreateInfo->pQueueCreateInfos[%" PRIu32
4713                 "]. Need to use vkGetDeviceQueue2 instead.",
4714                 queueIndex, device_queue_info.index);
4715         }
4716 
4717         if (device_queue_info.queue_count <= queueIndex) {
4718             skip |= LogError(device, "VUID-vkGetDeviceQueue-queueIndex-00385",
4719                              "vkGetDeviceQueue: queueIndex (=%" PRIu32
4720                              ") is not less than the number of queues requested from queueFamilyIndex (=%" PRIu32
4721                              ") when the device was created vkCreateDevice::pCreateInfo->pQueueCreateInfos[%" PRIu32
4722                              "] (i.e. is not less than %" PRIu32 ").",
4723                              queueIndex, queueFamilyIndex, device_queue_info.index, device_queue_info.queue_count);
4724         }
4725     }
4726     return skip;
4727 }
4728 
PreCallValidateGetDeviceQueue2(VkDevice device,const VkDeviceQueueInfo2 * pQueueInfo,VkQueue * pQueue) const4729 bool CoreChecks::PreCallValidateGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) const {
4730     bool skip = false;
4731 
4732     if (pQueueInfo) {
4733         const uint32_t queueFamilyIndex = pQueueInfo->queueFamilyIndex;
4734         const uint32_t queueIndex = pQueueInfo->queueIndex;
4735         const VkDeviceQueueCreateFlags flags = pQueueInfo->flags;
4736 
4737         skip |= ValidateDeviceQueueFamily(queueFamilyIndex, "vkGetDeviceQueue2", "pQueueInfo->queueFamilyIndex",
4738                                           "VUID-VkDeviceQueueInfo2-queueFamilyIndex-01842");
4739 
4740         // ValidateDeviceQueueFamily() already checks if queueFamilyIndex but need to make sure flags match with it
4741         bool valid_flags = false;
4742 
4743         for (size_t i = 0; i < device_queue_info_list.size(); i++) {
4744             const auto device_queue_info = device_queue_info_list.at(i);
4745             // vkGetDeviceQueue2 only checks if both family index AND flags are same as device creation
4746             // this handle case where the same queueFamilyIndex is used with/without the protected flag
4747             if ((device_queue_info.queue_family_index != queueFamilyIndex) || (device_queue_info.flags != flags)) {
4748                 continue;
4749             }
4750             valid_flags = true;
4751 
4752             if (device_queue_info.queue_count <= queueIndex) {
4753                 skip |= LogError(
4754                     device, "VUID-VkDeviceQueueInfo2-queueIndex-01843",
4755                     "vkGetDeviceQueue2: queueIndex (=%" PRIu32
4756                     ") is not less than the number of queues requested from [queueFamilyIndex (=%" PRIu32
4757                     "), flags (%s)] combination when the device was created vkCreateDevice::pCreateInfo->pQueueCreateInfos[%" PRIu32
4758                     "] (i.e. is not less than %" PRIu32 ").",
4759                     queueIndex, queueFamilyIndex, string_VkDeviceQueueCreateFlags(flags).c_str(), device_queue_info.index,
4760                     device_queue_info.queue_count);
4761             }
4762         }
4763 
4764         // Don't double error message if already skipping from ValidateDeviceQueueFamily
4765         if (!valid_flags && !skip) {
4766             skip |= LogError(device, "VUID-VkDeviceQueueInfo2-flags-06225",
4767                              "vkGetDeviceQueue2: The combination of queueFamilyIndex (=%" PRIu32
4768                              ") and flags (%s) were never both set together in any element of "
4769                              "vkCreateDevice::pCreateInfo->pQueueCreateInfos at device creation time.",
4770                              queueFamilyIndex, string_VkDeviceQueueCreateFlags(flags).c_str());
4771         }
4772     }
4773     return skip;
4774 }
4775 
PreCallValidateQueueWaitIdle(VkQueue queue) const4776 bool CoreChecks::PreCallValidateQueueWaitIdle(VkQueue queue) const {
4777     const auto queue_state = Get<QUEUE_STATE>(queue);
4778     return VerifyQueueStateToSeq(queue_state.get(), queue_state->seq + queue_state->submissions.size());
4779 }
4780 
PreCallValidateDeviceWaitIdle(VkDevice device) const4781 bool CoreChecks::PreCallValidateDeviceWaitIdle(VkDevice device) const {
4782     bool skip = false;
4783     ForEach<QUEUE_STATE>([this, &skip](const QUEUE_STATE &queue_state) {
4784         skip |= VerifyQueueStateToSeq(&queue_state, queue_state.seq + queue_state.submissions.size());
4785     });
4786     return skip;
4787 }
4788 
PreCallValidateCreateSemaphore(VkDevice device,const VkSemaphoreCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSemaphore * pSemaphore) const4789 bool CoreChecks::PreCallValidateCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
4790                                                 const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) const {
4791     bool skip = false;
4792     auto *sem_type_create_info = LvlFindInChain<VkSemaphoreTypeCreateInfo>(pCreateInfo->pNext);
4793 
4794     if (sem_type_create_info) {
4795         if (sem_type_create_info->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE && !enabled_features.core12.timelineSemaphore) {
4796             skip |= LogError(device, "VUID-VkSemaphoreTypeCreateInfo-timelineSemaphore-03252",
4797                              "VkCreateSemaphore: timelineSemaphore feature is not enabled, can not create timeline semaphores");
4798         }
4799 
4800         if (sem_type_create_info->semaphoreType == VK_SEMAPHORE_TYPE_BINARY && sem_type_create_info->initialValue != 0) {
4801             skip |= LogError(device, "VUID-VkSemaphoreTypeCreateInfo-semaphoreType-03279",
4802                              "vkCreateSemaphore: if semaphoreType is VK_SEMAPHORE_TYPE_BINARY, initialValue must be zero");
4803         }
4804     }
4805 
4806     return skip;
4807 }
4808 
PreCallValidateWaitSemaphores(VkDevice device,const VkSemaphoreWaitInfo * pWaitInfo,uint64_t timeout) const4809 bool CoreChecks::PreCallValidateWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout) const {
4810     return ValidateWaitSemaphores(device, pWaitInfo, timeout, "VkWaitSemaphores");
4811 }
4812 
PreCallValidateWaitSemaphoresKHR(VkDevice device,const VkSemaphoreWaitInfo * pWaitInfo,uint64_t timeout) const4813 bool CoreChecks::PreCallValidateWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout) const {
4814     return ValidateWaitSemaphores(device, pWaitInfo, timeout, "VkWaitSemaphoresKHR");
4815 }
4816 
ValidateWaitSemaphores(VkDevice device,const VkSemaphoreWaitInfo * pWaitInfo,uint64_t timeout,const char * apiName) const4817 bool CoreChecks::ValidateWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout,
4818                                         const char *apiName) const {
4819     bool skip = false;
4820 
4821     for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {
4822         auto semaphore_state = Get<SEMAPHORE_STATE>(pWaitInfo->pSemaphores[i]);
4823         if (semaphore_state && semaphore_state->type != VK_SEMAPHORE_TYPE_TIMELINE) {
4824             skip |= LogError(pWaitInfo->pSemaphores[i], "VUID-VkSemaphoreWaitInfo-pSemaphores-03256",
4825                              "%s(): all semaphores in pWaitInfo must be timeline semaphores, but %s is not", apiName,
4826                              report_data->FormatHandle(pWaitInfo->pSemaphores[i]).c_str());
4827         }
4828     }
4829 
4830     return skip;
4831 }
4832 
PreCallValidateDestroyFence(VkDevice device,VkFence fence,const VkAllocationCallbacks * pAllocator) const4833 bool CoreChecks::PreCallValidateDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) const {
4834     const auto fence_node = Get<FENCE_STATE>(fence);
4835     bool skip = false;
4836     if (fence_node) {
4837         if (fence_node->scope == kSyncScopeInternal && fence_node->state == FENCE_INFLIGHT) {
4838             skip |= LogError(fence, "VUID-vkDestroyFence-fence-01120", "%s is in use.", report_data->FormatHandle(fence).c_str());
4839         }
4840     }
4841     return skip;
4842 }
4843 
PreCallValidateDestroySemaphore(VkDevice device,VkSemaphore semaphore,const VkAllocationCallbacks * pAllocator) const4844 bool CoreChecks::PreCallValidateDestroySemaphore(VkDevice device, VkSemaphore semaphore,
4845                                                  const VkAllocationCallbacks *pAllocator) const {
4846     const auto sema_node = Get<SEMAPHORE_STATE>(semaphore);
4847     bool skip = false;
4848     if (sema_node) {
4849         skip |= ValidateObjectNotInUse(sema_node.get(), "vkDestroySemaphore", "VUID-vkDestroySemaphore-semaphore-01137");
4850     }
4851     return skip;
4852 }
4853 
PreCallValidateDestroyEvent(VkDevice device,VkEvent event,const VkAllocationCallbacks * pAllocator) const4854 bool CoreChecks::PreCallValidateDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) const {
4855     const auto event_state = Get<EVENT_STATE>(event);
4856     bool skip = false;
4857     if (event_state) {
4858         skip |= ValidateObjectNotInUse(event_state.get(), "vkDestroyEvent", "VUID-vkDestroyEvent-event-01145");
4859     }
4860     return skip;
4861 }
4862 
PreCallValidateDestroyQueryPool(VkDevice device,VkQueryPool queryPool,const VkAllocationCallbacks * pAllocator) const4863 bool CoreChecks::PreCallValidateDestroyQueryPool(VkDevice device, VkQueryPool queryPool,
4864                                                  const VkAllocationCallbacks *pAllocator) const {
4865     if (disabled[query_validation]) return false;
4866     const auto qp_state = Get<QUERY_POOL_STATE>(queryPool);
4867     bool skip = false;
4868     if (qp_state) {
4869         bool completed_by_get_results = true;
4870         for (uint32_t i = 0; i < qp_state->createInfo.queryCount; ++i) {
4871             auto state = qp_state->GetQueryState(i, 0);
4872             if (state != QUERYSTATE_AVAILABLE) {
4873                 completed_by_get_results = false;
4874                 break;
4875             }
4876         }
4877         if (!completed_by_get_results) {
4878             skip |= ValidateObjectNotInUse(qp_state.get(), "vkDestroyQueryPool", "VUID-vkDestroyQueryPool-queryPool-00793");
4879         }
4880     }
4881     return skip;
4882 }
4883 
ValidatePerformanceQueryResults(const char * cmd_name,const QUERY_POOL_STATE * query_pool_state,uint32_t firstQuery,uint32_t queryCount,VkQueryResultFlags flags) const4884 bool CoreChecks::ValidatePerformanceQueryResults(const char *cmd_name, const QUERY_POOL_STATE *query_pool_state,
4885                                                  uint32_t firstQuery, uint32_t queryCount, VkQueryResultFlags flags) const {
4886     bool skip = false;
4887 
4888     if (flags & (VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_64_BIT)) {
4889         string invalid_flags_string;
4890         for (auto flag : {VK_QUERY_RESULT_WITH_AVAILABILITY_BIT, VK_QUERY_RESULT_PARTIAL_BIT, VK_QUERY_RESULT_64_BIT}) {
4891             if (flag & flags) {
4892                 if (invalid_flags_string.size()) {
4893                     invalid_flags_string += " and ";
4894                 }
4895                 invalid_flags_string += string_VkQueryResultFlagBits(flag);
4896             }
4897         }
4898         skip |= LogError(query_pool_state->pool(),
4899                          strcmp(cmd_name, "vkGetQueryPoolResults") == 0 ? "VUID-vkGetQueryPoolResults-queryType-03230"
4900                                                                         : "VUID-vkCmdCopyQueryPoolResults-queryType-03233",
4901                          "%s: QueryPool %s was created with a queryType of"
4902                          "VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR but flags contains %s.",
4903                          cmd_name, report_data->FormatHandle(query_pool_state->pool()).c_str(), invalid_flags_string.c_str());
4904     }
4905 
4906     for (uint32_t query_index = firstQuery; query_index < queryCount; query_index++) {
4907         uint32_t submitted = 0;
4908         for (uint32_t pass_index = 0; pass_index < query_pool_state->n_performance_passes; pass_index++) {
4909             auto state = query_pool_state->GetQueryState(query_index, pass_index);
4910             if (state == QUERYSTATE_AVAILABLE) {
4911                 submitted++;
4912             }
4913         }
4914         if (submitted < query_pool_state->n_performance_passes) {
4915             skip |= LogError(query_pool_state->pool(), "VUID-vkGetQueryPoolResults-queryType-03231",
4916                              "%s: QueryPool %s has %u performance query passes, but the query has only been "
4917                              "submitted for %u of the passes.",
4918                              cmd_name, report_data->FormatHandle(query_pool_state->pool()).c_str(),
4919                              query_pool_state->n_performance_passes, submitted);
4920         }
4921     }
4922 
4923     return skip;
4924 }
4925 
ValidateGetQueryPoolPerformanceResults(VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,void * pData,VkDeviceSize stride,VkQueryResultFlags flags,const char * apiName) const4926 bool CoreChecks::ValidateGetQueryPoolPerformanceResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
4927                                                         void *pData, VkDeviceSize stride, VkQueryResultFlags flags,
4928                                                         const char *apiName) const {
4929     bool skip = false;
4930     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
4931 
4932     if (!query_pool_state || query_pool_state->createInfo.queryType != VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) return skip;
4933 
4934     if (((((uintptr_t)pData) % sizeof(VkPerformanceCounterResultKHR)) != 0 ||
4935          (stride % sizeof(VkPerformanceCounterResultKHR)) != 0)) {
4936         skip |= LogError(queryPool, "VUID-vkGetQueryPoolResults-queryType-03229",
4937                          "%s(): QueryPool %s was created with a queryType of "
4938                          "VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR but pData & stride are not multiple of the "
4939                          "size of VkPerformanceCounterResultKHR.",
4940                          apiName, report_data->FormatHandle(queryPool).c_str());
4941     }
4942 
4943     skip |= ValidatePerformanceQueryResults(apiName, query_pool_state.get(), firstQuery, queryCount, flags);
4944 
4945     return skip;
4946 }
4947 
PreCallValidateGetQueryPoolResults(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,size_t dataSize,void * pData,VkDeviceSize stride,VkQueryResultFlags flags) const4948 bool CoreChecks::PreCallValidateGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
4949                                                     uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride,
4950                                                     VkQueryResultFlags flags) const {
4951     if (disabled[query_validation]) return false;
4952     bool skip = false;
4953     skip |= ValidateQueryPoolStride("VUID-vkGetQueryPoolResults-flags-02827", "VUID-vkGetQueryPoolResults-flags-00815", stride,
4954                                     "dataSize", dataSize, flags);
4955     skip |= ValidateQueryPoolIndex(queryPool, firstQuery, queryCount, "vkGetQueryPoolResults()",
4956                                    "VUID-vkGetQueryPoolResults-firstQuery-00813", "VUID-vkGetQueryPoolResults-firstQuery-00816");
4957     skip |=
4958         ValidateGetQueryPoolPerformanceResults(queryPool, firstQuery, queryCount, pData, stride, flags, "vkGetQueryPoolResults");
4959 
4960     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
4961     if (query_pool_state) {
4962         if ((query_pool_state->createInfo.queryType == VK_QUERY_TYPE_TIMESTAMP) && (flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
4963             skip |= LogError(
4964                 queryPool, "VUID-vkGetQueryPoolResults-queryType-00818",
4965                 "%s was created with a queryType of VK_QUERY_TYPE_TIMESTAMP but flags contains VK_QUERY_RESULT_PARTIAL_BIT.",
4966                 report_data->FormatHandle(queryPool).c_str());
4967         }
4968 
4969         if (!skip) {
4970             uint32_t query_avail_data = (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) ? 1 : 0;
4971             uint32_t query_size_in_bytes = (flags & VK_QUERY_RESULT_64_BIT) ? sizeof(uint64_t) : sizeof(uint32_t);
4972             uint32_t query_items = 0;
4973             uint32_t query_size = 0;
4974 
4975             switch (query_pool_state->createInfo.queryType) {
4976                 case VK_QUERY_TYPE_OCCLUSION:
4977                     // Occlusion queries write one integer value - the number of samples passed.
4978                     query_items = 1;
4979                     query_size = query_size_in_bytes * (query_items + query_avail_data);
4980                     break;
4981 
4982                 case VK_QUERY_TYPE_PIPELINE_STATISTICS:
4983                     // Pipeline statistics queries write one integer value for each bit that is enabled in the pipelineStatistics
4984                     // when the pool is created
4985                     {
4986                         const int num_bits = sizeof(VkFlags) * CHAR_BIT;
4987                         std::bitset<num_bits> pipe_stats_bits(query_pool_state->createInfo.pipelineStatistics);
4988                         query_items = static_cast<uint32_t>(pipe_stats_bits.count());
4989                         query_size = query_size_in_bytes * (query_items + query_avail_data);
4990                     }
4991                     break;
4992 
4993                 case VK_QUERY_TYPE_TIMESTAMP:
4994                     // Timestamp queries write one integer
4995                     query_items = 1;
4996                     query_size = query_size_in_bytes * (query_items + query_avail_data);
4997                     break;
4998 
4999                 case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
5000                     // Transform feedback queries write two integers
5001                     query_items = 2;
5002                     query_size = query_size_in_bytes * (query_items + query_avail_data);
5003                     break;
5004 
5005                 case VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR:
5006                     // Performance queries store results in a tightly packed array of VkPerformanceCounterResultsKHR
5007                     query_items = query_pool_state->perf_counter_index_count;
5008                     query_size = sizeof(VkPerformanceCounterResultKHR) * query_items;
5009                     if (query_size > stride) {
5010                         skip |= LogError(queryPool, "VUID-vkGetQueryPoolResults-queryType-04519",
5011                                          "vkGetQueryPoolResults() on querypool %s specified stride %" PRIu64
5012                                          " which must be at least counterIndexCount (%d) "
5013                                          "multiplied by sizeof(VkPerformanceCounterResultKHR) (%zu).",
5014                                          report_data->FormatHandle(queryPool).c_str(), stride, query_items,
5015                                          sizeof(VkPerformanceCounterResultKHR));
5016                     }
5017                     break;
5018 
5019                 // These cases intentionally fall through to the default
5020                 case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR:  // VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV
5021                 case VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR:
5022                 case VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL:
5023                 default:
5024                     query_size = 0;
5025                     break;
5026             }
5027 
5028             if (query_size && (((queryCount - 1) * stride + query_size) > dataSize)) {
5029                 skip |= LogError(queryPool, "VUID-vkGetQueryPoolResults-dataSize-00817",
5030                                  "vkGetQueryPoolResults() on querypool %s specified dataSize %zu which is "
5031                                  "incompatible with the specified query type and options.",
5032                                  report_data->FormatHandle(queryPool).c_str(), dataSize);
5033             }
5034         }
5035         if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR &&
5036             (flags & VK_QUERY_RESULT_WITH_STATUS_BIT_KHR) == 0) {
5037             skip |= LogError(queryPool, "VUID-vkGetQueryPoolResults-queryType-04810",
5038                              "vkGetQueryPoolResults(): querypool %s was created with VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR "
5039                              "queryType, but flags do not contain VK_QUERY_RESULT_WITH_STATUS_BIT_KHR bit.",
5040                              report_data->FormatHandle(queryPool).c_str());
5041         }
5042     }
5043 
5044     return skip;
5045 }
5046 
ValidateInsertMemoryRange(const VulkanTypedHandle & typed_handle,const DEVICE_MEMORY_STATE * mem_info,VkDeviceSize memoryOffset,const char * api_name) const5047 bool CoreChecks::ValidateInsertMemoryRange(const VulkanTypedHandle &typed_handle, const DEVICE_MEMORY_STATE *mem_info,
5048                                            VkDeviceSize memoryOffset, const char *api_name) const {
5049     bool skip = false;
5050 
5051     if (memoryOffset >= mem_info->alloc_info.allocationSize) {
5052         const char *error_code = nullptr;
5053         if (typed_handle.type == kVulkanObjectTypeBuffer) {
5054             if (strcmp(api_name, "vkBindBufferMemory()") == 0) {
5055                 error_code = "VUID-vkBindBufferMemory-memoryOffset-01031";
5056             } else {
5057                 error_code = "VUID-VkBindBufferMemoryInfo-memoryOffset-01031";
5058             }
5059         } else if (typed_handle.type == kVulkanObjectTypeImage) {
5060             if (strcmp(api_name, "vkBindImageMemory()") == 0) {
5061                 error_code = "VUID-vkBindImageMemory-memoryOffset-01046";
5062             } else {
5063                 error_code = "VUID-VkBindImageMemoryInfo-memoryOffset-01046";
5064             }
5065         } else if (typed_handle.type == kVulkanObjectTypeAccelerationStructureNV) {
5066             error_code = "VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-03621";
5067         } else {
5068             // Unsupported object type
5069             assert(false);
5070         }
5071 
5072         LogObjectList objlist(mem_info->mem());
5073         objlist.add(typed_handle);
5074         skip = LogError(objlist, error_code,
5075                         "In %s, attempting to bind %s to %s, memoryOffset=0x%" PRIxLEAST64
5076                         " must be less than the memory allocation size 0x%" PRIxLEAST64 ".",
5077                         api_name, report_data->FormatHandle(mem_info->mem()).c_str(), report_data->FormatHandle(typed_handle).c_str(),
5078                         memoryOffset, mem_info->alloc_info.allocationSize);
5079     }
5080 
5081     return skip;
5082 }
5083 
ValidateInsertImageMemoryRange(VkImage image,const DEVICE_MEMORY_STATE * mem_info,VkDeviceSize mem_offset,const char * api_name) const5084 bool CoreChecks::ValidateInsertImageMemoryRange(VkImage image, const DEVICE_MEMORY_STATE *mem_info, VkDeviceSize mem_offset,
5085                                                 const char *api_name) const {
5086     return ValidateInsertMemoryRange(VulkanTypedHandle(image, kVulkanObjectTypeImage), mem_info, mem_offset, api_name);
5087 }
5088 
ValidateInsertBufferMemoryRange(VkBuffer buffer,const DEVICE_MEMORY_STATE * mem_info,VkDeviceSize mem_offset,const char * api_name) const5089 bool CoreChecks::ValidateInsertBufferMemoryRange(VkBuffer buffer, const DEVICE_MEMORY_STATE *mem_info, VkDeviceSize mem_offset,
5090                                                  const char *api_name) const {
5091     return ValidateInsertMemoryRange(VulkanTypedHandle(buffer, kVulkanObjectTypeBuffer), mem_info, mem_offset, api_name);
5092 }
5093 
ValidateInsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as,const DEVICE_MEMORY_STATE * mem_info,VkDeviceSize mem_offset,const char * api_name) const5094 bool CoreChecks::ValidateInsertAccelerationStructureMemoryRange(VkAccelerationStructureNV as, const DEVICE_MEMORY_STATE *mem_info,
5095                                                                 VkDeviceSize mem_offset, const char *api_name) const {
5096     return ValidateInsertMemoryRange(VulkanTypedHandle(as, kVulkanObjectTypeAccelerationStructureNV), mem_info, mem_offset,
5097                                      api_name);
5098 }
5099 
ValidateMemoryTypes(const DEVICE_MEMORY_STATE * mem_info,const uint32_t memory_type_bits,const char * funcName,const char * msgCode) const5100 bool CoreChecks::ValidateMemoryTypes(const DEVICE_MEMORY_STATE *mem_info, const uint32_t memory_type_bits, const char *funcName,
5101                                      const char *msgCode) const {
5102     bool skip = false;
5103     if (((1 << mem_info->alloc_info.memoryTypeIndex) & memory_type_bits) == 0) {
5104         skip = LogError(mem_info->mem(), msgCode,
5105                         "%s(): MemoryRequirements->memoryTypeBits (0x%X) for this object type are not compatible with the memory "
5106                         "type (0x%X) of %s.",
5107                         funcName, memory_type_bits, mem_info->alloc_info.memoryTypeIndex,
5108                         report_data->FormatHandle(mem_info->mem()).c_str());
5109     }
5110     return skip;
5111 }
5112 
ValidateBindBufferMemory(VkBuffer buffer,VkDeviceMemory mem,VkDeviceSize memoryOffset,const char * api_name) const5113 bool CoreChecks::ValidateBindBufferMemory(VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset,
5114                                           const char *api_name) const {
5115     const auto buffer_state = Get<BUFFER_STATE>(buffer);
5116     bool bind_buffer_mem_2 = strcmp(api_name, "vkBindBufferMemory()") != 0;
5117 
5118     bool skip = false;
5119     if (buffer_state) {
5120         // Track objects tied to memory
5121         skip = ValidateSetMemBinding(mem, *buffer_state, api_name);
5122 
5123         const auto mem_info = Get<DEVICE_MEMORY_STATE>(mem);
5124 
5125         // Validate memory requirements alignment
5126         if (SafeModulo(memoryOffset, buffer_state->requirements.alignment) != 0) {
5127             const char *vuid =
5128                 bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memoryOffset-01036" : "VUID-vkBindBufferMemory-memoryOffset-01036";
5129             skip |= LogError(buffer, vuid,
5130                              "%s: memoryOffset is 0x%" PRIxLEAST64
5131                              " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
5132                              ", returned from a call to vkGetBufferMemoryRequirements with buffer.",
5133                              api_name, memoryOffset, buffer_state->requirements.alignment);
5134         }
5135 
5136         if (mem_info) {
5137             // Validate bound memory range information
5138             skip |= ValidateInsertBufferMemoryRange(buffer, mem_info.get(), memoryOffset, api_name);
5139 
5140             const char *mem_type_vuid =
5141                 bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memory-01035" : "VUID-vkBindBufferMemory-memory-01035";
5142             skip |= ValidateMemoryTypes(mem_info.get(), buffer_state->requirements.memoryTypeBits, api_name, mem_type_vuid);
5143 
5144             // Validate memory requirements size
5145             if (buffer_state->requirements.size > (mem_info->alloc_info.allocationSize - memoryOffset)) {
5146                 const char *vuid =
5147                     bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-size-01037" : "VUID-vkBindBufferMemory-size-01037";
5148                 skip |= LogError(buffer, vuid,
5149                                  "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64
5150                                  " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64
5151                                  ", returned from a call to vkGetBufferMemoryRequirements with buffer.",
5152                                  api_name, mem_info->alloc_info.allocationSize - memoryOffset, buffer_state->requirements.size);
5153             }
5154 
5155             // Validate dedicated allocation
5156             if (mem_info->IsDedicatedBuffer() &&
5157                 ((mem_info->dedicated->handle.Cast<VkBuffer>() != buffer) || (memoryOffset != 0))) {
5158                 const char *vuid =
5159                     bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memory-01508" : "VUID-vkBindBufferMemory-memory-01508";
5160                 LogObjectList objlist(buffer);
5161                 objlist.add(mem);
5162                 objlist.add(mem_info->dedicated->handle);
5163                 skip |= LogError(objlist, vuid,
5164                                  "%s: for dedicated %s, VkMemoryDedicatedAllocateInfo::buffer %s must be equal "
5165                                  "to %s and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
5166                                  api_name, report_data->FormatHandle(mem).c_str(),
5167                                  report_data->FormatHandle(mem_info->dedicated->handle).c_str(),
5168                                  report_data->FormatHandle(buffer).c_str(), memoryOffset);
5169             }
5170 
5171             auto chained_flags_struct = LvlFindInChain<VkMemoryAllocateFlagsInfo>(mem_info->alloc_info.pNext);
5172             if (enabled_features.core12.bufferDeviceAddress &&
5173                 (buffer_state->createInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) &&
5174                 (!chained_flags_struct || !(chained_flags_struct->flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT))) {
5175                 skip |= LogError(buffer, "VUID-vkBindBufferMemory-bufferDeviceAddress-03339",
5176                                  "%s: If buffer was created with the VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT bit set, "
5177                                  "memory must have been allocated with the VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT bit set.",
5178                                  api_name);
5179             }
5180 
5181             // Validate export memory handles
5182             if ((mem_info->export_handle_type_flags != 0) &&
5183                 ((mem_info->export_handle_type_flags & buffer_state->external_memory_handle) == 0)) {
5184                 const char *vuid =
5185                     bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-memory-02726" : "VUID-vkBindBufferMemory-memory-02726";
5186                 LogObjectList objlist(buffer);
5187                 objlist.add(mem);
5188                 skip |= LogError(objlist, vuid,
5189                                  "%s: The VkDeviceMemory (%s) has an external handleType of %s which does not include at least one "
5190                                  "handle from VkBuffer (%s) handleType %s.",
5191                                  api_name, report_data->FormatHandle(mem).c_str(),
5192                                  string_VkExternalMemoryHandleTypeFlags(mem_info->export_handle_type_flags).c_str(),
5193                                  report_data->FormatHandle(buffer).c_str(),
5194                                  string_VkExternalMemoryHandleTypeFlags(buffer_state->external_memory_handle).c_str());
5195             }
5196 
5197             // Validate import memory handles
5198             if (mem_info->IsImportAHB() == true) {
5199                 skip |= ValidateBufferImportedHandleANDROID(api_name, buffer_state->external_memory_handle, mem, buffer);
5200             } else if (mem_info->IsImport() == true) {
5201                 if ((mem_info->import_handle_type_flags & buffer_state->external_memory_handle) == 0) {
5202                     const char *vuid = nullptr;
5203                     if ((bind_buffer_mem_2) && IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5204                         vuid = "VUID-VkBindBufferMemoryInfo-memory-02985";
5205                     } else if ((!bind_buffer_mem_2) &&
5206                                IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5207                         vuid = "VUID-vkBindBufferMemory-memory-02985";
5208                     } else if ((bind_buffer_mem_2) &&
5209                                !IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5210                         vuid = "VUID-VkBindBufferMemoryInfo-memory-02727";
5211                     } else if ((!bind_buffer_mem_2) &&
5212                                !IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5213                         vuid = "VUID-vkBindBufferMemory-memory-02727";
5214                     }
5215                     LogObjectList objlist(buffer);
5216                     objlist.add(mem);
5217                     skip |= LogError(objlist, vuid,
5218                                      "%s: The VkDeviceMemory (%s) was created with an import operation with handleType of %s which "
5219                                      "is not set in the VkBuffer (%s) VkExternalMemoryBufferCreateInfo::handleType (%s)",
5220                                      api_name, report_data->FormatHandle(mem).c_str(),
5221                                      string_VkExternalMemoryHandleTypeFlags(mem_info->import_handle_type_flags).c_str(),
5222                                      report_data->FormatHandle(buffer).c_str(),
5223                                      string_VkExternalMemoryHandleTypeFlags(buffer_state->external_memory_handle).c_str());
5224                 }
5225             }
5226 
5227             // Validate mix of protected buffer and memory
5228             if ((buffer_state->unprotected == false) && (mem_info->unprotected == true)) {
5229                 const char *vuid =
5230                     bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-None-01898" : "VUID-vkBindBufferMemory-None-01898";
5231                 LogObjectList objlist(buffer);
5232                 objlist.add(mem);
5233                 skip |= LogError(objlist, vuid,
5234                                  "%s: The VkDeviceMemory (%s) was not created with protected memory but the VkBuffer (%s) was set "
5235                                  "to use protected memory.",
5236                                  api_name, report_data->FormatHandle(mem).c_str(), report_data->FormatHandle(buffer).c_str());
5237             } else if ((buffer_state->unprotected == true) && (mem_info->unprotected == false)) {
5238                 const char *vuid =
5239                     bind_buffer_mem_2 ? "VUID-VkBindBufferMemoryInfo-None-01899" : "VUID-vkBindBufferMemory-None-01899";
5240                 LogObjectList objlist(buffer);
5241                 objlist.add(mem);
5242                 skip |= LogError(objlist, vuid,
5243                                  "%s: The VkDeviceMemory (%s) was created with protected memory but the VkBuffer (%s) was not set "
5244                                  "to use protected memory.",
5245                                  api_name, report_data->FormatHandle(mem).c_str(), report_data->FormatHandle(buffer).c_str());
5246             }
5247         }
5248     }
5249     return skip;
5250 }
5251 
PreCallValidateBindBufferMemory(VkDevice device,VkBuffer buffer,VkDeviceMemory mem,VkDeviceSize memoryOffset) const5252 bool CoreChecks::PreCallValidateBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem,
5253                                                  VkDeviceSize memoryOffset) const {
5254     const char *api_name = "vkBindBufferMemory()";
5255     return ValidateBindBufferMemory(buffer, mem, memoryOffset, api_name);
5256 }
5257 
PreCallValidateBindBufferMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindBufferMemoryInfo * pBindInfos) const5258 bool CoreChecks::PreCallValidateBindBufferMemory2(VkDevice device, uint32_t bindInfoCount,
5259                                                   const VkBindBufferMemoryInfo *pBindInfos) const {
5260     char api_name[64];
5261     bool skip = false;
5262 
5263     for (uint32_t i = 0; i < bindInfoCount; i++) {
5264         sprintf(api_name, "vkBindBufferMemory2() pBindInfos[%u]", i);
5265         skip |= ValidateBindBufferMemory(pBindInfos[i].buffer, pBindInfos[i].memory, pBindInfos[i].memoryOffset, api_name);
5266     }
5267     return skip;
5268 }
5269 
PreCallValidateBindBufferMemory2KHR(VkDevice device,uint32_t bindInfoCount,const VkBindBufferMemoryInfo * pBindInfos) const5270 bool CoreChecks::PreCallValidateBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount,
5271                                                      const VkBindBufferMemoryInfo *pBindInfos) const {
5272     char api_name[64];
5273     bool skip = false;
5274 
5275     for (uint32_t i = 0; i < bindInfoCount; i++) {
5276         sprintf(api_name, "vkBindBufferMemory2KHR() pBindInfos[%u]", i);
5277         skip |= ValidateBindBufferMemory(pBindInfos[i].buffer, pBindInfos[i].memory, pBindInfos[i].memoryOffset, api_name);
5278     }
5279     return skip;
5280 }
5281 
PreCallValidateGetImageMemoryRequirements(VkDevice device,VkImage image,VkMemoryRequirements * pMemoryRequirements) const5282 bool CoreChecks::PreCallValidateGetImageMemoryRequirements(VkDevice device, VkImage image,
5283                                                            VkMemoryRequirements *pMemoryRequirements) const {
5284     bool skip = false;
5285     if (IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5286         skip |= ValidateGetImageMemoryRequirementsANDROID(image, "vkGetImageMemoryRequirements()");
5287     }
5288 
5289     const auto image_state = Get<IMAGE_STATE>(image);
5290     if (image_state) {
5291         // Checks for no disjoint bit
5292         if (image_state->disjoint == true) {
5293             skip |= LogError(image, "VUID-vkGetImageMemoryRequirements-image-01588",
5294                              "vkGetImageMemoryRequirements(): %s must not have been created with the VK_IMAGE_CREATE_DISJOINT_BIT "
5295                              "(need to use vkGetImageMemoryRequirements2).",
5296                              report_data->FormatHandle(image).c_str());
5297         }
5298     }
5299     return skip;
5300 }
5301 
ValidateGetImageMemoryRequirements2(const VkImageMemoryRequirementsInfo2 * pInfo,const char * func_name) const5302 bool CoreChecks::ValidateGetImageMemoryRequirements2(const VkImageMemoryRequirementsInfo2 *pInfo, const char *func_name) const {
5303     bool skip = false;
5304     if (IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
5305         skip |= ValidateGetImageMemoryRequirementsANDROID(pInfo->image, func_name);
5306     }
5307 
5308     const auto image_state = Get<IMAGE_STATE>(pInfo->image);
5309     const VkFormat image_format = image_state->createInfo.format;
5310     const VkImageTiling image_tiling = image_state->createInfo.tiling;
5311     const VkImagePlaneMemoryRequirementsInfo *image_plane_info = LvlFindInChain<VkImagePlaneMemoryRequirementsInfo>(pInfo->pNext);
5312 
5313     if ((FormatIsMultiplane(image_format)) && (image_state->disjoint == true) && (image_plane_info == nullptr)) {
5314         skip |= LogError(pInfo->image, "VUID-VkImageMemoryRequirementsInfo2-image-01589",
5315                          "%s: %s image was created with a multi-planar format (%s) and "
5316                          "VK_IMAGE_CREATE_DISJOINT_BIT, but the current pNext doesn't include a "
5317                          "VkImagePlaneMemoryRequirementsInfo struct",
5318                          func_name, report_data->FormatHandle(pInfo->image).c_str(), string_VkFormat(image_format));
5319     }
5320 
5321     if ((image_state->disjoint == false) && (image_plane_info != nullptr)) {
5322         skip |= LogError(pInfo->image, "VUID-VkImageMemoryRequirementsInfo2-image-01590",
5323                          "%s: %s image was not created with VK_IMAGE_CREATE_DISJOINT_BIT,"
5324                          "but the current pNext includes a VkImagePlaneMemoryRequirementsInfo struct",
5325                          func_name, report_data->FormatHandle(pInfo->image).c_str());
5326     }
5327 
5328     if ((FormatIsMultiplane(image_format) == false) && (image_tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) &&
5329         (image_plane_info != nullptr)) {
5330         const char *vuid = IsExtEnabled(device_extensions.vk_ext_image_drm_format_modifier)
5331                                ? "VUID-VkImageMemoryRequirementsInfo2-image-02280"
5332                                : "VUID-VkImageMemoryRequirementsInfo2-image-01591";
5333         skip |= LogError(pInfo->image, vuid,
5334                          "%s: %s image is a single-plane format (%s) and does not have tiling of "
5335                          "VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,"
5336                          "but the current pNext includes a VkImagePlaneMemoryRequirementsInfo struct",
5337                          func_name, report_data->FormatHandle(pInfo->image).c_str(), string_VkFormat(image_format));
5338     }
5339 
5340     if (image_plane_info != nullptr) {
5341         if ((image_tiling == VK_IMAGE_TILING_LINEAR) || (image_tiling == VK_IMAGE_TILING_OPTIMAL)) {
5342             // Make sure planeAspect is only a single, valid plane
5343             uint32_t planes = FormatPlaneCount(image_format);
5344             VkImageAspectFlags aspect = image_plane_info->planeAspect;
5345             if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT)) {
5346                 skip |= LogError(
5347                     pInfo->image, "VUID-VkImagePlaneMemoryRequirementsInfo-planeAspect-02281",
5348                     "%s: Image %s VkImagePlaneMemoryRequirementsInfo::planeAspect is %s but can only be VK_IMAGE_ASPECT_PLANE_0_BIT"
5349                     "or VK_IMAGE_ASPECT_PLANE_1_BIT.",
5350                     func_name, report_data->FormatHandle(image_state->image()).c_str(), string_VkImageAspectFlags(aspect).c_str());
5351             }
5352             if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT) &&
5353                 (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT)) {
5354                 skip |= LogError(
5355                     pInfo->image, "VUID-VkImagePlaneMemoryRequirementsInfo-planeAspect-02281",
5356                     "%s: Image %s VkImagePlaneMemoryRequirementsInfo::planeAspect is %s but can only be VK_IMAGE_ASPECT_PLANE_0_BIT"
5357                     "or VK_IMAGE_ASPECT_PLANE_1_BIT or VK_IMAGE_ASPECT_PLANE_2_BIT.",
5358                     func_name, report_data->FormatHandle(image_state->image()).c_str(), string_VkImageAspectFlags(aspect).c_str());
5359             }
5360         }
5361     }
5362     return skip;
5363 }
5364 
PreCallValidateGetImageMemoryRequirements2(VkDevice device,const VkImageMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements) const5365 bool CoreChecks::PreCallValidateGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
5366                                                             VkMemoryRequirements2 *pMemoryRequirements) const {
5367     return ValidateGetImageMemoryRequirements2(pInfo, "vkGetImageMemoryRequirements2()");
5368 }
5369 
PreCallValidateGetImageMemoryRequirements2KHR(VkDevice device,const VkImageMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements) const5370 bool CoreChecks::PreCallValidateGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
5371                                                                VkMemoryRequirements2 *pMemoryRequirements) const {
5372     return ValidateGetImageMemoryRequirements2(pInfo, "vkGetImageMemoryRequirements2KHR()");
5373 }
5374 
PreCallValidateGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkImageFormatProperties2 * pImageFormatProperties) const5375 bool CoreChecks::PreCallValidateGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
5376                                                                         const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
5377                                                                         VkImageFormatProperties2 *pImageFormatProperties) const {
5378     // Can't wrap AHB-specific validation in a device extension check here, but no harm
5379     bool skip = ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(pImageFormatInfo, pImageFormatProperties);
5380     return skip;
5381 }
5382 
PreCallValidateGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkImageFormatProperties2 * pImageFormatProperties) const5383 bool CoreChecks::PreCallValidateGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice,
5384                                                                            const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
5385                                                                            VkImageFormatProperties2 *pImageFormatProperties) const {
5386     // Can't wrap AHB-specific validation in a device extension check here, but no harm
5387     bool skip = ValidateGetPhysicalDeviceImageFormatProperties2ANDROID(pImageFormatInfo, pImageFormatProperties);
5388     return skip;
5389 }
5390 
PreCallValidateDestroyPipeline(VkDevice device,VkPipeline pipeline,const VkAllocationCallbacks * pAllocator) const5391 bool CoreChecks::PreCallValidateDestroyPipeline(VkDevice device, VkPipeline pipeline,
5392                                                 const VkAllocationCallbacks *pAllocator) const {
5393     const auto pipeline_state = Get<PIPELINE_STATE>(pipeline);
5394     bool skip = false;
5395     if (pipeline_state) {
5396         skip |= ValidateObjectNotInUse(pipeline_state.get(), "vkDestroyPipeline", "VUID-vkDestroyPipeline-pipeline-00765");
5397     }
5398     return skip;
5399 }
5400 
PreCallValidateDestroySampler(VkDevice device,VkSampler sampler,const VkAllocationCallbacks * pAllocator) const5401 bool CoreChecks::PreCallValidateDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) const {
5402     const auto sampler_state = Get<SAMPLER_STATE>(sampler);
5403     bool skip = false;
5404     if (sampler_state) {
5405         skip |= ValidateObjectNotInUse(sampler_state.get(), "vkDestroySampler", "VUID-vkDestroySampler-sampler-01082");
5406     }
5407     return skip;
5408 }
5409 
PreCallValidateDestroyDescriptorPool(VkDevice device,VkDescriptorPool descriptorPool,const VkAllocationCallbacks * pAllocator) const5410 bool CoreChecks::PreCallValidateDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
5411                                                       const VkAllocationCallbacks *pAllocator) const {
5412     const auto desc_pool_state = Get<DESCRIPTOR_POOL_STATE>(descriptorPool);
5413     bool skip = false;
5414     if (desc_pool_state) {
5415         skip |= ValidateObjectNotInUse(desc_pool_state.get(), "vkDestroyDescriptorPool",
5416                                        "VUID-vkDestroyDescriptorPool-descriptorPool-00303");
5417     }
5418     return skip;
5419 }
5420 
5421 // Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip result
5422 //  If this is a secondary command buffer, then make sure its primary is also in-flight
5423 //  If primary is not in-flight, then remove secondary from global in-flight set
5424 // This function is only valid at a point when cmdBuffer is being reset or freed
CheckCommandBufferInFlight(const CMD_BUFFER_STATE * cb_node,const char * action,const char * error_code) const5425 bool CoreChecks::CheckCommandBufferInFlight(const CMD_BUFFER_STATE *cb_node, const char *action, const char *error_code) const {
5426     bool skip = false;
5427     if (cb_node->InUse()) {
5428         skip |= LogError(cb_node->commandBuffer(), error_code, "Attempt to %s %s which is in use.", action,
5429                          report_data->FormatHandle(cb_node->commandBuffer()).c_str());
5430     }
5431     return skip;
5432 }
5433 
5434 // Iterate over all cmdBuffers in given commandPool and verify that each is not in use
CheckCommandBuffersInFlight(const COMMAND_POOL_STATE * pPool,const char * action,const char * error_code) const5435 bool CoreChecks::CheckCommandBuffersInFlight(const COMMAND_POOL_STATE *pPool, const char *action, const char *error_code) const {
5436     bool skip = false;
5437     for (auto &entry : pPool->commandBuffers) {
5438         const auto cb_state = entry.second;
5439         skip |= CheckCommandBufferInFlight(cb_state, action, error_code);
5440     }
5441     return skip;
5442 }
5443 
PreCallValidateFreeCommandBuffers(VkDevice device,VkCommandPool commandPool,uint32_t commandBufferCount,const VkCommandBuffer * pCommandBuffers) const5444 bool CoreChecks::PreCallValidateFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount,
5445                                                    const VkCommandBuffer *pCommandBuffers) const {
5446     bool skip = false;
5447     for (uint32_t i = 0; i < commandBufferCount; i++) {
5448         const auto cb_node = Get<CMD_BUFFER_STATE>(pCommandBuffers[i]);
5449         // Delete CB information structure, and remove from commandBufferMap
5450         if (cb_node) {
5451             skip |= CheckCommandBufferInFlight(cb_node.get(), "free", "VUID-vkFreeCommandBuffers-pCommandBuffers-00047");
5452         }
5453     }
5454     return skip;
5455 }
5456 
PreCallValidateCreateCommandPool(VkDevice device,const VkCommandPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkCommandPool * pCommandPool) const5457 bool CoreChecks::PreCallValidateCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5458                                                   const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) const {
5459     bool skip = false;
5460     skip |= ValidateDeviceQueueFamily(pCreateInfo->queueFamilyIndex, "vkCreateCommandPool", "pCreateInfo->queueFamilyIndex",
5461                                       "VUID-vkCreateCommandPool-queueFamilyIndex-01937");
5462     if ((enabled_features.core11.protectedMemory == VK_FALSE) &&
5463         ((pCreateInfo->flags & VK_COMMAND_POOL_CREATE_PROTECTED_BIT) != 0)) {
5464         skip |= LogError(device, "VUID-VkCommandPoolCreateInfo-flags-02860",
5465                          "vkCreateCommandPool(): the protectedMemory device feature is disabled: CommandPools cannot be created "
5466                          "with the VK_COMMAND_POOL_CREATE_PROTECTED_BIT set.");
5467     }
5468 
5469     return skip;
5470 }
5471 
PreCallValidateCreateQueryPool(VkDevice device,const VkQueryPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkQueryPool * pQueryPool) const5472 bool CoreChecks::PreCallValidateCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
5473                                                 const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) const {
5474     if (disabled[query_validation]) return false;
5475     bool skip = false;
5476     if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
5477         if (!enabled_features.core.pipelineStatisticsQuery) {
5478             skip |= LogError(device, "VUID-VkQueryPoolCreateInfo-queryType-00791",
5479                              "vkCreateQueryPool(): Query pool with type VK_QUERY_TYPE_PIPELINE_STATISTICS created on a device with "
5480                              "VkDeviceCreateInfo.pEnabledFeatures.pipelineStatisticsQuery == VK_FALSE.");
5481         }
5482     }
5483     if (pCreateInfo && pCreateInfo->queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
5484         if (!enabled_features.performance_query_features.performanceCounterQueryPools) {
5485             skip |=
5486                 LogError(device, "VUID-VkQueryPoolPerformanceCreateInfoKHR-performanceCounterQueryPools-03237",
5487                          "vkCreateQueryPool(): Query pool with type VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR created on a device with "
5488                          "VkPhysicalDevicePerformanceQueryFeaturesKHR.performanceCounterQueryPools == VK_FALSE.");
5489         }
5490 
5491         auto perf_ci = LvlFindInChain<VkQueryPoolPerformanceCreateInfoKHR>(pCreateInfo->pNext);
5492         if (!perf_ci) {
5493             skip |= LogError(
5494                 device, "VUID-VkQueryPoolCreateInfo-queryType-03222",
5495                 "vkCreateQueryPool(): Query pool with type VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR created but the pNext chain of "
5496                 "pCreateInfo does not contain in instance of VkQueryPoolPerformanceCreateInfoKHR.");
5497         } else {
5498             const auto &perf_counter_iter = physical_device_state->perf_counters.find(perf_ci->queueFamilyIndex);
5499             if (perf_counter_iter == physical_device_state->perf_counters.end()) {
5500                 skip |= LogError(
5501                     device, "VUID-VkQueryPoolPerformanceCreateInfoKHR-queueFamilyIndex-03236",
5502                     "vkCreateQueryPool(): VkQueryPerformanceCreateInfoKHR::queueFamilyIndex is not a valid queue family index.");
5503             } else {
5504                 const QUEUE_FAMILY_PERF_COUNTERS *perf_counters = perf_counter_iter->second.get();
5505                 for (uint32_t idx = 0; idx < perf_ci->counterIndexCount; idx++) {
5506                     if (perf_ci->pCounterIndices[idx] >= perf_counters->counters.size()) {
5507                         skip |= LogError(
5508                             device, "VUID-VkQueryPoolPerformanceCreateInfoKHR-pCounterIndices-03321",
5509                             "vkCreateQueryPool(): VkQueryPerformanceCreateInfoKHR::pCounterIndices[%u] = %u is not a valid "
5510                             "counter index.",
5511                             idx, perf_ci->pCounterIndices[idx]);
5512                     }
5513                 }
5514             }
5515         }
5516     }
5517     return skip;
5518 }
5519 
PreCallValidateDestroyCommandPool(VkDevice device,VkCommandPool commandPool,const VkAllocationCallbacks * pAllocator) const5520 bool CoreChecks::PreCallValidateDestroyCommandPool(VkDevice device, VkCommandPool commandPool,
5521                                                    const VkAllocationCallbacks *pAllocator) const {
5522     const auto cp_state = Get<COMMAND_POOL_STATE>(commandPool);
5523     bool skip = false;
5524     if (cp_state) {
5525         // Verify that command buffers in pool are complete (not in-flight)
5526         skip |=
5527             CheckCommandBuffersInFlight(cp_state.get(), "destroy command pool with", "VUID-vkDestroyCommandPool-commandPool-00041");
5528     }
5529     return skip;
5530 }
5531 
PreCallValidateResetCommandPool(VkDevice device,VkCommandPool commandPool,VkCommandPoolResetFlags flags) const5532 bool CoreChecks::PreCallValidateResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) const {
5533     const auto command_pool_state = Get<COMMAND_POOL_STATE>(commandPool);
5534     return CheckCommandBuffersInFlight(command_pool_state.get(), "reset command pool with",
5535                                        "VUID-vkResetCommandPool-commandPool-00040");
5536 }
5537 
PreCallValidateResetFences(VkDevice device,uint32_t fenceCount,const VkFence * pFences) const5538 bool CoreChecks::PreCallValidateResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) const {
5539     bool skip = false;
5540     for (uint32_t i = 0; i < fenceCount; ++i) {
5541         const auto fence_state = Get<FENCE_STATE>(pFences[i]);
5542         if (fence_state && fence_state->scope == kSyncScopeInternal && fence_state->state == FENCE_INFLIGHT) {
5543             skip |= LogError(pFences[i], "VUID-vkResetFences-pFences-01123", "%s is in use.",
5544                              report_data->FormatHandle(pFences[i]).c_str());
5545         }
5546     }
5547     return skip;
5548 }
5549 
PreCallValidateDestroyFramebuffer(VkDevice device,VkFramebuffer framebuffer,const VkAllocationCallbacks * pAllocator) const5550 bool CoreChecks::PreCallValidateDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer,
5551                                                    const VkAllocationCallbacks *pAllocator) const {
5552     const auto framebuffer_state = Get<FRAMEBUFFER_STATE>(framebuffer);
5553     bool skip = false;
5554     if (framebuffer_state) {
5555         skip |=
5556             ValidateObjectNotInUse(framebuffer_state.get(), "vkDestroyFramebuffer", "VUID-vkDestroyFramebuffer-framebuffer-00892");
5557     }
5558     return skip;
5559 }
5560 
PreCallValidateDestroyRenderPass(VkDevice device,VkRenderPass renderPass,const VkAllocationCallbacks * pAllocator) const5561 bool CoreChecks::PreCallValidateDestroyRenderPass(VkDevice device, VkRenderPass renderPass,
5562                                                   const VkAllocationCallbacks *pAllocator) const {
5563     const auto rp_state = Get<RENDER_PASS_STATE>(renderPass);
5564     bool skip = false;
5565     if (rp_state) {
5566         skip |= ValidateObjectNotInUse(rp_state.get(), "vkDestroyRenderPass", "VUID-vkDestroyRenderPass-renderPass-00873");
5567     }
5568     return skip;
5569 }
5570 
5571 // Access helper functions for external modules
GetPDFormatProperties(const VkFormat format) const5572 VkFormatProperties CoreChecks::GetPDFormatProperties(const VkFormat format) const {
5573     VkFormatProperties format_properties;
5574     DispatchGetPhysicalDeviceFormatProperties(physical_device, format, &format_properties);
5575     return format_properties;
5576 }
5577 
ValidatePipelineVertexDivisors(std::vector<std::shared_ptr<PIPELINE_STATE>> const & pipe_state_vec,const uint32_t count,const VkGraphicsPipelineCreateInfo * pipe_cis) const5578 bool CoreChecks::ValidatePipelineVertexDivisors(std::vector<std::shared_ptr<PIPELINE_STATE>> const &pipe_state_vec,
5579                                                 const uint32_t count, const VkGraphicsPipelineCreateInfo *pipe_cis) const {
5580     bool skip = false;
5581     const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
5582 
5583     for (uint32_t i = 0; i < count; i++) {
5584         auto pvids_ci = (pipe_cis[i].pVertexInputState) ? LvlFindInChain<VkPipelineVertexInputDivisorStateCreateInfoEXT>(pipe_cis[i].pVertexInputState->pNext) : nullptr;
5585         if (nullptr == pvids_ci) continue;
5586 
5587         const PIPELINE_STATE *pipe_state = pipe_state_vec[i].get();
5588         for (uint32_t j = 0; j < pvids_ci->vertexBindingDivisorCount; j++) {
5589             const VkVertexInputBindingDivisorDescriptionEXT *vibdd = &(pvids_ci->pVertexBindingDivisors[j]);
5590             if (vibdd->binding >= device_limits->maxVertexInputBindings) {
5591                 skip |= LogError(
5592                     device, "VUID-VkVertexInputBindingDivisorDescriptionEXT-binding-01869",
5593                     "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
5594                     "pVertexBindingDivisors[%1u] binding index of (%1u) exceeds device maxVertexInputBindings (%1u).",
5595                     i, j, vibdd->binding, device_limits->maxVertexInputBindings);
5596             }
5597             if (vibdd->divisor > phys_dev_ext_props.vtx_attrib_divisor_props.maxVertexAttribDivisor) {
5598                 skip |= LogError(
5599                     device, "VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870",
5600                     "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
5601                     "pVertexBindingDivisors[%1u] divisor of (%1u) exceeds extension maxVertexAttribDivisor (%1u).",
5602                     i, j, vibdd->divisor, phys_dev_ext_props.vtx_attrib_divisor_props.maxVertexAttribDivisor);
5603             }
5604             if ((0 == vibdd->divisor) && !enabled_features.vtx_attrib_divisor_features.vertexAttributeInstanceRateZeroDivisor) {
5605                 skip |= LogError(
5606                     device, "VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228",
5607                     "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
5608                     "pVertexBindingDivisors[%1u] divisor must not be 0 when vertexAttributeInstanceRateZeroDivisor feature is not "
5609                     "enabled.",
5610                     i, j);
5611             }
5612             if ((1 != vibdd->divisor) && !enabled_features.vtx_attrib_divisor_features.vertexAttributeInstanceRateDivisor) {
5613                 skip |= LogError(
5614                     device, "VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229",
5615                     "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
5616                     "pVertexBindingDivisors[%1u] divisor (%1u) must be 1 when vertexAttributeInstanceRateDivisor feature is not "
5617                     "enabled.",
5618                     i, j, vibdd->divisor);
5619             }
5620 
5621             // Find the corresponding binding description and validate input rate setting
5622             bool failed_01871 = true;
5623             for (size_t k = 0; k < pipe_state->vertex_binding_descriptions_.size(); k++) {
5624                 if ((vibdd->binding == pipe_state->vertex_binding_descriptions_[k].binding) &&
5625                     (VK_VERTEX_INPUT_RATE_INSTANCE == pipe_state->vertex_binding_descriptions_[k].inputRate)) {
5626                     failed_01871 = false;
5627                     break;
5628                 }
5629             }
5630             if (failed_01871) {  // Description not found, or has incorrect inputRate value
5631                 skip |= LogError(
5632                     device, "VUID-VkVertexInputBindingDivisorDescriptionEXT-inputRate-01871",
5633                     "vkCreateGraphicsPipelines(): Pipeline[%1u] with chained VkPipelineVertexInputDivisorStateCreateInfoEXT, "
5634                     "pVertexBindingDivisors[%1u] specifies binding index (%1u), but that binding index's "
5635                     "VkVertexInputBindingDescription.inputRate member is not VK_VERTEX_INPUT_RATE_INSTANCE.",
5636                     i, j, vibdd->binding);
5637             }
5638         }
5639     }
5640     return skip;
5641 }
5642 
ValidatePipelineCacheControlFlags(VkPipelineCreateFlags flags,uint32_t index,const char * caller_name,const char * vuid) const5643 bool CoreChecks::ValidatePipelineCacheControlFlags(VkPipelineCreateFlags flags, uint32_t index, const char *caller_name,
5644                                                    const char *vuid) const {
5645     bool skip = false;
5646     if (enabled_features.pipeline_creation_cache_control_features.pipelineCreationCacheControl == VK_FALSE) {
5647         const VkPipelineCreateFlags invalid_flags =
5648             VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT | VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT;
5649         if ((flags & invalid_flags) != 0) {
5650             skip |= LogError(device, vuid,
5651                              "%s(): pipelineCreationCacheControl is turned off but pipeline[%u] has VkPipelineCreateFlags "
5652                              "containing VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT or "
5653                              "VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT",
5654                              caller_name, index);
5655         }
5656     }
5657     return skip;
5658 }
5659 
PreCallValidateCreatePipelineCache(VkDevice device,const VkPipelineCacheCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineCache * pPipelineCache) const5660 bool CoreChecks::PreCallValidateCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
5661                                                     const VkAllocationCallbacks *pAllocator,
5662                                                     VkPipelineCache *pPipelineCache) const {
5663     bool skip = false;
5664     if (enabled_features.pipeline_creation_cache_control_features.pipelineCreationCacheControl == VK_FALSE) {
5665         if ((pCreateInfo->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT) != 0) {
5666             skip |= LogError(device, "VUID-VkPipelineCacheCreateInfo-pipelineCreationCacheControl-02892",
5667                              "vkCreatePipelineCache(): pipelineCreationCacheControl is turned off but pCreateInfo::flags contains "
5668                              "VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT");
5669         }
5670     }
5671     return skip;
5672 }
5673 
PreCallValidateCreateGraphicsPipelines(VkDevice device,VkPipelineCache pipelineCache,uint32_t count,const VkGraphicsPipelineCreateInfo * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines,void * cgpl_state_data) const5674 bool CoreChecks::PreCallValidateCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
5675                                                         const VkGraphicsPipelineCreateInfo *pCreateInfos,
5676                                                         const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
5677                                                         void *cgpl_state_data) const {
5678     bool skip = StateTracker::PreCallValidateCreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
5679                                                                      pPipelines, cgpl_state_data);
5680     create_graphics_pipeline_api_state *cgpl_state = reinterpret_cast<create_graphics_pipeline_api_state *>(cgpl_state_data);
5681 
5682     for (uint32_t i = 0; i < count; i++) {
5683         if (pCreateInfos[i].renderPass == VK_NULL_HANDLE) {
5684             if (!enabled_features.dynamic_rendering_features.dynamicRendering) {
5685                 skip |= LogError(device, "VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06052",
5686                                  "vkCreateGraphicsPipeline: pCreateInfos[%" PRIu32
5687                                  "].renderPass is VK_NULL_HANDLE but dynamicRendering is not enabled.",
5688                                  i);
5689 
5690                 return true;
5691             }
5692         }
5693     }
5694 
5695     for (uint32_t i = 0; i < count; i++) {
5696         skip |= ValidatePipelineLocked(cgpl_state->pipe_state, i);
5697     }
5698 
5699     for (uint32_t i = 0; i < count; i++) {
5700         skip |= ValidatePipelineUnlocked(cgpl_state->pipe_state[i].get(), i);
5701     }
5702 
5703     if (IsExtEnabled(device_extensions.vk_ext_vertex_attribute_divisor)) {
5704         skip |= ValidatePipelineVertexDivisors(cgpl_state->pipe_state, count, pCreateInfos);
5705     }
5706 
5707     if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
5708         for (uint32_t i = 0; i < count; ++i) {
5709             // Validate depth-stencil state
5710             auto raster_state_ci = pCreateInfos[i].pRasterizationState;
5711             if ((VK_FALSE == enabled_features.portability_subset_features.separateStencilMaskRef) && raster_state_ci &&
5712                 (VK_CULL_MODE_NONE == raster_state_ci->cullMode)) {
5713                 auto depth_stencil_ci = pCreateInfos[i].pDepthStencilState;
5714                 if (depth_stencil_ci && (VK_TRUE == depth_stencil_ci->stencilTestEnable) &&
5715                     (depth_stencil_ci->front.reference != depth_stencil_ci->back.reference)) {
5716                     skip |= LogError(device, "VUID-VkPipelineDepthStencilStateCreateInfo-separateStencilMaskRef-04453",
5717                                      "Invalid Pipeline CreateInfo[%d] (portability error): VkStencilOpState::reference must be the "
5718                                      "same for front and back",
5719                                      i);
5720                 }
5721             }
5722 
5723             // Validate color attachments
5724             uint32_t subpass = pCreateInfos[i].subpass;
5725             const auto render_pass = Get<RENDER_PASS_STATE>(pCreateInfos[i].renderPass);
5726             bool ignore_color_blend_state = pCreateInfos[i].pRasterizationState->rasterizerDiscardEnable ||
5727                                             render_pass->createInfo.pSubpasses[subpass].colorAttachmentCount == 0;
5728             if ((VK_FALSE == enabled_features.portability_subset_features.constantAlphaColorBlendFactors) &&
5729                 !ignore_color_blend_state) {
5730                 auto color_blend_state = pCreateInfos[i].pColorBlendState;
5731                 const auto attachments = color_blend_state->pAttachments;
5732                 for (uint32_t color_attachment_index = 0; i < color_blend_state->attachmentCount; ++i) {
5733                     if ((VK_BLEND_FACTOR_CONSTANT_ALPHA == attachments[color_attachment_index].srcColorBlendFactor) ||
5734                         (VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA == attachments[color_attachment_index].srcColorBlendFactor)) {
5735                         skip |= LogError(
5736                             device, "VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04454",
5737                             "Invalid Pipeline CreateInfo[%d] (portability error): srcColorBlendFactor for color attachment %d must "
5738                             "not be VK_BLEND_FACTOR_CONSTANT_ALPHA or VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA",
5739                             i, color_attachment_index);
5740                     }
5741                     if ((VK_BLEND_FACTOR_CONSTANT_ALPHA == attachments[color_attachment_index].dstColorBlendFactor) ||
5742                         (VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA == attachments[color_attachment_index].dstColorBlendFactor)) {
5743                         skip |= LogError(
5744                             device, "VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04455",
5745                             "Invalid Pipeline CreateInfo[%d] (portability error): dstColorBlendFactor for color attachment %d must "
5746                             "not be VK_BLEND_FACTOR_CONSTANT_ALPHA or VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA",
5747                             i, color_attachment_index);
5748                     }
5749                 }
5750             }
5751         }
5752     }
5753 
5754     return skip;
5755 }
5756 
PreCallValidateCreateComputePipelines(VkDevice device,VkPipelineCache pipelineCache,uint32_t count,const VkComputePipelineCreateInfo * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines,void * ccpl_state_data) const5757 bool CoreChecks::PreCallValidateCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
5758                                                        const VkComputePipelineCreateInfo *pCreateInfos,
5759                                                        const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
5760                                                        void *ccpl_state_data) const {
5761     bool skip = StateTracker::PreCallValidateCreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
5762                                                                     pPipelines, ccpl_state_data);
5763 
5764     auto *ccpl_state = reinterpret_cast<create_compute_pipeline_api_state *>(ccpl_state_data);
5765     for (uint32_t i = 0; i < count; i++) {
5766         // TODO: Add Compute Pipeline Verification
5767         skip |= ValidateComputePipelineShaderState(ccpl_state->pipe_state[i].get());
5768         skip |= ValidatePipelineCacheControlFlags(pCreateInfos->flags, i, "vkCreateComputePipelines",
5769                                                   "VUID-VkComputePipelineCreateInfo-pipelineCreationCacheControl-02875");
5770     }
5771     return skip;
5772 }
5773 
PreCallValidateCreateRayTracingPipelinesNV(VkDevice device,VkPipelineCache pipelineCache,uint32_t count,const VkRayTracingPipelineCreateInfoNV * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines,void * crtpl_state_data) const5774 bool CoreChecks::PreCallValidateCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
5775                                                             const VkRayTracingPipelineCreateInfoNV *pCreateInfos,
5776                                                             const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
5777                                                             void *crtpl_state_data) const {
5778     bool skip = StateTracker::PreCallValidateCreateRayTracingPipelinesNV(device, pipelineCache, count, pCreateInfos, pAllocator,
5779                                                                          pPipelines, crtpl_state_data);
5780 
5781     auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_api_state *>(crtpl_state_data);
5782     for (uint32_t i = 0; i < count; i++) {
5783         PIPELINE_STATE *pipeline = crtpl_state->pipe_state[i].get();
5784         const auto &create_info = pipeline->create_info.raytracing;
5785         if (create_info.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
5786             std::shared_ptr<const PIPELINE_STATE> base_pipeline;
5787             if (create_info.basePipelineIndex != -1) {
5788                 base_pipeline = crtpl_state->pipe_state[create_info.basePipelineIndex];
5789             } else if (create_info.basePipelineHandle != VK_NULL_HANDLE) {
5790                 base_pipeline = Get<PIPELINE_STATE>(create_info.basePipelineHandle);
5791             }
5792             if (!base_pipeline || !(base_pipeline->GetPipelineCreateFlags() & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
5793                 skip |= LogError(
5794                     device, "VUID-vkCreateRayTracingPipelinesNV-flags-03416",
5795                     "vkCreateRayTracingPipelinesNV: If the flags member of any element of pCreateInfos contains the "
5796                     "VK_PIPELINE_CREATE_DERIVATIVE_BIT flag,"
5797                     "the base pipeline must have been created with the VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT flag set.");
5798             }
5799         }
5800         skip |= ValidateRayTracingPipeline(pipeline, pCreateInfos[i].flags, /*isKHR*/ false);
5801         skip |= ValidatePipelineCacheControlFlags(pCreateInfos[i].flags, i, "vkCreateRayTracingPipelinesNV",
5802                                                   "VUID-VkRayTracingPipelineCreateInfoNV-pipelineCreationCacheControl-02905");
5803     }
5804     return skip;
5805 }
5806 
PreCallValidateCreateRayTracingPipelinesKHR(VkDevice device,VkDeferredOperationKHR deferredOperation,VkPipelineCache pipelineCache,uint32_t count,const VkRayTracingPipelineCreateInfoKHR * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines,void * crtpl_state_data) const5807 bool CoreChecks::PreCallValidateCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
5808                                                              VkPipelineCache pipelineCache, uint32_t count,
5809                                                              const VkRayTracingPipelineCreateInfoKHR *pCreateInfos,
5810                                                              const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines,
5811                                                              void *crtpl_state_data) const {
5812     bool skip = StateTracker::PreCallValidateCreateRayTracingPipelinesKHR(device, deferredOperation, pipelineCache, count,
5813                                                                           pCreateInfos, pAllocator, pPipelines, crtpl_state_data);
5814 
5815     auto *crtpl_state = reinterpret_cast<create_ray_tracing_pipeline_khr_api_state *>(crtpl_state_data);
5816     for (uint32_t i = 0; i < count; i++) {
5817         PIPELINE_STATE *pipeline = crtpl_state->pipe_state[i].get();
5818         const auto &create_info = pipeline->create_info.raytracing;
5819         if (create_info.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
5820             std::shared_ptr<const PIPELINE_STATE> base_pipeline;
5821             if (create_info.basePipelineIndex != -1) {
5822                 base_pipeline = crtpl_state->pipe_state[create_info.basePipelineIndex];
5823             } else if (create_info.basePipelineHandle != VK_NULL_HANDLE) {
5824                 base_pipeline = Get<PIPELINE_STATE>(create_info.basePipelineHandle);
5825             }
5826             if (!base_pipeline || !(base_pipeline->GetPipelineCreateFlags() & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
5827                 skip |= LogError(
5828                     device, "VUID-vkCreateRayTracingPipelinesKHR-flags-03416",
5829                     "vkCreateRayTracingPipelinesKHR: If the flags member of any element of pCreateInfos contains the "
5830                     "VK_PIPELINE_CREATE_DERIVATIVE_BIT flag,"
5831                     "the base pipeline must have been created with the VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT flag set.");
5832             }
5833         }
5834         skip |= ValidateRayTracingPipeline(pipeline, pCreateInfos[i].flags, /*isKHR*/ true);
5835         skip |= ValidatePipelineCacheControlFlags(pCreateInfos[i].flags, i, "vkCreateRayTracingPipelinesKHR",
5836                                                   "VUID-VkRayTracingPipelineCreateInfoKHR-pipelineCreationCacheControl-02905");
5837         if (create_info.pLibraryInfo) {
5838             const std::vector<std::pair<const char *, VkPipelineCreateFlags>> vuid_map = {
5839                 {"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04718", VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR},
5840                 {"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04719", VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR},
5841                 {"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04720",
5842                  VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR},
5843                 {"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04721",
5844                  VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR},
5845                 {"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04722",
5846                  VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR},
5847                 {"VUID-VkRayTracingPipelineCreateInfoKHR-flags-04723", VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR},
5848             };
5849             for (uint32_t j = 0; j < create_info.pLibraryInfo->libraryCount; ++j) {
5850                 const auto lib = Get<PIPELINE_STATE>(create_info.pLibraryInfo->pLibraries[j]);
5851                 if ((lib->create_info.raytracing.flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) == 0) {
5852                     skip |= LogError(
5853                         device, "VUID-VkPipelineLibraryCreateInfoKHR-pLibraries-03381",
5854                                      "vkCreateRayTracingPipelinesKHR(): pCreateInfo[%" PRIu32 "].pLibraryInfo->pLibraries[%" PRIu32
5855                                      "] was not created with VK_PIPELINE_CREATE_LIBRARY_BIT_KHR.", i, j);
5856                 }
5857                 for (const auto &pair : vuid_map) {
5858                     if (create_info.flags & pair.second) {
5859                         if ((lib->create_info.raytracing.flags & pair.second) == 0) {
5860                             skip |= LogError(
5861                                 device, pair.first,
5862                                 "vkCreateRayTracingPipelinesKHR(): pCreateInfo[%" PRIu32
5863                                 "].flags contains %s bit, but pCreateInfo[%" PRIu32
5864                                 "].pLibraryInfo->pLibraries[%" PRIu32 "] was created without it.",
5865                                 i, string_VkPipelineCreateFlags(pair.second).c_str(), i, j);
5866                         }
5867                     }
5868                 }
5869             }
5870         }
5871     }
5872 
5873     return skip;
5874 }
5875 
PreCallValidateGetPipelineExecutablePropertiesKHR(VkDevice device,const VkPipelineInfoKHR * pPipelineInfo,uint32_t * pExecutableCount,VkPipelineExecutablePropertiesKHR * pProperties) const5876 bool CoreChecks::PreCallValidateGetPipelineExecutablePropertiesKHR(VkDevice device, const VkPipelineInfoKHR *pPipelineInfo,
5877                                                                    uint32_t *pExecutableCount,
5878                                                                    VkPipelineExecutablePropertiesKHR *pProperties) const {
5879     bool skip = false;
5880     skip |= ValidatePipelineExecutableInfo(device, nullptr, "vkGetPipelineExecutablePropertiesKHR",
5881                                            "VUID-vkGetPipelineExecutablePropertiesKHR-pipelineExecutableInfo-03270");
5882     return skip;
5883 }
5884 
ValidatePipelineExecutableInfo(VkDevice device,const VkPipelineExecutableInfoKHR * pExecutableInfo,const char * caller_name,const char * feature_vuid) const5885 bool CoreChecks::ValidatePipelineExecutableInfo(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo,
5886                                                 const char *caller_name, const char *feature_vuid) const {
5887     bool skip = false;
5888 
5889     if (!enabled_features.pipeline_exe_props_features.pipelineExecutableInfo) {
5890         skip |= LogError(device, feature_vuid, "%s(): called when pipelineExecutableInfo feature is not enabled.", caller_name);
5891     }
5892 
5893     // vkGetPipelineExecutablePropertiesKHR will not have struct to validate further
5894     if (pExecutableInfo) {
5895         auto pi = LvlInitStruct<VkPipelineInfoKHR>();
5896         pi.pipeline = pExecutableInfo->pipeline;
5897 
5898         // We could probably cache this instead of fetching it every time
5899         uint32_t executable_count = 0;
5900         DispatchGetPipelineExecutablePropertiesKHR(device, &pi, &executable_count, NULL);
5901 
5902         if (pExecutableInfo->executableIndex >= executable_count) {
5903             skip |= LogError(
5904                 pExecutableInfo->pipeline, "VUID-VkPipelineExecutableInfoKHR-executableIndex-03275",
5905                 "%s(): VkPipelineExecutableInfo::executableIndex (%1u) must be less than the number of executables associated with "
5906                 "the pipeline (%1u) as returned by vkGetPipelineExecutablePropertiessKHR",
5907                 caller_name, pExecutableInfo->executableIndex, executable_count);
5908         }
5909     }
5910 
5911     return skip;
5912 }
5913 
PreCallValidateGetPipelineExecutableStatisticsKHR(VkDevice device,const VkPipelineExecutableInfoKHR * pExecutableInfo,uint32_t * pStatisticCount,VkPipelineExecutableStatisticKHR * pStatistics) const5914 bool CoreChecks::PreCallValidateGetPipelineExecutableStatisticsKHR(VkDevice device,
5915                                                                    const VkPipelineExecutableInfoKHR *pExecutableInfo,
5916                                                                    uint32_t *pStatisticCount,
5917                                                                    VkPipelineExecutableStatisticKHR *pStatistics) const {
5918     bool skip = false;
5919     skip |= ValidatePipelineExecutableInfo(device, pExecutableInfo, "vkGetPipelineExecutableStatisticsKHR",
5920                                            "VUID-vkGetPipelineExecutableStatisticsKHR-pipelineExecutableInfo-03272");
5921 
5922     const auto pipeline_state = Get<PIPELINE_STATE>(pExecutableInfo->pipeline);
5923     if (!(pipeline_state->GetPipelineCreateFlags() & VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR)) {
5924         skip |= LogError(pExecutableInfo->pipeline, "VUID-vkGetPipelineExecutableStatisticsKHR-pipeline-03274",
5925                          "vkGetPipelineExecutableStatisticsKHR called on a pipeline created without the "
5926                          "VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR flag set");
5927     }
5928 
5929     return skip;
5930 }
5931 
PreCallValidateGetPipelineExecutableInternalRepresentationsKHR(VkDevice device,const VkPipelineExecutableInfoKHR * pExecutableInfo,uint32_t * pInternalRepresentationCount,VkPipelineExecutableInternalRepresentationKHR * pStatistics) const5932 bool CoreChecks::PreCallValidateGetPipelineExecutableInternalRepresentationsKHR(
5933     VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pInternalRepresentationCount,
5934     VkPipelineExecutableInternalRepresentationKHR *pStatistics) const {
5935     bool skip = false;
5936     skip |= ValidatePipelineExecutableInfo(device, pExecutableInfo, "vkGetPipelineExecutableInternalRepresentationsKHR",
5937                                            "VUID-vkGetPipelineExecutableInternalRepresentationsKHR-pipelineExecutableInfo-03276");
5938 
5939     const auto pipeline_state = Get<PIPELINE_STATE>(pExecutableInfo->pipeline);
5940     if (!(pipeline_state->GetPipelineCreateFlags() & VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR)) {
5941         skip |= LogError(pExecutableInfo->pipeline, "VUID-vkGetPipelineExecutableInternalRepresentationsKHR-pipeline-03278",
5942                          "vkGetPipelineExecutableInternalRepresentationsKHR called on a pipeline created without the "
5943                          "VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR flag set");
5944     }
5945 
5946     return skip;
5947 }
5948 
PreCallValidateCreateDescriptorSetLayout(VkDevice device,const VkDescriptorSetLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorSetLayout * pSetLayout) const5949 bool CoreChecks::PreCallValidateCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
5950                                                           const VkAllocationCallbacks *pAllocator,
5951                                                           VkDescriptorSetLayout *pSetLayout) const {
5952     return cvdescriptorset::ValidateDescriptorSetLayoutCreateInfo(
5953         this, pCreateInfo, IsExtEnabled(device_extensions.vk_khr_push_descriptor),
5954         phys_dev_ext_props.push_descriptor_props.maxPushDescriptors, IsExtEnabled(device_extensions.vk_ext_descriptor_indexing),
5955         &enabled_features.core12, &enabled_features.inline_uniform_block_features, &phys_dev_ext_props.inline_uniform_block_props,
5956         &enabled_features.ray_tracing_acceleration_structure_features, &device_extensions);
5957 }
5958 
5959 enum DSL_DESCRIPTOR_GROUPS {
5960     DSL_TYPE_SAMPLERS = 0,
5961     DSL_TYPE_UNIFORM_BUFFERS,
5962     DSL_TYPE_STORAGE_BUFFERS,
5963     DSL_TYPE_SAMPLED_IMAGES,
5964     DSL_TYPE_STORAGE_IMAGES,
5965     DSL_TYPE_INPUT_ATTACHMENTS,
5966     DSL_TYPE_INLINE_UNIFORM_BLOCK,
5967     DSL_TYPE_ACCELERATION_STRUCTURE,
5968     DSL_TYPE_ACCELERATION_STRUCTURE_NV,
5969     DSL_NUM_DESCRIPTOR_GROUPS
5970 };
5971 
5972 // Used by PreCallValidateCreatePipelineLayout.
5973 // Returns an array of size DSL_NUM_DESCRIPTOR_GROUPS of the maximum number of descriptors used in any single pipeline stage
GetDescriptorCountMaxPerStage(const DeviceFeatures * enabled_features,const std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> & set_layouts,bool skip_update_after_bind)5974 std::valarray<uint32_t> GetDescriptorCountMaxPerStage(
5975     const DeviceFeatures *enabled_features,
5976     const std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> &set_layouts, bool skip_update_after_bind) {
5977     // Identify active pipeline stages
5978     std::vector<VkShaderStageFlags> stage_flags = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
5979                                                    VK_SHADER_STAGE_COMPUTE_BIT};
5980     if (enabled_features->core.geometryShader) {
5981         stage_flags.push_back(VK_SHADER_STAGE_GEOMETRY_BIT);
5982     }
5983     if (enabled_features->core.tessellationShader) {
5984         stage_flags.push_back(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
5985         stage_flags.push_back(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
5986     }
5987 
5988     // Allow iteration over enum values
5989     std::vector<DSL_DESCRIPTOR_GROUPS> dsl_groups = {
5990         DSL_TYPE_SAMPLERS,
5991         DSL_TYPE_UNIFORM_BUFFERS,
5992         DSL_TYPE_STORAGE_BUFFERS,
5993         DSL_TYPE_SAMPLED_IMAGES,
5994         DSL_TYPE_STORAGE_IMAGES,
5995         DSL_TYPE_INPUT_ATTACHMENTS,
5996         DSL_TYPE_INLINE_UNIFORM_BLOCK,
5997         DSL_TYPE_ACCELERATION_STRUCTURE,
5998         DSL_TYPE_ACCELERATION_STRUCTURE_NV,
5999     };
6000 
6001     // Sum by layouts per stage, then pick max of stages per type
6002     std::valarray<uint32_t> max_sum(0U, DSL_NUM_DESCRIPTOR_GROUPS);  // max descriptor sum among all pipeline stages
6003     for (auto stage : stage_flags) {
6004         std::valarray<uint32_t> stage_sum(0U, DSL_NUM_DESCRIPTOR_GROUPS);  // per-stage sums
6005         for (const auto &dsl : set_layouts) {
6006             if (skip_update_after_bind && (dsl->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)) {
6007                 continue;
6008             }
6009 
6010             for (uint32_t binding_idx = 0; binding_idx < dsl->GetBindingCount(); binding_idx++) {
6011                 const VkDescriptorSetLayoutBinding *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
6012                 // Bindings with a descriptorCount of 0 are "reserved" and should be skipped
6013                 if (0 != (stage & binding->stageFlags) && binding->descriptorCount > 0) {
6014                     switch (binding->descriptorType) {
6015                         case VK_DESCRIPTOR_TYPE_SAMPLER:
6016                             stage_sum[DSL_TYPE_SAMPLERS] += binding->descriptorCount;
6017                             break;
6018                         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
6019                         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
6020                             stage_sum[DSL_TYPE_UNIFORM_BUFFERS] += binding->descriptorCount;
6021                             break;
6022                         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
6023                         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
6024                             stage_sum[DSL_TYPE_STORAGE_BUFFERS] += binding->descriptorCount;
6025                             break;
6026                         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
6027                         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
6028                             stage_sum[DSL_TYPE_SAMPLED_IMAGES] += binding->descriptorCount;
6029                             break;
6030                         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6031                         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
6032                             stage_sum[DSL_TYPE_STORAGE_IMAGES] += binding->descriptorCount;
6033                             break;
6034                         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6035                             stage_sum[DSL_TYPE_SAMPLED_IMAGES] += binding->descriptorCount;
6036                             stage_sum[DSL_TYPE_SAMPLERS] += binding->descriptorCount;
6037                             break;
6038                         case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
6039                             stage_sum[DSL_TYPE_INPUT_ATTACHMENTS] += binding->descriptorCount;
6040                             break;
6041                         case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
6042                             // count one block per binding. descriptorCount is number of bytes
6043                             stage_sum[DSL_TYPE_INLINE_UNIFORM_BLOCK]++;
6044                             break;
6045                         case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
6046                             stage_sum[DSL_TYPE_ACCELERATION_STRUCTURE] += binding->descriptorCount;
6047                             break;
6048                         case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
6049                             stage_sum[DSL_TYPE_ACCELERATION_STRUCTURE_NV] += binding->descriptorCount;
6050                             break;
6051                         default:
6052                             break;
6053                     }
6054                 }
6055             }
6056         }
6057         for (auto type : dsl_groups) {
6058             max_sum[type] = std::max(stage_sum[type], max_sum[type]);
6059         }
6060     }
6061     return max_sum;
6062 }
6063 
6064 // Used by PreCallValidateCreatePipelineLayout.
6065 // Returns a map indexed by VK_DESCRIPTOR_TYPE_* enum of the summed descriptors by type.
6066 // Note: descriptors only count against the limit once even if used by multiple stages.
GetDescriptorSum(const std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> & set_layouts,bool skip_update_after_bind)6067 std::map<uint32_t, uint32_t> GetDescriptorSum(
6068     const std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> &set_layouts, bool skip_update_after_bind) {
6069     std::map<uint32_t, uint32_t> sum_by_type;
6070     for (const auto &dsl : set_layouts) {
6071         if (skip_update_after_bind && (dsl->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)) {
6072             continue;
6073         }
6074 
6075         for (uint32_t binding_idx = 0; binding_idx < dsl->GetBindingCount(); binding_idx++) {
6076             const VkDescriptorSetLayoutBinding *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
6077             // Bindings with a descriptorCount of 0 are "reserved" and should be skipped
6078             if (binding->descriptorCount > 0) {
6079                 if (binding->descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
6080                     // count one block per binding. descriptorCount is number of bytes
6081                     sum_by_type[binding->descriptorType]++;
6082                 } else {
6083                     sum_by_type[binding->descriptorType] += binding->descriptorCount;
6084                 }
6085             }
6086         }
6087     }
6088     return sum_by_type;
6089 }
6090 
PreCallValidateCreatePipelineLayout(VkDevice device,const VkPipelineLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineLayout * pPipelineLayout) const6091 bool CoreChecks::PreCallValidateCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
6092                                                      const VkAllocationCallbacks *pAllocator,
6093                                                      VkPipelineLayout *pPipelineLayout) const {
6094     bool skip = false;
6095 
6096     std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> set_layouts(pCreateInfo->setLayoutCount, nullptr);
6097     unsigned int push_descriptor_set_count = 0;
6098     {
6099         for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; ++i) {
6100             set_layouts[i] = Get<cvdescriptorset::DescriptorSetLayout>(pCreateInfo->pSetLayouts[i]);
6101             if (set_layouts[i]->IsPushDescriptor()) ++push_descriptor_set_count;
6102             if (set_layouts[i]->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE) {
6103                 skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-04606",
6104                                  "vkCreatePipelineLayout(): pCreateInfo->pSetLayouts[%" PRIu32 "] was created with VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE bit.", i);
6105             }
6106         }
6107     }
6108 
6109     if (push_descriptor_set_count > 1) {
6110         skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00293",
6111                          "vkCreatePipelineLayout() Multiple push descriptor sets found.");
6112     }
6113 
6114     // Max descriptors by type, within a single pipeline stage
6115     std::valarray<uint32_t> max_descriptors_per_stage = GetDescriptorCountMaxPerStage(&enabled_features, set_layouts, true);
6116     // Samplers
6117     if (max_descriptors_per_stage[DSL_TYPE_SAMPLERS] > phys_dev_props.limits.maxPerStageDescriptorSamplers) {
6118         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6119                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03016"
6120                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00287";
6121         skip |= LogError(device, vuid,
6122                          "vkCreatePipelineLayout(): max per-stage sampler bindings count (%d) exceeds device "
6123                          "maxPerStageDescriptorSamplers limit (%d).",
6124                          max_descriptors_per_stage[DSL_TYPE_SAMPLERS], phys_dev_props.limits.maxPerStageDescriptorSamplers);
6125     }
6126 
6127     // Uniform buffers
6128     if (max_descriptors_per_stage[DSL_TYPE_UNIFORM_BUFFERS] > phys_dev_props.limits.maxPerStageDescriptorUniformBuffers) {
6129         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6130                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03017"
6131                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00288";
6132         skip |= LogError(device, vuid,
6133                          "vkCreatePipelineLayout(): max per-stage uniform buffer bindings count (%d) exceeds device "
6134                          "maxPerStageDescriptorUniformBuffers limit (%d).",
6135                          max_descriptors_per_stage[DSL_TYPE_UNIFORM_BUFFERS],
6136                          phys_dev_props.limits.maxPerStageDescriptorUniformBuffers);
6137     }
6138 
6139     // Storage buffers
6140     if (max_descriptors_per_stage[DSL_TYPE_STORAGE_BUFFERS] > phys_dev_props.limits.maxPerStageDescriptorStorageBuffers) {
6141         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6142                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03018"
6143                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00289";
6144         skip |= LogError(device, vuid,
6145                          "vkCreatePipelineLayout(): max per-stage storage buffer bindings count (%d) exceeds device "
6146                          "maxPerStageDescriptorStorageBuffers limit (%d).",
6147                          max_descriptors_per_stage[DSL_TYPE_STORAGE_BUFFERS],
6148                          phys_dev_props.limits.maxPerStageDescriptorStorageBuffers);
6149     }
6150 
6151     // Sampled images
6152     if (max_descriptors_per_stage[DSL_TYPE_SAMPLED_IMAGES] > phys_dev_props.limits.maxPerStageDescriptorSampledImages) {
6153         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6154                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03019"
6155                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00290";
6156         skip |=
6157             LogError(device, vuid,
6158                      "vkCreatePipelineLayout(): max per-stage sampled image bindings count (%d) exceeds device "
6159                      "maxPerStageDescriptorSampledImages limit (%d).",
6160                      max_descriptors_per_stage[DSL_TYPE_SAMPLED_IMAGES], phys_dev_props.limits.maxPerStageDescriptorSampledImages);
6161     }
6162 
6163     // Storage images
6164     if (max_descriptors_per_stage[DSL_TYPE_STORAGE_IMAGES] > phys_dev_props.limits.maxPerStageDescriptorStorageImages) {
6165         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6166                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03020"
6167                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00291";
6168         skip |=
6169             LogError(device, vuid,
6170                      "vkCreatePipelineLayout(): max per-stage storage image bindings count (%d) exceeds device "
6171                      "maxPerStageDescriptorStorageImages limit (%d).",
6172                      max_descriptors_per_stage[DSL_TYPE_STORAGE_IMAGES], phys_dev_props.limits.maxPerStageDescriptorStorageImages);
6173     }
6174 
6175     // Input attachments
6176     if (max_descriptors_per_stage[DSL_TYPE_INPUT_ATTACHMENTS] > phys_dev_props.limits.maxPerStageDescriptorInputAttachments) {
6177         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6178                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03021"
6179                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01676";
6180         skip |= LogError(device, vuid,
6181                          "vkCreatePipelineLayout(): max per-stage input attachment bindings count (%d) exceeds device "
6182                          "maxPerStageDescriptorInputAttachments limit (%d).",
6183                          max_descriptors_per_stage[DSL_TYPE_INPUT_ATTACHMENTS],
6184                          phys_dev_props.limits.maxPerStageDescriptorInputAttachments);
6185     }
6186 
6187     // Inline uniform blocks
6188     if (max_descriptors_per_stage[DSL_TYPE_INLINE_UNIFORM_BLOCK] >
6189         phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks) {
6190         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6191                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-02214"
6192                                : "VUID-VkPipelineLayoutCreateInfo-descriptorType-02212";
6193         skip |= LogError(device, vuid,
6194                          "vkCreatePipelineLayout(): max per-stage inline uniform block bindings count (%d) exceeds device "
6195                          "maxPerStageDescriptorInlineUniformBlocks limit (%d).",
6196                          max_descriptors_per_stage[DSL_TYPE_INLINE_UNIFORM_BLOCK],
6197                          phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks);
6198     }
6199     if (max_descriptors_per_stage[DSL_TYPE_ACCELERATION_STRUCTURE] >
6200         phys_dev_ext_props.acc_structure_props.maxPerStageDescriptorUpdateAfterBindAccelerationStructures) {
6201         skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03572",
6202                          "vkCreatePipelineLayout(): max per-stage acceleration structure bindings count (%" PRIu32 ") exceeds device "
6203                          "maxPerStageDescriptorInlineUniformBlocks limit (%" PRIu32 ").",
6204                          max_descriptors_per_stage[DSL_TYPE_ACCELERATION_STRUCTURE],
6205                          phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorInlineUniformBlocks);
6206     }
6207 
6208     // Total descriptors by type
6209     //
6210     std::map<uint32_t, uint32_t> sum_all_stages = GetDescriptorSum(set_layouts, true);
6211     // Samplers
6212     uint32_t sum = sum_all_stages[VK_DESCRIPTOR_TYPE_SAMPLER] + sum_all_stages[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER];
6213     if (sum > phys_dev_props.limits.maxDescriptorSetSamplers) {
6214         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6215                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03028"
6216                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01677";
6217         skip |= LogError(device, vuid,
6218                          "vkCreatePipelineLayout(): sum of sampler bindings among all stages (%d) exceeds device "
6219                          "maxDescriptorSetSamplers limit (%d).",
6220                          sum, phys_dev_props.limits.maxDescriptorSetSamplers);
6221     }
6222 
6223     // Uniform buffers
6224     if (sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] > phys_dev_props.limits.maxDescriptorSetUniformBuffers) {
6225         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6226                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03029"
6227                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01678";
6228         skip |= LogError(device, vuid,
6229                          "vkCreatePipelineLayout(): sum of uniform buffer bindings among all stages (%d) exceeds device "
6230                          "maxDescriptorSetUniformBuffers limit (%d).",
6231                          sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER], phys_dev_props.limits.maxDescriptorSetUniformBuffers);
6232     }
6233 
6234     // Dynamic uniform buffers
6235     if (sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] > phys_dev_props.limits.maxDescriptorSetUniformBuffersDynamic) {
6236         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6237                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03030"
6238                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01679";
6239         skip |= LogError(device, vuid,
6240                          "vkCreatePipelineLayout(): sum of dynamic uniform buffer bindings among all stages (%d) exceeds device "
6241                          "maxDescriptorSetUniformBuffersDynamic limit (%d).",
6242                          sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC],
6243                          phys_dev_props.limits.maxDescriptorSetUniformBuffersDynamic);
6244     }
6245 
6246     // Storage buffers
6247     if (sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] > phys_dev_props.limits.maxDescriptorSetStorageBuffers) {
6248         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6249                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03031"
6250                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01680";
6251         skip |= LogError(device, vuid,
6252                          "vkCreatePipelineLayout(): sum of storage buffer bindings among all stages (%d) exceeds device "
6253                          "maxDescriptorSetStorageBuffers limit (%d).",
6254                          sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER], phys_dev_props.limits.maxDescriptorSetStorageBuffers);
6255     }
6256 
6257     // Dynamic storage buffers
6258     if (sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] > phys_dev_props.limits.maxDescriptorSetStorageBuffersDynamic) {
6259         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6260                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03032"
6261                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01681";
6262         skip |= LogError(device, vuid,
6263                          "vkCreatePipelineLayout(): sum of dynamic storage buffer bindings among all stages (%d) exceeds device "
6264                          "maxDescriptorSetStorageBuffersDynamic limit (%d).",
6265                          sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC],
6266                          phys_dev_props.limits.maxDescriptorSetStorageBuffersDynamic);
6267     }
6268 
6269     //  Sampled images
6270     sum = sum_all_stages[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] + sum_all_stages[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] +
6271           sum_all_stages[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER];
6272     if (sum > phys_dev_props.limits.maxDescriptorSetSampledImages) {
6273         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6274                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03033"
6275                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01682";
6276         skip |= LogError(device, vuid,
6277                          "vkCreatePipelineLayout(): sum of sampled image bindings among all stages (%d) exceeds device "
6278                          "maxDescriptorSetSampledImages limit (%d).",
6279                          sum, phys_dev_props.limits.maxDescriptorSetSampledImages);
6280     }
6281 
6282     //  Storage images
6283     sum = sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] + sum_all_stages[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER];
6284     if (sum > phys_dev_props.limits.maxDescriptorSetStorageImages) {
6285         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6286                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03034"
6287                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01683";
6288         skip |= LogError(device, vuid,
6289                          "vkCreatePipelineLayout(): sum of storage image bindings among all stages (%d) exceeds device "
6290                          "maxDescriptorSetStorageImages limit (%d).",
6291                          sum, phys_dev_props.limits.maxDescriptorSetStorageImages);
6292     }
6293 
6294     // Input attachments
6295     if (sum_all_stages[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] > phys_dev_props.limits.maxDescriptorSetInputAttachments) {
6296         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6297                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-03035"
6298                                : "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-01684";
6299         skip |=
6300             LogError(device, vuid,
6301                      "vkCreatePipelineLayout(): sum of input attachment bindings among all stages (%d) exceeds device "
6302                      "maxDescriptorSetInputAttachments limit (%d).",
6303                      sum_all_stages[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT], phys_dev_props.limits.maxDescriptorSetInputAttachments);
6304     }
6305 
6306     // Inline uniform blocks
6307     if (sum_all_stages[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT] >
6308         phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetInlineUniformBlocks) {
6309         const char *vuid = IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)
6310                                ? "VUID-VkPipelineLayoutCreateInfo-descriptorType-02216"
6311                                : "VUID-VkPipelineLayoutCreateInfo-descriptorType-02213";
6312         skip |= LogError(device, vuid,
6313                          "vkCreatePipelineLayout(): sum of inline uniform block bindings among all stages (%d) exceeds device "
6314                          "maxDescriptorSetInlineUniformBlocks limit (%d).",
6315                          sum_all_stages[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT],
6316                          phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetInlineUniformBlocks);
6317     }
6318 
6319     // Acceleration structures NV
6320     if (sum_all_stages[VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV] >
6321         phys_dev_ext_props.ray_tracing_propsNV.maxDescriptorSetAccelerationStructures) {
6322         skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-02381",
6323                          "vkCreatePipelineLayout(): sum of acceleration structures NV bindings among all stages (%" PRIu32 ") exceeds device "
6324                          "VkPhysicalDeviceRayTracingPropertiesNV::maxDescriptorSetAccelerationStructures limit (%" PRIu32 ").",
6325                          sum_all_stages[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT],
6326                          phys_dev_ext_props.ray_tracing_propsNV.maxDescriptorSetAccelerationStructures);
6327     }
6328 
6329     if (IsExtEnabled(device_extensions.vk_ext_descriptor_indexing)) {
6330         // XXX TODO: replace with correct VU messages
6331 
6332         // Max descriptors by type, within a single pipeline stage
6333         std::valarray<uint32_t> max_descriptors_per_stage_update_after_bind =
6334             GetDescriptorCountMaxPerStage(&enabled_features, set_layouts, false);
6335         // Samplers
6336         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLERS] >
6337             phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindSamplers) {
6338             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03022",
6339                              "vkCreatePipelineLayout(): max per-stage sampler bindings count (%d) exceeds device "
6340                              "maxPerStageDescriptorUpdateAfterBindSamplers limit (%d).",
6341                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLERS],
6342                              phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindSamplers);
6343         }
6344 
6345         // Uniform buffers
6346         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_UNIFORM_BUFFERS] >
6347             phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindUniformBuffers) {
6348             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03023",
6349                              "vkCreatePipelineLayout(): max per-stage uniform buffer bindings count (%d) exceeds device "
6350                              "maxPerStageDescriptorUpdateAfterBindUniformBuffers limit (%d).",
6351                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_UNIFORM_BUFFERS],
6352                              phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindUniformBuffers);
6353         }
6354 
6355         // Storage buffers
6356         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_BUFFERS] >
6357             phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindStorageBuffers) {
6358             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03024",
6359                              "vkCreatePipelineLayout(): max per-stage storage buffer bindings count (%d) exceeds device "
6360                              "maxPerStageDescriptorUpdateAfterBindStorageBuffers limit (%d).",
6361                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_BUFFERS],
6362                              phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindStorageBuffers);
6363         }
6364 
6365         // Sampled images
6366         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLED_IMAGES] >
6367             phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindSampledImages) {
6368             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03025",
6369                              "vkCreatePipelineLayout(): max per-stage sampled image bindings count (%d) exceeds device "
6370                              "maxPerStageDescriptorUpdateAfterBindSampledImages limit (%d).",
6371                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_SAMPLED_IMAGES],
6372                              phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindSampledImages);
6373         }
6374 
6375         // Storage images
6376         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_IMAGES] >
6377             phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindStorageImages) {
6378             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03026",
6379                              "vkCreatePipelineLayout(): max per-stage storage image bindings count (%d) exceeds device "
6380                              "maxPerStageDescriptorUpdateAfterBindStorageImages limit (%d).",
6381                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_STORAGE_IMAGES],
6382                              phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindStorageImages);
6383         }
6384 
6385         // Input attachments
6386         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_INPUT_ATTACHMENTS] >
6387             phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindInputAttachments) {
6388             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-03027",
6389                              "vkCreatePipelineLayout(): max per-stage input attachment bindings count (%d) exceeds device "
6390                              "maxPerStageDescriptorUpdateAfterBindInputAttachments limit (%d).",
6391                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_INPUT_ATTACHMENTS],
6392                              phys_dev_props_core12.maxPerStageDescriptorUpdateAfterBindInputAttachments);
6393         }
6394 
6395         // Inline uniform blocks
6396         if (max_descriptors_per_stage_update_after_bind[DSL_TYPE_INLINE_UNIFORM_BLOCK] >
6397             phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks) {
6398             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-02215",
6399                              "vkCreatePipelineLayout(): max per-stage inline uniform block bindings count (%d) exceeds device "
6400                              "maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks limit (%d).",
6401                              max_descriptors_per_stage_update_after_bind[DSL_TYPE_INLINE_UNIFORM_BLOCK],
6402                              phys_dev_ext_props.inline_uniform_block_props.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks);
6403         }
6404 
6405         // Total descriptors by type, summed across all pipeline stages
6406         //
6407         std::map<uint32_t, uint32_t> sum_all_stages_update_after_bind = GetDescriptorSum(set_layouts, false);
6408         // Samplers
6409         sum = sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_SAMPLER] +
6410               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER];
6411         if (sum > phys_dev_props_core12.maxDescriptorSetUpdateAfterBindSamplers) {
6412             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03036",
6413                              "vkCreatePipelineLayout(): sum of sampler bindings among all stages (%d) exceeds device "
6414                              "maxDescriptorSetUpdateAfterBindSamplers limit (%d).",
6415                              sum, phys_dev_props_core12.maxDescriptorSetUpdateAfterBindSamplers);
6416         }
6417 
6418         // Uniform buffers
6419         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] >
6420             phys_dev_props_core12.maxDescriptorSetUpdateAfterBindUniformBuffers) {
6421             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03037",
6422                              "vkCreatePipelineLayout(): sum of uniform buffer bindings among all stages (%d) exceeds device "
6423                              "maxDescriptorSetUpdateAfterBindUniformBuffers limit (%d).",
6424                              sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER],
6425                              phys_dev_props_core12.maxDescriptorSetUpdateAfterBindUniformBuffers);
6426         }
6427 
6428         // Dynamic uniform buffers
6429         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] >
6430             phys_dev_props_core12.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic) {
6431             skip |=
6432                 LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03038",
6433                          "vkCreatePipelineLayout(): sum of dynamic uniform buffer bindings among all stages (%d) exceeds device "
6434                          "maxDescriptorSetUpdateAfterBindUniformBuffersDynamic limit (%d).",
6435                          sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC],
6436                          phys_dev_props_core12.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic);
6437         }
6438 
6439         // Storage buffers
6440         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] >
6441             phys_dev_props_core12.maxDescriptorSetUpdateAfterBindStorageBuffers) {
6442             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03039",
6443                              "vkCreatePipelineLayout(): sum of storage buffer bindings among all stages (%d) exceeds device "
6444                              "maxDescriptorSetUpdateAfterBindStorageBuffers limit (%d).",
6445                              sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER],
6446                              phys_dev_props_core12.maxDescriptorSetUpdateAfterBindStorageBuffers);
6447         }
6448 
6449         // Dynamic storage buffers
6450         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] >
6451             phys_dev_props_core12.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic) {
6452             skip |=
6453                 LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03040",
6454                          "vkCreatePipelineLayout(): sum of dynamic storage buffer bindings among all stages (%d) exceeds device "
6455                          "maxDescriptorSetUpdateAfterBindStorageBuffersDynamic limit (%d).",
6456                          sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC],
6457                          phys_dev_props_core12.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic);
6458         }
6459 
6460         //  Sampled images
6461         sum = sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] +
6462               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] +
6463               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER];
6464         if (sum > phys_dev_props_core12.maxDescriptorSetUpdateAfterBindSampledImages) {
6465             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03041",
6466                              "vkCreatePipelineLayout(): sum of sampled image bindings among all stages (%d) exceeds device "
6467                              "maxDescriptorSetUpdateAfterBindSampledImages limit (%d).",
6468                              sum, phys_dev_props_core12.maxDescriptorSetUpdateAfterBindSampledImages);
6469         }
6470 
6471         //  Storage images
6472         sum = sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] +
6473               sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER];
6474         if (sum > phys_dev_props_core12.maxDescriptorSetUpdateAfterBindStorageImages) {
6475             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03042",
6476                              "vkCreatePipelineLayout(): sum of storage image bindings among all stages (%d) exceeds device "
6477                              "maxDescriptorSetUpdateAfterBindStorageImages limit (%d).",
6478                              sum, phys_dev_props_core12.maxDescriptorSetUpdateAfterBindStorageImages);
6479         }
6480 
6481         // Input attachments
6482         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT] >
6483             phys_dev_props_core12.maxDescriptorSetUpdateAfterBindInputAttachments) {
6484             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pSetLayouts-03043",
6485                              "vkCreatePipelineLayout(): sum of input attachment bindings among all stages (%d) exceeds device "
6486                              "maxDescriptorSetUpdateAfterBindInputAttachments limit (%d).",
6487                              sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT],
6488                              phys_dev_props_core12.maxDescriptorSetUpdateAfterBindInputAttachments);
6489         }
6490 
6491         // Inline uniform blocks
6492         if (sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT] >
6493             phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetUpdateAfterBindInlineUniformBlocks) {
6494             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-descriptorType-02217",
6495                              "vkCreatePipelineLayout(): sum of inline uniform block bindings among all stages (%d) exceeds device "
6496                              "maxDescriptorSetUpdateAfterBindInlineUniformBlocks limit (%d).",
6497                              sum_all_stages_update_after_bind[VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT],
6498                              phys_dev_ext_props.inline_uniform_block_props.maxDescriptorSetUpdateAfterBindInlineUniformBlocks);
6499         }
6500     }
6501 
6502     if (IsExtEnabled(device_extensions.vk_ext_fragment_density_map2)) {
6503         uint32_t sum_subsampled_samplers = 0;
6504         for (const auto &dsl : set_layouts) {
6505             // find the number of subsampled samplers across all stages
6506             // NOTE: this does not use the GetDescriptorSum patter because it needs the Get<SAMPLER_STATE> method
6507             if ((dsl->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)) {
6508                 continue;
6509             }
6510             for (uint32_t binding_idx = 0; binding_idx < dsl->GetBindingCount(); binding_idx++) {
6511                 const VkDescriptorSetLayoutBinding *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
6512 
6513                 // Bindings with a descriptorCount of 0 are "reserved" and should be skipped
6514                 if (binding->descriptorCount > 0) {
6515                     if (((binding->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
6516                          (binding->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)) &&
6517                         (binding->pImmutableSamplers != nullptr)) {
6518                         for (uint32_t sampler_idx = 0; sampler_idx < binding->descriptorCount; sampler_idx++) {
6519                             const auto state = Get<SAMPLER_STATE>(binding->pImmutableSamplers[sampler_idx]);
6520                             if (state && (state->createInfo.flags & (VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT |
6521                                                                      VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT))) {
6522                                 sum_subsampled_samplers++;
6523                             }
6524                         }
6525                     }
6526                 }
6527             }
6528         }
6529         if (sum_subsampled_samplers > phys_dev_ext_props.fragment_density_map2_props.maxDescriptorSetSubsampledSamplers) {
6530             skip |= LogError(device, "VUID-VkPipelineLayoutCreateInfo-pImmutableSamplers-03566",
6531                              "vkCreatePipelineLayout(): sum of sampler bindings with flags containing "
6532                              "VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT or "
6533                              "VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT among all stages(% d) "
6534                              "exceeds device maxDescriptorSetSubsampledSamplers limit (%d).",
6535                              sum_subsampled_samplers,
6536                              phys_dev_ext_props.fragment_density_map2_props.maxDescriptorSetSubsampledSamplers);
6537         }
6538     }
6539     return skip;
6540 }
6541 
PreCallValidateResetDescriptorPool(VkDevice device,VkDescriptorPool descriptorPool,VkDescriptorPoolResetFlags flags) const6542 bool CoreChecks::PreCallValidateResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
6543                                                     VkDescriptorPoolResetFlags flags) const {
6544     // Make sure sets being destroyed are not currently in-use
6545     if (disabled[object_in_use]) return false;
6546     bool skip = false;
6547     const auto pool = Get<DESCRIPTOR_POOL_STATE>(descriptorPool);
6548     if (pool) {
6549         for (const auto &entry : pool->sets) {
6550             const auto *ds = entry.second;
6551             if (ds && ds->InUse()) {
6552                 skip |= LogError(descriptorPool, "VUID-vkResetDescriptorPool-descriptorPool-00313",
6553                                  "It is invalid to call vkResetDescriptorPool() with descriptor sets in use by a command buffer.");
6554                 if (skip) break;
6555             }
6556         }
6557     }
6558     return skip;
6559 }
6560 
6561 // Ensure the pool contains enough descriptors and descriptor sets to satisfy
6562 // an allocation request. Fills common_data with the total number of descriptors of each type required,
6563 // as well as DescriptorSetLayout ptrs used for later update.
PreCallValidateAllocateDescriptorSets(VkDevice device,const VkDescriptorSetAllocateInfo * pAllocateInfo,VkDescriptorSet * pDescriptorSets,void * ads_state_data) const6564 bool CoreChecks::PreCallValidateAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo,
6565                                                        VkDescriptorSet *pDescriptorSets, void *ads_state_data) const {
6566     StateTracker::PreCallValidateAllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets, ads_state_data);
6567 
6568     cvdescriptorset::AllocateDescriptorSetsData *ads_state =
6569         reinterpret_cast<cvdescriptorset::AllocateDescriptorSetsData *>(ads_state_data);
6570     // All state checks for AllocateDescriptorSets is done in single function
6571     return ValidateAllocateDescriptorSets(pAllocateInfo, ads_state);
6572 }
6573 
PreCallValidateFreeDescriptorSets(VkDevice device,VkDescriptorPool descriptorPool,uint32_t count,const VkDescriptorSet * pDescriptorSets) const6574 bool CoreChecks::PreCallValidateFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count,
6575                                                    const VkDescriptorSet *pDescriptorSets) const {
6576     // Make sure that no sets being destroyed are in-flight
6577     bool skip = false;
6578     // First make sure sets being destroyed are not currently in-use
6579     for (uint32_t i = 0; i < count; ++i) {
6580         if (pDescriptorSets[i] != VK_NULL_HANDLE) {
6581             skip |= ValidateIdleDescriptorSet(pDescriptorSets[i], "vkFreeDescriptorSets");
6582         }
6583     }
6584     const auto pool_state = Get<DESCRIPTOR_POOL_STATE>(descriptorPool);
6585     if (pool_state && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pool_state->createInfo.flags)) {
6586         // Can't Free from a NON_FREE pool
6587         skip |= LogError(descriptorPool, "VUID-vkFreeDescriptorSets-descriptorPool-00312",
6588                          "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
6589                          "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT.");
6590     }
6591     return skip;
6592 }
6593 
PreCallValidateUpdateDescriptorSets(VkDevice device,uint32_t descriptorWriteCount,const VkWriteDescriptorSet * pDescriptorWrites,uint32_t descriptorCopyCount,const VkCopyDescriptorSet * pDescriptorCopies) const6594 bool CoreChecks::PreCallValidateUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
6595                                                      const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount,
6596                                                      const VkCopyDescriptorSet *pDescriptorCopies) const {
6597     // First thing to do is perform map look-ups.
6598     // NOTE : UpdateDescriptorSets is somewhat unique in that it's operating on a number of DescriptorSets
6599     //  so we can't just do a single map look-up up-front, but do them individually in functions below
6600 
6601     // Now make call(s) that validate state, but don't perform state updates in this function
6602     // Note, here DescriptorSets is unique in that we don't yet have an instance. Using a helper function in the
6603     //  namespace which will parse params and make calls into specific class instances
6604     return ValidateUpdateDescriptorSets(descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies,
6605                                         "vkUpdateDescriptorSets()");
6606 }
6607 
UniqueImageViews(const VkRenderingInfoKHR * pRenderingInfo,VkImageView imageView)6608 static bool UniqueImageViews(const VkRenderingInfoKHR* pRenderingInfo, VkImageView imageView) {
6609     bool unique_views = true;
6610     for (uint32_t i = 0; i < pRenderingInfo->colorAttachmentCount; ++i) {
6611         if (pRenderingInfo->pColorAttachments[i].imageView == imageView) {
6612             unique_views = false;
6613         }
6614 
6615         if (pRenderingInfo->pColorAttachments[i].resolveImageView == imageView) {
6616             unique_views = false;
6617         }
6618     }
6619 
6620     if (pRenderingInfo->pDepthAttachment) {
6621         if (pRenderingInfo->pDepthAttachment->imageView == imageView) {
6622             unique_views = false;
6623         }
6624 
6625         if (pRenderingInfo->pDepthAttachment->resolveImageView == imageView) {
6626             unique_views = false;
6627         }
6628     }
6629 
6630     if (pRenderingInfo->pStencilAttachment) {
6631         if (pRenderingInfo->pStencilAttachment->imageView == imageView) {
6632             unique_views = false;
6633         }
6634 
6635         if (pRenderingInfo->pStencilAttachment->resolveImageView == imageView) {
6636             unique_views = false;
6637         }
6638     }
6639     return unique_views;
6640 }
6641 
PreCallValidateCmdBeginRenderingKHR(VkCommandBuffer commandBuffer,const VkRenderingInfoKHR * pRenderingInfo) const6642 bool CoreChecks::PreCallValidateCmdBeginRenderingKHR(VkCommandBuffer commandBuffer,
6643                                                      const VkRenderingInfoKHR *pRenderingInfo) const {
6644     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
6645     if (!cb_state) return false;
6646     bool skip = false;
6647 
6648     if (!enabled_features.dynamic_rendering_features.dynamicRendering) {
6649         skip |= LogError(commandBuffer, "VUID-vkCmdBeginRenderingKHR-dynamicRendering-06446",
6650                          "vkCmdBeginRenderingKHR(): dynamicRendering is not enabled.");
6651     }
6652 
6653     if ((cb_state->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) &&
6654         ((pRenderingInfo->flags & VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR) != 0)) {
6655         skip |= LogError(commandBuffer, "VUID-vkCmdBeginRenderingKHR-commandBuffer-06068",
6656                          "vkCmdBeginRenderingKHR(): pRenderingInfo->flags must not include "
6657                          "VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR in a secondary command buffer.");
6658     }
6659 
6660     if (pRenderingInfo->viewMask != 0 && pRenderingInfo->layerCount == 0) {
6661         skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-viewMask-06069",
6662                          "vkCmdBeginRenderingKHR(): If viewMask is not 0 (%u), layerCount must not be 0 (%u)",
6663                          pRenderingInfo->viewMask, pRenderingInfo->layerCount);
6664     }
6665 
6666     auto rendering_fragment_shading_rate_attachment_info = LvlFindInChain<VkRenderingFragmentShadingRateAttachmentInfoKHR>(pRenderingInfo->pNext);
6667     if (rendering_fragment_shading_rate_attachment_info && (rendering_fragment_shading_rate_attachment_info->imageView != VK_NULL_HANDLE)) {
6668         auto view_state = Get<IMAGE_VIEW_STATE>(rendering_fragment_shading_rate_attachment_info->imageView);
6669         if (pRenderingInfo->viewMask != 0) {
6670             uint32_t highest_view_bit = MostSignificantBit(pRenderingInfo->viewMask);
6671             if (view_state->create_info.subresourceRange.layerCount != 1 &&
6672                 view_state->create_info.subresourceRange.layerCount < highest_view_bit) {
6673                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-imageView-06124",
6674                     "vkCmdBeginRenderingKHR(): imageView must have a layerCount (%u) that either equal to 1 or greater than or equal to the index of the most significant bit in viewMask (%u)",
6675                     view_state->create_info.subresourceRange.layerCount, highest_view_bit);
6676             }
6677         }
6678 
6679         if (UniqueImageViews(pRenderingInfo, rendering_fragment_shading_rate_attachment_info->imageView) == false) {
6680             skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-imageView-06125",
6681                 "vkCmdBeginRenderingKHR(): imageView or resolveImageView member of pDepthAttachment, pStencilAttachment, or any element of pColorAttachments must not equal VkRenderingFragmentShadingRateAttachmentInfoKHR->vimageView");
6682         }
6683 
6684         if (rendering_fragment_shading_rate_attachment_info->imageLayout != VK_IMAGE_LAYOUT_GENERAL &&
6685             rendering_fragment_shading_rate_attachment_info->imageLayout != VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR) {
6686             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06147",
6687                 "vkCmdBeginRenderingKHR(): VkRenderingFragmentShadingRateAttachmentInfoKHR->layout (%s) must be VK_IMAGE_LAYOUT_GENERAL or VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR", string_VkImageLayout(rendering_fragment_shading_rate_attachment_info->imageLayout));
6688         }
6689 
6690         if (!IsPowerOfTwo(rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width)) {
6691             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06149",
6692                 "vkCmdBeginRenderingKHR(): shadingRateAttachmentTexelSize.width (%u) must be a power of two",
6693                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width);
6694         }
6695 
6696         auto max_frs_attach_texel_width = phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.width;
6697         if (rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width > max_frs_attach_texel_width) {
6698             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06150",
6699                 "vkCmdBeginRenderingKHR(): shadingRateAttachmentTexelSize.width (%u) must be less than or equal to maxFragmentShadingRateAttachmentTexelSize.width (%u)",
6700                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width,
6701                 max_frs_attach_texel_width);
6702         }
6703 
6704         auto min_frs_attach_texel_width = phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.width;
6705         if (rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width < min_frs_attach_texel_width) {
6706             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06151",
6707                 "vkCmdBeginRenderingKHR(): shadingRateAttachmentTexelSize.width (%u) must be greater than or equal to minFragmentShadingRateAttachmentTexelSize.width (%u)",
6708                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width,
6709                 min_frs_attach_texel_width);
6710         }
6711 
6712         if (!IsPowerOfTwo(rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height)) {
6713             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06152",
6714                 "vkCmdBeginRenderingKHR(): shadingRateAttachmentTexelSize.height (%u) must be a power of two",
6715                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height);
6716         }
6717 
6718         auto max_frs_attach_texel_height = phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.height;
6719         if (rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height > max_frs_attach_texel_height) {
6720             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06153",
6721                 "vkCmdBeginRenderingKHR(): shadingRateAttachmentTexelSize.height (%u) must be less than or equal to maxFragmentShadingRateAttachmentTexelSize.height (%u)",
6722                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height,
6723                 max_frs_attach_texel_height);
6724         }
6725 
6726         auto min_frs_attach_texel_height = phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.height;
6727         if (rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height < min_frs_attach_texel_height) {
6728             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06154",
6729                 "vkCmdBeginRenderingKHR(): shadingRateAttachmentTexelSize.height (%u) must be greater than or equal to minFragmentShadingRateAttachmentTexelSize.height (%u)",
6730                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height,
6731                 min_frs_attach_texel_height);
6732         }
6733 
6734         auto max_frs_attach_texel_aspect_ratio = phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSizeAspectRatio;
6735         if ((rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width / rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height) > max_frs_attach_texel_aspect_ratio) {
6736             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06155",
6737                 "vkCmdBeginRenderingKHR(): the quotient of shadingRateAttachmentTexelSize.width (%u) and shadingRateAttachmentTexelSize.height (%u) must be less than or equal to maxFragmentShadingRateAttachmentTexelSizeAspectRatio (%u)",
6738                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width,
6739                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height,
6740                 max_frs_attach_texel_aspect_ratio);
6741         }
6742 
6743         if ((rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height / rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width) > max_frs_attach_texel_aspect_ratio) {
6744             skip |= LogError(commandBuffer, "VUID-VkRenderingFragmentShadingRateAttachmentInfoKHR-imageView-06156",
6745                 "vkCmdBeginRenderingKHR(): the quotient of shadingRateAttachmentTexelSize.height (%u) and shadingRateAttachmentTexelSize.width (%u) must be less than or equal to maxFragmentShadingRateAttachmentTexelSizeAspectRatio (%u)",
6746                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.height,
6747                 rendering_fragment_shading_rate_attachment_info->shadingRateAttachmentTexelSize.width,
6748                 max_frs_attach_texel_aspect_ratio);
6749         }
6750     }
6751 
6752     if (!(IsExtEnabled(device_extensions.vk_amd_mixed_attachment_samples) ||
6753           IsExtEnabled(device_extensions.vk_nv_framebuffer_mixed_samples))) {
6754         uint32_t first_sample_count_attachment = VK_ATTACHMENT_UNUSED;
6755         for (uint32_t j = 0; j < pRenderingInfo->colorAttachmentCount; ++j) {
6756             if (pRenderingInfo->pColorAttachments[j].imageView != VK_NULL_HANDLE) {
6757                 auto image_view = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pColorAttachments[j].imageView);
6758                 first_sample_count_attachment = (j == 0u) ? static_cast<uint32_t>(image_view->samples) : first_sample_count_attachment;
6759 
6760                 if (first_sample_count_attachment != image_view->samples) {
6761                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-imageView-06070",
6762                                      "vkCmdBeginRenderingKHR(): Color attachment ref %u has sample count %s, whereas first color "
6763                                      "attachment ref has "
6764                                      "sample count %u.",
6765                                      j, string_VkSampleCountFlagBits(image_view->samples), (first_sample_count_attachment));
6766                 }
6767             }
6768         }
6769     }
6770 
6771     if (!(pRenderingInfo->colorAttachmentCount <= phys_dev_props.limits.maxColorAttachments)) {
6772         skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06106",
6773                          "vkCmdBeginRenderingKHR(): colorAttachmentCount (%u) must be less than or equal to "
6774                          "VkPhysicalDeviceLimits::maxColorAttachments (%u)",
6775                          pRenderingInfo->colorAttachmentCount, phys_dev_props.limits.maxColorAttachments);
6776     }
6777 
6778     auto fragment_density_map_attachment_info = LvlFindInChain<VkRenderingFragmentDensityMapAttachmentInfoEXT>(pRenderingInfo->pNext);
6779     if (fragment_density_map_attachment_info) {
6780         if (UniqueImageViews(pRenderingInfo, fragment_density_map_attachment_info->imageView) == false) {
6781             skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-imageView-06116",
6782                 "vkCmdBeginRenderingKHR(): imageView or resolveImageView member of pDepthAttachment, pStencilAttachment, or any element of pColorAttachments must not equal VkRenderingFragmentDensityMapAttachmentInfoEXT->imageView");
6783         }
6784     }
6785 
6786     if ((enabled_features.core11.multiview == VK_FALSE) && (pRenderingInfo->viewMask != 0)) {
6787         skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-multiview-06127",
6788                          "vkCmdBeginRenderingKHR(): If the multiview feature is not enabled, viewMask must be 0 (%u)",
6789                          pRenderingInfo->viewMask);
6790     }
6791 
6792     auto chained_device_group_struct = LvlFindInChain<VkDeviceGroupRenderPassBeginInfo>(pRenderingInfo->pNext);
6793     if (!chained_device_group_struct || (chained_device_group_struct && chained_device_group_struct->deviceRenderAreaCount == 0)) {
6794         if (pRenderingInfo->renderArea.offset.x < 0) {
6795             skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06077",
6796                              "vkCmdBeginRenderingKHR(): renderArea.offset.x is %d and must be greater than 0",
6797                              pRenderingInfo->renderArea.offset.x);
6798         }
6799 
6800         if (pRenderingInfo->renderArea.offset.y < 0) {
6801             skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06078",
6802                              "vkCmdBeginRenderingKHR(): renderArea.offset.y is %d and must be greater than 0",
6803                              pRenderingInfo->renderArea.offset.y);
6804         }
6805 
6806         for (uint32_t j = 0; j < pRenderingInfo->colorAttachmentCount; ++j) {
6807             if (pRenderingInfo->pColorAttachments[j].imageView != VK_NULL_HANDLE) {
6808                 auto image_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pColorAttachments[j].imageView);
6809                 IMAGE_STATE *image_state = image_view_state->image_state.get();
6810                 if (!(image_state->createInfo.extent.width >=
6811                       pRenderingInfo->renderArea.offset.x + pRenderingInfo->renderArea.extent.width)) {
6812                     skip |=
6813                         LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06079",
6814                                  "vkCmdBeginRenderingKHR(): width of the pColorAttachments[%u].imageView: %u must be greater than"
6815                                  "renderArea.offset.x +  renderArea.extent.width",
6816                                  j, image_state->createInfo.extent.width);
6817                 }
6818                 if (!(image_state->createInfo.extent.height >=
6819                       pRenderingInfo->renderArea.offset.y + pRenderingInfo->renderArea.extent.height)) {
6820                     skip |=
6821                         LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06080",
6822                                  "vkCmdBeginRenderingKHR(): height of the pColorAttachments[%u].imageView: %u must be greater than"
6823                                  "renderArea.offset.y +  renderArea.extent.height",
6824                                  j, image_state->createInfo.extent.height);
6825                 }
6826             }
6827         }
6828 
6829         if (pRenderingInfo->pDepthAttachment != VK_NULL_HANDLE && pRenderingInfo->pDepthAttachment->imageView != VK_NULL_HANDLE) {
6830             auto depth_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pDepthAttachment->imageView);
6831             IMAGE_STATE *image_state = depth_view_state->image_state.get();
6832             if (!(image_state->createInfo.extent.width >=
6833                   pRenderingInfo->renderArea.offset.x + pRenderingInfo->renderArea.extent.width)) {
6834                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06079",
6835                                  "vkCmdBeginRenderingKHR(): width of the pDepthAttachment->imageView: %u must be greater than"
6836                                  "renderArea.offset.x +  renderArea.extent.width",
6837                                  image_state->createInfo.extent.width);
6838             }
6839             if (!(image_state->createInfo.extent.height >=
6840                   pRenderingInfo->renderArea.offset.y + pRenderingInfo->renderArea.extent.height)) {
6841                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06080",
6842                                  "vkCmdBeginRenderingKHR(): height of the pDepthAttachment->imageView: %u must be greater than"
6843                                  "renderArea.offset.y +  renderArea.extent.height",
6844                                  image_state->createInfo.extent.height);
6845             }
6846         }
6847 
6848         if (pRenderingInfo->pStencilAttachment != VK_NULL_HANDLE && pRenderingInfo->pStencilAttachment->imageView != VK_NULL_HANDLE) {
6849             auto stencil_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pStencilAttachment->imageView);
6850             IMAGE_STATE *image_state = stencil_view_state->image_state.get();
6851             if (!(image_state->createInfo.extent.width >=
6852                   pRenderingInfo->renderArea.offset.x + pRenderingInfo->renderArea.extent.width)) {
6853                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06079",
6854                                  "vkCmdBeginRenderingKHR(): width of the pStencilAttachment->imageView: %u must be greater than"
6855                                  "renderArea.offset.x +  renderArea.extent.width",
6856                                  image_state->createInfo.extent.width);
6857             }
6858             if (!(image_state->createInfo.extent.height >=
6859                   pRenderingInfo->renderArea.offset.y + pRenderingInfo->renderArea.extent.height)) {
6860                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06080",
6861                                  "vkCmdBeginRenderingKHR(): height of the pStencilAttachment->imageView: %u must be greater than"
6862                                  "renderArea.offset.y +  renderArea.extent.height",
6863                                  image_state->createInfo.extent.height);
6864             }
6865         }
6866     }
6867 
6868     if (chained_device_group_struct) {
6869         for (uint32_t deviceRenderAreaIndex = 0; deviceRenderAreaIndex < chained_device_group_struct->deviceRenderAreaCount;
6870              ++deviceRenderAreaIndex) {
6871             auto offset_x = chained_device_group_struct->pDeviceRenderAreas[deviceRenderAreaIndex].offset.x;
6872             auto width = chained_device_group_struct->pDeviceRenderAreas[deviceRenderAreaIndex].extent.width;
6873             if (!(offset_x >= 0)) {
6874                 skip |= LogError(commandBuffer, "VUID-VkDeviceGroupRenderPassBeginInfo-offset-06166",
6875                                  "vkCmdBeginRenderingKHR(): pDeviceRenderAreas[%u].offset.x: %d must be greater than or equal to 0",
6876                                  deviceRenderAreaIndex, offset_x);
6877             }
6878             auto offset_y = chained_device_group_struct->pDeviceRenderAreas[deviceRenderAreaIndex].offset.y;
6879             auto height = chained_device_group_struct->pDeviceRenderAreas[deviceRenderAreaIndex].extent.height;
6880             if (!(offset_y >= 0)) {
6881                 skip |= LogError(commandBuffer, "VUID-VkDeviceGroupRenderPassBeginInfo-offset-06167",
6882                                  "vkCmdBeginRenderingKHR(): pDeviceRenderAreas[%u].offset.y: %d must be greater than or equal to 0",
6883                                  deviceRenderAreaIndex, offset_y);
6884             }
6885 
6886             for (uint32_t j = 0; j < pRenderingInfo->colorAttachmentCount; ++j) {
6887                 if (pRenderingInfo->pColorAttachments[j].imageView != VK_NULL_HANDLE) {
6888                     auto image_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pColorAttachments[j].imageView);
6889                     IMAGE_STATE *image_state = image_view_state->image_state.get();
6890                     if (!(image_state->createInfo.extent.width >= offset_x + width)) {
6891                         skip |= LogError(
6892                             commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06083",
6893                             "vkCmdBeginRenderingKHR(): width of the pColorAttachments[%u].imageView: %u must be greater than"
6894                             "renderArea.offset.x +  renderArea.extent.width",
6895                             j, image_state->createInfo.extent.width);
6896                     }
6897                     if (!(image_state->createInfo.extent.height >= offset_y + height)) {
6898                         skip |= LogError(
6899                             commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06084",
6900                             "vkCmdBeginRenderingKHR(): height of the pColorAttachments[%u].imageView: %u must be greater than"
6901                             "renderArea.offset.y +  renderArea.extent.height",
6902                             j, image_state->createInfo.extent.height);
6903                     }
6904                 }
6905             }
6906 
6907             if (pRenderingInfo->pDepthAttachment != VK_NULL_HANDLE) {
6908                 auto depth_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pDepthAttachment->imageView);
6909                 IMAGE_STATE *image_state = depth_view_state->image_state.get();
6910                 if (!(image_state->createInfo.extent.width >= offset_x + width)) {
6911                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06083",
6912                                      "vkCmdBeginRenderingKHR(): width of the pDepthAttachment->imageView: %u must be greater than"
6913                                      "renderArea.offset.x +  renderArea.extent.width",
6914                                      image_state->createInfo.extent.width);
6915                 }
6916                 if (!(image_state->createInfo.extent.height >= offset_y + height)) {
6917                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06084",
6918                                      "vkCmdBeginRenderingKHR(): height of the pDepthAttachment->imageView: %u must be greater than"
6919                                      "renderArea.offset.y +  renderArea.extent.height",
6920                                      image_state->createInfo.extent.height);
6921                 }
6922             }
6923 
6924             if (pRenderingInfo->pStencilAttachment != VK_NULL_HANDLE) {
6925                 auto stencil_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pStencilAttachment->imageView);
6926                 IMAGE_STATE *image_state = stencil_view_state->image_state.get();
6927                 if (!(image_state->createInfo.extent.width >= offset_x + width)) {
6928                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06083",
6929                                      "vkCmdBeginRenderingKHR(): width of the pStencilAttachment->imageView: %u must be greater than"
6930                                      "renderArea.offset.x +  renderArea.extent.width",
6931                                      image_state->createInfo.extent.width);
6932                 }
6933                 if (!(image_state->createInfo.extent.height >= offset_y + height)) {
6934                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pNext-06084",
6935                                      "vkCmdBeginRenderingKHR(): height of the pStencilAttachment->imageView: %u must be greater than"
6936                                      "renderArea.offset.y +  renderArea.extent.height",
6937                                      image_state->createInfo.extent.height);
6938                 }
6939             }
6940         }
6941     }
6942 
6943     if (pRenderingInfo->pDepthAttachment != NULL && pRenderingInfo->pStencilAttachment != NULL) {
6944         if (pRenderingInfo->pDepthAttachment->imageView != VK_NULL_HANDLE &&
6945             pRenderingInfo->pStencilAttachment->imageView != VK_NULL_HANDLE) {
6946             if (!(pRenderingInfo->pDepthAttachment->imageView == pRenderingInfo->pStencilAttachment->imageView)) {
6947                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06085",
6948                                  "vkCmdBeginRenderingKHR(): imageView of pDepthAttachment and pStencilAttachment must be the same");
6949             }
6950 
6951             if ((phys_dev_props_core12.independentResolveNone == VK_FALSE) &&
6952                 (pRenderingInfo->pDepthAttachment->resolveMode != pRenderingInfo->pStencilAttachment->resolveMode)) {
6953                 skip |= LogError(
6954                     commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06104",
6955                     "vkCmdBeginRenderingKHR(): The values of depthResolveMode (%u) and stencilResolveMode (%u) must be identical.",
6956                     pRenderingInfo->pDepthAttachment->resolveMode, pRenderingInfo->pStencilAttachment->resolveMode);
6957             }
6958 
6959             if ((phys_dev_props_core12.independentResolve == VK_FALSE) &&
6960                 (pRenderingInfo->pDepthAttachment->resolveMode != VK_RESOLVE_MODE_NONE) &&
6961                 (pRenderingInfo->pStencilAttachment->resolveMode != VK_RESOLVE_MODE_NONE) &&
6962                 (pRenderingInfo->pStencilAttachment->resolveMode != pRenderingInfo->pDepthAttachment->resolveMode)) {
6963                 skip |= LogError(device, "VUID-VkRenderingInfoKHR-pDepthAttachment-06105",
6964                                  "vkCmdBeginRenderingKHR(): The values of depthResolveMode (%u) and stencilResolveMode (%u) must "
6965                                  "be identical, or "
6966                                  "one of them must be %u.",
6967                                  pRenderingInfo->pDepthAttachment->resolveMode, pRenderingInfo->pStencilAttachment->resolveMode,
6968                                  VK_RESOLVE_MODE_NONE);
6969             }
6970         }
6971 
6972         if (pRenderingInfo->pDepthAttachment->resolveMode != VK_RESOLVE_MODE_NONE &&
6973             pRenderingInfo->pStencilAttachment->resolveMode != VK_RESOLVE_MODE_NONE) {
6974             if (!(pRenderingInfo->pDepthAttachment->resolveImageView == pRenderingInfo->pStencilAttachment->resolveImageView)) {
6975                 skip |= LogError(
6976                     commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06086",
6977                     "vkCmdBeginRenderingKHR(): resolveImageView of pDepthAttachment and pStencilAttachment must be the same");
6978             }
6979         }
6980     }
6981 
6982     for (uint32_t j = 0; j < pRenderingInfo->colorAttachmentCount; ++j) {
6983         skip |= ValidateRenderingAttachmentInfoKHR(commandBuffer, &pRenderingInfo->pColorAttachments[j]);
6984 
6985         if (pRenderingInfo->pColorAttachments[j].imageView != VK_NULL_HANDLE) {
6986             auto image_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pColorAttachments[j].imageView);
6987             IMAGE_STATE *image_state = image_view_state->image_state.get();
6988             if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
6989                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06087",
6990                                  "vkCmdBeginRenderingKHR(): VkRenderingInfoKHR->colorAttachment[%u] must have been created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT", j);
6991             }
6992 
6993             if (pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
6994                 pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) {
6995                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06090",
6996                                  "vkCmdBeginRenderingKHR(): imageLayout must not be "
6997                                  "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL or "
6998                                  "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL");
6999             }
7000 
7001             if (pRenderingInfo->pColorAttachments[j].resolveMode != VK_RESOLVE_MODE_NONE) {
7002                 if (pRenderingInfo->pColorAttachments[j].resolveImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
7003                     pRenderingInfo->pColorAttachments[j].resolveImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) {
7004                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06091",
7005                                      "vkCmdBeginRenderingKHR(): resolveImageLayout must not be "
7006                                      "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL or "
7007                                      "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL");
7008                 }
7009             }
7010 
7011             if (pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
7012                 pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) {
7013                 skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06096",
7014                                  "vkCmdBeginRenderingKHR(): imageLayout must not be "
7015                                  "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL "
7016                                  "or VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL");
7017             }
7018 
7019             if (pRenderingInfo->pColorAttachments[j].resolveMode != VK_RESOLVE_MODE_NONE) {
7020                 if (pRenderingInfo->pColorAttachments[j].resolveImageLayout ==
7021                         VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
7022                     pRenderingInfo->pColorAttachments[j].resolveImageLayout ==
7023                         VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) {
7024                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06097",
7025                                      "vkCmdBeginRenderingKHR(): resolveImageLayout must not be "
7026                                      "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL or "
7027                                      "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL");
7028                 }
7029             }
7030 
7031             if (pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
7032                 pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL ||
7033                 pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL ||
7034                 pRenderingInfo->pColorAttachments[j].imageLayout == VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL) {
7035                 skip |= LogError(
7036                     commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06100",
7037                     "vkCmdBeginRenderingKHR(): imageLayout must not be VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL"
7038                     " or VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"
7039                     " or VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL"
7040                     " or VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL");
7041             }
7042 
7043             if (pRenderingInfo->pColorAttachments[j].resolveMode != VK_RESOLVE_MODE_NONE) {
7044                 if (pRenderingInfo->pColorAttachments[j].resolveImageLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
7045                     pRenderingInfo->pColorAttachments[j].resolveImageLayout == VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL) {
7046                     skip |= LogError(
7047                         commandBuffer, "VUID-VkRenderingInfoKHR-colorAttachmentCount-06101",
7048                         "vkCmdBeginRenderingKHR(): resolveImageLayout must not be VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL or "
7049                         "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL");
7050                 }
7051             }
7052         }
7053     }
7054 
7055     if (pRenderingInfo->pDepthAttachment != NULL) {
7056         skip |= ValidateRenderingAttachmentInfoKHR(commandBuffer, pRenderingInfo->pDepthAttachment);
7057 
7058         if (pRenderingInfo->pDepthAttachment->imageView != VK_NULL_HANDLE) {
7059             auto depth_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pDepthAttachment->imageView);
7060             IMAGE_STATE *image_state = depth_view_state->image_state.get();
7061             if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
7062                 skip |= LogError(
7063                     commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06088",
7064                     "vkCmdBeginRenderingKHR(): depth image must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT");
7065             }
7066 
7067             if (pRenderingInfo->pDepthAttachment->imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
7068                 skip |= LogError(
7069                     commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06092",
7070                     "vkCmdBeginRenderingKHR(): image must not have been created with VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL");
7071             }
7072 
7073             if (pRenderingInfo->pDepthAttachment->resolveMode != VK_RESOLVE_MODE_NONE) {
7074                 if (pRenderingInfo->pDepthAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
7075                     skip |= LogError(
7076                         commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06093",
7077                         "vkCmdBeginRenderingKHR(): resolveImageLayout must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL");
7078                 }
7079 
7080                 if (pRenderingInfo->pDepthAttachment->resolveImageLayout ==
7081                     VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) {
7082                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pDepthAttachment-06098",
7083                                      "vkCmdBeginRenderingKHR(): resolveImageLayout must not be "
7084                                      "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL");
7085                 }
7086 
7087                 if (!(pRenderingInfo->pDepthAttachment->resolveMode & phys_dev_props_core12.supportedDepthResolveModes)) {
7088                     skip |= LogError(device, "VUID-VkRenderingInfoKHR-pDepthAttachment-06102",
7089                         "vkCmdBeginRenderingKHR(): Includes a resolveMode structure with invalid mode=%u.",
7090                         pRenderingInfo->pDepthAttachment->resolveMode);
7091                 }
7092             }
7093 
7094         }
7095     }
7096 
7097     if (pRenderingInfo->pStencilAttachment != NULL) {
7098         skip |= ValidateRenderingAttachmentInfoKHR(commandBuffer, pRenderingInfo->pStencilAttachment);
7099 
7100         if (pRenderingInfo->pStencilAttachment->imageView != VK_NULL_HANDLE) {
7101             auto stencil_view_state = Get<IMAGE_VIEW_STATE>(pRenderingInfo->pStencilAttachment->imageView);
7102             IMAGE_STATE *image_state = stencil_view_state->image_state.get();
7103             if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
7104                 skip |= LogError(
7105                     commandBuffer, "VUID-VkRenderingInfoKHR-pStencilAttachment-06089",
7106                     "vkCmdBeginRenderingKHR(): stencil image must have been created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT");
7107             }
7108 
7109             if (pRenderingInfo->pStencilAttachment->imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
7110                 skip |= LogError(
7111                     commandBuffer, "VUID-VkRenderingInfoKHR-pStencilAttachment-06094",
7112                     "vkCmdBeginRenderingKHR(): imageLayout must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL");
7113             }
7114 
7115             if (pRenderingInfo->pStencilAttachment->resolveMode != VK_RESOLVE_MODE_NONE) {
7116                 if (pRenderingInfo->pStencilAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
7117                     skip |= LogError(
7118                         commandBuffer, "VUID-VkRenderingInfoKHR-pStencilAttachment-06095",
7119                         "vkCmdBeginRenderingKHR(): resolveImageLayout must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL");
7120                 }
7121                 if (pRenderingInfo->pStencilAttachment->resolveImageLayout ==
7122                     VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) {
7123                     skip |= LogError(commandBuffer, "VUID-VkRenderingInfoKHR-pStencilAttachment-06099",
7124                                      "vkCmdBeginRenderingKHR(): resolveImageLayout must not be "
7125                                      "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL");
7126                 }
7127                 if (!(pRenderingInfo->pStencilAttachment->resolveMode & phys_dev_props_core12.supportedStencilResolveModes)) {
7128                     skip |= LogError(device, "VUID-VkRenderingInfoKHR-pStencilAttachment-06103",
7129                         "vkCmdBeginRenderingKHR(): Includes a resolveMode structure with invalid mode (%s).",
7130                         string_VkResolveModeFlagBits(pRenderingInfo->pStencilAttachment->resolveMode));
7131                 }
7132             }
7133 
7134         }
7135     }
7136 
7137     return skip;
7138 }
7139 
ValidateRenderingAttachmentInfoKHR(VkCommandBuffer commandBuffer,const VkRenderingAttachmentInfoKHR * pAttachment) const7140 bool CoreChecks::ValidateRenderingAttachmentInfoKHR(VkCommandBuffer commandBuffer,
7141                                                     const VkRenderingAttachmentInfoKHR *pAttachment) const {
7142     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7143     if (!cb_state) return false;
7144     bool skip = false;
7145 
7146     if (pAttachment->imageView != VK_NULL_HANDLE) {
7147         auto image_view_state = Get<IMAGE_VIEW_STATE>(pAttachment->imageView);
7148 
7149         if (pAttachment->imageLayout == VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR) {
7150             skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06143",
7151                 "vkCmdBeginRenderingKHR(): layout must not be VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR");
7152         }
7153 
7154         if (pAttachment->imageLayout == VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT) {
7155             skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06140",
7156                 "vkCmdBeginRenderingKHR(): layout must not be VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT");
7157         }
7158 
7159         if (pAttachment->resolveMode != VK_RESOLVE_MODE_NONE && image_view_state->samples == VK_SAMPLE_COUNT_1_BIT) {
7160             skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06132",
7161                              "Image sample count must not have a VK_SAMPLE_COUNT_1_BIT for Resolve Mode %s",
7162                              string_VkResolveModeFlags(pAttachment->resolveMode).c_str());
7163         }
7164 
7165         auto resolve_view_state = Get<IMAGE_VIEW_STATE>(pAttachment->resolveImageView);
7166         if (pAttachment->resolveMode != VK_RESOLVE_MODE_NONE && resolve_view_state->samples != VK_SAMPLE_COUNT_1_BIT) {
7167             skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06133",
7168                              "resolveImageView sample count must have a VK_SAMPLE_COUNT_1_BIT for Resolve Mode %s",
7169                              string_VkResolveModeFlags(pAttachment->resolveMode).c_str());
7170         }
7171 
7172         if (pAttachment->resolveMode != VK_RESOLVE_MODE_NONE) {
7173             if (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR) {
7174                 skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06144",
7175                     "vlCmdBeginRenderingKHR(): resolveImageLayout must not be VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR");
7176             }
7177 
7178             if (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT) {
7179                 skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06141",
7180                     "vlCmdBeginRenderingKHR(): resolveImageLayout must not be VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT");
7181             }
7182 
7183             if (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR) {
7184                 skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06142",
7185                     "vlCmdBeginRenderingKHR(): resolveImageLayout must not be VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR");
7186             }
7187 
7188             if (image_view_state->create_info.format != resolve_view_state->create_info.format) {
7189                 skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06134",
7190                                  "resolveImageView format (%u) and ImageView format (%u) must have the same VkFormat",
7191                                  resolve_view_state->create_info.format, image_view_state->create_info.format);
7192             }
7193 
7194             if (((pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_UNDEFINED) ||
7195                  (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
7196                  (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
7197                  (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) ||
7198                  (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) ||
7199                  (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_PREINITIALIZED))) {
7200                 skip |= LogError(
7201                     commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06136",
7202                     "resolveImageLayout (%s) must not be VK_IMAGE_LAYOUT_UNDEFINED, "
7203                     "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "
7204                     "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, or VK_IMAGE_LAYOUT_PREINITIALIZED",
7205                     string_VkImageLayout(pAttachment->resolveImageLayout));
7206             }
7207 
7208             if (((pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL) ||
7209                  (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL))) {
7210                 skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06137",
7211                                  "resolveImageLayout (%s) must not be VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "
7212                                  "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL",
7213                                  string_VkImageLayout(pAttachment->resolveImageLayout));
7214             }
7215         }
7216 
7217         if ((pAttachment->imageLayout == VK_IMAGE_LAYOUT_UNDEFINED) ||
7218             (pAttachment->imageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
7219             (pAttachment->imageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) ||
7220             (pAttachment->imageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) ||
7221             (pAttachment->imageLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)) {
7222             skip |= LogError(
7223                 commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06135",
7224                 "layout (%s) must not be VK_IMAGE_LAYOUT_UNDEFINED VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "
7225                 "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, or VK_IMAGE_LAYOUT_PREINITIALIZED",
7226                 string_VkImageLayout(pAttachment->imageLayout));
7227         }
7228 
7229         if (pAttachment->imageLayout == VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV) {
7230             skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06138",
7231                              "layout (%s) must not be VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV",
7232                              string_VkImageLayout(pAttachment->imageLayout));
7233         }
7234 
7235         if (pAttachment->resolveImageLayout == VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV) {
7236             skip |= LogError(commandBuffer, "VUID-VkRenderingAttachmentInfoKHR-imageView-06139",
7237                              "layout (%s) must not be VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV",
7238                              string_VkImageLayout(pAttachment->resolveImageLayout));
7239         }
7240     }
7241 
7242     return skip;
7243 }
7244 
PreCallValidateCmdEndRenderingKHR(VkCommandBuffer commandBuffer) const7245 bool CoreChecks::PreCallValidateCmdEndRenderingKHR(VkCommandBuffer commandBuffer) const {
7246     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7247     if (!cb_state) return false;
7248     bool skip = false;
7249 
7250     if (cb_state->activeRenderPass) {
7251         if (cb_state->activeRenderPass->use_dynamic_rendering == false) {
7252             skip |= LogError(
7253                 commandBuffer, "VUID-vkCmdEndRenderingKHR-None-06161",
7254                 "Calling vkCmdEndRenderingKHR() in a render pass instance that was not begun with vkCmdBeginRenderingKHR().");
7255         }
7256         if (cb_state->activeRenderPass->use_dynamic_rendering_inherited == true) {
7257             skip |= LogError(commandBuffer, "VUID-vkCmdEndRenderingKHR-commandBuffer-06162",
7258                              "Calling vkCmdEndRenderingKHR() in a render pass instance that was not begun in this command buffer.");
7259         }
7260     }
7261     return skip;
7262 }
7263 
PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer,const VkCommandBufferBeginInfo * pBeginInfo) const7264 bool CoreChecks::PreCallValidateBeginCommandBuffer(VkCommandBuffer commandBuffer,
7265                                                    const VkCommandBufferBeginInfo *pBeginInfo) const {
7266     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7267     if (!cb_state) return false;
7268     bool skip = false;
7269     if (cb_state->InUse()) {
7270         skip |= LogError(commandBuffer, "VUID-vkBeginCommandBuffer-commandBuffer-00049",
7271                          "Calling vkBeginCommandBuffer() on active %s before it has completed. You must check "
7272                          "command buffer fence before this call.",
7273                          report_data->FormatHandle(commandBuffer).c_str());
7274     }
7275     if (cb_state->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
7276         // Primary Command Buffer
7277         const VkCommandBufferUsageFlags invalid_usage =
7278             (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT);
7279         if ((pBeginInfo->flags & invalid_usage) == invalid_usage) {
7280             skip |= LogError(commandBuffer, "VUID-vkBeginCommandBuffer-commandBuffer-02840",
7281                              "vkBeginCommandBuffer(): Primary %s can't have both VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT and "
7282                              "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
7283                              report_data->FormatHandle(commandBuffer).c_str());
7284         }
7285     } else {
7286         // Secondary Command Buffer
7287         const VkCommandBufferInheritanceInfo *info = pBeginInfo->pInheritanceInfo;
7288         if (!info) {
7289             skip |= LogError(commandBuffer, "VUID-vkBeginCommandBuffer-commandBuffer-00051",
7290                              "vkBeginCommandBuffer(): Secondary %s must have inheritance info.",
7291                              report_data->FormatHandle(commandBuffer).c_str());
7292         } else {
7293             if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
7294                 const auto framebuffer = Get<FRAMEBUFFER_STATE>(info->framebuffer);
7295                 if (framebuffer) {
7296                     if (framebuffer->createInfo.renderPass != info->renderPass) {
7297                         const auto render_pass = Get<RENDER_PASS_STATE>(info->renderPass);
7298                         // renderPass that framebuffer was created with must be compatible with local renderPass
7299                         skip |= ValidateRenderPassCompatibility("framebuffer", framebuffer->rp_state.get(), "command buffer",
7300                                                                 render_pass.get(), "vkBeginCommandBuffer()",
7301                                                                 "VUID-VkCommandBufferBeginInfo-flags-00055");
7302                     }
7303                 }
7304 
7305                 if (info->renderPass != VK_NULL_HANDLE) {
7306                     const auto render_pass = Get<RENDER_PASS_STATE>(info->renderPass);
7307                     if (!render_pass) {
7308                         skip |= LogError(commandBuffer, "VUID-VkCommandBufferBeginInfo-flags-06000",
7309                             "vkBeginCommandBuffer(): Renderpass must be a valid VkRenderPass");
7310                     }
7311                     else {
7312                         if (info->subpass >= render_pass->createInfo.subpassCount) {
7313                             skip |= LogError(commandBuffer, "VUID-VkCommandBufferBeginInfo-flags-06001",
7314                                 "vkBeginCommandBuffer(): Subpass member of pInheritanceInfo must be a valid subpass index within pInheritanceInfo->renderPass");
7315                         }
7316                     }
7317                 } else {
7318                     auto p_inherited_rendering_info = LvlFindInChain<VkCommandBufferInheritanceRenderingInfoKHR>(info->pNext);
7319                     if (!p_inherited_rendering_info) {
7320                         // The pNext chain of pInheritanceInfo must include a VkCommandBufferInheritanceRenderingInfoKHR structure
7321                         skip |= LogError(commandBuffer, "VUID-VkCommandBufferBeginInfo-flags-06002",
7322                                          "vkBeginCommandBuffer():The pNext chain of pInheritanceInfo must include a VkCommandBufferInheritanceRenderingInfoKHR structure");
7323                     } else {
7324                         auto p_attachment_sample_count_info_amd = LvlFindInChain<VkAttachmentSampleCountInfoAMD>(info->pNext);
7325                         if (p_attachment_sample_count_info_amd &&
7326                             p_attachment_sample_count_info_amd->colorAttachmentCount != p_inherited_rendering_info->colorAttachmentCount) {
7327                                 skip |= LogError(commandBuffer, "VUID-VkCommandBufferBeginInfo-flags-06003",
7328                                             "vkBeginCommandBuffer(): VkAttachmentSampleCountInfoAMD->colorAttachmentCount[%u] must equal VkCommandBufferInheritanceRenderingInfoKHR->colorAttachmentCount[%u]",
7329                                              p_attachment_sample_count_info_amd->colorAttachmentCount, p_inherited_rendering_info->colorAttachmentCount);
7330                         }
7331 
7332                         auto p_attachment_sample_count_info_nv = LvlFindInChain<VkAttachmentSampleCountInfoNV>(info->pNext);
7333                         if (p_attachment_sample_count_info_nv &&
7334                             p_attachment_sample_count_info_nv->colorAttachmentCount != p_inherited_rendering_info->colorAttachmentCount) {
7335                                 skip |= LogError(commandBuffer, "VUID-VkCommandBufferBeginInfo-flags-06003",
7336                                     "vkBeginCommandBuffer(): VkAttachmentSampleCountInfoNV->colorAttachmentCount[%u] must equal VkCommandBufferInheritanceRenderingInfoKHR->colorAttachmentCount[%u]",
7337                                     p_attachment_sample_count_info_nv->colorAttachmentCount, p_inherited_rendering_info->colorAttachmentCount);
7338                         }
7339 
7340                         const VkFormatFeatureFlags valid_color_format = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
7341                         for (uint32_t i = 0; i < p_inherited_rendering_info->colorAttachmentCount; ++i) {
7342                             const VkFormat attachment_format = p_inherited_rendering_info->pColorAttachmentFormats[i];
7343                             if (attachment_format != VK_FORMAT_UNDEFINED) {
7344                                 const VkFormatFeatureFlags potential_format_features = GetPotentialFormatFeatures(attachment_format);
7345                                 if ((potential_format_features & valid_color_format) == 0) {
7346                                     skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceRenderingInfoKHR-pColorAttachmentFormats-06006",
7347                                         "vkBeginCommandBuffer(): VkCommandBufferInheritanceRenderingInfoKHR->pColorAttachmentFormats[%u] (%s) must be a format with potential format features that include VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT",
7348                                         i, string_VkFormat(attachment_format));
7349                                 }
7350                             }
7351                         }
7352 
7353                         const VkFormatFeatureFlags valid_depth_stencil_format = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
7354                         const VkFormat depth_format = p_inherited_rendering_info->depthAttachmentFormat;
7355                         if (depth_format != VK_FORMAT_UNDEFINED) {
7356                             const VkFormatFeatureFlags potential_format_features = GetPotentialFormatFeatures(depth_format);
7357                             if ((potential_format_features & valid_depth_stencil_format) == 0) {
7358                                 skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceRenderingInfoKHR-depthAttachmentFormat-06007",
7359                                     "vkBeginCommandBuffer(): VkCommandBufferInheritanceRenderingInfoKHR->depthAttachmentFormat (%s) must be a format with potential format features that include VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT",
7360                                     string_VkFormat(depth_format));
7361                             }
7362                         }
7363 
7364                         const VkFormat stencil_format = p_inherited_rendering_info->stencilAttachmentFormat;
7365                         if (stencil_format != VK_FORMAT_UNDEFINED) {
7366                             const VkFormatFeatureFlags potential_format_features = GetPotentialFormatFeatures(stencil_format);
7367                             if ((potential_format_features & valid_depth_stencil_format) == 0) {
7368                                 skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceRenderingInfoKHR-stencilAttachmentFormat-06199",
7369                                     "vkBeginCommandBuffer(): VkCommandBufferInheritanceRenderingInfoKHR->stencilAttachmentFormat (%s) must be a format with potential format features that include VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT",
7370                                     string_VkFormat(stencil_format));
7371                             }
7372                         }
7373 
7374                         if ((depth_format != VK_FORMAT_UNDEFINED && stencil_format != VK_FORMAT_UNDEFINED) && (depth_format != stencil_format)) {
7375                             skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceRenderingInfoKHR-depthAttachmentFormat-06200",
7376                                 "vkBeginCommandBuffer(): VkCommandBufferInheritanceRenderingInfoKHR->depthAttachmentFormat (%s) must equal VkCommandBufferInheritanceRenderingInfoKHR->stencilAttachmentFormat (%s)",
7377                                 string_VkFormat(depth_format), string_VkFormat(stencil_format));
7378                         }
7379 
7380                         if ((enabled_features.core11.multiview == VK_FALSE) && (p_inherited_rendering_info->viewMask != 0)) {
7381                             skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceRenderingInfoKHR-multiview-06008",
7382                                 "vkBeginCommandBuffer(): If the multiview feature is not enabled, viewMask must be 0 (%u)",
7383                                 p_inherited_rendering_info->viewMask);
7384                         }
7385 
7386                         if (MostSignificantBit(p_inherited_rendering_info->viewMask) >= phys_dev_props_core11.maxMultiviewViewCount) {
7387                             skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceRenderingInfoKHR-viewMask-06009",
7388                                 "vkBeginCommandBuffer(): Most significant bit VkCommandBufferInheritanceRenderingInfoKHR->viewMask(%u) must be less maxMultiviewViewCount(%u)",
7389                                 p_inherited_rendering_info->viewMask, phys_dev_props_core11.maxMultiviewViewCount);
7390                         }
7391                     }
7392                 }
7393             }
7394             if ((info->occlusionQueryEnable == VK_FALSE || enabled_features.core.occlusionQueryPrecise == VK_FALSE) &&
7395                 (info->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
7396                 skip |= LogError(commandBuffer, "VUID-vkBeginCommandBuffer-commandBuffer-00052",
7397                                  "vkBeginCommandBuffer(): Secondary %s must not have VK_QUERY_CONTROL_PRECISE_BIT if "
7398                                  "occulusionQuery is disabled or the device does not support precise occlusion queries.",
7399                                  report_data->FormatHandle(commandBuffer).c_str());
7400             }
7401             auto p_inherited_viewport_scissor_info = LvlFindInChain<VkCommandBufferInheritanceViewportScissorInfoNV>(info->pNext);
7402             if (p_inherited_viewport_scissor_info != nullptr && p_inherited_viewport_scissor_info->viewportScissor2D) {
7403                 if (!enabled_features.inherited_viewport_scissor_features.inheritedViewportScissor2D)
7404                 {
7405                     skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04782",
7406                                      "vkBeginCommandBuffer(): inheritedViewportScissor2D feature not enabled.");
7407                 }
7408                 if (!(pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
7409                     skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04786",
7410                                      "vkBeginCommandBuffer(): Secondary %s must be recorded with the"
7411                                      "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT if viewportScissor2D is VK_TRUE.",
7412                                      report_data->FormatHandle(commandBuffer).c_str());
7413                 }
7414                 if (p_inherited_viewport_scissor_info->viewportDepthCount == 0) {
7415                     skip |= LogError(commandBuffer, "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04784",
7416                                      "vkBeginCommandBuffer(): "
7417                                      "If viewportScissor2D is VK_TRUE, then viewportDepthCount must be greater than 0.");
7418                 }
7419             }
7420         }
7421         if (info && info->renderPass != VK_NULL_HANDLE) {
7422             const auto render_pass = Get<RENDER_PASS_STATE>(info->renderPass);
7423             if (render_pass) {
7424                 if (info->subpass >= render_pass->createInfo.subpassCount) {
7425                     skip |= LogError(commandBuffer, "VUID-VkCommandBufferBeginInfo-flags-00054",
7426                                      "vkBeginCommandBuffer(): Secondary %s must have a subpass index (%d) that is "
7427                                      "less than the number of subpasses (%d).",
7428                                      report_data->FormatHandle(commandBuffer).c_str(), info->subpass,
7429                                      render_pass->createInfo.subpassCount);
7430                 }
7431             }
7432         }
7433     }
7434     if (CB_RECORDING == cb_state->state) {
7435         skip |= LogError(commandBuffer, "VUID-vkBeginCommandBuffer-commandBuffer-00049",
7436                          "vkBeginCommandBuffer(): Cannot call Begin on %s in the RECORDING state. Must first call "
7437                          "vkEndCommandBuffer().",
7438                          report_data->FormatHandle(commandBuffer).c_str());
7439     } else if (CB_RECORDED == cb_state->state || CB_INVALID_COMPLETE == cb_state->state) {
7440         VkCommandPool cmd_pool = cb_state->createInfo.commandPool;
7441         const auto *pool = cb_state->command_pool;
7442         if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pool->createFlags)) {
7443             LogObjectList objlist(commandBuffer);
7444             objlist.add(cmd_pool);
7445             skip |= LogError(objlist, "VUID-vkBeginCommandBuffer-commandBuffer-00050",
7446                              "Call to vkBeginCommandBuffer() on %s attempts to implicitly reset cmdBuffer created from "
7447                              "%s that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
7448                              report_data->FormatHandle(commandBuffer).c_str(), report_data->FormatHandle(cmd_pool).c_str());
7449         }
7450     }
7451     auto chained_device_group_struct = LvlFindInChain<VkDeviceGroupCommandBufferBeginInfo>(pBeginInfo->pNext);
7452     if (chained_device_group_struct) {
7453         skip |= ValidateDeviceMaskToPhysicalDeviceCount(chained_device_group_struct->deviceMask, commandBuffer,
7454                                                         "VUID-VkDeviceGroupCommandBufferBeginInfo-deviceMask-00106");
7455         skip |= ValidateDeviceMaskToZero(chained_device_group_struct->deviceMask, commandBuffer,
7456                                          "VUID-VkDeviceGroupCommandBufferBeginInfo-deviceMask-00107");
7457     }
7458     return skip;
7459 }
7460 
PreCallValidateEndCommandBuffer(VkCommandBuffer commandBuffer) const7461 bool CoreChecks::PreCallValidateEndCommandBuffer(VkCommandBuffer commandBuffer) const {
7462     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7463     if (!cb_state) return false;
7464     bool skip = false;
7465     if ((VK_COMMAND_BUFFER_LEVEL_PRIMARY == cb_state->createInfo.level) ||
7466         !(cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
7467         // This needs spec clarification to update valid usage, see comments in PR:
7468         // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/165
7469         skip |= InsideRenderPass(cb_state.get(), "vkEndCommandBuffer()", "VUID-vkEndCommandBuffer-commandBuffer-00060");
7470     }
7471 
7472     if (cb_state->state == CB_INVALID_COMPLETE || cb_state->state == CB_INVALID_INCOMPLETE) {
7473         skip |= ReportInvalidCommandBuffer(cb_state.get(), "vkEndCommandBuffer()");
7474     } else if (CB_RECORDING != cb_state->state) {
7475         skip |= LogError(
7476             commandBuffer, "VUID-vkEndCommandBuffer-commandBuffer-00059",
7477             "vkEndCommandBuffer(): Cannot call End on %s when not in the RECORDING state. Must first call vkBeginCommandBuffer().",
7478             report_data->FormatHandle(commandBuffer).c_str());
7479     }
7480 
7481     for (const auto &query : cb_state->activeQueries) {
7482         skip |= LogError(commandBuffer, "VUID-vkEndCommandBuffer-commandBuffer-00061",
7483                          "vkEndCommandBuffer(): Ending command buffer with in progress query: %s, query %d.",
7484                          report_data->FormatHandle(query.pool).c_str(), query.query);
7485     }
7486     if (cb_state->conditional_rendering_active) {
7487         skip |= LogError(commandBuffer, "VUID-vkEndCommandBuffer-None-01978",
7488                          "vkEndCommandBuffer(): Ending command buffer with active conditional rendering.");
7489     }
7490     return skip;
7491 }
7492 
PreCallValidateResetCommandBuffer(VkCommandBuffer commandBuffer,VkCommandBufferResetFlags flags) const7493 bool CoreChecks::PreCallValidateResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) const {
7494     bool skip = false;
7495     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7496     if (!cb_state) return false;
7497     VkCommandPool cmd_pool = cb_state->createInfo.commandPool;
7498     const auto *pool = cb_state->command_pool;
7499 
7500     if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & pool->createFlags)) {
7501         LogObjectList objlist(commandBuffer);
7502         objlist.add(cmd_pool);
7503         skip |= LogError(objlist, "VUID-vkResetCommandBuffer-commandBuffer-00046",
7504                          "vkResetCommandBuffer(): Attempt to reset %s created from %s that does NOT have the "
7505                          "VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
7506                          report_data->FormatHandle(commandBuffer).c_str(), report_data->FormatHandle(cmd_pool).c_str());
7507     }
7508     skip |= CheckCommandBufferInFlight(cb_state.get(), "reset", "VUID-vkResetCommandBuffer-commandBuffer-00045");
7509 
7510     return skip;
7511 }
7512 
GetPipelineTypeName(VkPipelineBindPoint pipelineBindPoint)7513 static const char *GetPipelineTypeName(VkPipelineBindPoint pipelineBindPoint) {
7514     switch (pipelineBindPoint) {
7515         case VK_PIPELINE_BIND_POINT_GRAPHICS:
7516             return "graphics";
7517         case VK_PIPELINE_BIND_POINT_COMPUTE:
7518             return "compute";
7519         case VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR:
7520             return "ray-tracing";
7521         case VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI:
7522             return "subpass-shading";
7523         default:
7524             return "unknown";
7525     }
7526 }
7527 
ValidateGraphicsPipelineBindPoint(const CMD_BUFFER_STATE * cb_state,const PIPELINE_STATE * pipeline_state) const7528 bool CoreChecks::ValidateGraphicsPipelineBindPoint(const CMD_BUFFER_STATE *cb_state, const PIPELINE_STATE *pipeline_state) const {
7529     bool skip = false;
7530 
7531     if (cb_state->inheritedViewportDepths.size() != 0) {
7532         bool dyn_viewport = IsDynamic(pipeline_state, VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT)
7533                          || IsDynamic(pipeline_state, VK_DYNAMIC_STATE_VIEWPORT);
7534         bool dyn_scissor = IsDynamic(pipeline_state, VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT)
7535                          || IsDynamic(pipeline_state, VK_DYNAMIC_STATE_SCISSOR);
7536         if (!dyn_viewport || !dyn_scissor) {
7537             skip |= LogError(device, "VUID-vkCmdBindPipeline-commandBuffer-04808",
7538                 "Graphics pipeline incompatible with viewport/scissor inheritance.");
7539         }
7540         const auto &create_info = pipeline_state->create_info.graphics;
7541         const auto *discard_rectangle_state = LvlFindInChain<VkPipelineDiscardRectangleStateCreateInfoEXT>(create_info.pNext);
7542         if (discard_rectangle_state && discard_rectangle_state->discardRectangleCount != 0) {
7543             if (!IsDynamic(pipeline_state, VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT)) {
7544                 skip |= LogError(device, "VUID-vkCmdBindPipeline-commandBuffer-04809",
7545                                  "vkCmdBindPipeline(): commandBuffer is a secondary command buffer with "
7546                                  "VkCommandBufferInheritanceViewportScissorInfoNV::viewportScissor2D enabled, pipelineBindPoint is "
7547                                  "VK_PIPELINE_BIND_POINT_GRAPHICS and pipeline was created with "
7548                                  "VkPipelineDiscardRectangleStateCreateInfoEXT::discardRectangleCount = %" PRIu32
7549                                  ", but without VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT.",
7550                                  discard_rectangle_state->discardRectangleCount);
7551             }
7552         }
7553     }
7554 
7555     return skip;
7556 }
7557 
PreCallValidateCmdBindPipeline(VkCommandBuffer commandBuffer,VkPipelineBindPoint pipelineBindPoint,VkPipeline pipeline) const7558 bool CoreChecks::PreCallValidateCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
7559                                                 VkPipeline pipeline) const {
7560     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7561     assert(cb_state);
7562 
7563     bool skip = false;
7564     skip |= ValidateCmd(cb_state.get(), CMD_BINDPIPELINE);
7565     static const std::map<VkPipelineBindPoint, std::string> bindpoint_errors = {
7566         std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdBindPipeline-pipelineBindPoint-00777"),
7567         std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdBindPipeline-pipelineBindPoint-00778"),
7568         std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, "VUID-vkCmdBindPipeline-pipelineBindPoint-02391")};
7569 
7570     skip |= ValidatePipelineBindPoint(cb_state.get(), pipelineBindPoint, "vkCmdBindPipeline()", bindpoint_errors);
7571 
7572     const auto pipeline_state = Get<PIPELINE_STATE>(pipeline);
7573     assert(pipeline_state);
7574 
7575     const auto pipeline_state_bind_point = pipeline_state->GetPipelineType();
7576 
7577     if (pipelineBindPoint != pipeline_state_bind_point) {
7578         if (pipelineBindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) {
7579             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindPipeline-pipelineBindPoint-00779",
7580                              "Cannot bind a pipeline of type %s to the graphics pipeline bind point",
7581                              GetPipelineTypeName(pipeline_state_bind_point));
7582         } else if (pipelineBindPoint == VK_PIPELINE_BIND_POINT_COMPUTE) {
7583             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindPipeline-pipelineBindPoint-00780",
7584                              "Cannot bind a pipeline of type %s to the compute pipeline bind point",
7585                              GetPipelineTypeName(pipeline_state_bind_point));
7586         } else if (pipelineBindPoint == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
7587             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindPipeline-pipelineBindPoint-02392",
7588                              "Cannot bind a pipeline of type %s to the ray-tracing pipeline bind point",
7589                              GetPipelineTypeName(pipeline_state_bind_point));
7590         }
7591     } else {
7592         if (pipelineBindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) {
7593             skip |= ValidateGraphicsPipelineBindPoint(cb_state.get(), pipeline_state.get());
7594 
7595             if (cb_state->activeRenderPass &&
7596                 phys_dev_ext_props.provoking_vertex_props.provokingVertexModePerPipeline == VK_FALSE) {
7597                 const auto lvl_bind_point = ConvertToLvlBindPoint(pipelineBindPoint);
7598                 const auto &last_bound_it = cb_state->lastBound[lvl_bind_point];
7599                 if (last_bound_it.pipeline_state) {
7600                     auto last_bound_provoking_vertex_state_ci =
7601                         LvlFindInChain<VkPipelineRasterizationProvokingVertexStateCreateInfoEXT>(
7602                             last_bound_it.pipeline_state->create_info.graphics.pRasterizationState->pNext);
7603 
7604                     auto current_provoking_vertex_state_ci =
7605                         LvlFindInChain<VkPipelineRasterizationProvokingVertexStateCreateInfoEXT>(
7606                             pipeline_state->create_info.graphics.pRasterizationState->pNext);
7607 
7608                     if (last_bound_provoking_vertex_state_ci && !current_provoking_vertex_state_ci) {
7609                         skip |= LogError(pipeline, "VUID-vkCmdBindPipeline-pipelineBindPoint-04881",
7610                                          "Previous %s's provokingVertexMode is %s, but %s doesn't chain "
7611                                          "VkPipelineRasterizationProvokingVertexStateCreateInfoEXT.",
7612                                          report_data->FormatHandle(last_bound_it.pipeline_state->pipeline()).c_str(),
7613                                          string_VkProvokingVertexModeEXT(last_bound_provoking_vertex_state_ci->provokingVertexMode),
7614                                          report_data->FormatHandle(pipeline).c_str());
7615                     } else if (!last_bound_provoking_vertex_state_ci && current_provoking_vertex_state_ci) {
7616                         skip |= LogError(pipeline, "VUID-vkCmdBindPipeline-pipelineBindPoint-04881",
7617                                          " %s's provokingVertexMode is %s, but previous %s doesn't chain "
7618                                          "VkPipelineRasterizationProvokingVertexStateCreateInfoEXT.",
7619                                          report_data->FormatHandle(pipeline).c_str(),
7620                                          string_VkProvokingVertexModeEXT(current_provoking_vertex_state_ci->provokingVertexMode),
7621                                          report_data->FormatHandle(last_bound_it.pipeline_state->pipeline()).c_str());
7622                     } else if (last_bound_provoking_vertex_state_ci && current_provoking_vertex_state_ci &&
7623                                last_bound_provoking_vertex_state_ci->provokingVertexMode !=
7624                                    current_provoking_vertex_state_ci->provokingVertexMode) {
7625                         skip |=
7626                             LogError(pipeline, "VUID-vkCmdBindPipeline-pipelineBindPoint-04881",
7627                                      "%s's provokingVertexMode is %s, but previous %s's provokingVertexMode is %s.",
7628                                      report_data->FormatHandle(pipeline).c_str(),
7629                                      string_VkProvokingVertexModeEXT(current_provoking_vertex_state_ci->provokingVertexMode),
7630                                      report_data->FormatHandle(last_bound_it.pipeline_state->pipeline()).c_str(),
7631                                      string_VkProvokingVertexModeEXT(last_bound_provoking_vertex_state_ci->provokingVertexMode));
7632                     }
7633                 }
7634             }
7635 
7636             if (cb_state->activeRenderPass && phys_dev_ext_props.sample_locations_props.variableSampleLocations == VK_FALSE) {
7637                 const auto *sample_locations =
7638                     LvlFindInChain<VkPipelineSampleLocationsStateCreateInfoEXT>(pipeline_state->create_info.graphics.pNext);
7639                 if (sample_locations && sample_locations->sampleLocationsEnable == VK_TRUE &&
7640                     !IsDynamic(pipeline_state.get(), VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT)) {
7641                     const VkRenderPassSampleLocationsBeginInfoEXT *sample_locations_begin_info =
7642                         LvlFindInChain<VkRenderPassSampleLocationsBeginInfoEXT>(cb_state->activeRenderPassBeginInfo.pNext);
7643                     bool found = false;
7644                     if (sample_locations_begin_info) {
7645                         for (uint32_t i = 0; i < sample_locations_begin_info->postSubpassSampleLocationsCount; ++i) {
7646                             if (sample_locations_begin_info->pPostSubpassSampleLocations[i].subpassIndex ==
7647                                 cb_state->activeSubpass) {
7648                                 if (MatchSampleLocationsInfo(
7649                                         &sample_locations_begin_info->pPostSubpassSampleLocations[i].sampleLocationsInfo,
7650                                         &sample_locations->sampleLocationsInfo)) {
7651                                     found = true;
7652                                 }
7653                             }
7654                         }
7655                     }
7656                     if (!found) {
7657                         skip |=
7658                             LogError(pipeline, "VUID-vkCmdBindPipeline-variableSampleLocations-01525",
7659                                      "vkCmdBindPipeline(): VkPhysicalDeviceSampleLocationsPropertiesEXT::variableSampleLocations "
7660                                      "is false, pipeline is a graphics pipeline with "
7661                                      "VkPipelineSampleLocationsStateCreateInfoEXT::sampleLocationsEnable equal to true and without "
7662                                      "VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT, but the current render pass (%" PRIu32
7663                                      ") was not begun with any element of "
7664                                      "VkRenderPassSampleLocationsBeginInfoEXT::pPostSubpassSampleLocations subpassIndex "
7665                                      "matching the current subpass index and sampleLocationsInfo matching sampleLocationsInfo of "
7666                                      "VkPipelineSampleLocationsStateCreateInfoEXT the pipeline was created with.",
7667                                      cb_state->activeSubpass);
7668                     }
7669                 }
7670             }
7671         }
7672         if (pipeline_state->GetPipelineCreateFlags() & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) {
7673             skip |= LogError(
7674                 pipeline, "VUID-vkCmdBindPipeline-pipeline-03382",
7675                 "vkCmdBindPipeline(): Cannot bind a pipeline that was created with the VK_PIPELINE_CREATE_LIBRARY_BIT_KHR flag.");
7676         }
7677         if (cb_state->transform_feedback_active) {
7678             skip |= LogError(pipeline, "VUID-vkCmdBindPipeline-None-02323", "vkCmdBindPipeline(): transform feedback is active.");
7679         }
7680     }
7681 
7682     return skip;
7683 }
7684 
ForbidInheritedViewportScissor(VkCommandBuffer commandBuffer,const CMD_BUFFER_STATE * cb_state,const char * vuid,const char * cmdName) const7685 bool CoreChecks::ForbidInheritedViewportScissor(VkCommandBuffer commandBuffer, const CMD_BUFFER_STATE *cb_state,
7686                                                 const char* vuid, const char *cmdName) const {
7687     bool skip = false;
7688     if (cb_state->inheritedViewportDepths.size() != 0) {
7689         skip |= LogError(
7690             commandBuffer, vuid,
7691             "%s: commandBuffer must not have VkCommandBufferInheritanceViewportScissorInfoNV::viewportScissor2D enabled.", cmdName);
7692     }
7693     return skip;
7694 }
7695 
PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer,uint32_t firstViewport,uint32_t viewportCount,const VkViewport * pViewports) const7696 bool CoreChecks::PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
7697                                                const VkViewport *pViewports) const {
7698     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7699     assert(cb_state);
7700     bool skip = false;
7701     skip |= ValidateCmd(cb_state.get(), CMD_SETVIEWPORT);
7702     skip |= ForbidInheritedViewportScissor(commandBuffer, cb_state.get(), "VUID-vkCmdSetViewport-commandBuffer-04821",
7703                                            "vkCmdSetViewport");
7704     return skip;
7705 }
7706 
PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer,uint32_t firstScissor,uint32_t scissorCount,const VkRect2D * pScissors) const7707 bool CoreChecks::PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount,
7708                                               const VkRect2D *pScissors) const {
7709     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7710     assert(cb_state);
7711     bool skip = false;
7712     skip |= ValidateCmd(cb_state.get(), CMD_SETSCISSOR);
7713     skip |= ForbidInheritedViewportScissor(commandBuffer, cb_state.get(), "VUID-vkCmdSetScissor-viewportScissor2D-04789",
7714                                            "vkCmdSetScissor");
7715     return skip;
7716 }
7717 
PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer,uint32_t firstExclusiveScissor,uint32_t exclusiveScissorCount,const VkRect2D * pExclusiveScissors) const7718 bool CoreChecks::PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor,
7719                                                          uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors) const {
7720     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7721     assert(cb_state);
7722     bool skip = false;
7723     skip |= ValidateCmd(cb_state.get(), CMD_SETEXCLUSIVESCISSORNV);
7724     if (!enabled_features.exclusive_scissor_features.exclusiveScissor) {
7725         skip |= LogError(commandBuffer, "VUID-vkCmdSetExclusiveScissorNV-None-02031",
7726                          "vkCmdSetExclusiveScissorNV: The exclusiveScissor feature is disabled.");
7727     }
7728     return skip;
7729 }
7730 
PreCallValidateCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer,VkImageView imageView,VkImageLayout imageLayout) const7731 bool CoreChecks::PreCallValidateCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView,
7732                                                           VkImageLayout imageLayout) const {
7733     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7734     assert(cb_state);
7735     bool skip = false;
7736 
7737     skip |= ValidateCmd(cb_state.get(), CMD_BINDSHADINGRATEIMAGENV);
7738 
7739     if (!enabled_features.shading_rate_image_features.shadingRateImage) {
7740         skip |= LogError(commandBuffer, "VUID-vkCmdBindShadingRateImageNV-None-02058",
7741                          "vkCmdBindShadingRateImageNV: The shadingRateImage feature is disabled.");
7742     }
7743 
7744     if (imageView == VK_NULL_HANDLE) {
7745         return skip;
7746     }
7747     const auto view_state = Get<IMAGE_VIEW_STATE>(imageView);
7748     if (!view_state) {
7749         skip |= LogError(imageView, "VUID-vkCmdBindShadingRateImageNV-imageView-02059",
7750                          "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, it must be a valid "
7751                          "VkImageView handle.");
7752         return skip;
7753     }
7754     const auto &ivci = view_state->create_info;
7755     if (ivci.viewType != VK_IMAGE_VIEW_TYPE_2D && ivci.viewType != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
7756         skip |= LogError(imageView, "VUID-vkCmdBindShadingRateImageNV-imageView-02059",
7757                          "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, it must be a valid "
7758                          "VkImageView handle of type VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
7759     }
7760 
7761     if (ivci.format != VK_FORMAT_R8_UINT) {
7762         skip |= LogError(
7763             imageView, "VUID-vkCmdBindShadingRateImageNV-imageView-02060",
7764             "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, it must have a format of VK_FORMAT_R8_UINT.");
7765     }
7766 
7767     const auto image_state = view_state->image_state.get();
7768     auto usage = image_state->createInfo.usage;
7769     if (!(usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV)) {
7770         skip |= LogError(imageView, "VUID-vkCmdBindShadingRateImageNV-imageView-02061",
7771                          "vkCmdBindShadingRateImageNV: If imageView is not VK_NULL_HANDLE, the image must have been "
7772                          "created with VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV set.");
7773     }
7774 
7775     bool hit_error = false;
7776 
7777     // XXX TODO: While the VUID says "each subresource", only the base mip level is
7778     // actually used. Since we don't have an existing convenience function to iterate
7779     // over all mip levels, just don't bother with non-base levels.
7780     const VkImageSubresourceRange &range = view_state->normalized_subresource_range;
7781     VkImageSubresourceLayers subresource = {range.aspectMask, range.baseMipLevel, range.baseArrayLayer, range.layerCount};
7782 
7783     if (image_state) {
7784         skip |= VerifyImageLayout(cb_state.get(), image_state, subresource, imageLayout, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV,
7785                                   "vkCmdCopyImage()", "VUID-vkCmdBindShadingRateImageNV-imageLayout-02063",
7786                                   "VUID-vkCmdBindShadingRateImageNV-imageView-02062", &hit_error);
7787     }
7788 
7789     return skip;
7790 }
7791 
PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer,uint32_t firstViewport,uint32_t viewportCount,const VkShadingRatePaletteNV * pShadingRatePalettes) const7792 bool CoreChecks::PreCallValidateCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
7793                                                                    uint32_t viewportCount,
7794                                                                    const VkShadingRatePaletteNV *pShadingRatePalettes) const {
7795     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7796     assert(cb_state);
7797     bool skip = false;
7798 
7799     skip |= ValidateCmd(cb_state.get(), CMD_SETVIEWPORTSHADINGRATEPALETTENV);
7800 
7801     if (!enabled_features.shading_rate_image_features.shadingRateImage) {
7802         skip |= LogError(commandBuffer, "VUID-vkCmdSetViewportShadingRatePaletteNV-None-02064",
7803                          "vkCmdSetViewportShadingRatePaletteNV: The shadingRateImage feature is disabled.");
7804     }
7805 
7806     for (uint32_t i = 0; i < viewportCount; ++i) {
7807         auto *palette = &pShadingRatePalettes[i];
7808         if (palette->shadingRatePaletteEntryCount == 0 ||
7809             palette->shadingRatePaletteEntryCount > phys_dev_ext_props.shading_rate_image_props.shadingRatePaletteSize) {
7810             skip |= LogError(
7811                 commandBuffer, "VUID-VkShadingRatePaletteNV-shadingRatePaletteEntryCount-02071",
7812                 "vkCmdSetViewportShadingRatePaletteNV: shadingRatePaletteEntryCount must be between 1 and shadingRatePaletteSize.");
7813         }
7814     }
7815 
7816     return skip;
7817 }
7818 
ValidateGeometryTrianglesNV(const VkGeometryTrianglesNV & triangles,const char * func_name) const7819 bool CoreChecks::ValidateGeometryTrianglesNV(const VkGeometryTrianglesNV &triangles, const char *func_name) const {
7820     bool skip = false;
7821 
7822     const auto vb_state = Get<BUFFER_STATE>(triangles.vertexData);
7823     if (vb_state != nullptr && vb_state->createInfo.size <= triangles.vertexOffset) {
7824         skip |= LogError(device, "VUID-VkGeometryTrianglesNV-vertexOffset-02428", "%s", func_name);
7825     }
7826 
7827     const auto ib_state = Get<BUFFER_STATE>(triangles.indexData);
7828     if (ib_state != nullptr && ib_state->createInfo.size <= triangles.indexOffset) {
7829         skip |= LogError(device, "VUID-VkGeometryTrianglesNV-indexOffset-02431", "%s", func_name);
7830     }
7831 
7832     const auto td_state = Get<BUFFER_STATE>(triangles.transformData);
7833     if (td_state != nullptr && td_state->createInfo.size <= triangles.transformOffset) {
7834         skip |= LogError(device, "VUID-VkGeometryTrianglesNV-transformOffset-02437", "%s", func_name);
7835     }
7836 
7837     return skip;
7838 }
7839 
ValidateGeometryAABBNV(const VkGeometryAABBNV & aabbs,const char * func_name) const7840 bool CoreChecks::ValidateGeometryAABBNV(const VkGeometryAABBNV &aabbs, const char *func_name) const {
7841     bool skip = false;
7842 
7843     const auto aabb_state = Get<BUFFER_STATE>(aabbs.aabbData);
7844     if (aabb_state != nullptr && aabb_state->createInfo.size > 0 && aabb_state->createInfo.size <= aabbs.offset) {
7845         skip |= LogError(device, "VUID-VkGeometryAABBNV-offset-02439", "%s", func_name);
7846     }
7847 
7848     return skip;
7849 }
7850 
ValidateGeometryNV(const VkGeometryNV & geometry,const char * func_name) const7851 bool CoreChecks::ValidateGeometryNV(const VkGeometryNV &geometry, const char *func_name) const {
7852     bool skip = false;
7853     if (geometry.geometryType == VK_GEOMETRY_TYPE_TRIANGLES_NV) {
7854         skip = ValidateGeometryTrianglesNV(geometry.geometry.triangles, func_name);
7855     } else if (geometry.geometryType == VK_GEOMETRY_TYPE_AABBS_NV) {
7856         skip = ValidateGeometryAABBNV(geometry.geometry.aabbs, func_name);
7857     }
7858     return skip;
7859 }
7860 
PreCallValidateCreateAccelerationStructureNV(VkDevice device,const VkAccelerationStructureCreateInfoNV * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkAccelerationStructureNV * pAccelerationStructure) const7861 bool CoreChecks::PreCallValidateCreateAccelerationStructureNV(VkDevice device,
7862                                                               const VkAccelerationStructureCreateInfoNV *pCreateInfo,
7863                                                               const VkAllocationCallbacks *pAllocator,
7864                                                               VkAccelerationStructureNV *pAccelerationStructure) const {
7865     bool skip = false;
7866     if (pCreateInfo != nullptr && pCreateInfo->info.type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV) {
7867         for (uint32_t i = 0; i < pCreateInfo->info.geometryCount; i++) {
7868             skip |= ValidateGeometryNV(pCreateInfo->info.pGeometries[i], "vkCreateAccelerationStructureNV():");
7869         }
7870     }
7871     return skip;
7872 }
7873 
PreCallValidateCreateAccelerationStructureKHR(VkDevice device,const VkAccelerationStructureCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkAccelerationStructureKHR * pAccelerationStructure) const7874 bool CoreChecks::PreCallValidateCreateAccelerationStructureKHR(VkDevice device,
7875                                                                const VkAccelerationStructureCreateInfoKHR *pCreateInfo,
7876                                                                const VkAllocationCallbacks *pAllocator,
7877                                                                VkAccelerationStructureKHR *pAccelerationStructure) const {
7878     bool skip = false;
7879     if (pCreateInfo) {
7880         const auto buffer_state = Get<BUFFER_STATE>(pCreateInfo->buffer);
7881         if (buffer_state) {
7882             if (!(buffer_state->createInfo.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR)) {
7883                 skip |=
7884                     LogError(device, "VUID-VkAccelerationStructureCreateInfoKHR-buffer-03614",
7885                              "VkAccelerationStructureCreateInfoKHR(): buffer must have been created with a usage value containing "
7886                              "VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR.");
7887             }
7888             if (buffer_state->createInfo.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) {
7889                 skip |= LogError(device, "VUID-VkAccelerationStructureCreateInfoKHR-buffer-03615",
7890                                  "VkAccelerationStructureCreateInfoKHR(): buffer must not have been created with "
7891                                  "VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT.");
7892             }
7893             if (pCreateInfo->offset + pCreateInfo->size > buffer_state->createInfo.size) {
7894                 skip |= LogError(
7895                     device, "VUID-VkAccelerationStructureCreateInfoKHR-offset-03616",
7896                     "VkAccelerationStructureCreateInfoKHR(): The sum of offset and size must be less than the size of buffer.");
7897             }
7898         }
7899     }
7900     return skip;
7901 }
ValidateBindAccelerationStructureMemory(VkDevice device,const VkBindAccelerationStructureMemoryInfoNV & info) const7902 bool CoreChecks::ValidateBindAccelerationStructureMemory(VkDevice device,
7903                                                          const VkBindAccelerationStructureMemoryInfoNV &info) const {
7904     bool skip = false;
7905 
7906     const auto as_state = Get<ACCELERATION_STRUCTURE_STATE>(info.accelerationStructure);
7907     if (!as_state) {
7908         return skip;
7909     }
7910     if (!as_state->GetBoundMemory().empty()) {
7911         skip |=
7912             LogError(info.accelerationStructure, "VUID-VkBindAccelerationStructureMemoryInfoNV-accelerationStructure-03620",
7913                      "vkBindAccelerationStructureMemoryNV(): accelerationStructure must not already be backed by a memory object.");
7914     }
7915 
7916     // Validate bound memory range information
7917     const auto mem_info = Get<DEVICE_MEMORY_STATE>(info.memory);
7918     if (mem_info) {
7919         skip |= ValidateInsertAccelerationStructureMemoryRange(info.accelerationStructure, mem_info.get(), info.memoryOffset,
7920                                                                "vkBindAccelerationStructureMemoryNV()");
7921         skip |= ValidateMemoryTypes(mem_info.get(), as_state->memory_requirements.memoryRequirements.memoryTypeBits,
7922                                     "vkBindAccelerationStructureMemoryNV()",
7923                                     "VUID-VkBindAccelerationStructureMemoryInfoNV-memory-03622");
7924     }
7925 
7926     // Validate memory requirements alignment
7927     if (SafeModulo(info.memoryOffset, as_state->memory_requirements.memoryRequirements.alignment) != 0) {
7928         skip |= LogError(info.accelerationStructure, "VUID-VkBindAccelerationStructureMemoryInfoNV-memoryOffset-03623",
7929                          "vkBindAccelerationStructureMemoryNV(): memoryOffset  0x%" PRIxLEAST64
7930                          " must be an integer multiple of the alignment 0x%" PRIxLEAST64
7931                          " member of the VkMemoryRequirements structure returned from "
7932                          "a call to vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure and type of "
7933                          "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV",
7934                          info.memoryOffset, as_state->memory_requirements.memoryRequirements.alignment);
7935     }
7936 
7937     if (mem_info) {
7938         // Validate memory requirements size
7939         if (as_state->memory_requirements.memoryRequirements.size > (mem_info->alloc_info.allocationSize - info.memoryOffset)) {
7940             skip |= LogError(info.accelerationStructure, "VUID-VkBindAccelerationStructureMemoryInfoNV-size-03624",
7941                              "vkBindAccelerationStructureMemoryNV(): The size 0x%" PRIxLEAST64
7942                              " member of the VkMemoryRequirements structure returned from a call to "
7943                              "vkGetAccelerationStructureMemoryRequirementsNV with accelerationStructure and type of "
7944                              "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV must be less than or equal to the size "
7945                              "of memory minus memoryOffset 0x%" PRIxLEAST64 ".",
7946                              as_state->memory_requirements.memoryRequirements.size,
7947                              mem_info->alloc_info.allocationSize - info.memoryOffset);
7948         }
7949     }
7950 
7951     return skip;
7952 }
PreCallValidateBindAccelerationStructureMemoryNV(VkDevice device,uint32_t bindInfoCount,const VkBindAccelerationStructureMemoryInfoNV * pBindInfos) const7953 bool CoreChecks::PreCallValidateBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount,
7954                                                                   const VkBindAccelerationStructureMemoryInfoNV *pBindInfos) const {
7955     bool skip = false;
7956     for (uint32_t i = 0; i < bindInfoCount; i++) {
7957         skip |= ValidateBindAccelerationStructureMemory(device, pBindInfos[i]);
7958     }
7959     return skip;
7960 }
7961 
PreCallValidateGetAccelerationStructureHandleNV(VkDevice device,VkAccelerationStructureNV accelerationStructure,size_t dataSize,void * pData) const7962 bool CoreChecks::PreCallValidateGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
7963                                                                  size_t dataSize, void *pData) const {
7964     bool skip = false;
7965 
7966     const auto as_state = Get<ACCELERATION_STRUCTURE_STATE>(accelerationStructure);
7967     if (as_state != nullptr) {
7968         // TODO: update the fake VUID below once the real one is generated.
7969         skip = ValidateMemoryIsBoundToAccelerationStructure(
7970             as_state.get(), "vkGetAccelerationStructureHandleNV",
7971             "UNASSIGNED-vkGetAccelerationStructureHandleNV-accelerationStructure-XXXX");
7972     }
7973 
7974     return skip;
7975 }
7976 
PreCallValidateCmdBuildAccelerationStructuresKHR(VkCommandBuffer commandBuffer,uint32_t infoCount,const VkAccelerationStructureBuildGeometryInfoKHR * pInfos,const VkAccelerationStructureBuildRangeInfoKHR * const * ppBuildRangeInfos) const7977 bool CoreChecks::PreCallValidateCmdBuildAccelerationStructuresKHR(
7978     VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos,
7979     const VkAccelerationStructureBuildRangeInfoKHR *const *ppBuildRangeInfos) const {
7980     bool skip = false;
7981     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
7982     assert(cb_state);
7983     skip |= ValidateCmd(cb_state.get(), CMD_BUILDACCELERATIONSTRUCTURESKHR);
7984     if (pInfos != NULL) {
7985         for (uint32_t info_index = 0; info_index < infoCount; ++info_index) {
7986             const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[info_index].srcAccelerationStructure);
7987             const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[info_index].dstAccelerationStructure);
7988             if (pInfos[info_index].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) {
7989                 if (src_as_state == nullptr || !src_as_state->built ||
7990                     !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) {
7991                     skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03667",
7992                                      "vkCmdBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is "
7993                                      "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its srcAccelerationStructure member must "
7994                                      "have been built before with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR set in "
7995                                      "VkAccelerationStructureBuildGeometryInfoKHR::flags.");
7996                 }
7997                 if (pInfos[info_index].geometryCount != src_as_state->build_info_khr.geometryCount) {
7998                     skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03758",
7999                                      "vkCmdBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is "
8000                                      "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR,"
8001                                      " its geometryCount member must have the same value which was specified when "
8002                                      "srcAccelerationStructure was last built.");
8003                 }
8004                 if (pInfos[info_index].flags != src_as_state->build_info_khr.flags) {
8005                     skip |=
8006                         LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03759",
8007                                  "vkCmdBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is"
8008                                  " VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its flags member must have the same value which"
8009                                  " was specified when srcAccelerationStructure was last built.");
8010                 }
8011                 if (pInfos[info_index].type != src_as_state->build_info_khr.type) {
8012                     skip |=
8013                         LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03760",
8014                                  "vkCmdBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is"
8015                                  " VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its type member must have the same value which"
8016                                  " was specified when srcAccelerationStructure was last built.");
8017                 }
8018             }
8019             if (pInfos[info_index].type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) {
8020                 if (!dst_as_state ||
8021                     (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR &&
8022                      dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) {
8023                     skip |=
8024                         LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03700",
8025                                  "vkCmdBuildAccelerationStructuresKHR(): For each element of pInfos, if its type member is "
8026                                  "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, its dstAccelerationStructure member must have "
8027                                  "been created with a value of VkAccelerationStructureCreateInfoKHR::type equal to either "
8028                                  "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.");
8029                 }
8030             }
8031             if (pInfos[info_index].type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) {
8032                 if (!dst_as_state ||
8033                     (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR &&
8034                      dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) {
8035                     skip |=
8036                         LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03699",
8037                                  "vkCmdBuildAccelerationStructuresKHR(): For each element of pInfos, if its type member is "
8038                                  "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, its dstAccelerationStructure member must have been "
8039                                  "created with a value of VkAccelerationStructureCreateInfoKHR::type equal to either "
8040                                  "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.");
8041                 }
8042             }
8043 
8044             skip |= ValidateAccelerationBuffers(info_index, pInfos[info_index], "vkCmdBuildAccelerationStructuresKHR");
8045         }
8046     }
8047     return skip;
8048 }
8049 
ValidateAccelerationBuffers(uint32_t info_index,const VkAccelerationStructureBuildGeometryInfoKHR & info,const char * func_name) const8050 bool CoreChecks::ValidateAccelerationBuffers(uint32_t info_index, const VkAccelerationStructureBuildGeometryInfoKHR &info,
8051                                              const char *func_name) const {
8052     bool skip = false;
8053     const auto geometry_count = info.geometryCount;
8054     const auto *p_geometries = info.pGeometries;
8055     const auto *const *const pp_geometries = info.ppGeometries;
8056 
8057     auto buffer_check = [this, info_index, func_name](uint32_t gi, const VkDeviceOrHostAddressConstKHR address,
8058                                                       const char *field) -> bool {
8059         const auto itr = buffer_address_map_.find(address.deviceAddress);
8060         if (itr != buffer_address_map_.cend() &&
8061             !(itr->second->createInfo.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR)) {
8062             LogObjectList objlist(device);
8063             objlist.add(itr->second->Handle());
8064             return LogError(objlist, "VUID-vkCmdBuildAccelerationStructuresKHR-geometry-03673",
8065                             "%s(): The buffer associated with pInfos[%" PRIu32 "].pGeometries[%" PRIu32
8066                             "].%s was not created with VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR.",
8067                             func_name, info_index, gi, field);
8068         }
8069         return false;
8070     };
8071 
8072     // Parameter validation has already checked VUID-VkAccelerationStructureBuildGeometryInfoKHR-pGeometries-03788
8073     // !(pGeometries && ppGeometries)
8074     std::function<const VkAccelerationStructureGeometryKHR &(uint32_t)> geom_accessor;
8075     if (p_geometries) {
8076         geom_accessor = [p_geometries](uint32_t i) -> const VkAccelerationStructureGeometryKHR & { return p_geometries[i]; };
8077     } else if (pp_geometries) {
8078         geom_accessor = [pp_geometries](uint32_t i) -> const VkAccelerationStructureGeometryKHR & {
8079             // pp_geometries[i] is assumed to be a valid pointer
8080             return *pp_geometries[i];
8081         };
8082     }
8083 
8084     if (geom_accessor) {
8085         for (uint32_t geom_index = 0; geom_index < geometry_count; ++geom_index) {
8086             const auto &geom_data = geom_accessor(geom_index);
8087             switch (geom_data.geometryType) {
8088                 case VK_GEOMETRY_TYPE_TRIANGLES_KHR:  // == VK_GEOMETRY_TYPE_TRIANGLES_NV
8089                     skip |= buffer_check(geom_index, geom_data.geometry.triangles.vertexData, "geometry.triangles.vertexData");
8090                     skip |= buffer_check(geom_index, geom_data.geometry.triangles.indexData, "geometry.triangles.indexData");
8091                     skip |=
8092                         buffer_check(geom_index, geom_data.geometry.triangles.transformData, "geometry.triangles.transformData");
8093                     break;
8094                 case VK_GEOMETRY_TYPE_INSTANCES_KHR:
8095                     skip |= buffer_check(geom_index, geom_data.geometry.instances.data, "geometry.instances.data");
8096                     break;
8097                 case VK_GEOMETRY_TYPE_AABBS_KHR:  // == VK_GEOMETRY_TYPE_AABBS_NV
8098                     skip |= buffer_check(geom_index, geom_data.geometry.aabbs.data, "geometry.aabbs.data");
8099                     break;
8100                 default:
8101                     // no-op
8102                     break;
8103             }
8104         }
8105     }
8106 
8107     const auto itr = buffer_address_map_.find(info.scratchData.deviceAddress);
8108     if (itr != buffer_address_map_.cend() && !(itr->second->createInfo.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) {
8109         skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresKHR-pInfos-03674",
8110                          "vkBuildAccelerationStructuresKHR(): The buffer associated with pInfos[%" PRIu32
8111                          "].scratchData.deviceAddress was not created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT bit.",
8112                          info_index);
8113     }
8114 
8115     return skip;
8116 }
8117 
PreCallValidateBuildAccelerationStructuresKHR(VkDevice device,VkDeferredOperationKHR deferredOperation,uint32_t infoCount,const VkAccelerationStructureBuildGeometryInfoKHR * pInfos,const VkAccelerationStructureBuildRangeInfoKHR * const * ppBuildRangeInfos) const8118 bool CoreChecks::PreCallValidateBuildAccelerationStructuresKHR(
8119     VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount,
8120     const VkAccelerationStructureBuildGeometryInfoKHR *pInfos,
8121     const VkAccelerationStructureBuildRangeInfoKHR *const *ppBuildRangeInfos) const {
8122     bool skip = false;
8123     for (uint32_t i = 0; i < infoCount; ++i) {
8124         const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].srcAccelerationStructure);
8125         const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].dstAccelerationStructure);
8126         if (pInfos[i].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) {
8127             if (src_as_state == nullptr || !src_as_state->built ||
8128                 !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) {
8129                 skip |= LogError(device, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03667",
8130                                  "vkBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is "
8131                                  "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its srcAccelerationStructure member must have "
8132                                  "been built before with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR set in "
8133                                  "VkAccelerationStructureBuildGeometryInfoKHR::flags.");
8134             }
8135             if (pInfos[i].geometryCount != src_as_state->build_info_khr.geometryCount) {
8136                 skip |= LogError(device, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03758",
8137                                  "vkBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is "
8138                                  "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR,"
8139                                  " its geometryCount member must have the same value which was specified when "
8140                                  "srcAccelerationStructure was last built.");
8141             }
8142             if (pInfos[i].flags != src_as_state->build_info_khr.flags) {
8143                 skip |= LogError(device, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03759",
8144                                  "vkBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is"
8145                                  " VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its flags member must have the same value which"
8146                                  " was specified when srcAccelerationStructure was last built.");
8147             }
8148             if (pInfos[i].type != src_as_state->build_info_khr.type) {
8149                 skip |= LogError(device, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03760",
8150                                  "vkBuildAccelerationStructuresKHR(): For each element of pInfos, if its mode member is"
8151                                  " VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its type member must have the same value which"
8152                                  " was specified when srcAccelerationStructure was last built.");
8153             }
8154         }
8155         if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) {
8156             if (!dst_as_state ||
8157                 (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR &&
8158                  dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) {
8159                 skip |= LogError(device, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03700",
8160                                  "vkBuildAccelerationStructuresKHR(): For each element of pInfos, if its type member is "
8161                                  "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, its dstAccelerationStructure member must have "
8162                                  "been created with a value of VkAccelerationStructureCreateInfoKHR::type equal to either "
8163                                  "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.");
8164             }
8165         }
8166         if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) {
8167             if (!dst_as_state ||
8168                 (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR &&
8169                  dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) {
8170                 skip |= LogError(device, "VUID-vkBuildAccelerationStructuresKHR-pInfos-03699",
8171                                  "vkBuildAccelerationStructuresKHR(): For each element of pInfos, if its type member is "
8172                                  "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, its dstAccelerationStructure member must have been "
8173                                  "created with a value of VkAccelerationStructureCreateInfoKHR::type equal to either "
8174                                  "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.");
8175             }
8176         }
8177     }
8178     return skip;
8179 }
PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer,const VkAccelerationStructureInfoNV * pInfo,VkBuffer instanceData,VkDeviceSize instanceOffset,VkBool32 update,VkAccelerationStructureNV dst,VkAccelerationStructureNV src,VkBuffer scratch,VkDeviceSize scratchOffset) const8180 bool CoreChecks::PreCallValidateCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer,
8181                                                                 const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData,
8182                                                                 VkDeviceSize instanceOffset, VkBool32 update,
8183                                                                 VkAccelerationStructureNV dst, VkAccelerationStructureNV src,
8184                                                                 VkBuffer scratch, VkDeviceSize scratchOffset) const {
8185     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8186     assert(cb_state);
8187     bool skip = false;
8188 
8189     skip |= ValidateCmd(cb_state.get(), CMD_BUILDACCELERATIONSTRUCTURENV);
8190 
8191     if (pInfo != nullptr && pInfo->type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV) {
8192         for (uint32_t i = 0; i < pInfo->geometryCount; i++) {
8193             skip |= ValidateGeometryNV(pInfo->pGeometries[i], "vkCmdBuildAccelerationStructureNV():");
8194         }
8195     }
8196 
8197     if (pInfo != nullptr && pInfo->geometryCount > phys_dev_ext_props.ray_tracing_propsNV.maxGeometryCount) {
8198         skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-geometryCount-02241",
8199                          "vkCmdBuildAccelerationStructureNV(): geometryCount [%d] must be less than or equal to "
8200                          "VkPhysicalDeviceRayTracingPropertiesNV::maxGeometryCount.",
8201                          pInfo->geometryCount);
8202     }
8203 
8204     const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE>(dst);
8205     const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE>(src);
8206     const auto scratch_buffer_state = Get<BUFFER_STATE>(scratch);
8207 
8208     if (dst_as_state != nullptr && pInfo != nullptr) {
8209         if (dst_as_state->create_infoNV.info.type != pInfo->type) {
8210             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8211                              "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::type"
8212                              "[%s] must be identical to build info VkAccelerationStructureInfoNV::type [%s].",
8213                              string_VkAccelerationStructureTypeNV(dst_as_state->create_infoNV.info.type),
8214                              string_VkAccelerationStructureTypeNV(pInfo->type));
8215         }
8216         if (dst_as_state->create_infoNV.info.flags != pInfo->flags) {
8217             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8218                              "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::flags"
8219                              "[0x%X] must be identical to build info VkAccelerationStructureInfoNV::flags [0x%X].",
8220                              dst_as_state->create_infoNV.info.flags, pInfo->flags);
8221         }
8222         if (dst_as_state->create_infoNV.info.instanceCount < pInfo->instanceCount) {
8223             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8224                              "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::instanceCount "
8225                              "[%d] must be greater than or equal to build info VkAccelerationStructureInfoNV::instanceCount [%d].",
8226                              dst_as_state->create_infoNV.info.instanceCount, pInfo->instanceCount);
8227         }
8228         if (dst_as_state->create_infoNV.info.geometryCount < pInfo->geometryCount) {
8229             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8230                              "vkCmdBuildAccelerationStructureNV(): create info VkAccelerationStructureInfoNV::geometryCount"
8231                              "[%d] must be greater than or equal to build info VkAccelerationStructureInfoNV::geometryCount [%d].",
8232                              dst_as_state->create_infoNV.info.geometryCount, pInfo->geometryCount);
8233         } else {
8234             for (uint32_t i = 0; i < pInfo->geometryCount; i++) {
8235                 const VkGeometryDataNV &create_geometry_data = dst_as_state->create_infoNV.info.pGeometries[i].geometry;
8236                 const VkGeometryDataNV &build_geometry_data = pInfo->pGeometries[i].geometry;
8237                 if (create_geometry_data.triangles.vertexCount < build_geometry_data.triangles.vertexCount) {
8238                     skip |= LogError(
8239                         commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8240                         "vkCmdBuildAccelerationStructureNV(): create info pGeometries[%d].geometry.triangles.vertexCount [%d]"
8241                         "must be greater than or equal to build info pGeometries[%d].geometry.triangles.vertexCount [%d].",
8242                         i, create_geometry_data.triangles.vertexCount, i, build_geometry_data.triangles.vertexCount);
8243                     break;
8244                 }
8245                 if (create_geometry_data.triangles.indexCount < build_geometry_data.triangles.indexCount) {
8246                     skip |= LogError(
8247                         commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8248                         "vkCmdBuildAccelerationStructureNV(): create info pGeometries[%d].geometry.triangles.indexCount [%d]"
8249                         "must be greater than or equal to build info pGeometries[%d].geometry.triangles.indexCount [%d].",
8250                         i, create_geometry_data.triangles.indexCount, i, build_geometry_data.triangles.indexCount);
8251                     break;
8252                 }
8253                 if (create_geometry_data.aabbs.numAABBs < build_geometry_data.aabbs.numAABBs) {
8254                     skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-dst-02488",
8255                                      "vkCmdBuildAccelerationStructureNV(): create info pGeometries[%d].geometry.aabbs.numAABBs [%d]"
8256                                      "must be greater than or equal to build info pGeometries[%d].geometry.aabbs.numAABBs [%d].",
8257                                      i, create_geometry_data.aabbs.numAABBs, i, build_geometry_data.aabbs.numAABBs);
8258                     break;
8259                 }
8260             }
8261         }
8262     }
8263 
8264     if (dst_as_state != nullptr) {
8265         skip |= ValidateMemoryIsBoundToAccelerationStructure(
8266             dst_as_state.get(), "vkCmdBuildAccelerationStructureNV()",
8267             "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkAccelerationStructureNV");
8268     }
8269 
8270     if (update == VK_TRUE) {
8271         if (src == VK_NULL_HANDLE) {
8272             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-update-02489",
8273                              "vkCmdBuildAccelerationStructureNV(): If update is VK_TRUE, src must not be VK_NULL_HANDLE.");
8274         } else {
8275             if (src_as_state == nullptr || !src_as_state->built ||
8276                 !(src_as_state->build_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV)) {
8277                 skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-update-02490",
8278                                  "vkCmdBuildAccelerationStructureNV(): If update is VK_TRUE, src must have been built before "
8279                                  "with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV set in "
8280                                  "VkAccelerationStructureInfoNV::flags.");
8281             }
8282         }
8283         if (dst_as_state != nullptr && !dst_as_state->update_scratch_memory_requirements_checked) {
8284             skip |=
8285                 LogWarning(dst, kVUID_Core_CmdBuildAccelNV_NoUpdateMemReqQuery,
8286                            "vkCmdBuildAccelerationStructureNV(): Updating %s but vkGetAccelerationStructureMemoryRequirementsNV() "
8287                            "has not been called for update scratch memory.",
8288                            report_data->FormatHandle(dst_as_state->acceleration_structure()).c_str());
8289             // Use requirements fetched at create time
8290         }
8291         if (scratch_buffer_state != nullptr && dst_as_state != nullptr &&
8292             dst_as_state->update_scratch_memory_requirements.memoryRequirements.size >
8293                 (scratch_buffer_state->createInfo.size - scratchOffset)) {
8294             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-update-02492",
8295                              "vkCmdBuildAccelerationStructureNV(): If update is VK_TRUE, The size member of the "
8296                              "VkMemoryRequirements structure returned from a call to "
8297                              "vkGetAccelerationStructureMemoryRequirementsNV with "
8298                              "VkAccelerationStructureMemoryRequirementsInfoNV::accelerationStructure set to dst and "
8299                              "VkAccelerationStructureMemoryRequirementsInfoNV::type set to "
8300                              "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV must be less than "
8301                              "or equal to the size of scratch minus scratchOffset");
8302         }
8303     } else {
8304         if (dst_as_state != nullptr && !dst_as_state->build_scratch_memory_requirements_checked) {
8305             skip |= LogWarning(dst, kVUID_Core_CmdBuildAccelNV_NoScratchMemReqQuery,
8306                                "vkCmdBuildAccelerationStructureNV(): Assigning scratch buffer to %s but "
8307                                "vkGetAccelerationStructureMemoryRequirementsNV() has not been called for scratch memory.",
8308                                report_data->FormatHandle(dst_as_state->acceleration_structure()).c_str());
8309             // Use requirements fetched at create time
8310         }
8311         if (scratch_buffer_state != nullptr && dst_as_state != nullptr &&
8312             dst_as_state->build_scratch_memory_requirements.memoryRequirements.size >
8313                 (scratch_buffer_state->createInfo.size - scratchOffset)) {
8314             skip |= LogError(commandBuffer, "VUID-vkCmdBuildAccelerationStructureNV-update-02491",
8315                              "vkCmdBuildAccelerationStructureNV(): If update is VK_FALSE, The size member of the "
8316                              "VkMemoryRequirements structure returned from a call to "
8317                              "vkGetAccelerationStructureMemoryRequirementsNV with "
8318                              "VkAccelerationStructureMemoryRequirementsInfoNV::accelerationStructure set to dst and "
8319                              "VkAccelerationStructureMemoryRequirementsInfoNV::type set to "
8320                              "VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV must be less than "
8321                              "or equal to the size of scratch minus scratchOffset");
8322         }
8323     }
8324     if (instanceData != VK_NULL_HANDLE) {
8325         const auto buffer_state = Get<BUFFER_STATE>(instanceData);
8326         if (buffer_state) {
8327             skip |= ValidateBufferUsageFlags(buffer_state.get(), VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, true,
8328                                              "VUID-VkAccelerationStructureInfoNV-instanceData-02782",
8329                                              "vkCmdBuildAccelerationStructureNV()", "VK_BUFFER_USAGE_RAY_TRACING_BIT_NV");
8330         }
8331     }
8332     if (scratch_buffer_state) {
8333         skip |= ValidateBufferUsageFlags(scratch_buffer_state.get(), VK_BUFFER_USAGE_RAY_TRACING_BIT_NV, true,
8334                                          "VUID-VkAccelerationStructureInfoNV-scratch-02781", "vkCmdBuildAccelerationStructureNV()",
8335                                          "VK_BUFFER_USAGE_RAY_TRACING_BIT_NV");
8336     }
8337     return skip;
8338 }
8339 
PreCallValidateCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer,VkAccelerationStructureNV dst,VkAccelerationStructureNV src,VkCopyAccelerationStructureModeNV mode) const8340 bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst,
8341                                                                VkAccelerationStructureNV src,
8342                                                                VkCopyAccelerationStructureModeNV mode) const {
8343     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8344     assert(cb_state);
8345     bool skip = false;
8346 
8347     skip |= ValidateCmd(cb_state.get(), CMD_COPYACCELERATIONSTRUCTURENV);
8348     const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE>(dst);
8349     const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE>(src);
8350 
8351     if (dst_as_state != nullptr) {
8352         skip |= ValidateMemoryIsBoundToAccelerationStructure(
8353             dst_as_state.get(), "vkCmdBuildAccelerationStructureNV()",
8354             "UNASSIGNED-CoreValidation-DrawState-InvalidCommandBuffer-VkAccelerationStructureNV");
8355     }
8356 
8357     if (mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV) {
8358         if (src_as_state != nullptr &&
8359             (!src_as_state->built || !(src_as_state->build_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV))) {
8360             skip |= LogError(commandBuffer, "VUID-vkCmdCopyAccelerationStructureNV-src-03411",
8361                              "vkCmdCopyAccelerationStructureNV(): src must have been built with "
8362                              "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV if mode is "
8363                              "VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV.");
8364         }
8365     }
8366     if (!(mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV || mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR)) {
8367         skip |= LogError(commandBuffer, "VUID-vkCmdCopyAccelerationStructureNV-mode-03410",
8368                          "vkCmdCopyAccelerationStructureNV():mode must be VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR"
8369                          "or VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR.");
8370     }
8371     return skip;
8372 }
8373 
PreCallValidateDestroyAccelerationStructureNV(VkDevice device,VkAccelerationStructureNV accelerationStructure,const VkAllocationCallbacks * pAllocator) const8374 bool CoreChecks::PreCallValidateDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure,
8375                                                                const VkAllocationCallbacks *pAllocator) const {
8376     const auto as_state = Get<ACCELERATION_STRUCTURE_STATE>(accelerationStructure);
8377     bool skip = false;
8378     if (as_state) {
8379         skip |= ValidateObjectNotInUse(as_state.get(), "vkDestroyAccelerationStructureNV",
8380                                        "VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-02442");
8381     }
8382     return skip;
8383 }
8384 
PreCallValidateDestroyAccelerationStructureKHR(VkDevice device,VkAccelerationStructureKHR accelerationStructure,const VkAllocationCallbacks * pAllocator) const8385 bool CoreChecks::PreCallValidateDestroyAccelerationStructureKHR(VkDevice device, VkAccelerationStructureKHR accelerationStructure,
8386                                                                 const VkAllocationCallbacks *pAllocator) const {
8387     const auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(accelerationStructure);
8388     bool skip = false;
8389     if (as_state) {
8390         skip |= ValidateObjectNotInUse(as_state.get(), "vkDestroyAccelerationStructureKHR",
8391                                        "VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-02442");
8392     }
8393     if (pAllocator && !as_state->allocator) {
8394         skip |= LogError(device, "VUID-vkDestroyAccelerationStructureKHR-accelerationStructure-02444",
8395                          "vkDestroyAccelerationStructureKH:If no VkAllocationCallbacks were provided when accelerationStructure"
8396                          "was created, pAllocator must be NULL.");
8397     }
8398     return skip;
8399 }
8400 
PreCallValidateCmdSetViewportWScalingNV(VkCommandBuffer commandBuffer,uint32_t firstViewport,uint32_t viewportCount,const VkViewportWScalingNV * pViewportWScalings) const8401 bool CoreChecks::PreCallValidateCmdSetViewportWScalingNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
8402                                                          uint32_t viewportCount,
8403                                                          const VkViewportWScalingNV *pViewportWScalings) const {
8404     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8405     assert(cb_state);
8406     bool skip = false;
8407 
8408     skip |= ValidateCmd(cb_state.get(), CMD_SETVIEWPORTWSCALINGNV);
8409 
8410     return skip;
8411 }
8412 
PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer,float lineWidth) const8413 bool CoreChecks::PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) const {
8414     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8415     assert(cb_state);
8416     bool skip = false;
8417     skip |= ValidateCmd(cb_state.get(), CMD_SETLINEWIDTH);
8418     return skip;
8419 }
8420 
PreCallValidateCmdSetLineStippleEXT(VkCommandBuffer commandBuffer,uint32_t lineStippleFactor,uint16_t lineStipplePattern) const8421 bool CoreChecks::PreCallValidateCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor,
8422                                                      uint16_t lineStipplePattern) const {
8423     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8424     assert(cb_state);
8425     bool skip = false;
8426     skip |= ValidateCmd(cb_state.get(), CMD_SETLINESTIPPLEEXT);
8427     return skip;
8428 }
8429 
PreCallValidateCmdSetDepthBias(VkCommandBuffer commandBuffer,float depthBiasConstantFactor,float depthBiasClamp,float depthBiasSlopeFactor) const8430 bool CoreChecks::PreCallValidateCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp,
8431                                                 float depthBiasSlopeFactor) const {
8432     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8433     assert(cb_state);
8434     bool skip = false;
8435     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHBIAS);
8436     if ((depthBiasClamp != 0.0) && (!enabled_features.core.depthBiasClamp)) {
8437         skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthBias-depthBiasClamp-00790",
8438                          "vkCmdSetDepthBias(): the depthBiasClamp device feature is disabled: the depthBiasClamp parameter must "
8439                          "be set to 0.0.");
8440     }
8441     return skip;
8442 }
8443 
PreCallValidateCmdSetBlendConstants(VkCommandBuffer commandBuffer,const float blendConstants[4]) const8444 bool CoreChecks::PreCallValidateCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) const {
8445     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8446     assert(cb_state);
8447     bool skip = false;
8448     skip |= ValidateCmd(cb_state.get(), CMD_SETBLENDCONSTANTS);
8449     return skip;
8450 }
8451 
PreCallValidateCmdSetDepthBounds(VkCommandBuffer commandBuffer,float minDepthBounds,float maxDepthBounds) const8452 bool CoreChecks::PreCallValidateCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) const {
8453     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8454     assert(cb_state);
8455     bool skip = false;
8456     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHBOUNDS);
8457 
8458     // The extension was not created with a feature bit whichs prevents displaying the 2 variations of the VUIDs
8459     if (!IsExtEnabled(device_extensions.vk_ext_depth_range_unrestricted)) {
8460         if (!(minDepthBounds >= 0.0) || !(minDepthBounds <= 1.0)) {
8461             // Also VUID-vkCmdSetDepthBounds-minDepthBounds-00600
8462             skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthBounds-minDepthBounds-02508",
8463                              "vkCmdSetDepthBounds(): VK_EXT_depth_range_unrestricted extension is not enabled and minDepthBounds "
8464                              "(=%f) is not within the [0.0, 1.0] range.",
8465                              minDepthBounds);
8466         }
8467 
8468         if (!(maxDepthBounds >= 0.0) || !(maxDepthBounds <= 1.0)) {
8469             // Also VUID-vkCmdSetDepthBounds-maxDepthBounds-00601
8470             skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthBounds-maxDepthBounds-02509",
8471                              "vkCmdSetDepthBounds(): VK_EXT_depth_range_unrestricted extension is not enabled and maxDepthBounds "
8472                              "(=%f) is not within the [0.0, 1.0] range.",
8473                              maxDepthBounds);
8474         }
8475     }
8476     return skip;
8477 }
8478 
PreCallValidateCmdSetStencilCompareMask(VkCommandBuffer commandBuffer,VkStencilFaceFlags faceMask,uint32_t compareMask) const8479 bool CoreChecks::PreCallValidateCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
8480                                                          uint32_t compareMask) const {
8481     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8482     assert(cb_state);
8483     bool skip = false;
8484     skip |= ValidateCmd(cb_state.get(), CMD_SETSTENCILCOMPAREMASK);
8485     return skip;
8486 }
8487 
PreCallValidateCmdSetStencilWriteMask(VkCommandBuffer commandBuffer,VkStencilFaceFlags faceMask,uint32_t writeMask) const8488 bool CoreChecks::PreCallValidateCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
8489                                                        uint32_t writeMask) const {
8490     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8491     assert(cb_state);
8492     bool skip = false;
8493     skip |= ValidateCmd(cb_state.get(), CMD_SETSTENCILWRITEMASK);
8494     return skip;
8495 }
8496 
PreCallValidateCmdSetStencilReference(VkCommandBuffer commandBuffer,VkStencilFaceFlags faceMask,uint32_t reference) const8497 bool CoreChecks::PreCallValidateCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask,
8498                                                        uint32_t reference) const {
8499     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8500     assert(cb_state);
8501     bool skip = false;
8502     skip |= ValidateCmd(cb_state.get(), CMD_SETSTENCILREFERENCE);
8503     return skip;
8504 }
8505 
PreCallValidateCmdBindDescriptorSets(VkCommandBuffer commandBuffer,VkPipelineBindPoint pipelineBindPoint,VkPipelineLayout layout,uint32_t firstSet,uint32_t setCount,const VkDescriptorSet * pDescriptorSets,uint32_t dynamicOffsetCount,const uint32_t * pDynamicOffsets) const8506 bool CoreChecks::PreCallValidateCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
8507                                                       VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
8508                                                       const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
8509                                                       const uint32_t *pDynamicOffsets) const {
8510     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8511     assert(cb_state);
8512     bool skip = false;
8513     skip |= ValidateCmd(cb_state.get(), CMD_BINDDESCRIPTORSETS);
8514     // Track total count of dynamic descriptor types to make sure we have an offset for each one
8515     uint32_t total_dynamic_descriptors = 0;
8516     string error_string = "";
8517 
8518     const auto pipeline_layout = Get<PIPELINE_LAYOUT_STATE>(layout);
8519     for (uint32_t set_idx = 0; set_idx < setCount; set_idx++) {
8520         const auto descriptor_set = Get<cvdescriptorset::DescriptorSet>(pDescriptorSets[set_idx]);
8521         if (descriptor_set) {
8522             // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
8523             if (!VerifySetLayoutCompatibility(report_data, descriptor_set.get(), pipeline_layout.get(), set_idx + firstSet,
8524                                               error_string)) {
8525                 skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358",
8526                                  "vkCmdBindDescriptorSets(): descriptorSet #%u being bound is not compatible with overlapping "
8527                                  "descriptorSetLayout at index %u of "
8528                                  "%s due to: %s.",
8529                                  set_idx, set_idx + firstSet, report_data->FormatHandle(layout).c_str(), error_string.c_str());
8530             }
8531 
8532             auto set_dynamic_descriptor_count = descriptor_set->GetDynamicDescriptorCount();
8533             if (set_dynamic_descriptor_count) {
8534                 // First make sure we won't overstep bounds of pDynamicOffsets array
8535                 if ((total_dynamic_descriptors + set_dynamic_descriptor_count) > dynamicOffsetCount) {
8536                     // Test/report this here, such that we don't run past the end of pDynamicOffsets in the else clause
8537                     skip |=
8538                         LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359",
8539                                  "vkCmdBindDescriptorSets(): descriptorSet #%u (%s) requires %u dynamicOffsets, but only %u "
8540                                  "dynamicOffsets are left in "
8541                                  "pDynamicOffsets array. There must be one dynamic offset for each dynamic descriptor being bound.",
8542                                  set_idx, report_data->FormatHandle(pDescriptorSets[set_idx]).c_str(),
8543                                  descriptor_set->GetDynamicDescriptorCount(), (dynamicOffsetCount - total_dynamic_descriptors));
8544                     // Set the number found to the maximum to prevent duplicate messages, or subsquent descriptor sets from
8545                     // testing against the "short tail" we're skipping below.
8546                     total_dynamic_descriptors = dynamicOffsetCount;
8547                 } else {  // Validate dynamic offsets and Dynamic Offset Minimums
8548                     // offset for all sets (pDynamicOffsets)
8549                     uint32_t cur_dyn_offset = total_dynamic_descriptors;
8550                     // offset into this descriptor set
8551                     uint32_t set_dyn_offset = 0;
8552                     const auto &dsl = descriptor_set->GetLayout();
8553                     const auto binding_count = dsl->GetBindingCount();
8554                     const auto &limits = phys_dev_props.limits;
8555                     for (uint32_t i = 0; i < binding_count; i++) {
8556                         const auto *binding = dsl->GetDescriptorSetLayoutBindingPtrFromIndex(i);
8557                         // skip checking binding if not needed
8558                         if (cvdescriptorset::IsDynamicDescriptor(binding->descriptorType) == false) {
8559                             continue;
8560                         }
8561 
8562                         // If a descriptor set has only binding 0 and 2 the binding_index will be 0 and 2
8563                         const uint32_t binding_index = binding->binding;
8564                         const uint32_t descriptorCount = binding->descriptorCount;
8565 
8566                         // Need to loop through each descriptor count inside the binding
8567                         // if descriptorCount is zero the binding with a dynamic descriptor type does not count
8568                         for (uint32_t j = 0; j < descriptorCount; j++) {
8569                             const uint32_t offset = pDynamicOffsets[cur_dyn_offset];
8570                             if (offset == 0) {
8571                                 // offset of zero is equivalent of not having the dynamic offset
8572                                 cur_dyn_offset++;
8573                                 set_dyn_offset++;
8574                                 continue;
8575                             }
8576 
8577                             // Validate alignment with limit
8578                             if ((binding->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) &&
8579                                 (SafeModulo(offset, limits.minUniformBufferOffsetAlignment) != 0)) {
8580                                 skip |= LogError(commandBuffer, "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971",
8581                                                  "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is %u, but must be a multiple of "
8582                                                  "device limit minUniformBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
8583                                                  cur_dyn_offset, offset, limits.minUniformBufferOffsetAlignment);
8584                             }
8585                             if ((binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) &&
8586                                 (SafeModulo(offset, limits.minStorageBufferOffsetAlignment) != 0)) {
8587                                 skip |= LogError(commandBuffer, "VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972",
8588                                                  "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is %u, but must be a multiple of "
8589                                                  "device limit minStorageBufferOffsetAlignment 0x%" PRIxLEAST64 ".",
8590                                                  cur_dyn_offset, offset, limits.minStorageBufferOffsetAlignment);
8591                             }
8592 
8593                             auto *descriptor = descriptor_set->GetDescriptorFromDynamicOffsetIndex(set_dyn_offset);
8594                             assert(descriptor != nullptr);
8595                             // Currently only GeneralBuffer are dynamic and need to be checked
8596                             if (descriptor->GetClass() == cvdescriptorset::DescriptorClass::GeneralBuffer) {
8597                                 const auto *buffer_descriptor = static_cast<const cvdescriptorset::BufferDescriptor *>(descriptor);
8598                                 const VkDeviceSize bound_range = buffer_descriptor->GetRange();
8599                                 const VkDeviceSize bound_offset = buffer_descriptor->GetOffset();
8600                                 //NOTE: null / invalid buffers may show up here, errors are raised elsewhere for this.
8601                                 const auto buffer_state = buffer_descriptor->GetBufferState();
8602 
8603                                 // Validate offset didn't go over buffer
8604                                 if ((bound_range == VK_WHOLE_SIZE) && (offset > 0)) {
8605                                     LogObjectList objlist(commandBuffer);
8606                                     objlist.add(pDescriptorSets[set_idx]);
8607                                     objlist.add(buffer_descriptor->GetBuffer());
8608                                     skip |=
8609                                         LogError(objlist, "VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979",
8610                                                  "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is 0x%x, but must be zero since "
8611                                                  "the buffer descriptor's range is VK_WHOLE_SIZE in descriptorSet #%u binding #%u "
8612                                                  "descriptor[%u].",
8613                                                  cur_dyn_offset, offset, set_idx, binding_index, j);
8614 
8615                                 } else if (buffer_state && (bound_range != VK_WHOLE_SIZE) &&
8616                                            ((offset + bound_range + bound_offset) > buffer_state->createInfo.size)) {
8617                                     LogObjectList objlist(commandBuffer);
8618                                     objlist.add(pDescriptorSets[set_idx]);
8619                                     objlist.add(buffer_descriptor->GetBuffer());
8620                                     skip |=
8621                                         LogError(objlist, "VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979",
8622                                                  "vkCmdBindDescriptorSets(): pDynamicOffsets[%u] is 0x%x which when added to the "
8623                                                  "buffer descriptor's range (0x%" PRIxLEAST64
8624                                                  ") is greater than the size of the buffer (0x%" PRIxLEAST64
8625                                                  ") in descriptorSet #%u binding #%u descriptor[%u].",
8626                                                  cur_dyn_offset, offset, bound_range, buffer_state->createInfo.size, set_idx,
8627                                                  binding_index, j);
8628                                 }
8629                             }
8630                             cur_dyn_offset++;
8631                             set_dyn_offset++;
8632                         }  // descriptorCount loop
8633                     }      // bindingCount loop
8634                     // Keep running total of dynamic descriptor count to verify at the end
8635                     total_dynamic_descriptors += set_dynamic_descriptor_count;
8636                 }
8637             }
8638             if (descriptor_set->GetPoolState()->createInfo.flags & VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE) {
8639                 skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-pDescriptorSets-04616",
8640                                  "vkCmdBindDescriptorSets(): pDescriptorSets[%" PRIu32 "] was allocated from a pool that was created with VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE.", set_idx);
8641             }
8642         } else {
8643             skip |= LogError(pDescriptorSets[set_idx], "VUID-vkCmdBindDescriptorSets-pDescriptorSets-parameter",
8644                              "vkCmdBindDescriptorSets(): Attempt to bind %s that doesn't exist!",
8645                              report_data->FormatHandle(pDescriptorSets[set_idx]).c_str());
8646         }
8647     }
8648     //  dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
8649     if (total_dynamic_descriptors != dynamicOffsetCount) {
8650         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359",
8651                          "vkCmdBindDescriptorSets(): Attempting to bind %u descriptorSets with %u dynamic descriptors, but "
8652                          "dynamicOffsetCount is %u. It should "
8653                          "exactly match the number of dynamic descriptors.",
8654                          setCount, total_dynamic_descriptors, dynamicOffsetCount);
8655     }
8656     // firstSet and descriptorSetCount sum must be less than setLayoutCount
8657     if ((firstSet + setCount) > static_cast<uint32_t>(pipeline_layout->set_layouts.size())) {
8658         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBindDescriptorSets-firstSet-00360",
8659                          "vkCmdBindDescriptorSets(): Sum of firstSet (%u) and descriptorSetCount (%u) is greater than "
8660                          "VkPipelineLayoutCreateInfo::setLayoutCount "
8661                          "(%zu) when pipeline layout was created",
8662                          firstSet, setCount, pipeline_layout->set_layouts.size());
8663     }
8664 
8665     static const std::map<VkPipelineBindPoint, std::string> bindpoint_errors = {
8666         std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361"),
8667         std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361"),
8668         std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_NV, "VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361")};
8669     skip |= ValidatePipelineBindPoint(cb_state.get(), pipelineBindPoint, "vkCmdBindPipeline()", bindpoint_errors);
8670 
8671     return skip;
8672 }
8673 
8674 // Validates that the supplied bind point is supported for the command buffer (vis. the command pool)
8675 // Takes array of error codes as some of the VUID's (e.g. vkCmdBindPipeline) are written per bindpoint
8676 // TODO add vkCmdBindPipeline bind_point validation using this call.
ValidatePipelineBindPoint(const CMD_BUFFER_STATE * cb_state,VkPipelineBindPoint bind_point,const char * func_name,const std::map<VkPipelineBindPoint,std::string> & bind_errors) const8677 bool CoreChecks::ValidatePipelineBindPoint(const CMD_BUFFER_STATE *cb_state, VkPipelineBindPoint bind_point, const char *func_name,
8678                                            const std::map<VkPipelineBindPoint, std::string> &bind_errors) const {
8679     bool skip = false;
8680     auto pool = cb_state->command_pool;
8681     if (pool) {  // The loss of a pool in a recording cmd is reported in DestroyCommandPool
8682         static const std::map<VkPipelineBindPoint, VkQueueFlags> flag_mask = {
8683             std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT)),
8684             std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, static_cast<VkQueueFlags>(VK_QUEUE_COMPUTE_BIT)),
8685             std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
8686                            static_cast<VkQueueFlags>(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)),
8687         };
8688         const auto &qfp = physical_device_state->queue_family_properties[pool->queueFamilyIndex];
8689         if (0 == (qfp.queueFlags & flag_mask.at(bind_point))) {
8690             const std::string &error = bind_errors.at(bind_point);
8691             LogObjectList objlist(cb_state->commandBuffer());
8692             objlist.add(cb_state->createInfo.commandPool);
8693             skip |= LogError(objlist, error, "%s: %s was allocated from %s that does not support bindpoint %s.", func_name,
8694                              report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
8695                              report_data->FormatHandle(cb_state->createInfo.commandPool).c_str(),
8696                              string_VkPipelineBindPoint(bind_point));
8697         }
8698     }
8699     return skip;
8700 }
8701 
PreCallValidateCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer,VkPipelineBindPoint pipelineBindPoint,VkPipelineLayout layout,uint32_t set,uint32_t descriptorWriteCount,const VkWriteDescriptorSet * pDescriptorWrites) const8702 bool CoreChecks::PreCallValidateCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
8703                                                         VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount,
8704                                                         const VkWriteDescriptorSet *pDescriptorWrites) const {
8705     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8706     assert(cb_state);
8707     const char *func_name = "vkCmdPushDescriptorSetKHR()";
8708     bool skip = false;
8709     skip |= ValidateCmd(cb_state.get(), CMD_PUSHDESCRIPTORSETKHR);
8710 
8711     static const std::map<VkPipelineBindPoint, std::string> bind_errors = {
8712         std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363"),
8713         std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363"),
8714         std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, "VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363")};
8715 
8716     skip |= ValidatePipelineBindPoint(cb_state.get(), pipelineBindPoint, func_name, bind_errors);
8717     const auto layout_data = Get<PIPELINE_LAYOUT_STATE>(layout);
8718 
8719     // Validate the set index points to a push descriptor set and is in range
8720     if (layout_data) {
8721         const auto &set_layouts = layout_data->set_layouts;
8722         if (set < set_layouts.size()) {
8723             const auto &dsl = set_layouts[set];
8724             if (dsl) {
8725                 if (!dsl->IsPushDescriptor()) {
8726                     skip = LogError(layout, "VUID-vkCmdPushDescriptorSetKHR-set-00365",
8727                                     "%s: Set index %" PRIu32 " does not match push descriptor set layout index for %s.", func_name,
8728                                     set, report_data->FormatHandle(layout).c_str());
8729                 } else {
8730                     // Create an empty proxy in order to use the existing descriptor set update validation
8731                     // TODO move the validation (like this) that doesn't need descriptor set state to the DSL object so we
8732                     // don't have to do this.
8733                     cvdescriptorset::DescriptorSet proxy_ds(VK_NULL_HANDLE, nullptr, dsl, 0, this);
8734                     skip |= ValidatePushDescriptorsUpdate(&proxy_ds, descriptorWriteCount, pDescriptorWrites, func_name);
8735                 }
8736             }
8737         } else {
8738             skip = LogError(layout, "VUID-vkCmdPushDescriptorSetKHR-set-00364",
8739                             "%s: Set index %" PRIu32 " is outside of range for %s (set < %" PRIu32 ").", func_name, set,
8740                             report_data->FormatHandle(layout).c_str(), static_cast<uint32_t>(set_layouts.size()));
8741         }
8742     }
8743 
8744     return skip;
8745 }
8746 
PreCallValidateCmdBindIndexBuffer(VkCommandBuffer commandBuffer,VkBuffer buffer,VkDeviceSize offset,VkIndexType indexType) const8747 bool CoreChecks::PreCallValidateCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset,
8748                                                    VkIndexType indexType) const {
8749     const auto buffer_state = Get<BUFFER_STATE>(buffer);
8750     const auto cb_node = Get<CMD_BUFFER_STATE>(commandBuffer);
8751     assert(buffer_state);
8752     assert(cb_node);
8753 
8754     bool skip = ValidateBufferUsageFlags(buffer_state.get(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, true,
8755                                          "VUID-vkCmdBindIndexBuffer-buffer-00433", "vkCmdBindIndexBuffer()",
8756                                          "VK_BUFFER_USAGE_INDEX_BUFFER_BIT");
8757     skip |= ValidateCmd(cb_node.get(), CMD_BINDINDEXBUFFER);
8758     skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), "vkCmdBindIndexBuffer()", "VUID-vkCmdBindIndexBuffer-buffer-00434");
8759     const auto offset_align = GetIndexAlignment(indexType);
8760     if (offset % offset_align) {
8761         skip |= LogError(commandBuffer, "VUID-vkCmdBindIndexBuffer-offset-00432",
8762                          "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") does not fall on alignment (%s) boundary.", offset,
8763                          string_VkIndexType(indexType));
8764     }
8765     if (offset >= buffer_state->requirements.size) {
8766         skip |= LogError(commandBuffer, "VUID-vkCmdBindIndexBuffer-offset-00431",
8767                          "vkCmdBindIndexBuffer() offset (0x%" PRIxLEAST64 ") is not less than the size (0x%" PRIxLEAST64
8768                          ") of buffer (%s).",
8769                          offset, buffer_state->requirements.size, report_data->FormatHandle(buffer_state->buffer()).c_str());
8770     }
8771 
8772     return skip;
8773 }
8774 
PreCallValidateCmdBindVertexBuffers(VkCommandBuffer commandBuffer,uint32_t firstBinding,uint32_t bindingCount,const VkBuffer * pBuffers,const VkDeviceSize * pOffsets) const8775 bool CoreChecks::PreCallValidateCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount,
8776                                                      const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) const {
8777     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8778     assert(cb_state);
8779 
8780     bool skip = false;
8781     skip |= ValidateCmd(cb_state.get(), CMD_BINDVERTEXBUFFERS);
8782     for (uint32_t i = 0; i < bindingCount; ++i) {
8783         const auto buffer_state = Get<BUFFER_STATE>(pBuffers[i]);
8784         if (buffer_state) {
8785             skip |= ValidateBufferUsageFlags(buffer_state.get(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, true,
8786                                              "VUID-vkCmdBindVertexBuffers-pBuffers-00627", "vkCmdBindVertexBuffers()",
8787                                              "VK_BUFFER_USAGE_VERTEX_BUFFER_BIT");
8788             skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), "vkCmdBindVertexBuffers()",
8789                                                   "VUID-vkCmdBindVertexBuffers-pBuffers-00628");
8790             if (pOffsets[i] >= buffer_state->createInfo.size) {
8791                 skip |=
8792                     LogError(buffer_state->buffer(), "VUID-vkCmdBindVertexBuffers-pOffsets-00626",
8793                              "vkCmdBindVertexBuffers() offset (0x%" PRIxLEAST64 ") is beyond the end of the buffer.", pOffsets[i]);
8794             }
8795         }
8796     }
8797     return skip;
8798 }
8799 
8800 // Validate that an image's sampleCount matches the requirement for a specific API call
ValidateImageSampleCount(const IMAGE_STATE * image_state,VkSampleCountFlagBits sample_count,const char * location,const std::string & msgCode) const8801 bool CoreChecks::ValidateImageSampleCount(const IMAGE_STATE *image_state, VkSampleCountFlagBits sample_count, const char *location,
8802                                           const std::string &msgCode) const {
8803     bool skip = false;
8804     if (image_state->createInfo.samples != sample_count) {
8805         skip = LogError(image_state->image(), msgCode, "%s for %s was created with a sample count of %s but must be %s.", location,
8806                         report_data->FormatHandle(image_state->image()).c_str(),
8807                         string_VkSampleCountFlagBits(image_state->createInfo.samples), string_VkSampleCountFlagBits(sample_count));
8808     }
8809     return skip;
8810 }
8811 
PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer,VkBuffer dstBuffer,VkDeviceSize dstOffset,VkDeviceSize dataSize,const void * pData) const8812 bool CoreChecks::PreCallValidateCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
8813                                                 VkDeviceSize dataSize, const void *pData) const {
8814     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8815     assert(cb_state);
8816     const auto dst_buffer_state = Get<BUFFER_STATE>(dstBuffer);
8817     assert(dst_buffer_state);
8818 
8819     bool skip = false;
8820     skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state.get(), "vkCmdUpdateBuffer()", "VUID-vkCmdUpdateBuffer-dstBuffer-00035");
8821     // Validate that DST buffer has correct usage flags set
8822     skip |= ValidateBufferUsageFlags(dst_buffer_state.get(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
8823                                      "VUID-vkCmdUpdateBuffer-dstBuffer-00034", "vkCmdUpdateBuffer()",
8824                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8825     skip |= ValidateCmd(cb_state.get(), CMD_UPDATEBUFFER);
8826     skip |= ValidateProtectedBuffer(cb_state.get(), dst_buffer_state.get(), "vkCmdUpdateBuffer()",
8827                                     "VUID-vkCmdUpdateBuffer-commandBuffer-01813");
8828     skip |= ValidateUnprotectedBuffer(cb_state.get(), dst_buffer_state.get(), "vkCmdUpdateBuffer()",
8829                                       "VUID-vkCmdUpdateBuffer-commandBuffer-01814");
8830     if (dstOffset >= dst_buffer_state->createInfo.size) {
8831         skip |= LogError(
8832             commandBuffer, "VUID-vkCmdUpdateBuffer-dstOffset-00032",
8833             "vkCmdUpdateBuffer() dstOffset (0x%" PRIxLEAST64 ") is not less than the size (0x%" PRIxLEAST64 ") of buffer (%s).",
8834             dstOffset, dst_buffer_state->createInfo.size, report_data->FormatHandle(dst_buffer_state->buffer()).c_str());
8835     } else if (dataSize > dst_buffer_state->createInfo.size - dstOffset) {
8836         skip |= LogError(commandBuffer, "VUID-vkCmdUpdateBuffer-dataSize-00033",
8837                          "vkCmdUpdateBuffer() dataSize (0x%" PRIxLEAST64 ") is not less than the size (0x%" PRIxLEAST64
8838                          ") of buffer (%s) minus dstOffset (0x%" PRIxLEAST64 ").",
8839                          dataSize, dst_buffer_state->createInfo.size, report_data->FormatHandle(dst_buffer_state->buffer()).c_str(),
8840                          dstOffset);
8841     }
8842     return skip;
8843 }
8844 
PreCallValidateCmdSetEvent(VkCommandBuffer commandBuffer,VkEvent event,VkPipelineStageFlags stageMask) const8845 bool CoreChecks::PreCallValidateCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) const {
8846     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8847     assert(cb_state);
8848     bool skip = false;
8849     skip |= ValidateCmd(cb_state.get(), CMD_SETEVENT);
8850     Location loc(Func::vkCmdSetEvent, Field::stageMask);
8851     LogObjectList objects(commandBuffer);
8852     skip |= ValidatePipelineStage(objects, loc, cb_state->GetQueueFlags(), stageMask);
8853     skip |= ValidateStageMaskHost(loc, stageMask);
8854     return skip;
8855 }
8856 
PreCallValidateCmdSetEvent2KHR(VkCommandBuffer commandBuffer,VkEvent event,const VkDependencyInfoKHR * pDependencyInfo) const8857 bool CoreChecks::PreCallValidateCmdSetEvent2KHR(VkCommandBuffer commandBuffer, VkEvent event,
8858                                                 const VkDependencyInfoKHR *pDependencyInfo) const {
8859     LogObjectList objects(commandBuffer);
8860     objects.add(event);
8861 
8862     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8863     assert(cb_state);
8864     bool skip = false;
8865     if (!enabled_features.synchronization2_features.synchronization2) {
8866         skip |= LogError(commandBuffer, "VUID-vkCmdSetEvent2KHR-synchronization2-03824",
8867                          "vkCmdSetEvent2KHR(): Synchronization2 feature is not enabled");
8868     }
8869     skip |= ValidateCmd(cb_state.get(), CMD_SETEVENT);
8870     Location loc(Func::vkCmdSetEvent2KHR, Field::pDependencyInfo);
8871     if (pDependencyInfo->dependencyFlags != 0) {
8872         skip |= LogError(objects, "VUID-vkCmdSetEvent2KHR-dependencyFlags-03825", "%s (%s) must be 0",
8873                          loc.dot(Field::dependencyFlags).Message().c_str(),
8874                          string_VkDependencyFlags(pDependencyInfo->dependencyFlags).c_str());
8875     }
8876     skip |= ValidateDependencyInfo(objects, loc, cb_state.get(), pDependencyInfo);
8877     return skip;
8878 }
8879 
PreCallValidateCmdResetEvent(VkCommandBuffer commandBuffer,VkEvent event,VkPipelineStageFlags stageMask) const8880 bool CoreChecks::PreCallValidateCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) const {
8881     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8882     assert(cb_state);
8883     LogObjectList objects(commandBuffer);
8884     Location loc(Func::vkCmdResetEvent, Field::stageMask);
8885 
8886     bool skip = false;
8887     skip |= ValidateCmd(cb_state.get(), CMD_RESETEVENT);
8888     skip |= ValidatePipelineStage(objects, loc, cb_state->GetQueueFlags(), stageMask);
8889     skip |= ValidateStageMaskHost(loc, stageMask);
8890     return skip;
8891 }
8892 
PreCallValidateCmdResetEvent2KHR(VkCommandBuffer commandBuffer,VkEvent event,VkPipelineStageFlags2KHR stageMask) const8893 bool CoreChecks::PreCallValidateCmdResetEvent2KHR(VkCommandBuffer commandBuffer, VkEvent event,
8894                                                   VkPipelineStageFlags2KHR stageMask) const {
8895     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
8896     assert(cb_state);
8897     LogObjectList objects(commandBuffer);
8898     Location loc(Func::vkCmdResetEvent2KHR, Field::stageMask);
8899 
8900     bool skip = false;
8901     if (!enabled_features.synchronization2_features.synchronization2) {
8902         skip |= LogError(commandBuffer, "VUID-vkCmdResetEvent2KHR-synchronization2-03829",
8903                          "vkCmdResetEvent2KHR(): Synchronization2 feature is not enabled");
8904     }
8905     skip |= ValidateCmd(cb_state.get(), CMD_RESETEVENT);
8906     skip |= ValidatePipelineStage(objects, loc, cb_state->GetQueueFlags(), stageMask);
8907     skip |= ValidateStageMaskHost(loc, stageMask);
8908     return skip;
8909 }
8910 
HasNonFramebufferStagePipelineStageFlags(VkPipelineStageFlags2KHR inflags)8911 static bool HasNonFramebufferStagePipelineStageFlags(VkPipelineStageFlags2KHR inflags) {
8912     return (inflags & ~(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
8913                         VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)) != 0;
8914 }
8915 
8916 // transient helper struct for checking parts of VUID 02285
8917 struct RenderPassDepState {
8918     using Location = core_error::Location;
8919     using Func = core_error::Func;
8920     using Struct = core_error::Struct;
8921     using Field = core_error::Field;
8922 
8923     const CoreChecks *core;
8924     const std::string func_name;
8925     const std::string vuid;
8926     uint32_t active_subpass;
8927     const VkRenderPass rp_handle;
8928     const VkPipelineStageFlags2KHR disabled_features;
8929     const std::vector<uint32_t> &self_dependencies;
8930     const safe_VkSubpassDependency2 *dependencies;
8931 
RenderPassDepStateRenderPassDepState8932     RenderPassDepState(const CoreChecks *c, const std::string &f, const std::string &v, uint32_t subpass, const VkRenderPass handle,
8933                        const DeviceFeatures &features, const std::vector<uint32_t> &self_deps,
8934                        const safe_VkSubpassDependency2 *deps)
8935         : core(c),
8936           func_name(f),
8937           vuid(v),
8938           active_subpass(subpass),
8939           rp_handle(handle),
8940           disabled_features(sync_utils::DisabledPipelineStages(features)),
8941           self_dependencies(self_deps),
8942           dependencies(deps) {}
8943 
GetSubPassDepBarrierRenderPassDepState8944     VkMemoryBarrier2KHR GetSubPassDepBarrier(const safe_VkSubpassDependency2 &dep) {
8945         VkMemoryBarrier2KHR result;
8946 
8947         const auto *barrier = LvlFindInChain<VkMemoryBarrier2KHR>(dep.pNext);
8948         if (barrier) {
8949             result = *barrier;
8950         } else {
8951             result.srcStageMask = dep.srcStageMask;
8952             result.dstStageMask = dep.dstStageMask;
8953             result.srcAccessMask = dep.srcAccessMask;
8954             result.dstAccessMask = dep.dstAccessMask;
8955         }
8956         return result;
8957     }
8958 
ValidateStageRenderPassDepState8959     bool ValidateStage(const Location &loc, VkPipelineStageFlags2KHR src_stage_mask, VkPipelineStageFlags2KHR dst_stage_mask) {
8960         // Look for matching mask in any self-dependency
8961         bool match = false;
8962         for (const auto self_dep_index : self_dependencies) {
8963             const auto sub_dep = GetSubPassDepBarrier(dependencies[self_dep_index]);
8964             auto sub_src_stage_mask =
8965                 sync_utils::ExpandPipelineStages(sub_dep.srcStageMask, sync_utils::kAllQueueTypes, disabled_features);
8966             auto sub_dst_stage_mask =
8967                 sync_utils::ExpandPipelineStages(sub_dep.dstStageMask, sync_utils::kAllQueueTypes, disabled_features);
8968             match = ((sub_src_stage_mask == VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) ||
8969                      (src_stage_mask == (sub_src_stage_mask & src_stage_mask))) &&
8970                     ((sub_dst_stage_mask == VK_PIPELINE_STAGE_ALL_COMMANDS_BIT) ||
8971                      (dst_stage_mask == (sub_dst_stage_mask & dst_stage_mask)));
8972             if (match) break;
8973         }
8974         if (!match) {
8975             std::stringstream self_dep_ss;
8976             stream_join(self_dep_ss, ", ", self_dependencies);
8977             core->LogError(rp_handle, vuid,
8978                            "%s (0x%" PRIx64
8979                            ") is not a subset of VkSubpassDependency srcAccessMask "
8980                            "for any self-dependency of subpass %d of %s for which dstAccessMask is also a subset. "
8981                            "Candidate VkSubpassDependency are pDependencies entries [%s].",
8982                            loc.dot(Field::srcStageMask).Message().c_str(), src_stage_mask, active_subpass,
8983                            core->report_data->FormatHandle(rp_handle).c_str(), self_dep_ss.str().c_str());
8984             core->LogError(rp_handle, vuid,
8985                            "%s (0x%" PRIx64
8986                            ") is not a subset of VkSubpassDependency dstAccessMask "
8987                            "for any self-dependency of subpass %d of %s for which srcAccessMask is also a subset. "
8988                            "Candidate VkSubpassDependency are pDependencies entries [%s].",
8989                            loc.dot(Field::dstStageMask).Message().c_str(), dst_stage_mask, active_subpass,
8990                            core->report_data->FormatHandle(rp_handle).c_str(), self_dep_ss.str().c_str());
8991         }
8992         return !match;
8993     }
8994 
ValidateAccessRenderPassDepState8995     bool ValidateAccess(const Location &loc, VkAccessFlags2KHR src_access_mask, VkAccessFlags2KHR dst_access_mask) {
8996         bool match = false;
8997 
8998         for (const auto self_dep_index : self_dependencies) {
8999             const auto sub_dep = GetSubPassDepBarrier(dependencies[self_dep_index]);
9000             match = (src_access_mask == (sub_dep.srcAccessMask & src_access_mask)) &&
9001                     (dst_access_mask == (sub_dep.dstAccessMask & dst_access_mask));
9002             if (match) break;
9003         }
9004         if (!match) {
9005             std::stringstream self_dep_ss;
9006             stream_join(self_dep_ss, ", ", self_dependencies);
9007             core->LogError(rp_handle, vuid,
9008                            "%s (0x%" PRIx64
9009                            ") is not a subset of VkSubpassDependency "
9010                            "srcAccessMask of subpass %d of %s. Candidate VkSubpassDependency are pDependencies entries [%s].",
9011                            loc.dot(Field::srcAccessMask).Message().c_str(), src_access_mask, active_subpass,
9012                            core->report_data->FormatHandle(rp_handle).c_str(), self_dep_ss.str().c_str());
9013             core->LogError(rp_handle, vuid,
9014                            "%s (0x%" PRIx64
9015                            ") is not a subset of VkSubpassDependency "
9016                            "dstAccessMask of subpass %d of %s. Candidate VkSubpassDependency are pDependencies entries [%s].",
9017                            loc.dot(Field::dstAccessMask).Message().c_str(), dst_access_mask, active_subpass,
9018                            core->report_data->FormatHandle(rp_handle).c_str(), self_dep_ss.str().c_str());
9019         }
9020         return !match;
9021     }
9022 
ValidateDependencyFlagRenderPassDepState9023     bool ValidateDependencyFlag(VkDependencyFlags dependency_flags) {
9024         bool match = false;
9025 
9026         for (const auto self_dep_index : self_dependencies) {
9027             const auto &sub_dep = dependencies[self_dep_index];
9028             match = sub_dep.dependencyFlags == dependency_flags;
9029             if (match) break;
9030         }
9031         if (!match) {
9032             std::stringstream self_dep_ss;
9033             stream_join(self_dep_ss, ", ", self_dependencies);
9034             core->LogError(rp_handle, vuid,
9035                            "%s: dependencyFlags param (0x%X) does not equal VkSubpassDependency dependencyFlags value for any "
9036                            "self-dependency of subpass %d of %s. Candidate VkSubpassDependency are pDependencies entries [%s].",
9037                            func_name.c_str(), dependency_flags, active_subpass, core->report_data->FormatHandle(rp_handle).c_str(),
9038                            self_dep_ss.str().c_str());
9039         }
9040         return !match;
9041     }
9042 };
9043 
9044 // Validate VUs for Pipeline Barriers that are within a renderPass
9045 // Pre: cb_state->activeRenderPass must be a pointer to valid renderPass state
ValidateRenderPassPipelineBarriers(const Location & outer_loc,const CMD_BUFFER_STATE * cb_state,VkPipelineStageFlags src_stage_mask,VkPipelineStageFlags dst_stage_mask,VkDependencyFlags dependency_flags,uint32_t mem_barrier_count,const VkMemoryBarrier * mem_barriers,uint32_t buffer_mem_barrier_count,const VkBufferMemoryBarrier * buffer_mem_barriers,uint32_t image_mem_barrier_count,const VkImageMemoryBarrier * image_barriers) const9046 bool CoreChecks::ValidateRenderPassPipelineBarriers(const Location &outer_loc, const CMD_BUFFER_STATE *cb_state,
9047                                                     VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
9048                                                     VkDependencyFlags dependency_flags, uint32_t mem_barrier_count,
9049                                                     const VkMemoryBarrier *mem_barriers, uint32_t buffer_mem_barrier_count,
9050                                                     const VkBufferMemoryBarrier *buffer_mem_barriers,
9051                                                     uint32_t image_mem_barrier_count,
9052                                                     const VkImageMemoryBarrier *image_barriers) const {
9053     bool skip = false;
9054     const auto& rp_state = cb_state->activeRenderPass;
9055     RenderPassDepState state(this, outer_loc.StringFunc().c_str(), "VUID-vkCmdPipelineBarrier-pDependencies-02285",
9056                              cb_state->activeSubpass, rp_state->renderPass(), enabled_features,
9057                              rp_state->self_dependencies[cb_state->activeSubpass], rp_state->createInfo.pDependencies);
9058     if (state.self_dependencies.size() == 0) {
9059         skip |= LogError(state.rp_handle, "VUID-vkCmdPipelineBarrier-pDependencies-02285",
9060                          "%s Barriers cannot be set during subpass %d of %s with no self-dependency specified.",
9061                          outer_loc.Message().c_str(), state.active_subpass, report_data->FormatHandle(state.rp_handle).c_str());
9062         return skip;
9063     }
9064     // Grab ref to current subpassDescription up-front for use below
9065     const auto &sub_desc = rp_state->createInfo.pSubpasses[state.active_subpass];
9066     skip |= state.ValidateStage(outer_loc, src_stage_mask, dst_stage_mask);
9067 
9068     if (0 != buffer_mem_barrier_count) {
9069         skip |= LogError(state.rp_handle, "VUID-vkCmdPipelineBarrier-bufferMemoryBarrierCount-01178",
9070                          "%s: bufferMemoryBarrierCount is non-zero (%d) for subpass %d of %s.", state.func_name.c_str(),
9071                          buffer_mem_barrier_count, state.active_subpass, report_data->FormatHandle(rp_state->renderPass()).c_str());
9072     }
9073     for (uint32_t i = 0; i < mem_barrier_count; ++i) {
9074         const auto &mem_barrier = mem_barriers[i];
9075         Location loc(outer_loc.function, Struct::VkMemoryBarrier, Field::pMemoryBarriers, i);
9076         skip |= state.ValidateAccess(loc, mem_barrier.srcAccessMask, mem_barrier.dstAccessMask);
9077     }
9078 
9079     for (uint32_t i = 0; i < image_mem_barrier_count; ++i) {
9080         const auto &img_barrier = image_barriers[i];
9081         Location loc(outer_loc.function, Struct::VkImageMemoryBarrier, Field::pImageMemoryBarriers, i);
9082         skip |= state.ValidateAccess(loc, img_barrier.srcAccessMask, img_barrier.dstAccessMask);
9083 
9084         if (VK_QUEUE_FAMILY_IGNORED != img_barrier.srcQueueFamilyIndex ||
9085             VK_QUEUE_FAMILY_IGNORED != img_barrier.dstQueueFamilyIndex) {
9086             skip |= LogError(state.rp_handle, "VUID-vkCmdPipelineBarrier-srcQueueFamilyIndex-01182",
9087                              "%s is %d and dstQueueFamilyIndex is %d but both must be VK_QUEUE_FAMILY_IGNORED.",
9088                              loc.dot(Field::srcQueueFamilyIndex).Message().c_str(), img_barrier.srcQueueFamilyIndex,
9089                              img_barrier.dstQueueFamilyIndex);
9090         }
9091         // Secondary CBs can have null framebuffer so record will queue up validation in that case 'til FB is known
9092         if (VK_NULL_HANDLE != cb_state->activeFramebuffer) {
9093             skip |= ValidateImageBarrierAttachment(loc, cb_state, cb_state->activeFramebuffer.get(), state.active_subpass, sub_desc,
9094                                                    state.rp_handle, img_barrier);
9095         }
9096     }
9097     skip |= state.ValidateDependencyFlag(dependency_flags);
9098     return skip;
9099 }
9100 
ValidateRenderPassPipelineBarriers(const Location & outer_loc,const CMD_BUFFER_STATE * cb_state,const VkDependencyInfoKHR * dep_info) const9101 bool CoreChecks::ValidateRenderPassPipelineBarriers(const Location &outer_loc, const CMD_BUFFER_STATE *cb_state,
9102                                                     const VkDependencyInfoKHR *dep_info) const {
9103     bool skip = false;
9104     const auto& rp_state = cb_state->activeRenderPass;
9105     RenderPassDepState state(this, outer_loc.StringFunc().c_str(), "VUID-vkCmdPipelineBarrier2KHR-pDependencies-02285",
9106                              cb_state->activeSubpass, rp_state->renderPass(), enabled_features,
9107                              rp_state->self_dependencies[cb_state->activeSubpass], rp_state->createInfo.pDependencies);
9108 
9109     if (state.self_dependencies.size() == 0) {
9110         skip |= LogError(state.rp_handle, state.vuid,
9111                          "%s: Barriers cannot be set during subpass %d of %s with no self-dependency specified.",
9112                          state.func_name.c_str(), state.active_subpass, report_data->FormatHandle(rp_state->renderPass()).c_str());
9113         return skip;
9114     }
9115     // Grab ref to current subpassDescription up-front for use below
9116     const auto &sub_desc = rp_state->createInfo.pSubpasses[state.active_subpass];
9117     for (uint32_t i = 0; i < dep_info->memoryBarrierCount; ++i) {
9118         const auto &mem_barrier = dep_info->pMemoryBarriers[i];
9119         Location loc(outer_loc.function, Struct::VkMemoryBarrier2KHR, Field::pMemoryBarriers, i);
9120         skip |= state.ValidateStage(loc, mem_barrier.srcStageMask, mem_barrier.dstStageMask);
9121         skip |= state.ValidateAccess(loc, mem_barrier.srcAccessMask, mem_barrier.dstAccessMask);
9122     }
9123     if (0 != dep_info->bufferMemoryBarrierCount) {
9124         skip |=
9125             LogError(state.rp_handle, "VUID-vkCmdPipelineBarrier2KHR-bufferMemoryBarrierCount-01178",
9126                      "%s: bufferMemoryBarrierCount is non-zero (%d) for subpass %d of %s.", state.func_name.c_str(),
9127                      dep_info->bufferMemoryBarrierCount, state.active_subpass, report_data->FormatHandle(state.rp_handle).c_str());
9128     }
9129     for (uint32_t i = 0; i < dep_info->imageMemoryBarrierCount; ++i) {
9130         const auto &img_barrier = dep_info->pImageMemoryBarriers[i];
9131         Location loc(outer_loc.function, Struct::VkImageMemoryBarrier2KHR, Field::pImageMemoryBarriers, i);
9132 
9133         skip |= state.ValidateStage(loc, img_barrier.srcStageMask, img_barrier.dstStageMask);
9134         skip |= state.ValidateAccess(loc, img_barrier.srcAccessMask, img_barrier.dstAccessMask);
9135 
9136         if (VK_QUEUE_FAMILY_IGNORED != img_barrier.srcQueueFamilyIndex ||
9137             VK_QUEUE_FAMILY_IGNORED != img_barrier.dstQueueFamilyIndex) {
9138             skip |= LogError(state.rp_handle, "VUID-vkCmdPipelineBarrier2KHR-srcQueueFamilyIndex-01182",
9139                              "%s is %d and dstQueueFamilyIndex is %d but both must be VK_QUEUE_FAMILY_IGNORED.",
9140                              loc.dot(Field::srcQueueFamilyIndex).Message().c_str(), img_barrier.srcQueueFamilyIndex,
9141                              img_barrier.dstQueueFamilyIndex);
9142         }
9143         // Secondary CBs can have null framebuffer so record will queue up validation in that case 'til FB is known
9144         if (VK_NULL_HANDLE != cb_state->activeFramebuffer) {
9145             skip |= ValidateImageBarrierAttachment(loc, cb_state, cb_state->activeFramebuffer.get(), state.active_subpass, sub_desc,
9146                                                    state.rp_handle, img_barrier);
9147         }
9148     }
9149     skip |= state.ValidateDependencyFlag(dep_info->dependencyFlags);
9150     return skip;
9151 }
9152 
ValidateStageMasksAgainstQueueCapabilities(const LogObjectList & objects,const Location & loc,VkQueueFlags queue_flags,VkPipelineStageFlags2KHR stage_mask) const9153 bool CoreChecks::ValidateStageMasksAgainstQueueCapabilities(const LogObjectList &objects, const Location &loc,
9154                                                             VkQueueFlags queue_flags, VkPipelineStageFlags2KHR stage_mask) const {
9155     bool skip = false;
9156     // these are always allowed.
9157     stage_mask &= ~(VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR | VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR |
9158                     VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR | VK_PIPELINE_STAGE_2_HOST_BIT_KHR);
9159     if (stage_mask == 0) {
9160         return skip;
9161     }
9162 
9163     static const std::map<VkPipelineStageFlags2KHR, VkQueueFlags> metaFlags{
9164         {VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR, VK_QUEUE_GRAPHICS_BIT},
9165         {VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT},
9166         {VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR, VK_QUEUE_GRAPHICS_BIT},
9167         {VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR, VK_QUEUE_GRAPHICS_BIT},
9168     };
9169 
9170     for (const auto &entry : metaFlags) {
9171         if (((entry.first & stage_mask) != 0) && ((entry.second & queue_flags) == 0)) {
9172             const auto& vuid = sync_vuid_maps::GetStageQueueCapVUID(loc, entry.first);
9173             skip |= LogError(objects, vuid,
9174                              "%s flag %s is not compatible with the queue family properties (%s) of this command buffer.",
9175                              loc.Message().c_str(), sync_utils::StringPipelineStageFlags(entry.first).c_str(),
9176                              string_VkQueueFlags(queue_flags).c_str());
9177         }
9178         stage_mask &= ~entry.first;
9179     }
9180     if (stage_mask == 0) {
9181         return skip;
9182     }
9183 
9184     auto supported_flags = sync_utils::ExpandPipelineStages(VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR, queue_flags);
9185 
9186     auto bad_flags = stage_mask & ~supported_flags;
9187 
9188     // Lookup each bit in the stagemask and check for overlap between its table bits and queue_flags
9189     for (size_t i = 0; i < sizeof(bad_flags) * 8; i++) {
9190         VkPipelineStageFlags2KHR bit = (1ULL << i) & bad_flags;
9191         if (bit) {
9192             const auto& vuid = sync_vuid_maps::GetStageQueueCapVUID(loc, bit);
9193             skip |= LogError(
9194                 objects, vuid, "%s flag %s is not compatible with the queue family properties (%s) of this command buffer.",
9195                 loc.Message().c_str(), sync_utils::StringPipelineStageFlags(bit).c_str(), string_VkQueueFlags(queue_flags).c_str());
9196         }
9197     }
9198     return skip;
9199 }
9200 
ValidatePipelineStageFeatureEnables(const LogObjectList & objects,const Location & loc,VkPipelineStageFlags2KHR stage_mask) const9201 bool CoreChecks::ValidatePipelineStageFeatureEnables(const LogObjectList &objects, const Location &loc,
9202                                                      VkPipelineStageFlags2KHR stage_mask) const {
9203     bool skip = false;
9204     if (!enabled_features.synchronization2_features.synchronization2 && stage_mask == 0) {
9205         const auto& vuid = sync_vuid_maps::GetBadFeatureVUID(loc, 0);
9206         std::stringstream msg;
9207         msg << loc.Message() << " must not be 0 unless synchronization2 is enabled.";
9208         skip |= LogError(objects, vuid, "%s", msg.str().c_str());
9209     }
9210 
9211     auto disabled_stages = sync_utils::DisabledPipelineStages(enabled_features);
9212     auto bad_bits = stage_mask & disabled_stages;
9213     if (bad_bits == 0) {
9214         return skip;
9215     }
9216     for (size_t i = 0; i < sizeof(bad_bits) * 8; i++) {
9217         VkPipelineStageFlags2KHR bit = 1ULL << i;
9218         if (bit & bad_bits) {
9219             const auto& vuid = sync_vuid_maps::GetBadFeatureVUID(loc, bit);
9220             std::stringstream msg;
9221             msg << loc.Message() << " includes " << sync_utils::StringPipelineStageFlags(bit) << " when the device does not have "
9222                 << sync_vuid_maps::kFeatureNameMap.at(bit) << " feature enabled.";
9223 
9224             skip |= LogError(objects, vuid, "%s", msg.str().c_str());
9225         }
9226     }
9227     return skip;
9228 }
9229 
ValidatePipelineStage(const LogObjectList & objects,const Location & loc,VkQueueFlags queue_flags,VkPipelineStageFlags2KHR stage_mask) const9230 bool CoreChecks::ValidatePipelineStage(const LogObjectList &objects, const Location &loc, VkQueueFlags queue_flags,
9231                                        VkPipelineStageFlags2KHR stage_mask) const {
9232     bool skip = false;
9233     skip |= ValidateStageMasksAgainstQueueCapabilities(objects, loc, queue_flags, stage_mask);
9234     skip |= ValidatePipelineStageFeatureEnables(objects, loc, stage_mask);
9235     return skip;
9236 }
9237 
ValidateAccessMask(const LogObjectList & objects,const Location & loc,VkQueueFlags queue_flags,VkAccessFlags2KHR access_mask,VkPipelineStageFlags2KHR stage_mask) const9238 bool CoreChecks::ValidateAccessMask(const LogObjectList &objects, const Location &loc, VkQueueFlags queue_flags,
9239                                     VkAccessFlags2KHR access_mask, VkPipelineStageFlags2KHR stage_mask) const {
9240     bool skip = false;
9241     // Early out if all commands set
9242     if ((stage_mask & VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR) != 0) return skip;
9243 
9244     // or if only generic memory accesses are specified (or we got a 0 mask)
9245     access_mask &= ~(VK_ACCESS_2_MEMORY_READ_BIT_KHR | VK_ACCESS_2_MEMORY_WRITE_BIT_KHR);
9246     if (access_mask == 0) return skip;
9247 
9248     auto expanded_stages = sync_utils::ExpandPipelineStages(stage_mask, queue_flags);  // TODO:
9249     auto valid_accesses = sync_utils::CompatibleAccessMask(expanded_stages);
9250     auto bad_accesses = (access_mask & ~valid_accesses);
9251     if (bad_accesses == 0) {
9252         return skip;
9253     }
9254     for (size_t i = 0; i < sizeof(bad_accesses) * 8; i++) {
9255         VkAccessFlags2KHR bit = (1ULL << i);
9256         if (bad_accesses & bit) {
9257             const auto& vuid = sync_vuid_maps::GetBadAccessFlagsVUID(loc, bit);
9258             std::stringstream msg;
9259             msg << loc.Message() << " bit " << sync_utils::StringAccessFlags(bit) << " is not supported by stage mask ("
9260                 << sync_utils::StringPipelineStageFlags(stage_mask) << ").";
9261             skip |= LogError(objects, vuid, "%s", msg.str().c_str());
9262         }
9263     }
9264     return skip;
9265 }
9266 
ValidateEventStageMask(const ValidationStateTracker * state_data,const CMD_BUFFER_STATE * pCB,size_t eventCount,size_t firstEventIndex,VkPipelineStageFlags2KHR sourceStageMask,EventToStageMap * localEventToStageMap)9267 bool CoreChecks::ValidateEventStageMask(const ValidationStateTracker *state_data, const CMD_BUFFER_STATE *pCB, size_t eventCount,
9268                                         size_t firstEventIndex, VkPipelineStageFlags2KHR sourceStageMask,
9269                                         EventToStageMap *localEventToStageMap) {
9270     bool skip = false;
9271     VkPipelineStageFlags2KHR stage_mask = 0;
9272     const auto max_event = std::min((firstEventIndex + eventCount), pCB->events.size());
9273     for (size_t event_index = firstEventIndex; event_index < max_event; ++event_index) {
9274         auto event = pCB->events[event_index];
9275         auto event_data = localEventToStageMap->find(event);
9276         if (event_data != localEventToStageMap->end()) {
9277             stage_mask |= event_data->second;
9278         } else {
9279             auto global_event_data = state_data->Get<EVENT_STATE>(event);
9280             if (!global_event_data) {
9281                 skip |= state_data->LogError(event, kVUID_Core_DrawState_InvalidEvent,
9282                                              "%s cannot be waited on if it has never been set.",
9283                                              state_data->report_data->FormatHandle(event).c_str());
9284             } else {
9285                 stage_mask |= global_event_data->stageMask;
9286             }
9287         }
9288     }
9289     // TODO: Need to validate that host_bit is only set if set event is called
9290     // but set event can be called at any time.
9291     if (sourceStageMask != stage_mask && sourceStageMask != (stage_mask | VK_PIPELINE_STAGE_HOST_BIT)) {
9292         skip |= state_data->LogError(
9293             pCB->commandBuffer(), "VUID-vkCmdWaitEvents-srcStageMask-parameter",
9294             "Submitting cmdbuffer with call to VkCmdWaitEvents using srcStageMask 0x%" PRIx64
9295             " which must be the bitwise OR of "
9296             "the stageMask parameters used in calls to vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if used with "
9297             "vkSetEvent but instead is 0x%" PRIx64 ".",
9298             sourceStageMask, stage_mask);
9299     }
9300     return skip;
9301 }
9302 
PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer,uint32_t eventCount,const VkEvent * pEvents,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,uint32_t memoryBarrierCount,const VkMemoryBarrier * pMemoryBarriers,uint32_t bufferMemoryBarrierCount,const VkBufferMemoryBarrier * pBufferMemoryBarriers,uint32_t imageMemoryBarrierCount,const VkImageMemoryBarrier * pImageMemoryBarriers) const9303 bool CoreChecks::PreCallValidateCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9304                                               VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
9305                                               uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9306                                               uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9307                                               uint32_t imageMemoryBarrierCount,
9308                                               const VkImageMemoryBarrier *pImageMemoryBarriers) const {
9309     bool skip = false;
9310     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9311     assert(cb_state);
9312 
9313     auto queue_flags = cb_state->GetQueueFlags();
9314     LogObjectList objects(commandBuffer);
9315     Location loc(Func::vkCmdWaitEvents);
9316 
9317     skip |= ValidatePipelineStage(objects, loc.dot(Field::srcStageMask), queue_flags, srcStageMask);
9318     skip |= ValidatePipelineStage(objects, loc.dot(Field::dstStageMask), queue_flags, dstStageMask);
9319 
9320     skip |= ValidateCmd(cb_state.get(), CMD_WAITEVENTS);
9321     skip |= ValidateBarriers(loc.dot(Field::pDependencyInfo), cb_state.get(), srcStageMask, dstStageMask, memoryBarrierCount,
9322                              pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
9323                              pImageMemoryBarriers);
9324     for (uint32_t i = 0; i < bufferMemoryBarrierCount; ++i) {
9325         if (pBufferMemoryBarriers[i].srcQueueFamilyIndex != pBufferMemoryBarriers[i].dstQueueFamilyIndex) {
9326             skip |= LogError(commandBuffer, "VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803",
9327                              "vkCmdWaitEvents(): pBufferMemoryBarriers[%" PRIu32 "] has different srcQueueFamilyIndex (%" PRIu32
9328                              ") and dstQueueFamilyIndex (%" PRIu32 ").",
9329                              i, pBufferMemoryBarriers[i].srcQueueFamilyIndex, pBufferMemoryBarriers[i].dstQueueFamilyIndex);
9330         }
9331     }
9332     for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
9333         if (pImageMemoryBarriers[i].srcQueueFamilyIndex != pImageMemoryBarriers[i].dstQueueFamilyIndex) {
9334             skip |= LogError(commandBuffer, "VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803",
9335                              "vkCmdWaitEvents(): pImageMemoryBarriers[%" PRIu32 "] has different srcQueueFamilyIndex (%" PRIu32
9336                              ") and dstQueueFamilyIndex (%" PRIu32 ").",
9337                              i, pImageMemoryBarriers[i].srcQueueFamilyIndex, pImageMemoryBarriers[i].dstQueueFamilyIndex);
9338         }
9339     }
9340     return skip;
9341 }
9342 
PreCallValidateCmdWaitEvents2KHR(VkCommandBuffer commandBuffer,uint32_t eventCount,const VkEvent * pEvents,const VkDependencyInfoKHR * pDependencyInfos) const9343 bool CoreChecks::PreCallValidateCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9344                                                   const VkDependencyInfoKHR *pDependencyInfos) const {
9345     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9346     assert(cb_state);
9347 
9348     bool skip = false;
9349     if (!enabled_features.synchronization2_features.synchronization2) {
9350         skip |= LogError(commandBuffer, "VUID-vkCmdWaitEvents2KHR-synchronization2-03836",
9351                          "vkCmdWaitEvents2KHR(): Synchronization2 feature is not enabled");
9352     }
9353     for (uint32_t i = 0; (i < eventCount) && !skip; i++) {
9354         LogObjectList objects(commandBuffer);
9355         objects.add(pEvents[i]);
9356         Location loc(Func::vkCmdWaitEvents2KHR, Field::pDependencyInfos, i);
9357         if (pDependencyInfos[i].dependencyFlags != 0) {
9358             skip |= LogError(objects, "VUID-vkCmdWaitEvents2KHR-dependencyFlags-03844", "%s (%s) must be 0.",
9359                              loc.dot(Field::dependencyFlags).Message().c_str(),
9360                              string_VkDependencyFlags(pDependencyInfos[i].dependencyFlags).c_str());
9361         }
9362         skip |= ValidateDependencyInfo(objects, loc, cb_state.get(), &pDependencyInfos[i]);
9363     }
9364     skip |= ValidateCmd(cb_state.get(), CMD_WAITEVENTS);
9365     return skip;
9366 }
9367 
PreCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer,uint32_t eventCount,const VkEvent * pEvents,VkPipelineStageFlags sourceStageMask,VkPipelineStageFlags dstStageMask,uint32_t memoryBarrierCount,const VkMemoryBarrier * pMemoryBarriers,uint32_t bufferMemoryBarrierCount,const VkBufferMemoryBarrier * pBufferMemoryBarriers,uint32_t imageMemoryBarrierCount,const VkImageMemoryBarrier * pImageMemoryBarriers)9368 void CoreChecks::PreCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9369                                             VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
9370                                             uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9371                                             uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9372                                             uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
9373     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9374     // The StateTracker added will add to the events vector.
9375     auto first_event_index = cb_state->events.size();
9376     StateTracker::PreCallRecordCmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask, memoryBarrierCount,
9377                                              pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
9378                                              imageMemoryBarrierCount, pImageMemoryBarriers);
9379     auto event_added_count = cb_state->events.size() - first_event_index;
9380 
9381     const auto cb_state_const = std::static_pointer_cast<const CMD_BUFFER_STATE>(cb_state);
9382     cb_state->eventUpdates.emplace_back(
9383         [cb_state_const, event_added_count, first_event_index, sourceStageMask](
9384             const ValidationStateTracker *device_data, bool do_validate, EventToStageMap *localEventToStageMap) {
9385             if (!do_validate) return false;
9386             return ValidateEventStageMask(device_data, cb_state_const.get(), event_added_count, first_event_index, sourceStageMask,
9387                                           localEventToStageMap);
9388         });
9389     TransitionImageLayouts(cb_state.get(), imageMemoryBarrierCount, pImageMemoryBarriers);
9390 }
9391 
PreCallRecordCmdWaitEvents2KHR(VkCommandBuffer commandBuffer,uint32_t eventCount,const VkEvent * pEvents,const VkDependencyInfoKHR * pDependencyInfos)9392 void CoreChecks::PreCallRecordCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9393                                                 const VkDependencyInfoKHR *pDependencyInfos) {
9394     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9395     // The StateTracker added will add to the events vector.
9396     auto first_event_index = cb_state->events.size();
9397     StateTracker::PreCallRecordCmdWaitEvents2KHR(commandBuffer, eventCount, pEvents, pDependencyInfos);
9398     auto event_added_count = cb_state->events.size() - first_event_index;
9399     const auto cb_state_const = std::static_pointer_cast<const CMD_BUFFER_STATE>(cb_state);
9400     for (uint32_t i = 0; i < eventCount; i++) {
9401         const auto &dep_info = pDependencyInfos[i];
9402         auto stage_masks = sync_utils::GetGlobalStageMasks(dep_info);
9403         cb_state->eventUpdates.emplace_back(
9404             [cb_state_const, event_added_count, first_event_index, stage_masks](
9405                 const ValidationStateTracker *device_data, bool do_validate, EventToStageMap *localEventToStageMap) {
9406                 if (!do_validate) return false;
9407                 return ValidateEventStageMask(device_data, cb_state_const.get(), event_added_count, first_event_index,
9408                                               stage_masks.src, localEventToStageMap);
9409             });
9410         TransitionImageLayouts(cb_state.get(), dep_info.imageMemoryBarrierCount, dep_info.pImageMemoryBarriers);
9411     }
9412 }
9413 
PostCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer,uint32_t eventCount,const VkEvent * pEvents,VkPipelineStageFlags sourceStageMask,VkPipelineStageFlags dstStageMask,uint32_t memoryBarrierCount,const VkMemoryBarrier * pMemoryBarriers,uint32_t bufferMemoryBarrierCount,const VkBufferMemoryBarrier * pBufferMemoryBarriers,uint32_t imageMemoryBarrierCount,const VkImageMemoryBarrier * pImageMemoryBarriers)9414 void CoreChecks::PostCallRecordCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9415                                              VkPipelineStageFlags sourceStageMask, VkPipelineStageFlags dstStageMask,
9416                                              uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9417                                              uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9418                                              uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
9419     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9420     RecordBarriers(Func::vkCmdWaitEvents, cb_state.get(), bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount,
9421                    pImageMemoryBarriers);
9422 }
9423 
PostCallRecordCmdWaitEvents2KHR(VkCommandBuffer commandBuffer,uint32_t eventCount,const VkEvent * pEvents,const VkDependencyInfoKHR * pDependencyInfos)9424 void CoreChecks::PostCallRecordCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents,
9425                                                  const VkDependencyInfoKHR *pDependencyInfos) {
9426     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9427     for (uint32_t i = 0; i < eventCount; i++) {
9428         const auto &dep_info = pDependencyInfos[i];
9429         RecordBarriers(Func::vkCmdWaitEvents2KHR, cb_state.get(), dep_info);
9430     }
9431 }
9432 
PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,VkDependencyFlags dependencyFlags,uint32_t memoryBarrierCount,const VkMemoryBarrier * pMemoryBarriers,uint32_t bufferMemoryBarrierCount,const VkBufferMemoryBarrier * pBufferMemoryBarriers,uint32_t imageMemoryBarrierCount,const VkImageMemoryBarrier * pImageMemoryBarriers) const9433 bool CoreChecks::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
9434                                                    VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
9435                                                    uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9436                                                    uint32_t bufferMemoryBarrierCount,
9437                                                    const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9438                                                    uint32_t imageMemoryBarrierCount,
9439                                                    const VkImageMemoryBarrier *pImageMemoryBarriers) const {
9440     bool skip = false;
9441     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9442     assert(cb_state);
9443     LogObjectList objects(commandBuffer);
9444     auto queue_flags = cb_state->GetQueueFlags();
9445     Location loc(Func::vkCmdPipelineBarrier);
9446 
9447     skip |= ValidatePipelineStage(objects, loc.dot(Field::srcStageMask), queue_flags, srcStageMask);
9448     skip |= ValidatePipelineStage(objects, loc.dot(Field::dstStageMask), queue_flags, dstStageMask);
9449     skip |= ValidateCmd(cb_state.get(), CMD_PIPELINEBARRIER);
9450     if (cb_state->activeRenderPass && !cb_state->activeRenderPass->use_dynamic_rendering) {
9451         skip |= ValidateRenderPassPipelineBarriers(loc, cb_state.get(), srcStageMask, dstStageMask, dependencyFlags,
9452                                                    memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
9453                                                    pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
9454         if (skip) return true;  // Early return to avoid redundant errors from below calls
9455     } else {
9456         if (dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) {
9457             skip = LogError(objects, "VUID-vkCmdPipelineBarrier-dependencyFlags-01186",
9458                             "%s VK_DEPENDENCY_VIEW_LOCAL_BIT must not be set outside of a render pass instance",
9459                             loc.dot(Field::dependencyFlags).Message().c_str());
9460         }
9461     }
9462     skip |= ValidateBarriers(loc, cb_state.get(), srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers,
9463                              bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
9464     return skip;
9465 }
9466 
PreCallValidateCmdPipelineBarrier2KHR(VkCommandBuffer commandBuffer,const VkDependencyInfoKHR * pDependencyInfo) const9467 bool CoreChecks::PreCallValidateCmdPipelineBarrier2KHR(VkCommandBuffer commandBuffer,
9468                                                        const VkDependencyInfoKHR *pDependencyInfo) const {
9469     bool skip = false;
9470     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9471     assert(cb_state);
9472     LogObjectList objects(commandBuffer);
9473 
9474     Location loc(Func::vkCmdPipelineBarrier2KHR, Field::pDependencyInfo);
9475     if (!enabled_features.synchronization2_features.synchronization2) {
9476         skip |= LogError(commandBuffer, "VUID-vkCmdPipelineBarrier2KHR-synchronization2-03848",
9477                          "vkCmdPipelineBarrier2KHR(): Synchronization2 feature is not enabled");
9478     }
9479     skip |= ValidateCmd(cb_state.get(), CMD_PIPELINEBARRIER);
9480     if (cb_state->activeRenderPass) {
9481         skip |= ValidateRenderPassPipelineBarriers(loc, cb_state.get(), pDependencyInfo);
9482         if (skip) return true;  // Early return to avoid redundant errors from below calls
9483     } else {
9484         if (pDependencyInfo->dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) {
9485             skip = LogError(objects, "VUID-vkCmdPipelineBarrier2KHR-dependencyFlags-01186",
9486                             "%s VK_DEPENDENCY_VIEW_LOCAL_BIT must not be set outside of a render pass instance",
9487                             loc.dot(Field::dependencyFlags).Message().c_str());
9488         }
9489     }
9490     skip |= ValidateDependencyInfo(objects, loc, cb_state.get(), pDependencyInfo);
9491     return skip;
9492 }
9493 
PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,VkDependencyFlags dependencyFlags,uint32_t memoryBarrierCount,const VkMemoryBarrier * pMemoryBarriers,uint32_t bufferMemoryBarrierCount,const VkBufferMemoryBarrier * pBufferMemoryBarriers,uint32_t imageMemoryBarrierCount,const VkImageMemoryBarrier * pImageMemoryBarriers)9494 void CoreChecks::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
9495                                                  VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
9496                                                  uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
9497                                                  uint32_t bufferMemoryBarrierCount,
9498                                                  const VkBufferMemoryBarrier *pBufferMemoryBarriers,
9499                                                  uint32_t imageMemoryBarrierCount,
9500                                                  const VkImageMemoryBarrier *pImageMemoryBarriers) {
9501     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9502 
9503     RecordBarriers(Func::vkCmdPipelineBarrier, cb_state.get(), bufferMemoryBarrierCount, pBufferMemoryBarriers,
9504                    imageMemoryBarrierCount, pImageMemoryBarriers);
9505     TransitionImageLayouts(cb_state.get(), imageMemoryBarrierCount, pImageMemoryBarriers);
9506 
9507     StateTracker::PreCallRecordCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
9508                                                   pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers,
9509                                                   imageMemoryBarrierCount, pImageMemoryBarriers);
9510 }
9511 
PreCallRecordCmdPipelineBarrier2KHR(VkCommandBuffer commandBuffer,const VkDependencyInfoKHR * pDependencyInfo)9512 void CoreChecks::PreCallRecordCmdPipelineBarrier2KHR(VkCommandBuffer commandBuffer, const VkDependencyInfoKHR *pDependencyInfo) {
9513     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9514 
9515     RecordBarriers(Func::vkCmdPipelineBarrier2KHR, cb_state.get(), *pDependencyInfo);
9516     TransitionImageLayouts(cb_state.get(), pDependencyInfo->imageMemoryBarrierCount, pDependencyInfo->pImageMemoryBarriers);
9517 
9518     StateTracker::PreCallRecordCmdPipelineBarrier2KHR(commandBuffer, pDependencyInfo);
9519 }
9520 
ValidateBeginQuery(const CMD_BUFFER_STATE * cb_state,const QueryObject & query_obj,VkFlags flags,uint32_t index,CMD_TYPE cmd,const ValidateBeginQueryVuids * vuids) const9521 bool CoreChecks::ValidateBeginQuery(const CMD_BUFFER_STATE *cb_state, const QueryObject &query_obj, VkFlags flags, uint32_t index,
9522                                     CMD_TYPE cmd, const ValidateBeginQueryVuids *vuids) const {
9523     bool skip = false;
9524     const auto query_pool_state = Get<QUERY_POOL_STATE>(query_obj.pool);
9525     const auto &query_pool_ci = query_pool_state->createInfo;
9526     const char *cmd_name = CommandTypeString(cmd);
9527 
9528     if (query_pool_ci.queryType == VK_QUERY_TYPE_TIMESTAMP) {
9529         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBeginQuery-queryType-02804",
9530                          "%s: The querypool's query type must not be VK_QUERY_TYPE_TIMESTAMP.", cmd_name);
9531     }
9532 
9533     // Check for nested queries
9534     if (cb_state->activeQueries.size()) {
9535         for (const auto &a_query : cb_state->activeQueries) {
9536             auto active_query_pool_state = Get<QUERY_POOL_STATE>(a_query.pool);
9537             if (active_query_pool_state->createInfo.queryType == query_pool_ci.queryType && a_query.index == index) {
9538                 LogObjectList obj_list(cb_state->commandBuffer());
9539                 obj_list.add(query_obj.pool);
9540                 obj_list.add(a_query.pool);
9541                 skip |= LogError(obj_list, vuids->vuid_dup_query_type,
9542                                  "%s: Within the same command buffer %s, query %d from pool %s has same queryType as active query "
9543                                  "%d from pool %s.",
9544                                  cmd_name, report_data->FormatHandle(cb_state->commandBuffer()).c_str(), query_obj.index,
9545                                  report_data->FormatHandle(query_obj.pool).c_str(), a_query.index,
9546                                  report_data->FormatHandle(a_query.pool).c_str());
9547             }
9548         }
9549     }
9550 
9551     // There are tighter queue constraints to test for certain query pools
9552     if (query_pool_ci.queryType == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
9553         skip |= ValidateCmdQueueFlags(cb_state, cmd_name, VK_QUEUE_GRAPHICS_BIT, vuids->vuid_queue_feedback);
9554         if (!phys_dev_ext_props.transform_feedback_props.transformFeedbackQueries) {
9555             const char *vuid = cmd == CMD_BEGINQUERYINDEXEDEXT ? "VUID-vkCmdBeginQueryIndexedEXT-queryType-02341"
9556                                                                : "VUID-vkCmdBeginQuery-queryType-02328";
9557             skip |= LogError(cb_state->commandBuffer(), vuid,
9558                              "%s: queryPool was created with queryType VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, but "
9559                              "VkPhysicalDeviceTransformFeedbackPropertiesEXT::transformFeedbackQueries is not supported.",
9560                              cmd_name);
9561         }
9562     }
9563     if (query_pool_ci.queryType == VK_QUERY_TYPE_OCCLUSION) {
9564         skip |= ValidateCmdQueueFlags(cb_state, cmd_name, VK_QUEUE_GRAPHICS_BIT, vuids->vuid_queue_occlusion);
9565     }
9566     if (query_pool_ci.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
9567         if (!cb_state->performance_lock_acquired) {
9568             skip |= LogError(cb_state->commandBuffer(), vuids->vuid_profile_lock,
9569                              "%s: profiling lock must be held before vkBeginCommandBuffer is called on "
9570                              "a command buffer where performance queries are recorded.",
9571                              cmd_name);
9572         }
9573 
9574         if (query_pool_state->has_perf_scope_command_buffer && cb_state->commandCount > 0) {
9575             skip |= LogError(cb_state->commandBuffer(), vuids->vuid_scope_not_first,
9576                              "%s: Query pool %s was created with a counter of scope "
9577                              "VK_QUERY_SCOPE_COMMAND_BUFFER_KHR but %s is not the first recorded "
9578                              "command in the command buffer.",
9579                              cmd_name, report_data->FormatHandle(query_obj.pool).c_str(), cmd_name);
9580         }
9581 
9582         if (query_pool_state->has_perf_scope_render_pass && cb_state->activeRenderPass) {
9583             skip |= LogError(cb_state->commandBuffer(), vuids->vuid_scope_in_rp,
9584                              "%s: Query pool %s was created with a counter of scope "
9585                              "VK_QUERY_SCOPE_RENDER_PASS_KHR but %s is inside a render pass.",
9586                              cmd_name, report_data->FormatHandle(query_obj.pool).c_str(), cmd_name);
9587         }
9588     }
9589     if (query_pool_ci.queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR ||
9590         query_pool_ci.queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR) {
9591         const char *vuid = cmd == CMD_BEGINQUERYINDEXEDEXT ? "VUID-vkCmdBeginQueryIndexedEXT-queryType-04728"
9592                                                            : "VUID-vkCmdBeginQuery-queryType-04728";
9593         skip |= LogError(cb_state->commandBuffer(), vuid, "%s: QueryPool was created with queryType %s.", cmd_name,
9594                          string_VkQueryType(query_pool_ci.queryType));
9595     }
9596     if (query_pool_ci.queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV) {
9597         const char *vuid = cmd == CMD_BEGINQUERYINDEXEDEXT ? "VUID-vkCmdBeginQueryIndexedEXT-queryType-04729"
9598                                                            : "VUID-vkCmdBeginQuery-queryType-04729";
9599         skip |=
9600             LogError(cb_state->commandBuffer(), vuid,
9601                      "%s: QueryPool was created with queryType VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV.", cmd_name);
9602     }
9603 
9604     skip |= ValidateCmdQueueFlags(cb_state, cmd_name, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, vuids->vuid_queue_flags);
9605 
9606     if (flags & VK_QUERY_CONTROL_PRECISE_BIT) {
9607         if (!enabled_features.core.occlusionQueryPrecise) {
9608             skip |= LogError(cb_state->commandBuffer(), vuids->vuid_precise,
9609                              "%s: VK_QUERY_CONTROL_PRECISE_BIT provided, but precise occlusion queries not enabled on the device.",
9610                              cmd_name);
9611         }
9612 
9613         if (query_pool_ci.queryType != VK_QUERY_TYPE_OCCLUSION) {
9614             skip |=
9615                 LogError(cb_state->commandBuffer(), vuids->vuid_precise,
9616                          "%s: VK_QUERY_CONTROL_PRECISE_BIT provided, but pool query type is not VK_QUERY_TYPE_OCCLUSION", cmd_name);
9617         }
9618     }
9619 
9620     if (query_obj.query >= query_pool_ci.queryCount) {
9621         skip |= LogError(cb_state->commandBuffer(), vuids->vuid_query_count,
9622                          "%s: Query index %" PRIu32 " must be less than query count %" PRIu32 " of %s.", cmd_name, query_obj.query,
9623                          query_pool_ci.queryCount, report_data->FormatHandle(query_obj.pool).c_str());
9624     }
9625 
9626     if (cb_state->unprotected == false) {
9627         skip |= LogError(cb_state->commandBuffer(), vuids->vuid_protected_cb,
9628                          "%s: command can't be used in protected command buffers.", cmd_name);
9629     }
9630 
9631     skip |= ValidateCmd(cb_state, cmd);
9632     return skip;
9633 }
9634 
PreCallValidateCmdBeginQuery(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t slot,VkFlags flags) const9635 bool CoreChecks::PreCallValidateCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot,
9636                                               VkFlags flags) const {
9637     if (disabled[query_validation]) return false;
9638     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9639     assert(cb_state);
9640     QueryObject query_obj(queryPool, slot);
9641     struct BeginQueryVuids : ValidateBeginQueryVuids {
9642         BeginQueryVuids() : ValidateBeginQueryVuids() {
9643             vuid_queue_flags = "VUID-vkCmdBeginQuery-commandBuffer-cmdpool";
9644             vuid_queue_feedback = "VUID-vkCmdBeginQuery-queryType-02327";
9645             vuid_queue_occlusion = "VUID-vkCmdBeginQuery-queryType-00803";
9646             vuid_precise = "VUID-vkCmdBeginQuery-queryType-00800";
9647             vuid_query_count = "VUID-vkCmdBeginQuery-query-00802";
9648             vuid_profile_lock = "VUID-vkCmdBeginQuery-queryPool-03223";
9649             vuid_scope_not_first = "VUID-vkCmdBeginQuery-queryPool-03224";
9650             vuid_scope_in_rp = "VUID-vkCmdBeginQuery-queryPool-03225";
9651             vuid_dup_query_type = "VUID-vkCmdBeginQuery-queryPool-01922";
9652             vuid_protected_cb = "VUID-vkCmdBeginQuery-commandBuffer-01885";
9653         }
9654     };
9655     BeginQueryVuids vuids;
9656     return ValidateBeginQuery(cb_state.get(), query_obj, flags, 0, CMD_BEGINQUERY, &vuids);
9657 }
9658 
GetLocalQueryState(const QueryMap * localQueryToStateMap,VkQueryPool queryPool,uint32_t queryIndex,uint32_t perfPass)9659 static QueryState GetLocalQueryState(const QueryMap *localQueryToStateMap, VkQueryPool queryPool, uint32_t queryIndex,
9660                                      uint32_t perfPass) {
9661     QueryObject query = QueryObject(QueryObject(queryPool, queryIndex), perfPass);
9662 
9663     auto iter = localQueryToStateMap->find(query);
9664     if (iter != localQueryToStateMap->end()) return iter->second;
9665 
9666     return QUERYSTATE_UNKNOWN;
9667 }
9668 
VerifyQueryIsReset(const ValidationStateTracker * state_data,VkCommandBuffer commandBuffer,QueryObject query_obj,const char * func_name,VkQueryPool & firstPerfQueryPool,uint32_t perfPass,QueryMap * localQueryToStateMap)9669 bool CoreChecks::VerifyQueryIsReset(const ValidationStateTracker *state_data, VkCommandBuffer commandBuffer, QueryObject query_obj,
9670                                     const char *func_name, VkQueryPool &firstPerfQueryPool, uint32_t perfPass,
9671                                     QueryMap *localQueryToStateMap) {
9672     bool skip = false;
9673 
9674     const auto query_pool_state = state_data->Get<QUERY_POOL_STATE>(query_obj.pool);
9675     const auto &query_pool_ci = query_pool_state->createInfo;
9676 
9677     QueryState state = GetLocalQueryState(localQueryToStateMap, query_obj.pool, query_obj.query, perfPass);
9678     // If reset was in another command buffer, check the global map
9679     if (state == QUERYSTATE_UNKNOWN) {
9680         state = query_pool_state->GetQueryState(query_obj.query, perfPass);
9681     }
9682     // Performance queries have limitation upon when they can be
9683     // reset.
9684     if (query_pool_ci.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR && state == QUERYSTATE_UNKNOWN &&
9685         perfPass >= query_pool_state->n_performance_passes) {
9686         // If the pass is invalid, assume RESET state, another error
9687         // will be raised in ValidatePerformanceQuery().
9688         state = QUERYSTATE_RESET;
9689     }
9690 
9691     if (state != QUERYSTATE_RESET) {
9692         skip |= state_data->LogError(commandBuffer, kVUID_Core_DrawState_QueryNotReset,
9693                                      "%s: %s and query %" PRIu32
9694                                      ": query not reset. "
9695                                      "After query pool creation, each query must be reset before it is used. "
9696                                      "Queries must also be reset between uses.",
9697                                      func_name, state_data->report_data->FormatHandle(query_obj.pool).c_str(), query_obj.query);
9698     }
9699 
9700     return skip;
9701 }
9702 
ValidatePerformanceQuery(const ValidationStateTracker * state_data,VkCommandBuffer commandBuffer,QueryObject query_obj,const char * func_name,VkQueryPool & firstPerfQueryPool,uint32_t perfPass,QueryMap * localQueryToStateMap)9703 bool CoreChecks::ValidatePerformanceQuery(const ValidationStateTracker *state_data, VkCommandBuffer commandBuffer,
9704                                           QueryObject query_obj, const char *func_name, VkQueryPool &firstPerfQueryPool,
9705                                           uint32_t perfPass, QueryMap *localQueryToStateMap) {
9706     const auto query_pool_state = state_data->Get<QUERY_POOL_STATE>(query_obj.pool);
9707     const auto &query_pool_ci = query_pool_state->createInfo;
9708 
9709     if (query_pool_ci.queryType != VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) return false;
9710 
9711     const auto cb_state = state_data->Get<CMD_BUFFER_STATE>(commandBuffer);
9712     bool skip = false;
9713 
9714     if (perfPass >= query_pool_state->n_performance_passes) {
9715         skip |= state_data->LogError(commandBuffer, "VUID-VkPerformanceQuerySubmitInfoKHR-counterPassIndex-03221",
9716                                      "Invalid counterPassIndex (%u, maximum allowed %u) value for query pool %s.", perfPass,
9717                                      query_pool_state->n_performance_passes,
9718                                      state_data->report_data->FormatHandle(query_obj.pool).c_str());
9719     }
9720 
9721     if (!cb_state->performance_lock_acquired || cb_state->performance_lock_released) {
9722         skip |= state_data->LogError(commandBuffer, "VUID-vkQueueSubmit-pCommandBuffers-03220",
9723                                      "Commandbuffer %s was submitted and contains a performance query but the"
9724                                      "profiling lock was not held continuously throughout the recording of commands.",
9725                                      state_data->report_data->FormatHandle(commandBuffer).c_str());
9726     }
9727 
9728     QueryState command_buffer_state = GetLocalQueryState(localQueryToStateMap, query_obj.pool, query_obj.query, perfPass);
9729     if (command_buffer_state == QUERYSTATE_RESET) {
9730         skip |= state_data->LogError(
9731             commandBuffer, query_obj.indexed ? "VUID-vkCmdBeginQueryIndexedEXT-None-02863" : "VUID-vkCmdBeginQuery-None-02863",
9732             "VkQuery begin command recorded in a command buffer that, either directly or "
9733             "through secondary command buffers, also contains a vkCmdResetQueryPool command "
9734             "affecting the same query.");
9735     }
9736 
9737     if (firstPerfQueryPool != VK_NULL_HANDLE) {
9738         if (firstPerfQueryPool != query_obj.pool &&
9739             !state_data->enabled_features.performance_query_features.performanceCounterMultipleQueryPools) {
9740             skip |= state_data->LogError(
9741                 commandBuffer,
9742                 query_obj.indexed ? "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03226" : "VUID-vkCmdBeginQuery-queryPool-03226",
9743                 "Commandbuffer %s contains more than one performance query pool but "
9744                 "performanceCounterMultipleQueryPools is not enabled.",
9745                 state_data->report_data->FormatHandle(commandBuffer).c_str());
9746         }
9747     } else {
9748         firstPerfQueryPool = query_obj.pool;
9749     }
9750 
9751     return skip;
9752 }
9753 
EnqueueVerifyBeginQuery(VkCommandBuffer command_buffer,const QueryObject & query_obj,const char * func_name)9754 void CoreChecks::EnqueueVerifyBeginQuery(VkCommandBuffer command_buffer, const QueryObject &query_obj, const char *func_name) {
9755     auto cb_state = Get<CMD_BUFFER_STATE>(command_buffer);
9756 
9757     // Enqueue the submit time validation here, ahead of the submit time state update in the StateTracker's PostCallRecord
9758     cb_state->queryUpdates.emplace_back([command_buffer, query_obj, func_name](const ValidationStateTracker *device_data,
9759                                                                                bool do_validate, VkQueryPool &firstPerfQueryPool,
9760                                                                                uint32_t perfPass, QueryMap *localQueryToStateMap) {
9761         if (!do_validate) return false;
9762         bool skip = false;
9763         skip |= ValidatePerformanceQuery(device_data, command_buffer, query_obj, func_name, firstPerfQueryPool, perfPass,
9764                                          localQueryToStateMap);
9765         skip |= VerifyQueryIsReset(device_data, command_buffer, query_obj, func_name, firstPerfQueryPool, perfPass,
9766                                    localQueryToStateMap);
9767         return skip;
9768     });
9769 }
9770 
PreCallRecordCmdBeginQuery(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t slot,VkFlags flags)9771 void CoreChecks::PreCallRecordCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
9772     if (disabled[query_validation]) return;
9773     QueryObject query_obj = {queryPool, slot};
9774     EnqueueVerifyBeginQuery(commandBuffer, query_obj, "vkCmdBeginQuery()");
9775 }
9776 
EnqueueVerifyEndQuery(VkCommandBuffer command_buffer,const QueryObject & query_obj)9777 void CoreChecks::EnqueueVerifyEndQuery(VkCommandBuffer command_buffer, const QueryObject &query_obj) {
9778     auto cb_state = Get<CMD_BUFFER_STATE>(command_buffer);
9779 
9780     // Enqueue the submit time validation here, ahead of the submit time state update in the StateTracker's PostCallRecord
9781     cb_state->queryUpdates.emplace_back([command_buffer, query_obj](const ValidationStateTracker *device_data, bool do_validate,
9782                                                                     VkQueryPool &firstPerfQueryPool, uint32_t perfPass,
9783                                                                     QueryMap *localQueryToStateMap) {
9784         if (!do_validate) return false;
9785         bool skip = false;
9786         const auto cb_state = device_data->Get<CMD_BUFFER_STATE>(command_buffer);
9787         const auto query_pool_state = device_data->Get<QUERY_POOL_STATE>(query_obj.pool);
9788         if (query_pool_state->has_perf_scope_command_buffer && (cb_state->commandCount - 1) != query_obj.endCommandIndex) {
9789             skip |= device_data->LogError(command_buffer, "VUID-vkCmdEndQuery-queryPool-03227",
9790                                           "vkCmdEndQuery: Query pool %s was created with a counter of scope"
9791                                           "VK_QUERY_SCOPE_COMMAND_BUFFER_KHR but the end of the query is not the last "
9792                                           "command in the command buffer %s.",
9793                                           device_data->report_data->FormatHandle(query_obj.pool).c_str(),
9794                                           device_data->report_data->FormatHandle(command_buffer).c_str());
9795         }
9796         return skip;
9797     });
9798 }
9799 
ValidateCmdEndQuery(const CMD_BUFFER_STATE * cb_state,const QueryObject & query_obj,uint32_t index,CMD_TYPE cmd,const ValidateEndQueryVuids * vuids) const9800 bool CoreChecks::ValidateCmdEndQuery(const CMD_BUFFER_STATE *cb_state, const QueryObject &query_obj, uint32_t index, CMD_TYPE cmd,
9801                                      const ValidateEndQueryVuids *vuids) const {
9802     bool skip = false;
9803     const char *cmd_name = CommandTypeString(cmd);
9804     if (!cb_state->activeQueries.count(query_obj)) {
9805         skip |=
9806             LogError(cb_state->commandBuffer(), vuids->vuid_active_queries, "%s: Ending a query before it was started: %s, index %d.",
9807                      cmd_name, report_data->FormatHandle(query_obj.pool).c_str(), query_obj.query);
9808     }
9809     const auto query_pool_state = Get<QUERY_POOL_STATE>(query_obj.pool);
9810     const auto &query_pool_ci = query_pool_state->createInfo;
9811     if (query_pool_ci.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
9812         if (query_pool_state->has_perf_scope_render_pass && cb_state->activeRenderPass) {
9813             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdEndQuery-queryPool-03228",
9814                              "%s: Query pool %s was created with a counter of scope "
9815                              "VK_QUERY_SCOPE_RENDER_PASS_KHR but %s is inside a render pass.",
9816                              cmd_name, report_data->FormatHandle(query_obj.pool).c_str(), cmd_name);
9817         }
9818     }
9819     skip |= ValidateCmdQueueFlags(cb_state, cmd_name, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, vuids->vuid_queue_flags);
9820     skip |= ValidateCmd(cb_state, cmd);
9821 
9822     if (cb_state->unprotected == false) {
9823         skip |= LogError(cb_state->commandBuffer(), vuids->vuid_protected_cb,
9824                          "%s: command can't be used in protected command buffers.", cmd_name);
9825     }
9826     return skip;
9827 }
9828 
PreCallValidateCmdEndQuery(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t slot) const9829 bool CoreChecks::PreCallValidateCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) const {
9830     if (disabled[query_validation]) return false;
9831     bool skip = false;
9832     QueryObject query_obj = {queryPool, slot};
9833     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9834     assert(cb_state);
9835 
9836     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
9837     if (query_pool_state) {
9838         const uint32_t available_query_count = query_pool_state->createInfo.queryCount;
9839         // Only continue validating if the slot is even within range
9840         if (slot >= available_query_count) {
9841             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdEndQuery-query-00810",
9842                              "vkCmdEndQuery(): query index (%u) is greater or equal to the queryPool size (%u).", slot,
9843                              available_query_count);
9844         } else {
9845             struct EndQueryVuids : ValidateEndQueryVuids {
9846                 EndQueryVuids() : ValidateEndQueryVuids() {
9847                     vuid_queue_flags = "VUID-vkCmdEndQuery-commandBuffer-cmdpool";
9848                     vuid_active_queries = "VUID-vkCmdEndQuery-None-01923";
9849                     vuid_protected_cb = "VUID-vkCmdEndQuery-commandBuffer-01886";
9850                 }
9851             };
9852             EndQueryVuids vuids;
9853             skip |= ValidateCmdEndQuery(cb_state.get(), query_obj, 0, CMD_ENDQUERY, &vuids);
9854         }
9855     }
9856     return skip;
9857 }
9858 
PreCallRecordCmdEndQuery(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t slot)9859 void CoreChecks::PreCallRecordCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
9860     if (disabled[query_validation]) return;
9861     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9862     QueryObject query_obj = {queryPool, slot};
9863     query_obj.endCommandIndex = cb_state->commandCount - 1;
9864     EnqueueVerifyEndQuery(commandBuffer, query_obj);
9865 }
9866 
ValidateQueryPoolIndex(VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,const char * func_name,const char * first_vuid,const char * sum_vuid) const9867 bool CoreChecks::ValidateQueryPoolIndex(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, const char *func_name,
9868                                         const char *first_vuid, const char *sum_vuid) const {
9869     bool skip = false;
9870     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
9871     if (query_pool_state) {
9872         const uint32_t available_query_count = query_pool_state->createInfo.queryCount;
9873         if (firstQuery >= available_query_count) {
9874             skip |= LogError(queryPool, first_vuid,
9875                              "%s: In Query %s the firstQuery (%u) is greater or equal to the queryPool size (%u).", func_name,
9876                              report_data->FormatHandle(queryPool).c_str(), firstQuery, available_query_count);
9877         }
9878         if ((firstQuery + queryCount) > available_query_count) {
9879             skip |=
9880                 LogError(queryPool, sum_vuid,
9881                          "%s: In Query %s the sum of firstQuery (%u) + queryCount (%u) is greater than the queryPool size (%u).",
9882                          func_name, report_data->FormatHandle(queryPool).c_str(), firstQuery, queryCount, available_query_count);
9883         }
9884     }
9885     return skip;
9886 }
9887 
PreCallValidateCmdResetQueryPool(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount) const9888 bool CoreChecks::PreCallValidateCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
9889                                                   uint32_t queryCount) const {
9890     if (disabled[query_validation]) return false;
9891     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9892     assert(cb_state);
9893 
9894     bool skip = false;
9895     skip |= ValidateCmd(cb_state.get(), CMD_RESETQUERYPOOL);
9896     skip |= ValidateQueryPoolIndex(queryPool, firstQuery, queryCount, "VkCmdResetQueryPool()",
9897                                    "VUID-vkCmdResetQueryPool-firstQuery-00796", "VUID-vkCmdResetQueryPool-firstQuery-00797");
9898 
9899     return skip;
9900 }
9901 
GetQueryResultType(QueryState state,VkQueryResultFlags flags)9902 static QueryResultType GetQueryResultType(QueryState state, VkQueryResultFlags flags) {
9903     switch (state) {
9904         case QUERYSTATE_UNKNOWN:
9905             return QUERYRESULT_UNKNOWN;
9906         case QUERYSTATE_RESET:
9907         case QUERYSTATE_RUNNING:
9908             if (flags & VK_QUERY_RESULT_WAIT_BIT) {
9909                 return ((state == QUERYSTATE_RESET) ? QUERYRESULT_WAIT_ON_RESET : QUERYRESULT_WAIT_ON_RUNNING);
9910             } else if ((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) {
9911                 return QUERYRESULT_SOME_DATA;
9912             } else {
9913                 return QUERYRESULT_NO_DATA;
9914             }
9915         case QUERYSTATE_ENDED:
9916             if ((flags & VK_QUERY_RESULT_WAIT_BIT) || (flags & VK_QUERY_RESULT_PARTIAL_BIT) ||
9917                 (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) {
9918                 return QUERYRESULT_SOME_DATA;
9919             } else {
9920                 return QUERYRESULT_UNKNOWN;
9921             }
9922         case QUERYSTATE_AVAILABLE:
9923             return QUERYRESULT_SOME_DATA;
9924     }
9925     assert(false);
9926     return QUERYRESULT_UNKNOWN;
9927 }
9928 
ValidateCopyQueryPoolResults(const ValidationStateTracker * state_data,VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,uint32_t perfPass,VkQueryResultFlags flags,QueryMap * localQueryToStateMap)9929 bool CoreChecks::ValidateCopyQueryPoolResults(const ValidationStateTracker *state_data, VkCommandBuffer commandBuffer,
9930                                               VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, uint32_t perfPass,
9931                                               VkQueryResultFlags flags, QueryMap *localQueryToStateMap) {
9932     bool skip = false;
9933     for (uint32_t i = 0; i < queryCount; i++) {
9934         QueryState state = GetLocalQueryState(localQueryToStateMap, queryPool, firstQuery + i, perfPass);
9935         QueryResultType result_type = GetQueryResultType(state, flags);
9936         if (result_type != QUERYRESULT_SOME_DATA && result_type != QUERYRESULT_UNKNOWN) {
9937             skip |= state_data->LogError(
9938                 commandBuffer, kVUID_Core_DrawState_InvalidQuery,
9939                 "vkCmdCopyQueryPoolResults(): Requesting a copy from query to buffer on %s query %" PRIu32 ": %s",
9940                 state_data->report_data->FormatHandle(queryPool).c_str(), firstQuery + i, string_QueryResultType(result_type));
9941         }
9942     }
9943     return skip;
9944 }
9945 
PreCallValidateCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,VkBuffer dstBuffer,VkDeviceSize dstOffset,VkDeviceSize stride,VkQueryResultFlags flags) const9946 bool CoreChecks::PreCallValidateCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
9947                                                         uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
9948                                                         VkDeviceSize stride, VkQueryResultFlags flags) const {
9949     if (disabled[query_validation]) return false;
9950     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
9951     const auto dst_buff_state = Get<BUFFER_STATE>(dstBuffer);
9952     assert(cb_state);
9953     assert(dst_buff_state);
9954     bool skip = ValidateMemoryIsBoundToBuffer(dst_buff_state.get(), "vkCmdCopyQueryPoolResults()",
9955                                               "VUID-vkCmdCopyQueryPoolResults-dstBuffer-00826");
9956     skip |= ValidateQueryPoolStride("VUID-vkCmdCopyQueryPoolResults-flags-00822", "VUID-vkCmdCopyQueryPoolResults-flags-00823",
9957                                     stride, "dstOffset", dstOffset, flags);
9958     // Validate that DST buffer has correct usage flags set
9959     skip |= ValidateBufferUsageFlags(dst_buff_state.get(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
9960                                      "VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825", "vkCmdCopyQueryPoolResults()",
9961                                      "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
9962     skip |= ValidateCmd(cb_state.get(), CMD_COPYQUERYPOOLRESULTS);
9963     skip |= ValidateQueryPoolIndex(queryPool, firstQuery, queryCount, "vkCmdCopyQueryPoolResults()",
9964                                    "VUID-vkCmdCopyQueryPoolResults-firstQuery-00820",
9965                                    "VUID-vkCmdCopyQueryPoolResults-firstQuery-00821");
9966 
9967     if (dstOffset >= dst_buff_state->requirements.size) {
9968         skip |= LogError(commandBuffer, "VUID-vkCmdCopyQueryPoolResults-dstOffset-00819",
9969                          "vkCmdCopyQueryPoolResults() dstOffset (0x%" PRIxLEAST64 ") is not less than the size (0x%" PRIxLEAST64
9970                          ") of buffer (%s).",
9971                          dstOffset, dst_buff_state->requirements.size, report_data->FormatHandle(dst_buff_state->buffer()).c_str());
9972     } else if (dstOffset + (queryCount * stride) > dst_buff_state->requirements.size) {
9973         skip |=
9974             LogError(commandBuffer, "VUID-vkCmdCopyQueryPoolResults-dstBuffer-00824",
9975                      "vkCmdCopyQueryPoolResults() storage required (0x%" PRIxLEAST64
9976                      ") equal to dstOffset + (queryCount * stride) is greater than the size (0x%" PRIxLEAST64 ") of buffer (%s).",
9977                      dstOffset + (queryCount * stride), dst_buff_state->requirements.size,
9978                      report_data->FormatHandle(dst_buff_state->buffer()).c_str());
9979     }
9980 
9981     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
9982     if (query_pool_state) {
9983         if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR) {
9984             skip |=
9985                 ValidatePerformanceQueryResults("vkCmdCopyQueryPoolResults", query_pool_state.get(), firstQuery, queryCount, flags);
9986             if (!phys_dev_ext_props.performance_query_props.allowCommandBufferQueryCopies) {
9987                 skip |= LogError(commandBuffer, "VUID-vkCmdCopyQueryPoolResults-queryType-03232",
9988                                  "vkCmdCopyQueryPoolResults called with query pool %s but "
9989                                  "VkPhysicalDevicePerformanceQueryPropertiesKHR::allowCommandBufferQueryCopies "
9990                                  "is not set.",
9991                                  report_data->FormatHandle(queryPool).c_str());
9992             }
9993         }
9994         if ((query_pool_state->createInfo.queryType == VK_QUERY_TYPE_TIMESTAMP) && ((flags & VK_QUERY_RESULT_PARTIAL_BIT) != 0)) {
9995             skip |= LogError(commandBuffer, "VUID-vkCmdCopyQueryPoolResults-queryType-00827",
9996                              "vkCmdCopyQueryPoolResults() query pool %s was created with VK_QUERY_TYPE_TIMESTAMP so flags must not "
9997                              "contain VK_QUERY_RESULT_PARTIAL_BIT.",
9998                              report_data->FormatHandle(queryPool).c_str());
9999         }
10000         if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL) {
10001             skip |= LogError(queryPool, "VUID-vkCmdCopyQueryPoolResults-queryType-02734",
10002                              "vkCmdCopyQueryPoolResults() called but QueryPool %s was created with queryType "
10003                              "VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL.",
10004                              report_data->FormatHandle(queryPool).c_str());
10005         }
10006         if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR ||
10007             query_pool_state->createInfo.queryType == VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR) {
10008             skip |=
10009                 LogError(queryPool, "VUID-vkCmdCopyQueryPoolResults-queryType-04812",
10010                          "vkCmdCopyQueryPoolResults(): called but QueryPool %s was created with queryType "
10011                          "%s.",
10012                          report_data->FormatHandle(queryPool).c_str(), string_VkQueryType(query_pool_state->createInfo.queryType));
10013         }
10014     }
10015 
10016     return skip;
10017 }
10018 
PreCallRecordCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,VkBuffer dstBuffer,VkDeviceSize dstOffset,VkDeviceSize stride,VkQueryResultFlags flags)10019 void CoreChecks::PreCallRecordCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery,
10020                                                       uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset,
10021                                                       VkDeviceSize stride, VkQueryResultFlags flags) {
10022     if (disabled[query_validation]) return;
10023     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10024     cb_state->queryUpdates.emplace_back([commandBuffer, queryPool, firstQuery, queryCount, flags](
10025                                             const ValidationStateTracker *device_data, bool do_validate,
10026                                             VkQueryPool &firstPerfQueryPool, uint32_t perfPass, QueryMap *localQueryToStateMap) {
10027         if (!do_validate) return false;
10028         return ValidateCopyQueryPoolResults(device_data, commandBuffer, queryPool, firstQuery, queryCount, perfPass, flags,
10029                                             localQueryToStateMap);
10030     });
10031 }
10032 
PreCallValidateCmdPushConstants(VkCommandBuffer commandBuffer,VkPipelineLayout layout,VkShaderStageFlags stageFlags,uint32_t offset,uint32_t size,const void * pValues) const10033 bool CoreChecks::PreCallValidateCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout,
10034                                                  VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
10035                                                  const void *pValues) const {
10036     bool skip = false;
10037     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10038     assert(cb_state);
10039     skip |= ValidateCmd(cb_state.get(), CMD_PUSHCONSTANTS);
10040 
10041     // Check if pipeline_layout VkPushConstantRange(s) overlapping offset, size have stageFlags set for each stage in the command
10042     // stageFlags argument, *and* that the command stageFlags argument has bits set for the stageFlags in each overlapping range.
10043     if (!skip) {
10044         auto layout_state = Get<PIPELINE_LAYOUT_STATE>(layout);
10045         const auto &ranges = *layout_state->push_constant_ranges;
10046         VkShaderStageFlags found_stages = 0;
10047         for (const auto &range : ranges) {
10048             if ((offset >= range.offset) && (offset + size <= range.offset + range.size)) {
10049                 VkShaderStageFlags matching_stages = range.stageFlags & stageFlags;
10050                 if (matching_stages != range.stageFlags) {
10051                     skip |=
10052                         LogError(commandBuffer, "VUID-vkCmdPushConstants-offset-01796",
10053                                  "vkCmdPushConstants(): stageFlags (%s, offset (%" PRIu32 "), and size (%" PRIu32
10054                                  "),  must contain all stages in overlapping VkPushConstantRange stageFlags (%s), offset (%" PRIu32
10055                                  "), and size (%" PRIu32 ") in %s.",
10056                                  string_VkShaderStageFlags(stageFlags).c_str(), offset, size,
10057                                  string_VkShaderStageFlags(range.stageFlags).c_str(), range.offset, range.size,
10058                                  report_data->FormatHandle(layout).c_str());
10059                 }
10060 
10061                 // Accumulate all stages we've found
10062                 found_stages = matching_stages | found_stages;
10063             }
10064         }
10065         if (found_stages != stageFlags) {
10066             uint32_t missing_stages = ~found_stages & stageFlags;
10067             skip |= LogError(
10068                 commandBuffer, "VUID-vkCmdPushConstants-offset-01795",
10069                 "vkCmdPushConstants(): %s, VkPushConstantRange in %s overlapping offset = %d and size = %d, do not contain %s.",
10070                 string_VkShaderStageFlags(stageFlags).c_str(), report_data->FormatHandle(layout).c_str(), offset, size,
10071                 string_VkShaderStageFlags(missing_stages).c_str());
10072         }
10073     }
10074     return skip;
10075 }
10076 
PreCallValidateCmdWriteTimestamp(VkCommandBuffer commandBuffer,VkPipelineStageFlagBits pipelineStage,VkQueryPool queryPool,uint32_t slot) const10077 bool CoreChecks::PreCallValidateCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
10078                                                   VkQueryPool queryPool, uint32_t slot) const {
10079     if (disabled[query_validation]) return false;
10080     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10081     assert(cb_state);
10082     bool skip = false;
10083     skip |= ValidateCmd(cb_state.get(), CMD_WRITETIMESTAMP);
10084 
10085     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
10086     if ((query_pool_state != nullptr) && (query_pool_state->createInfo.queryType != VK_QUERY_TYPE_TIMESTAMP)) {
10087         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp-queryPool-01416",
10088                          "vkCmdWriteTimestamp(): Query Pool %s was not created with VK_QUERY_TYPE_TIMESTAMP.",
10089                          report_data->FormatHandle(queryPool).c_str());
10090     }
10091 
10092     const uint32_t timestamp_valid_bits =
10093         physical_device_state->queue_family_properties[cb_state->command_pool->queueFamilyIndex].timestampValidBits;
10094     if (timestamp_valid_bits == 0) {
10095         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp-timestampValidBits-00829",
10096                          "vkCmdWriteTimestamp(): Query Pool %s has a timestampValidBits value of zero.",
10097                          report_data->FormatHandle(queryPool).c_str());
10098     }
10099 
10100     if ((query_pool_state != nullptr) && (slot >= query_pool_state->createInfo.queryCount)) {
10101         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp-query-04904",
10102                          "vkCmdWriteTimestamp(): query (%" PRIu32 ") is not lower than the number of queries (%" PRIu32
10103                          ") in Query pool %s.",
10104                          slot, query_pool_state->createInfo.queryCount, report_data->FormatHandle(queryPool).c_str());
10105     }
10106 
10107     return skip;
10108 }
10109 
PreCallValidateCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer,VkPipelineStageFlags2KHR stage,VkQueryPool queryPool,uint32_t slot) const10110 bool CoreChecks::PreCallValidateCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR stage,
10111                                                       VkQueryPool queryPool, uint32_t slot) const {
10112     if (disabled[query_validation]) return false;
10113     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10114     assert(cb_state);
10115     bool skip = false;
10116     if (!enabled_features.synchronization2_features.synchronization2) {
10117         skip |= LogError(commandBuffer, "VUID-vkCmdWriteTimestamp2KHR-synchronization2-03858",
10118                          "vkCmdWriteTimestamp2KHR(): Synchronization2 feature is not enabled");
10119     }
10120     skip |= ValidateCmd(cb_state.get(), CMD_WRITETIMESTAMP);
10121 
10122     Location loc(Func::vkCmdWriteTimestamp2KHR, Field::stage);
10123     if ((stage & (stage - 1)) != 0) {
10124         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp2KHR-stage-03859",
10125                          "%s (%s) must only set a single pipeline stage.", loc.Message().c_str(),
10126                          string_VkPipelineStageFlags2KHR(stage).c_str());
10127     }
10128     skip |= ValidatePipelineStage(LogObjectList(cb_state->commandBuffer()), loc, cb_state->GetQueueFlags(), stage);
10129 
10130     loc.field = Field::queryPool;
10131     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
10132     if (query_pool_state) {
10133         if (query_pool_state->createInfo.queryType != VK_QUERY_TYPE_TIMESTAMP) {
10134             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp2KHR-queryPool-03861",
10135                              "%s Query Pool %s was not created with VK_QUERY_TYPE_TIMESTAMP.", loc.Message().c_str(),
10136                              report_data->FormatHandle(queryPool).c_str());
10137         }
10138 
10139         if (slot >= query_pool_state->createInfo.queryCount) {
10140             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp2KHR-query-04903",
10141                              "vkCmdWriteTimestamp2KHR(): query (%" PRIu32 ") is not lower than the number of queries (%" PRIu32
10142                              ") in Query pool %s.",
10143                              slot, query_pool_state->createInfo.queryCount, report_data->FormatHandle(queryPool).c_str());
10144         }
10145     }
10146 
10147     const uint32_t timestampValidBits =
10148         physical_device_state->queue_family_properties[cb_state->command_pool->queueFamilyIndex].timestampValidBits;
10149     if (timestampValidBits == 0) {
10150         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdWriteTimestamp2KHR-timestampValidBits-03863",
10151                          "%s Query Pool %s has a timestampValidBits value of zero.", loc.Message().c_str(),
10152                          report_data->FormatHandle(queryPool).c_str());
10153     }
10154 
10155     return skip;
10156 }
10157 
PreCallRecordCmdWriteTimestamp(VkCommandBuffer commandBuffer,VkPipelineStageFlagBits pipelineStage,VkQueryPool queryPool,uint32_t slot)10158 void CoreChecks::PreCallRecordCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage,
10159                                                 VkQueryPool queryPool, uint32_t slot) {
10160     if (disabled[query_validation]) return;
10161     // Enqueue the submit time validation check here, before the submit time state update in StateTracker::PostCall...
10162     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10163     QueryObject query = {queryPool, slot};
10164     const char *func_name = "vkCmdWriteTimestamp()";
10165     cb_state->queryUpdates.emplace_back([commandBuffer, query, func_name](const ValidationStateTracker *device_data,
10166                                                                           bool do_validate, VkQueryPool &firstPerfQueryPool,
10167                                                                           uint32_t perfPass, QueryMap *localQueryToStateMap) {
10168         if (!do_validate) return false;
10169         return VerifyQueryIsReset(device_data, commandBuffer, query, func_name, firstPerfQueryPool, perfPass, localQueryToStateMap);
10170     });
10171 }
10172 
PreCallRecordCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer,VkPipelineStageFlags2KHR pipelineStage,VkQueryPool queryPool,uint32_t slot)10173 void CoreChecks::PreCallRecordCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineStageFlags2KHR pipelineStage,
10174                                                     VkQueryPool queryPool, uint32_t slot) {
10175     if (disabled[query_validation]) return;
10176     // Enqueue the submit time validation check here, before the submit time state update in StateTracker::PostCall...
10177     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10178     QueryObject query = {queryPool, slot};
10179     const char *func_name = "vkCmdWriteTimestamp()";
10180     cb_state->queryUpdates.emplace_back([commandBuffer, query, func_name](const ValidationStateTracker *device_data,
10181                                                                           bool do_validate, VkQueryPool &firstPerfQueryPool,
10182                                                                           uint32_t perfPass, QueryMap *localQueryToStateMap) {
10183         if (!do_validate) return false;
10184         return VerifyQueryIsReset(device_data, commandBuffer, query, func_name, firstPerfQueryPool, perfPass, localQueryToStateMap);
10185     });
10186 }
10187 
PreCallRecordCmdWriteAccelerationStructuresPropertiesKHR(VkCommandBuffer commandBuffer,uint32_t accelerationStructureCount,const VkAccelerationStructureKHR * pAccelerationStructures,VkQueryType queryType,VkQueryPool queryPool,uint32_t firstQuery)10188 void CoreChecks::PreCallRecordCmdWriteAccelerationStructuresPropertiesKHR(VkCommandBuffer commandBuffer,
10189                                                                           uint32_t accelerationStructureCount,
10190                                                                           const VkAccelerationStructureKHR *pAccelerationStructures,
10191                                                                           VkQueryType queryType, VkQueryPool queryPool,
10192                                                                           uint32_t firstQuery) {
10193     if (disabled[query_validation]) return;
10194     // Enqueue the submit time validation check here, before the submit time state update in StateTracker::PostCall...
10195     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
10196     const char *func_name = "vkCmdWriteAccelerationStructuresPropertiesKHR()";
10197     cb_state->queryUpdates.emplace_back([accelerationStructureCount, commandBuffer, firstQuery, func_name, queryPool](
10198                                             const ValidationStateTracker *device_data, bool do_validate,
10199                                             VkQueryPool &firstPerfQueryPool, uint32_t perfPass, QueryMap *localQueryToStateMap) {
10200         if (!do_validate) return false;
10201         bool skip = false;
10202         for (uint32_t i = 0; i < accelerationStructureCount; i++) {
10203             QueryObject query = {{queryPool, firstQuery + i}, perfPass};
10204             skip |= VerifyQueryIsReset(device_data, commandBuffer, query, func_name, firstPerfQueryPool, perfPass,
10205                                        localQueryToStateMap);
10206         }
10207         return skip;
10208     });
10209 }
10210 
MatchUsage(uint32_t count,const VkAttachmentReference2 * attachments,const VkFramebufferCreateInfo * fbci,VkImageUsageFlagBits usage_flag,const char * error_code) const10211 bool CoreChecks::MatchUsage(uint32_t count, const VkAttachmentReference2 *attachments, const VkFramebufferCreateInfo *fbci,
10212                             VkImageUsageFlagBits usage_flag, const char *error_code) const {
10213     bool skip = false;
10214 
10215     if (attachments) {
10216         for (uint32_t attach = 0; attach < count; attach++) {
10217             if (attachments[attach].attachment != VK_ATTACHMENT_UNUSED) {
10218                 // Attachment counts are verified elsewhere, but prevent an invalid access
10219                 if (attachments[attach].attachment < fbci->attachmentCount) {
10220                     if ((fbci->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) == 0) {
10221                         const VkImageView *image_view = &fbci->pAttachments[attachments[attach].attachment];
10222                         auto view_state = Get<IMAGE_VIEW_STATE>(*image_view);
10223                         if (view_state) {
10224                             const auto &ici = view_state->image_state->createInfo;
10225                             auto creation_usage = ici.usage;
10226                             const auto stencil_usage_info = LvlFindInChain<VkImageStencilUsageCreateInfo>(ici.pNext);
10227                             if (stencil_usage_info) {
10228                                 creation_usage |= stencil_usage_info->stencilUsage;
10229                             }
10230                             if ((creation_usage & usage_flag) == 0) {
10231                                 skip |= LogError(device, error_code,
10232                                                  "vkCreateFramebuffer:  Framebuffer Attachment (%d) conflicts with the image's "
10233                                                  "IMAGE_USAGE flags (%s).",
10234                                                  attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag));
10235                             }
10236                         }
10237                     } else {
10238                         const VkFramebufferAttachmentsCreateInfo *fbaci =
10239                             LvlFindInChain<VkFramebufferAttachmentsCreateInfo>(fbci->pNext);
10240                         if (fbaci != nullptr && fbaci->pAttachmentImageInfos != nullptr &&
10241                             fbaci->attachmentImageInfoCount > attachments[attach].attachment) {
10242                             uint32_t image_usage = fbaci->pAttachmentImageInfos[attachments[attach].attachment].usage;
10243                             if ((image_usage & usage_flag) == 0) {
10244                                 skip |=
10245                                     LogError(device, error_code,
10246                                              "vkCreateFramebuffer:  Framebuffer attachment info (%d) conflicts with the image's "
10247                                              "IMAGE_USAGE flags (%s).",
10248                                              attachments[attach].attachment, string_VkImageUsageFlagBits(usage_flag));
10249                             }
10250                         }
10251                     }
10252                 }
10253             }
10254         }
10255     }
10256     return skip;
10257 }
10258 
ValidateFramebufferCreateInfo(const VkFramebufferCreateInfo * pCreateInfo) const10259 bool CoreChecks::ValidateFramebufferCreateInfo(const VkFramebufferCreateInfo *pCreateInfo) const {
10260     bool skip = false;
10261 
10262     const VkFramebufferAttachmentsCreateInfo *framebuffer_attachments_create_info =
10263         LvlFindInChain<VkFramebufferAttachmentsCreateInfo>(pCreateInfo->pNext);
10264     if ((pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) != 0) {
10265         if (!enabled_features.core12.imagelessFramebuffer) {
10266             skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-03189",
10267                              "vkCreateFramebuffer(): VkFramebufferCreateInfo flags includes VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, "
10268                              "but the imagelessFramebuffer feature is not enabled.");
10269         }
10270 
10271         if (framebuffer_attachments_create_info == nullptr) {
10272             skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-03190",
10273                              "vkCreateFramebuffer(): VkFramebufferCreateInfo flags includes VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, "
10274                              "but no instance of VkFramebufferAttachmentsCreateInfo is present in the pNext chain.");
10275         } else {
10276             if (framebuffer_attachments_create_info->attachmentImageInfoCount != 0 &&
10277                 framebuffer_attachments_create_info->attachmentImageInfoCount != pCreateInfo->attachmentCount) {
10278                 skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-03191",
10279                                  "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount is %u, but "
10280                                  "VkFramebufferAttachmentsCreateInfo attachmentImageInfoCount is %u.",
10281                                  pCreateInfo->attachmentCount, framebuffer_attachments_create_info->attachmentImageInfoCount);
10282             }
10283         }
10284     }
10285     if (framebuffer_attachments_create_info) {
10286         for (uint32_t i = 0; i < framebuffer_attachments_create_info->attachmentImageInfoCount; ++i) {
10287             if (framebuffer_attachments_create_info->pAttachmentImageInfos[i].pNext != nullptr) {
10288                 skip |= LogError(device, "VUID-VkFramebufferAttachmentImageInfo-pNext-pNext",
10289                                  "vkCreateFramebuffer(): VkFramebufferAttachmentsCreateInfo[%" PRIu32 "].pNext is not NULL.", i);
10290             }
10291         }
10292     }
10293 
10294     auto rp_state = Get<RENDER_PASS_STATE>(pCreateInfo->renderPass);
10295     if (rp_state) {
10296         const VkRenderPassCreateInfo2 *rpci = rp_state->createInfo.ptr();
10297         if (rpci->attachmentCount != pCreateInfo->attachmentCount) {
10298             skip |= LogError(pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-attachmentCount-00876",
10299                              "vkCreateFramebuffer(): VkFramebufferCreateInfo attachmentCount of %u does not match attachmentCount "
10300                              "of %u of %s being used to create Framebuffer.",
10301                              pCreateInfo->attachmentCount, rpci->attachmentCount,
10302                              report_data->FormatHandle(pCreateInfo->renderPass).c_str());
10303         } else {
10304             // attachmentCounts match, so make sure corresponding attachment details line up
10305             if ((pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) == 0) {
10306                 const VkImageView *image_views = pCreateInfo->pAttachments;
10307                 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
10308                     auto view_state = Get<IMAGE_VIEW_STATE>(image_views[i]);
10309                     if (view_state == nullptr) {
10310                         skip |= LogError(
10311                             image_views[i], "VUID-VkFramebufferCreateInfo-flags-02778",
10312                             "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u is not a valid VkImageView.", i);
10313                     } else {
10314                         auto &ivci = view_state->create_info;
10315                         auto &subresource_range = view_state->normalized_subresource_range;
10316                         if (ivci.format != rpci->pAttachments[i].format) {
10317                             skip |= LogError(
10318                                 pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-pAttachments-00880",
10319                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has format of %s that does not "
10320                                 "match the format of %s used by the corresponding attachment for %s.",
10321                                 i, string_VkFormat(ivci.format), string_VkFormat(rpci->pAttachments[i].format),
10322                                 report_data->FormatHandle(pCreateInfo->renderPass).c_str());
10323                         }
10324                         const auto &ici = view_state->image_state->createInfo;
10325                         if (ici.samples != rpci->pAttachments[i].samples) {
10326                             skip |=
10327                                 LogError(pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-pAttachments-00881",
10328                                          "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has %s samples that do not "
10329                                          "match the %s "
10330                                          "samples used by the corresponding attachment for %s.",
10331                                          i, string_VkSampleCountFlagBits(ici.samples),
10332                                          string_VkSampleCountFlagBits(rpci->pAttachments[i].samples),
10333                                          report_data->FormatHandle(pCreateInfo->renderPass).c_str());
10334                         }
10335 
10336                         // Verify that image memory is valid
10337                         auto image_data = Get<IMAGE_STATE>(ivci.image);
10338                         skip |= ValidateMemoryIsBoundToImage(image_data.get(), "vkCreateFramebuffer()",
10339                                                              kVUID_Core_Bound_Resource_FreedMemoryAccess);
10340 
10341                         // Verify that view only has a single mip level
10342                         if (subresource_range.levelCount != 1) {
10343                             skip |= LogError(
10344                                 device, "VUID-VkFramebufferCreateInfo-pAttachments-00883",
10345                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has mip levelCount of %u but "
10346                                 "only a single mip level (levelCount ==  1) is allowed when creating a Framebuffer.",
10347                                 i, subresource_range.levelCount);
10348                         }
10349                         const uint32_t mip_level = subresource_range.baseMipLevel;
10350                         uint32_t mip_width = max(1u, ici.extent.width >> mip_level);
10351                         uint32_t mip_height = max(1u, ici.extent.height >> mip_level);
10352                         bool used_as_input_color_resolve_depth_stencil_attachment = false;
10353                         bool used_as_fragment_shading_rate_attachment = false;
10354                         bool fsr_non_zero_viewmasks = false;
10355 
10356                         for (uint32_t j = 0; j < rpci->subpassCount; ++j) {
10357                             const VkSubpassDescription2 &subpass = rpci->pSubpasses[j];
10358 
10359                             uint32_t highest_view_bit = MostSignificantBit(subpass.viewMask);
10360 
10361                             for (uint32_t k = 0; k < rpci->pSubpasses[j].inputAttachmentCount; ++k) {
10362                                 if (subpass.pInputAttachments[k].attachment == i) {
10363                                     used_as_input_color_resolve_depth_stencil_attachment = true;
10364                                     break;
10365                                 }
10366                             }
10367 
10368                             for (uint32_t k = 0; k < rpci->pSubpasses[j].colorAttachmentCount; ++k) {
10369                                 if (subpass.pColorAttachments[k].attachment == i ||
10370                                     (subpass.pResolveAttachments && subpass.pResolveAttachments[k].attachment == i)) {
10371                                     used_as_input_color_resolve_depth_stencil_attachment = true;
10372                                     break;
10373                                 }
10374                             }
10375 
10376                             if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment == i) {
10377                                 used_as_input_color_resolve_depth_stencil_attachment = true;
10378                             }
10379 
10380                             if (used_as_input_color_resolve_depth_stencil_attachment) {
10381                                 if (subresource_range.layerCount <= highest_view_bit) {
10382                                     skip |= LogError(
10383                                         device, "VUID-VkFramebufferCreateInfo-renderPass-04536",
10384                                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has a layer count (%u) "
10385                                         "less than or equal to the highest bit in the view mask (%u) of subpass %u.",
10386                                         i, subresource_range.layerCount, highest_view_bit, j);
10387                                 }
10388                             }
10389 
10390                             if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
10391                                 const VkFragmentShadingRateAttachmentInfoKHR *fsr_attachment;
10392                                 fsr_attachment = LvlFindInChain<VkFragmentShadingRateAttachmentInfoKHR>(subpass.pNext);
10393                                 if (fsr_attachment && fsr_attachment->pFragmentShadingRateAttachment &&
10394                                     fsr_attachment->pFragmentShadingRateAttachment->attachment == i) {
10395                                     used_as_fragment_shading_rate_attachment = true;
10396                                     if ((mip_width * fsr_attachment->shadingRateAttachmentTexelSize.width) < pCreateInfo->width) {
10397                                         skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-04539",
10398                                                          "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level "
10399                                                          "%u is used as a "
10400                                                          "fragment shading rate attachment in subpass %u, but the product of its "
10401                                                          "width (%u) and the "
10402                                                          "specified shading rate texel width (%u) are smaller than the "
10403                                                          "corresponding framebuffer width (%u).",
10404                                                          i, subresource_range.baseMipLevel, j, mip_width,
10405                                                          fsr_attachment->shadingRateAttachmentTexelSize.width, pCreateInfo->width);
10406                                     }
10407                                     if ((mip_height * fsr_attachment->shadingRateAttachmentTexelSize.height) <
10408                                         pCreateInfo->height) {
10409                                         skip |=
10410                                             LogError(device, "VUID-VkFramebufferCreateInfo-flags-04540",
10411                                                      "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u "
10412                                                      "is used as a "
10413                                                      "fragment shading rate attachment in subpass %u, but the product of its "
10414                                                      "height (%u) and the "
10415                                                      "specified shading rate texel height (%u) are smaller than the corresponding "
10416                                                      "framebuffer height (%u).",
10417                                                      i, subresource_range.baseMipLevel, j, mip_height,
10418                                                      fsr_attachment->shadingRateAttachmentTexelSize.height, pCreateInfo->height);
10419                                     }
10420                                     if (highest_view_bit != 0) {
10421                                         fsr_non_zero_viewmasks = true;
10422                                     }
10423                                     if (subresource_range.layerCount <= highest_view_bit) {
10424                                         skip |= LogError(
10425                                             device, "VUID-VkFramebufferCreateInfo-flags-04537",
10426                                             "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has a layer count (%u) "
10427                                             "less than or equal to the highest bit in the view mask (%u) of subpass %u.",
10428                                             i, subresource_range.layerCount, highest_view_bit, j);
10429                                     }
10430                                 }
10431                             }
10432                         }
10433 
10434                         if (enabled_features.fragment_density_map_features.fragmentDensityMap) {
10435                             const VkRenderPassFragmentDensityMapCreateInfoEXT *fdm_attachment;
10436                             fdm_attachment = LvlFindInChain<VkRenderPassFragmentDensityMapCreateInfoEXT>(rpci->pNext);
10437                             if (fdm_attachment && fdm_attachment->fragmentDensityMapAttachment.attachment == i) {
10438                                 uint32_t ceiling_width = static_cast<uint32_t>(ceil(
10439                                     static_cast<float>(pCreateInfo->width) /
10440                                     std::max(static_cast<float>(
10441                                                  phys_dev_ext_props.fragment_density_map_props.maxFragmentDensityTexelSize.width),
10442                                              1.0f)));
10443                                 if (mip_width < ceiling_width) {
10444                                     skip |= LogError(
10445                                         device, "VUID-VkFramebufferCreateInfo-pAttachments-02555",
10446                                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has width "
10447                                         "smaller than the corresponding the ceiling of framebuffer width / "
10448                                         "maxFragmentDensityTexelSize.width "
10449                                         "Here are the respective dimensions for attachment #%u, the ceiling value:\n "
10450                                         "attachment #%u, framebuffer:\n"
10451                                         "width: %u, the ceiling value: %u\n",
10452                                         i, subresource_range.baseMipLevel, i, i, mip_width, ceiling_width);
10453                                 }
10454                                 uint32_t ceiling_height = static_cast<uint32_t>(ceil(
10455                                     static_cast<float>(pCreateInfo->height) /
10456                                     std::max(static_cast<float>(
10457                                                  phys_dev_ext_props.fragment_density_map_props.maxFragmentDensityTexelSize.height),
10458                                              1.0f)));
10459                                 if (mip_height < ceiling_height) {
10460                                     skip |= LogError(
10461                                         device, "VUID-VkFramebufferCreateInfo-pAttachments-02556",
10462                                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has height "
10463                                         "smaller than the corresponding the ceiling of framebuffer height / "
10464                                         "maxFragmentDensityTexelSize.height "
10465                                         "Here are the respective dimensions for attachment #%u, the ceiling value:\n "
10466                                         "attachment #%u, framebuffer:\n"
10467                                         "height: %u, the ceiling value: %u\n",
10468                                         i, subresource_range.baseMipLevel, i, i, mip_height, ceiling_height);
10469                                 }
10470                                 if (view_state->normalized_subresource_range.layerCount != 1) {
10471                                     skip |= LogError(device, "VUID-VkFramebufferCreateInfo-pAttachments-02744",
10472                                                      "vkCreateFramebuffer(): pCreateInfo->pAttachments[%" PRIu32
10473                                                      "] is referenced by "
10474                                                      "VkRenderPassFragmentDensityMapCreateInfoEXT::fragmentDensityMapAttachment in "
10475                                                      "the pNext chain, but it was create with subresourceRange.layerCount (%" PRIu32
10476                                                      ") different from 1.",
10477                                                      i, view_state->normalized_subresource_range.layerCount);
10478                                 }
10479                             }
10480                         }
10481 
10482                         if (used_as_input_color_resolve_depth_stencil_attachment) {
10483                             if (mip_width < pCreateInfo->width) {
10484                                 skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-04533",
10485                                                  "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has "
10486                                                  "width (%u) smaller than the corresponding framebuffer width (%u).",
10487                                                  i, mip_level, mip_width, pCreateInfo->width);
10488                             }
10489                             if (mip_height < pCreateInfo->height) {
10490                                 skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-04534",
10491                                                  "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u mip level %u has "
10492                                                  "height (%u) smaller than the corresponding framebuffer height (%u).",
10493                                                  i, mip_level, mip_height, pCreateInfo->height);
10494                             }
10495                             uint32_t layerCount = view_state->create_info.subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS
10496                                                       ? view_state->image_state->createInfo.arrayLayers
10497                                                       : view_state->create_info.subresourceRange.layerCount;
10498                             if (layerCount < pCreateInfo->layers) {
10499                                 skip |=
10500                                     LogError(device, "VUID-VkFramebufferCreateInfo-flags-04535",
10501                                              "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has a layer count (%u) "
10502                                              "smaller than the corresponding framebuffer layer count (%u).",
10503                                              i, layerCount, pCreateInfo->layers);
10504                             }
10505                         }
10506 
10507                         if (used_as_fragment_shading_rate_attachment && !fsr_non_zero_viewmasks) {
10508                             if (subresource_range.layerCount != 1 && subresource_range.layerCount < pCreateInfo->layers) {
10509                                 skip |=
10510                                     LogError(device, "VUID-VkFramebufferCreateInfo-flags-04538",
10511                                              "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has a layer count (%u) "
10512                                              "smaller than the corresponding framebuffer layer count (%u).",
10513                                              i, subresource_range.layerCount, pCreateInfo->layers);
10514                             }
10515                         }
10516 
10517                         if (IsIdentitySwizzle(ivci.components) == false) {
10518                             skip |= LogError(
10519                                 device, "VUID-VkFramebufferCreateInfo-pAttachments-00884",
10520                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has non-identy swizzle. All "
10521                                 "framebuffer attachments must have been created with the identity swizzle. Here are the actual "
10522                                 "swizzle values:\n"
10523                                 "r swizzle = %s\n"
10524                                 "g swizzle = %s\n"
10525                                 "b swizzle = %s\n"
10526                                 "a swizzle = %s\n",
10527                                 i, string_VkComponentSwizzle(ivci.components.r), string_VkComponentSwizzle(ivci.components.g),
10528                                 string_VkComponentSwizzle(ivci.components.b), string_VkComponentSwizzle(ivci.components.a));
10529                         }
10530                         if ((ivci.viewType == VK_IMAGE_VIEW_TYPE_2D) || (ivci.viewType == VK_IMAGE_VIEW_TYPE_2D)) {
10531                             const auto image_state = Get<IMAGE_STATE>(ivci.image);
10532                             if (image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
10533                                 if (FormatIsDepthOrStencil(ivci.format)) {
10534                                     LogObjectList objlist(device);
10535                                     objlist.add(ivci.image);
10536                                     skip |= LogError(
10537                                         objlist, "VUID-VkFramebufferCreateInfo-pAttachments-00891",
10538                                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has an image view type of "
10539                                         "%s "
10540                                         "which was taken from image %s of type VK_IMAGE_TYPE_3D, but the image view format is a "
10541                                         "depth/stencil format %s",
10542                                         i, string_VkImageViewType(ivci.viewType), report_data->FormatHandle(ivci.image).c_str(),
10543                                         string_VkFormat(ivci.format));
10544                                 }
10545                             }
10546                         }
10547                         if (ivci.viewType == VK_IMAGE_VIEW_TYPE_3D) {
10548                             LogObjectList objlist(device);
10549                             objlist.add(image_views[i]);
10550                             skip |= LogError(objlist, "VUID-VkFramebufferCreateInfo-flags-04113",
10551                                              "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has an image view type "
10552                                              "of VK_IMAGE_VIEW_TYPE_3D",
10553                                              i);
10554                         }
10555                     }
10556                 }
10557             } else if (framebuffer_attachments_create_info) {
10558                 // VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT is set
10559                 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
10560                     auto &aii = framebuffer_attachments_create_info->pAttachmentImageInfos[i];
10561                     bool format_found = false;
10562                     for (uint32_t j = 0; j < aii.viewFormatCount; ++j) {
10563                         if (aii.pViewFormats[j] == rpci->pAttachments[i].format) {
10564                             format_found = true;
10565                         }
10566                     }
10567                     if (!format_found) {
10568                         skip |= LogError(pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-flags-03205",
10569                                          "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info #%u does not include "
10570                                          "format %s used "
10571                                          "by the corresponding attachment for renderPass (%s).",
10572                                          i, string_VkFormat(rpci->pAttachments[i].format),
10573                                          report_data->FormatHandle(pCreateInfo->renderPass).c_str());
10574                     }
10575 
10576                     bool used_as_input_color_resolve_depth_stencil_attachment = false;
10577                     bool used_as_fragment_shading_rate_attachment = false;
10578                     bool fsr_non_zero_viewmasks = false;
10579 
10580                     for (uint32_t j = 0; j < rpci->subpassCount; ++j) {
10581                         const VkSubpassDescription2 &subpass = rpci->pSubpasses[j];
10582 
10583                         uint32_t highest_view_bit = 0;
10584                         for (int k = 0; k < 32; ++k) {
10585                             if (((subpass.viewMask >> k) & 1) != 0) {
10586                                 highest_view_bit = k;
10587                             }
10588                         }
10589 
10590                         for (uint32_t k = 0; k < rpci->pSubpasses[j].inputAttachmentCount; ++k) {
10591                             if (subpass.pInputAttachments[k].attachment == i) {
10592                                 used_as_input_color_resolve_depth_stencil_attachment = true;
10593                                 break;
10594                             }
10595                         }
10596 
10597                         for (uint32_t k = 0; k < rpci->pSubpasses[j].colorAttachmentCount; ++k) {
10598                             if (subpass.pColorAttachments[k].attachment == i ||
10599                                 (subpass.pResolveAttachments && subpass.pResolveAttachments[k].attachment == i)) {
10600                                 used_as_input_color_resolve_depth_stencil_attachment = true;
10601                                 break;
10602                             }
10603                         }
10604 
10605                         if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment == i) {
10606                             used_as_input_color_resolve_depth_stencil_attachment = true;
10607                         }
10608 
10609                         if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
10610                             const VkFragmentShadingRateAttachmentInfoKHR *fsr_attachment;
10611                             fsr_attachment = LvlFindInChain<VkFragmentShadingRateAttachmentInfoKHR>(subpass.pNext);
10612                             if (fsr_attachment && fsr_attachment->pFragmentShadingRateAttachment->attachment == i) {
10613                                 used_as_fragment_shading_rate_attachment = true;
10614                                 if ((aii.width * fsr_attachment->shadingRateAttachmentTexelSize.width) < pCreateInfo->width) {
10615                                     skip |= LogError(
10616                                         device, "VUID-VkFramebufferCreateInfo-flags-04543",
10617                                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u is used as a "
10618                                         "fragment shading rate attachment in subpass %u, but the product of its width (%u) and the "
10619                                         "specified shading rate texel width (%u) are smaller than the corresponding framebuffer "
10620                                         "width (%u).",
10621                                         i, j, aii.width, fsr_attachment->shadingRateAttachmentTexelSize.width, pCreateInfo->width);
10622                                 }
10623                                 if ((aii.height * fsr_attachment->shadingRateAttachmentTexelSize.height) < pCreateInfo->height) {
10624                                     skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-04544",
10625                                                      "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u is used as a "
10626                                                      "fragment shading rate attachment in subpass %u, but the product of its "
10627                                                      "height (%u) and the "
10628                                                      "specified shading rate texel height (%u) are smaller than the corresponding "
10629                                                      "framebuffer height (%u).",
10630                                                      i, j, aii.height, fsr_attachment->shadingRateAttachmentTexelSize.height,
10631                                                      pCreateInfo->height);
10632                                 }
10633                                 if (highest_view_bit != 0) {
10634                                     fsr_non_zero_viewmasks = true;
10635                                 }
10636                                 if (aii.layerCount != 1 && aii.layerCount <= highest_view_bit) {
10637                                     skip |= LogError(
10638                                         device, kVUIDUndefined,
10639                                         "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has a layer count (%u) "
10640                                         "less than or equal to the highest bit in the view mask (%u) of subpass %u.",
10641                                         i, aii.layerCount, highest_view_bit, j);
10642                                 }
10643                             }
10644                         }
10645                     }
10646 
10647                     if (used_as_input_color_resolve_depth_stencil_attachment) {
10648                         if (aii.width < pCreateInfo->width) {
10649                             skip |= LogError(
10650                                 device, "VUID-VkFramebufferCreateInfo-flags-04541",
10651                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info #%u has a width of only #%u, "
10652                                 "but framebuffer has a width of #%u.",
10653                                 i, aii.width, pCreateInfo->width);
10654                         }
10655 
10656                         if (aii.height < pCreateInfo->height) {
10657                             skip |= LogError(
10658                                 device, "VUID-VkFramebufferCreateInfo-flags-04542",
10659                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info #%u has a height of only #%u, "
10660                                 "but framebuffer has a height of #%u.",
10661                                 i, aii.height, pCreateInfo->height);
10662                         }
10663 
10664                         const char *mismatched_layers_no_multiview_vuid = IsExtEnabled(device_extensions.vk_khr_multiview)
10665                                                                               ? "VUID-VkFramebufferCreateInfo-renderPass-04546"
10666                                                                               : "VUID-VkFramebufferCreateInfo-flags-04547";
10667                         if ((rpci->subpassCount == 0) || (rpci->pSubpasses[0].viewMask == 0)) {
10668                             if (aii.layerCount < pCreateInfo->layers) {
10669                                 skip |= LogError(
10670                                     device, mismatched_layers_no_multiview_vuid,
10671                                     "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info #%u has only #%u layers, "
10672                                     "but framebuffer has #%u layers.",
10673                                     i, aii.layerCount, pCreateInfo->layers);
10674                             }
10675                         }
10676                     }
10677 
10678                     if (used_as_fragment_shading_rate_attachment && !fsr_non_zero_viewmasks) {
10679                         if (aii.layerCount != 1 && aii.layerCount < pCreateInfo->layers) {
10680                             skip |= LogError(device, "VUID-VkFramebufferCreateInfo-flags-04545",
10681                                              "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment #%u has a layer count (%u) "
10682                                              "smaller than the corresponding framebuffer layer count (%u).",
10683                                              i, aii.layerCount, pCreateInfo->layers);
10684                         }
10685                     }
10686                 }
10687 
10688                 // Validate image usage
10689                 uint32_t attachment_index = VK_ATTACHMENT_UNUSED;
10690                 for (uint32_t i = 0; i < rpci->subpassCount; ++i) {
10691                     skip |= MatchUsage(rpci->pSubpasses[i].colorAttachmentCount, rpci->pSubpasses[i].pColorAttachments, pCreateInfo,
10692                                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-flags-03201");
10693                     skip |=
10694                         MatchUsage(rpci->pSubpasses[i].colorAttachmentCount, rpci->pSubpasses[i].pResolveAttachments, pCreateInfo,
10695                                    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-flags-03201");
10696                     skip |= MatchUsage(1, rpci->pSubpasses[i].pDepthStencilAttachment, pCreateInfo,
10697                                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-flags-03202");
10698                     skip |= MatchUsage(rpci->pSubpasses[i].inputAttachmentCount, rpci->pSubpasses[i].pInputAttachments, pCreateInfo,
10699                                        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-flags-03204");
10700 
10701                     const VkSubpassDescriptionDepthStencilResolve *depth_stencil_resolve =
10702                         LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(rpci->pSubpasses[i].pNext);
10703                     if (IsExtEnabled(device_extensions.vk_khr_depth_stencil_resolve) && depth_stencil_resolve != nullptr) {
10704                         skip |= MatchUsage(1, depth_stencil_resolve->pDepthStencilResolveAttachment, pCreateInfo,
10705                                            VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-flags-03203");
10706                     }
10707 
10708                     const VkFragmentShadingRateAttachmentInfoKHR *fragment_shading_rate_attachment_info =
10709                         LvlFindInChain<VkFragmentShadingRateAttachmentInfoKHR>(rpci->pSubpasses[i].pNext);
10710                     if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate &&
10711                         fragment_shading_rate_attachment_info != nullptr) {
10712                         skip |= MatchUsage(1, fragment_shading_rate_attachment_info->pFragmentShadingRateAttachment, pCreateInfo,
10713                                            VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
10714                                            "VUID-VkFramebufferCreateInfo-flags-04549");
10715                     }
10716                 }
10717 
10718                 if (IsExtEnabled(device_extensions.vk_khr_multiview)) {
10719                     if ((rpci->subpassCount > 0) && (rpci->pSubpasses[0].viewMask != 0)) {
10720                         for (uint32_t i = 0; i < rpci->subpassCount; ++i) {
10721                             const VkSubpassDescriptionDepthStencilResolve *depth_stencil_resolve =
10722                                 LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(rpci->pSubpasses[i].pNext);
10723                             uint32_t view_bits = rpci->pSubpasses[i].viewMask;
10724                             uint32_t highest_view_bit = 0;
10725 
10726                             for (int j = 0; j < 32; ++j) {
10727                                 if (((view_bits >> j) & 1) != 0) {
10728                                     highest_view_bit = j;
10729                                 }
10730                             }
10731 
10732                             for (uint32_t j = 0; j < rpci->pSubpasses[i].colorAttachmentCount; ++j) {
10733                                 attachment_index = rpci->pSubpasses[i].pColorAttachments[j].attachment;
10734                                 if (attachment_index != VK_ATTACHMENT_UNUSED) {
10735                                     uint32_t layer_count =
10736                                         framebuffer_attachments_create_info->pAttachmentImageInfos[attachment_index].layerCount;
10737                                     if (layer_count <= highest_view_bit) {
10738                                         skip |= LogError(
10739                                             pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-renderPass-03198",
10740                                             "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info %u "
10741                                             "only specifies %u layers, but the view mask for subpass %u in renderPass (%s) "
10742                                             "includes layer %u, with that attachment specified as a color attachment %u.",
10743                                             attachment_index, layer_count, i,
10744                                             report_data->FormatHandle(pCreateInfo->renderPass).c_str(), highest_view_bit, j);
10745                                     }
10746                                 }
10747                                 if (rpci->pSubpasses[i].pResolveAttachments) {
10748                                     attachment_index = rpci->pSubpasses[i].pResolveAttachments[j].attachment;
10749                                     if (attachment_index != VK_ATTACHMENT_UNUSED) {
10750                                         uint32_t layer_count =
10751                                             framebuffer_attachments_create_info->pAttachmentImageInfos[attachment_index].layerCount;
10752                                         if (layer_count <= highest_view_bit) {
10753                                             skip |= LogError(
10754                                                 pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-renderPass-03198",
10755                                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info %u "
10756                                                 "only specifies %u layers, but the view mask for subpass %u in renderPass (%s) "
10757                                                 "includes layer %u, with that attachment specified as a resolve attachment %u.",
10758                                                 attachment_index, layer_count, i,
10759                                                 report_data->FormatHandle(pCreateInfo->renderPass).c_str(), highest_view_bit, j);
10760                                         }
10761                                     }
10762                                 }
10763                             }
10764 
10765                             for (uint32_t j = 0; j < rpci->pSubpasses[i].inputAttachmentCount; ++j) {
10766                                 attachment_index = rpci->pSubpasses[i].pInputAttachments[j].attachment;
10767                                 if (attachment_index != VK_ATTACHMENT_UNUSED) {
10768                                     uint32_t layer_count =
10769                                         framebuffer_attachments_create_info->pAttachmentImageInfos[attachment_index].layerCount;
10770                                     if (layer_count <= highest_view_bit) {
10771                                         skip |= LogError(
10772                                             pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-renderPass-03198",
10773                                             "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info %u "
10774                                             "only specifies %u layers, but the view mask for subpass %u in renderPass (%s) "
10775                                             "includes layer %u, with that attachment specified as an input attachment %u.",
10776                                             attachment_index, layer_count, i,
10777                                             report_data->FormatHandle(pCreateInfo->renderPass).c_str(), highest_view_bit, j);
10778                                     }
10779                                 }
10780                             }
10781 
10782                             if (rpci->pSubpasses[i].pDepthStencilAttachment != nullptr) {
10783                                 attachment_index = rpci->pSubpasses[i].pDepthStencilAttachment->attachment;
10784                                 if (attachment_index != VK_ATTACHMENT_UNUSED) {
10785                                     uint32_t layer_count =
10786                                         framebuffer_attachments_create_info->pAttachmentImageInfos[attachment_index].layerCount;
10787                                     if (layer_count <= highest_view_bit) {
10788                                         skip |= LogError(
10789                                             pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-renderPass-03198",
10790                                             "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info %u "
10791                                             "only specifies %u layers, but the view mask for subpass %u in renderPass (%s) "
10792                                             "includes layer %u, with that attachment specified as a depth/stencil attachment.",
10793                                             attachment_index, layer_count, i,
10794                                             report_data->FormatHandle(pCreateInfo->renderPass).c_str(), highest_view_bit);
10795                                     }
10796                                 }
10797 
10798                                 if (IsExtEnabled(device_extensions.vk_khr_depth_stencil_resolve) &&
10799                                     depth_stencil_resolve != nullptr &&
10800                                     depth_stencil_resolve->pDepthStencilResolveAttachment != nullptr) {
10801                                     attachment_index = depth_stencil_resolve->pDepthStencilResolveAttachment->attachment;
10802                                     if (attachment_index != VK_ATTACHMENT_UNUSED) {
10803                                         uint32_t layer_count =
10804                                             framebuffer_attachments_create_info->pAttachmentImageInfos[attachment_index].layerCount;
10805                                         if (layer_count <= highest_view_bit) {
10806                                             skip |= LogError(
10807                                                 pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-renderPass-03198",
10808                                                 "vkCreateFramebuffer(): VkFramebufferCreateInfo attachment info %u "
10809                                                 "only specifies %u layers, but the view mask for subpass %u in renderPass (%s) "
10810                                                 "includes layer %u, with that attachment specified as a depth/stencil resolve "
10811                                                 "attachment.",
10812                                                 attachment_index, layer_count, i,
10813                                                 report_data->FormatHandle(pCreateInfo->renderPass).c_str(), highest_view_bit);
10814                                         }
10815                                     }
10816                                 }
10817                             }
10818                         }
10819                     }
10820                 }
10821             }
10822 
10823             if ((pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) == 0) {
10824                 // Verify correct attachment usage flags
10825                 for (uint32_t subpass = 0; subpass < rpci->subpassCount; subpass++) {
10826                     const VkSubpassDescription2 &subpass_description = rpci->pSubpasses[subpass];
10827                     // Verify input attachments:
10828                     skip |= MatchUsage(subpass_description.inputAttachmentCount, subpass_description.pInputAttachments, pCreateInfo,
10829                                        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-pAttachments-00879");
10830                     // Verify color attachments:
10831                     skip |= MatchUsage(subpass_description.colorAttachmentCount, subpass_description.pColorAttachments, pCreateInfo,
10832                                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-pAttachments-00877");
10833                     // Verify depth/stencil attachments:
10834                     skip |=
10835                         MatchUsage(1, subpass_description.pDepthStencilAttachment, pCreateInfo,
10836                                    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, "VUID-VkFramebufferCreateInfo-pAttachments-02633");
10837                     // Verify depth/stecnil resolve
10838                     if (IsExtEnabled(device_extensions.vk_khr_depth_stencil_resolve)) {
10839                         const VkSubpassDescriptionDepthStencilResolve *ds_resolve =
10840                             LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(subpass_description.pNext);
10841                         if (ds_resolve) {
10842                             skip |= MatchUsage(1, ds_resolve->pDepthStencilResolveAttachment, pCreateInfo,
10843                                                VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
10844                                                "VUID-VkFramebufferCreateInfo-pAttachments-02634");
10845                         }
10846                     }
10847 
10848                     // Verify fragment shading rate attachments
10849                     if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
10850                         const VkFragmentShadingRateAttachmentInfoKHR *fragment_shading_rate_attachment_info =
10851                             LvlFindInChain<VkFragmentShadingRateAttachmentInfoKHR>(subpass_description.pNext);
10852                         if (fragment_shading_rate_attachment_info) {
10853                             skip |= MatchUsage(1, fragment_shading_rate_attachment_info->pFragmentShadingRateAttachment,
10854                                                pCreateInfo, VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
10855                                                "VUID-VkFramebufferCreateInfo-flags-04548");
10856                         }
10857                     }
10858                 }
10859             }
10860 
10861             bool b_has_non_zero_view_masks = false;
10862             for (uint32_t i = 0; i < rpci->subpassCount; ++i) {
10863                 if (rpci->pSubpasses[i].viewMask != 0) {
10864                     b_has_non_zero_view_masks = true;
10865                     break;
10866                 }
10867             }
10868 
10869             if (b_has_non_zero_view_masks && pCreateInfo->layers != 1) {
10870                 skip |= LogError(pCreateInfo->renderPass, "VUID-VkFramebufferCreateInfo-renderPass-02531",
10871                                  "vkCreateFramebuffer(): VkFramebufferCreateInfo has #%u layers but "
10872                                  "renderPass (%s) was specified with non-zero view masks\n",
10873                                  pCreateInfo->layers, report_data->FormatHandle(pCreateInfo->renderPass).c_str());
10874             }
10875         }
10876     }
10877     // Verify FB dimensions are within physical device limits
10878     if (pCreateInfo->width > phys_dev_props.limits.maxFramebufferWidth) {
10879         skip |= LogError(device, "VUID-VkFramebufferCreateInfo-width-00886",
10880                          "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width exceeds physical device limits. Requested "
10881                          "width: %u, device max: %u\n",
10882                          pCreateInfo->width, phys_dev_props.limits.maxFramebufferWidth);
10883     }
10884     if (pCreateInfo->height > phys_dev_props.limits.maxFramebufferHeight) {
10885         skip |=
10886             LogError(device, "VUID-VkFramebufferCreateInfo-height-00888",
10887                      "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height exceeds physical device limits. Requested "
10888                      "height: %u, device max: %u\n",
10889                      pCreateInfo->height, phys_dev_props.limits.maxFramebufferHeight);
10890     }
10891     if (pCreateInfo->layers > phys_dev_props.limits.maxFramebufferLayers) {
10892         skip |=
10893             LogError(device, "VUID-VkFramebufferCreateInfo-layers-00890",
10894                      "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers exceeds physical device limits. Requested "
10895                      "layers: %u, device max: %u\n",
10896                      pCreateInfo->layers, phys_dev_props.limits.maxFramebufferLayers);
10897     }
10898     // Verify FB dimensions are greater than zero
10899     if (pCreateInfo->width <= 0) {
10900         skip |= LogError(device, "VUID-VkFramebufferCreateInfo-width-00885",
10901                          "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo width must be greater than zero.");
10902     }
10903     if (pCreateInfo->height <= 0) {
10904         skip |= LogError(device, "VUID-VkFramebufferCreateInfo-height-00887",
10905                          "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo height must be greater than zero.");
10906     }
10907     if (pCreateInfo->layers <= 0) {
10908         skip |= LogError(device, "VUID-VkFramebufferCreateInfo-layers-00889",
10909                          "vkCreateFramebuffer(): Requested VkFramebufferCreateInfo layers must be greater than zero.");
10910     }
10911     return skip;
10912 }
10913 
PreCallValidateCreateFramebuffer(VkDevice device,const VkFramebufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkFramebuffer * pFramebuffer) const10914 bool CoreChecks::PreCallValidateCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
10915                                                   const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) const {
10916     // TODO : Verify that renderPass FB is created with is compatible with FB
10917     bool skip = false;
10918     skip |= ValidateFramebufferCreateInfo(pCreateInfo);
10919     return skip;
10920 }
10921 
FindDependency(const uint32_t index,const uint32_t dependent,const std::vector<DAGNode> & subpass_to_node,layer_data::unordered_set<uint32_t> & processed_nodes)10922 static bool FindDependency(const uint32_t index, const uint32_t dependent, const std::vector<DAGNode> &subpass_to_node,
10923                            layer_data::unordered_set<uint32_t> &processed_nodes) {
10924     // If we have already checked this node we have not found a dependency path so return false.
10925     if (processed_nodes.count(index)) return false;
10926     processed_nodes.insert(index);
10927     const DAGNode &node = subpass_to_node[index];
10928     // Look for a dependency path. If one exists return true else recurse on the previous nodes.
10929     if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
10930         for (auto elem : node.prev) {
10931             if (FindDependency(elem, dependent, subpass_to_node, processed_nodes)) return true;
10932         }
10933     } else {
10934         return true;
10935     }
10936     return false;
10937 }
10938 
IsImageLayoutReadOnly(VkImageLayout layout) const10939 bool CoreChecks::IsImageLayoutReadOnly(VkImageLayout layout) const {
10940     if ((layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) || (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
10941         (layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) ||
10942         (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL)) {
10943         return true;
10944     }
10945     return false;
10946 }
10947 
CheckDependencyExists(const VkRenderPass renderpass,const uint32_t subpass,const VkImageLayout layout,const std::vector<SubpassLayout> & dependent_subpasses,const std::vector<DAGNode> & subpass_to_node,bool & skip) const10948 bool CoreChecks::CheckDependencyExists(const VkRenderPass renderpass, const uint32_t subpass, const VkImageLayout layout,
10949                                        const std::vector<SubpassLayout> &dependent_subpasses,
10950                                        const std::vector<DAGNode> &subpass_to_node, bool &skip) const {
10951     bool result = true;
10952     bool b_image_layout_read_only = IsImageLayoutReadOnly(layout);
10953     // Loop through all subpasses that share the same attachment and make sure a dependency exists
10954     for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
10955         const SubpassLayout &sp = dependent_subpasses[k];
10956         if (subpass == sp.index) continue;
10957         if (b_image_layout_read_only && IsImageLayoutReadOnly(sp.layout)) continue;
10958 
10959         const DAGNode &node = subpass_to_node[subpass];
10960         // Check for a specified dependency between the two nodes. If one exists we are done.
10961         auto prev_elem = std::find(node.prev.begin(), node.prev.end(), sp.index);
10962         auto next_elem = std::find(node.next.begin(), node.next.end(), sp.index);
10963         if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
10964             // If no dependency exits an implicit dependency still might. If not, throw an error.
10965             layer_data::unordered_set<uint32_t> processed_nodes;
10966             if (!(FindDependency(subpass, sp.index, subpass_to_node, processed_nodes) ||
10967                   FindDependency(sp.index, subpass, subpass_to_node, processed_nodes))) {
10968                 skip |=
10969                     LogError(renderpass, kVUID_Core_DrawState_InvalidRenderpass,
10970                              "A dependency between subpasses %d and %d must exist but one is not specified.", subpass, sp.index);
10971                 result = false;
10972             }
10973         }
10974     }
10975     return result;
10976 }
10977 
CheckPreserved(const VkRenderPass renderpass,const VkRenderPassCreateInfo2 * pCreateInfo,const int index,const uint32_t attachment,const std::vector<DAGNode> & subpass_to_node,int depth,bool & skip) const10978 bool CoreChecks::CheckPreserved(const VkRenderPass renderpass, const VkRenderPassCreateInfo2 *pCreateInfo, const int index,
10979                                 const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth,
10980                                 bool &skip) const {
10981     const DAGNode &node = subpass_to_node[index];
10982     // If this node writes to the attachment return true as next nodes need to preserve the attachment.
10983     const VkSubpassDescription2 &subpass = pCreateInfo->pSubpasses[index];
10984     for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
10985         if (attachment == subpass.pColorAttachments[j].attachment) return true;
10986     }
10987     for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
10988         if (attachment == subpass.pInputAttachments[j].attachment) return true;
10989     }
10990     if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
10991         if (attachment == subpass.pDepthStencilAttachment->attachment) return true;
10992     }
10993     bool result = false;
10994     // Loop through previous nodes and see if any of them write to the attachment.
10995     for (auto elem : node.prev) {
10996         result |= CheckPreserved(renderpass, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip);
10997     }
10998     // If the attachment was written to by a previous node than this node needs to preserve it.
10999     if (result && depth > 0) {
11000         bool has_preserved = false;
11001         for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
11002             if (subpass.pPreserveAttachments[j] == attachment) {
11003                 has_preserved = true;
11004                 break;
11005             }
11006         }
11007         if (!has_preserved) {
11008             skip |= LogError(renderpass, kVUID_Core_DrawState_InvalidRenderpass,
11009                              "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
11010         }
11011     }
11012     return result;
11013 }
11014 
11015 template <class T>
IsRangeOverlapping(T offset1,T size1,T offset2,T size2)11016 bool IsRangeOverlapping(T offset1, T size1, T offset2, T size2) {
11017     return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
11018            ((offset1 > offset2) && (offset1 < (offset2 + size2)));
11019 }
11020 
IsRegionOverlapping(VkImageSubresourceRange range1,VkImageSubresourceRange range2)11021 bool IsRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
11022     return (IsRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
11023             IsRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
11024 }
11025 
ValidateDependencies(FRAMEBUFFER_STATE const * framebuffer,RENDER_PASS_STATE const * renderPass) const11026 bool CoreChecks::ValidateDependencies(FRAMEBUFFER_STATE const *framebuffer, RENDER_PASS_STATE const *renderPass) const {
11027     bool skip = false;
11028     auto const framebuffer_info = framebuffer->createInfo.ptr();
11029     auto const create_info = renderPass->createInfo.ptr();
11030     auto const &subpass_to_node = renderPass->subpass_to_node;
11031 
11032     struct Attachment {
11033         std::vector<SubpassLayout> outputs;
11034         std::vector<SubpassLayout> inputs;
11035         std::vector<uint32_t> overlapping;
11036     };
11037 
11038     std::vector<Attachment> attachments(create_info->attachmentCount);
11039 
11040     if (!(framebuffer_info->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT)) {
11041         // Find overlapping attachments
11042         for (uint32_t i = 0; i < create_info->attachmentCount; ++i) {
11043             for (uint32_t j = i + 1; j < create_info->attachmentCount; ++j) {
11044                 VkImageView viewi = framebuffer_info->pAttachments[i];
11045                 VkImageView viewj = framebuffer_info->pAttachments[j];
11046                 if (viewi == viewj) {
11047                     attachments[i].overlapping.emplace_back(j);
11048                     attachments[j].overlapping.emplace_back(i);
11049                     continue;
11050                 }
11051                 auto *view_state_i = framebuffer->attachments_view_state[i].get();
11052                 auto *view_state_j = framebuffer->attachments_view_state[j].get();
11053                 if (!view_state_i || !view_state_j) {
11054                     continue;
11055                 }
11056                 auto view_ci_i = view_state_i->create_info;
11057                 auto view_ci_j = view_state_j->create_info;
11058                 if (view_ci_i.image == view_ci_j.image &&
11059                     IsRegionOverlapping(view_ci_i.subresourceRange, view_ci_j.subresourceRange)) {
11060                     attachments[i].overlapping.emplace_back(j);
11061                     attachments[j].overlapping.emplace_back(i);
11062                     continue;
11063                 }
11064                 auto *image_data_i = view_state_i->image_state.get();
11065                 auto *image_data_j = view_state_j->image_state.get();
11066                 if (!image_data_i || !image_data_j) {
11067                     continue;
11068                 }
11069                 const auto *binding_i = image_data_i->Binding();
11070                 const auto *binding_j = image_data_j->Binding();
11071                 if (binding_i && binding_j && binding_i->mem_state == binding_j->mem_state &&
11072                     IsRangeOverlapping(binding_i->offset, binding_i->size, binding_j->offset, binding_j->size)) {
11073                     attachments[i].overlapping.emplace_back(j);
11074                     attachments[j].overlapping.emplace_back(i);
11075                 }
11076             }
11077         }
11078     }
11079     // Find for each attachment the subpasses that use them.
11080     layer_data::unordered_set<uint32_t> attachment_indices;
11081     for (uint32_t i = 0; i < create_info->subpassCount; ++i) {
11082         const VkSubpassDescription2 &subpass = create_info->pSubpasses[i];
11083         attachment_indices.clear();
11084         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
11085             uint32_t attachment = subpass.pInputAttachments[j].attachment;
11086             if (attachment == VK_ATTACHMENT_UNUSED) continue;
11087             SubpassLayout sp = {i, subpass.pInputAttachments[j].layout};
11088             attachments[attachment].inputs.emplace_back(sp);
11089             for (auto overlapping_attachment : attachments[attachment].overlapping) {
11090                 attachments[overlapping_attachment].inputs.emplace_back(sp);
11091             }
11092         }
11093         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
11094             uint32_t attachment = subpass.pColorAttachments[j].attachment;
11095             if (attachment == VK_ATTACHMENT_UNUSED) continue;
11096             SubpassLayout sp = {i, subpass.pColorAttachments[j].layout};
11097             attachments[attachment].outputs.emplace_back(sp);
11098             for (auto overlapping_attachment : attachments[attachment].overlapping) {
11099                 attachments[overlapping_attachment].outputs.emplace_back(sp);
11100             }
11101             attachment_indices.insert(attachment);
11102         }
11103         if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
11104             uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
11105             SubpassLayout sp = {i, subpass.pDepthStencilAttachment->layout};
11106             attachments[attachment].outputs.emplace_back(sp);
11107             for (auto overlapping_attachment : attachments[attachment].overlapping) {
11108                 attachments[overlapping_attachment].outputs.emplace_back(sp);
11109             }
11110 
11111             if (attachment_indices.count(attachment)) {
11112                 skip |=
11113                     LogError(renderPass->renderPass(), kVUID_Core_DrawState_InvalidRenderpass,
11114                              "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).", attachment, i);
11115             }
11116         }
11117     }
11118     // If there is a dependency needed make sure one exists
11119     for (uint32_t i = 0; i < create_info->subpassCount; ++i) {
11120         const VkSubpassDescription2 &subpass = create_info->pSubpasses[i];
11121         // If the attachment is an input then all subpasses that output must have a dependency relationship
11122         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
11123             uint32_t attachment = subpass.pInputAttachments[j].attachment;
11124             if (attachment == VK_ATTACHMENT_UNUSED) continue;
11125             CheckDependencyExists(renderPass->renderPass(), i, subpass.pInputAttachments[j].layout, attachments[attachment].outputs,
11126                                   subpass_to_node, skip);
11127         }
11128         // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
11129         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
11130             uint32_t attachment = subpass.pColorAttachments[j].attachment;
11131             if (attachment == VK_ATTACHMENT_UNUSED) continue;
11132             CheckDependencyExists(renderPass->renderPass(), i, subpass.pColorAttachments[j].layout, attachments[attachment].outputs,
11133                                   subpass_to_node, skip);
11134             CheckDependencyExists(renderPass->renderPass(), i, subpass.pColorAttachments[j].layout, attachments[attachment].inputs,
11135                                   subpass_to_node, skip);
11136         }
11137         if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
11138             const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
11139             CheckDependencyExists(renderPass->renderPass(), i, subpass.pDepthStencilAttachment->layout,
11140                                   attachments[attachment].outputs, subpass_to_node, skip);
11141             CheckDependencyExists(renderPass->renderPass(), i, subpass.pDepthStencilAttachment->layout,
11142                                   attachments[attachment].inputs, subpass_to_node, skip);
11143         }
11144     }
11145     // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
11146     // written.
11147     for (uint32_t i = 0; i < create_info->subpassCount; ++i) {
11148         const VkSubpassDescription2 &subpass = create_info->pSubpasses[i];
11149         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
11150             CheckPreserved(renderPass->renderPass(), create_info, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0,
11151                            skip);
11152         }
11153     }
11154     return skip;
11155 }
11156 
ValidateRenderPassDAG(RenderPassCreateVersion rp_version,const VkRenderPassCreateInfo2 * pCreateInfo) const11157 bool CoreChecks::ValidateRenderPassDAG(RenderPassCreateVersion rp_version, const VkRenderPassCreateInfo2 *pCreateInfo) const {
11158     bool skip = false;
11159     const char *vuid;
11160     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
11161 
11162     for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
11163         const VkSubpassDependency2 &dependency = pCreateInfo->pDependencies[i];
11164         auto latest_src_stage = sync_utils::GetLogicallyLatestGraphicsPipelineStage(dependency.srcStageMask);
11165         auto earliest_dst_stage = sync_utils::GetLogicallyEarliestGraphicsPipelineStage(dependency.dstStageMask);
11166 
11167         // The first subpass here serves as a good proxy for "is multiview enabled" - since all view masks need to be non-zero if
11168         // any are, which enables multiview.
11169         if (use_rp2 && (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) && (pCreateInfo->pSubpasses[0].viewMask == 0)) {
11170             skip |= LogError(
11171                 device, "VUID-VkRenderPassCreateInfo2-viewMask-03059",
11172                 "Dependency %u specifies the VK_DEPENDENCY_VIEW_LOCAL_BIT, but multiview is not enabled for this render pass.", i);
11173         } else if (use_rp2 && !(dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) && dependency.viewOffset != 0) {
11174             skip |= LogError(device, "VUID-VkSubpassDependency2-dependencyFlags-03092",
11175                              "Dependency %u specifies the VK_DEPENDENCY_VIEW_LOCAL_BIT, but also specifies a view offset of %u.", i,
11176                              dependency.viewOffset);
11177         } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL || dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
11178             if (dependency.srcSubpass == dependency.dstSubpass) {
11179                 vuid = use_rp2 ? "VUID-VkSubpassDependency2-srcSubpass-03085" : "VUID-VkSubpassDependency-srcSubpass-00865";
11180                 skip |= LogError(device, vuid, "The src and dst subpasses in dependency %u are both external.", i);
11181             } else if (dependency.dependencyFlags & VK_DEPENDENCY_VIEW_LOCAL_BIT) {
11182                 if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL) {
11183                     vuid = "VUID-VkSubpassDependency-dependencyFlags-02520";
11184                 } else {  // dependency.dstSubpass == VK_SUBPASS_EXTERNAL
11185                     vuid = "VUID-VkSubpassDependency-dependencyFlags-02521";
11186                 }
11187                 if (use_rp2) {
11188                     // Create render pass 2 distinguishes between source and destination external dependencies.
11189                     if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL) {
11190                         vuid = "VUID-VkSubpassDependency2-dependencyFlags-03090";
11191                     } else {
11192                         vuid = "VUID-VkSubpassDependency2-dependencyFlags-03091";
11193                     }
11194                 }
11195                 skip |=
11196                     LogError(device, vuid,
11197                              "Dependency %u specifies an external dependency but also specifies VK_DEPENDENCY_VIEW_LOCAL_BIT.", i);
11198             }
11199         } else if (dependency.srcSubpass > dependency.dstSubpass) {
11200             vuid = use_rp2 ? "VUID-VkSubpassDependency2-srcSubpass-03084" : "VUID-VkSubpassDependency-srcSubpass-00864";
11201             skip |= LogError(device, vuid,
11202                              "Dependency %u specifies a dependency from a later subpass (%u) to an earlier subpass (%u), which is "
11203                              "disallowed to prevent cyclic dependencies.",
11204                              i, dependency.srcSubpass, dependency.dstSubpass);
11205         } else if (dependency.srcSubpass == dependency.dstSubpass) {
11206             if (dependency.viewOffset != 0) {
11207                 vuid = use_rp2 ? "VUID-VkSubpassDependency2-viewOffset-02530" : "VUID-VkRenderPassCreateInfo-pNext-01930";
11208                 skip |= LogError(device, vuid, "Dependency %u specifies a self-dependency but has a non-zero view offset of %u", i,
11209                                  dependency.viewOffset);
11210             } else if ((dependency.dependencyFlags | VK_DEPENDENCY_VIEW_LOCAL_BIT) != dependency.dependencyFlags &&
11211                        pCreateInfo->pSubpasses[dependency.srcSubpass].viewMask > 1) {
11212                 vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-pDependencies-03060" : "VUID-VkSubpassDependency-srcSubpass-00872";
11213                 skip |= LogError(device, vuid,
11214                                  "Dependency %u specifies a self-dependency for subpass %u with a non-zero view mask, but does not "
11215                                  "specify VK_DEPENDENCY_VIEW_LOCAL_BIT.",
11216                                  i, dependency.srcSubpass);
11217             } else if ((HasNonFramebufferStagePipelineStageFlags(dependency.srcStageMask) ||
11218                         HasNonFramebufferStagePipelineStageFlags(dependency.dstStageMask)) &&
11219                        (sync_utils::GetGraphicsPipelineStageLogicalOrdinal(latest_src_stage) >
11220                         sync_utils::GetGraphicsPipelineStageLogicalOrdinal(earliest_dst_stage))) {
11221                 vuid = use_rp2 ? "VUID-VkSubpassDependency2-srcSubpass-03087" : "VUID-VkSubpassDependency-srcSubpass-00867";
11222                 skip |= LogError(
11223                     device, vuid,
11224                     "Dependency %u specifies a self-dependency from logically-later stage (%s) to a logically-earlier stage (%s).",
11225                     i, sync_utils::StringPipelineStageFlags(latest_src_stage).c_str(),
11226                     sync_utils::StringPipelineStageFlags(earliest_dst_stage).c_str());
11227             } else if ((HasNonFramebufferStagePipelineStageFlags(dependency.srcStageMask) == false) &&
11228                        (HasNonFramebufferStagePipelineStageFlags(dependency.dstStageMask) == false) &&
11229                        ((dependency.dependencyFlags & VK_DEPENDENCY_BY_REGION_BIT) == 0)) {
11230                 vuid = use_rp2 ? "VUID-VkSubpassDependency2-srcSubpass-02245" : "VUID-VkSubpassDependency-srcSubpass-02243";
11231                 skip |= LogError(device, vuid,
11232                                  "Dependency %u specifies a self-dependency for subpass %u with both stages including a "
11233                                  "framebuffer-space stage, but does not specify VK_DEPENDENCY_BY_REGION_BIT in dependencyFlags.",
11234                                  i, dependency.srcSubpass);
11235             }
11236         } else if ((dependency.srcSubpass < dependency.dstSubpass) &&
11237                    ((pCreateInfo->pSubpasses[dependency.srcSubpass].flags & VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM) != 0)) {
11238             vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-flags-04909" : "VUID-VkSubpassDescription-flags-03343";
11239             skip |= LogError(device, vuid,
11240                              "Dependency %u specifies that subpass %u has a dependency on a later subpass"
11241                              "and includes VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM subpass flags.",
11242                              i, dependency.srcSubpass);
11243         }
11244     }
11245     return skip;
11246 }
11247 
ValidateAttachmentIndex(RenderPassCreateVersion rp_version,uint32_t attachment,uint32_t attachment_count,const char * error_type,const char * function_name) const11248 bool CoreChecks::ValidateAttachmentIndex(RenderPassCreateVersion rp_version, uint32_t attachment, uint32_t attachment_count,
11249                                          const char *error_type, const char *function_name) const {
11250     bool skip = false;
11251     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
11252     assert(attachment != VK_ATTACHMENT_UNUSED);
11253     if (attachment >= attachment_count) {
11254         const char *vuid =
11255             use_rp2 ? "VUID-VkRenderPassCreateInfo2-attachment-03051" : "VUID-VkRenderPassCreateInfo-attachment-00834";
11256         skip |= LogError(device, vuid, "%s: %s attachment %d must be less than the total number of attachments %d.", function_name,
11257                          error_type, attachment, attachment_count);
11258     }
11259     return skip;
11260 }
11261 
11262 enum AttachmentType {
11263     ATTACHMENT_COLOR = 1,
11264     ATTACHMENT_DEPTH = 2,
11265     ATTACHMENT_INPUT = 4,
11266     ATTACHMENT_PRESERVE = 8,
11267     ATTACHMENT_RESOLVE = 16,
11268 };
11269 
StringAttachmentType(uint8_t type)11270 char const *StringAttachmentType(uint8_t type) {
11271     switch (type) {
11272         case ATTACHMENT_COLOR:
11273             return "color";
11274         case ATTACHMENT_DEPTH:
11275             return "depth";
11276         case ATTACHMENT_INPUT:
11277             return "input";
11278         case ATTACHMENT_PRESERVE:
11279             return "preserve";
11280         case ATTACHMENT_RESOLVE:
11281             return "resolve";
11282         default:
11283             return "(multiple)";
11284     }
11285 }
11286 
AddAttachmentUse(RenderPassCreateVersion rp_version,uint32_t subpass,std::vector<uint8_t> & attachment_uses,std::vector<VkImageLayout> & attachment_layouts,uint32_t attachment,uint8_t new_use,VkImageLayout new_layout) const11287 bool CoreChecks::AddAttachmentUse(RenderPassCreateVersion rp_version, uint32_t subpass, std::vector<uint8_t> &attachment_uses,
11288                                   std::vector<VkImageLayout> &attachment_layouts, uint32_t attachment, uint8_t new_use,
11289                                   VkImageLayout new_layout) const {
11290     if (attachment >= attachment_uses.size()) return false; /* out of range, but already reported */
11291 
11292     bool skip = false;
11293     auto &uses = attachment_uses[attachment];
11294     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
11295     const char *vuid;
11296     const char *const function_name = use_rp2 ? "vkCreateRenderPass2()" : "vkCreateRenderPass()";
11297 
11298     if (uses & new_use) {
11299         if (attachment_layouts[attachment] != new_layout) {
11300             vuid = use_rp2 ? "VUID-VkSubpassDescription2-layout-02528" : "VUID-VkSubpassDescription-layout-02519";
11301             skip |= LogError(device, vuid, "%s: subpass %u already uses attachment %u with a different image layout (%s vs %s).",
11302                              function_name, subpass, attachment, string_VkImageLayout(attachment_layouts[attachment]),
11303                              string_VkImageLayout(new_layout));
11304         }
11305     } else if (((new_use & ATTACHMENT_COLOR) && (uses & ATTACHMENT_DEPTH)) ||
11306                ((uses & ATTACHMENT_COLOR) && (new_use & ATTACHMENT_DEPTH))) {
11307         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pDepthStencilAttachment-04440"
11308                        : "VUID-VkSubpassDescription-pDepthStencilAttachment-04438";
11309         skip |= LogError(device, vuid, "%s: subpass %u uses attachment %u as both %s and %s attachment.", function_name, subpass,
11310                          attachment, StringAttachmentType(uses), StringAttachmentType(new_use));
11311     } else if ((uses && (new_use & ATTACHMENT_PRESERVE)) || (new_use && (uses & ATTACHMENT_PRESERVE))) {
11312         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pPreserveAttachments-03074"
11313                        : "VUID-VkSubpassDescription-pPreserveAttachments-00854";
11314         skip |= LogError(device, vuid, "%s: subpass %u uses attachment %u as both %s and %s attachment.", function_name, subpass,
11315                          attachment, StringAttachmentType(uses), StringAttachmentType(new_use));
11316     } else {
11317         attachment_layouts[attachment] = new_layout;
11318         uses |= new_use;
11319     }
11320 
11321     return skip;
11322 }
11323 
11324 // Handles attachment references regardless of type (input, color, depth, etc)
11325 // Input attachments have extra VUs associated with them
ValidateAttachmentReference(RenderPassCreateVersion rp_version,VkAttachmentReference2 reference,const VkFormat attachment_format,bool input,const char * error_type,const char * function_name) const11326 bool CoreChecks::ValidateAttachmentReference(RenderPassCreateVersion rp_version, VkAttachmentReference2 reference,
11327                                              const VkFormat attachment_format, bool input, const char *error_type,
11328                                              const char *function_name) const {
11329     bool skip = false;
11330 
11331     // Currently all VUs require attachment to not be UNUSED
11332     assert(reference.attachment != VK_ATTACHMENT_UNUSED);
11333 
11334     // currently VkAttachmentReference and VkAttachmentReference2 have no overlapping VUs
11335     if (rp_version == RENDER_PASS_VERSION_1) {
11336         switch (reference.layout) {
11337             case VK_IMAGE_LAYOUT_UNDEFINED:
11338             case VK_IMAGE_LAYOUT_PREINITIALIZED:
11339             case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
11340             case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
11341             case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL:
11342             case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL:
11343             case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL:
11344                 skip |= LogError(device, "VUID-VkAttachmentReference-layout-00857",
11345                                  "%s: Layout for %s is %s but must not be "
11346                                  "VK_IMAGE_LAYOUT_[UNDEFINED|PREINITIALIZED|PRESENT_SRC_KHR|DEPTH_ATTACHMENT_OPTIMAL|DEPTH_READ_"
11347                                  "ONLY_OPTIMAL|STENCIL_ATTACHMENT_OPTIMAL|STENCIL_READ_ONLY_OPTIMAL].",
11348                                  function_name, error_type, string_VkImageLayout(reference.layout));
11349                 break;
11350             default:
11351                 break;
11352         }
11353     } else {
11354         const auto *attachment_reference_stencil_layout = LvlFindInChain<VkAttachmentReferenceStencilLayout>(reference.pNext);
11355         switch (reference.layout) {
11356             case VK_IMAGE_LAYOUT_UNDEFINED:
11357             case VK_IMAGE_LAYOUT_PREINITIALIZED:
11358             case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
11359                 skip |=
11360                     LogError(device, "VUID-VkAttachmentReference2-layout-03077",
11361                              "%s: Layout for %s is %s but must not be VK_IMAGE_LAYOUT_[UNDEFINED|PREINITIALIZED|PRESENT_SRC_KHR].",
11362                              function_name, error_type, string_VkImageLayout(reference.layout));
11363                 break;
11364 
11365             // Only other layouts in VUs to be checked
11366             case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
11367             case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL:
11368             case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL:
11369             case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL:
11370                 // First need to make sure feature bit is enabled and the format is actually a depth and/or stencil
11371                 if (!enabled_features.core12.separateDepthStencilLayouts) {
11372                     skip |= LogError(device, "VUID-VkAttachmentReference2-separateDepthStencilLayouts-03313",
11373                                      "%s: Layout for %s is %s but without separateDepthStencilLayouts enabled the layout must not "
11374                                      "be VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "
11375                                      "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL.",
11376                                      function_name, error_type, string_VkImageLayout(reference.layout));
11377                 } else if (!FormatIsDepthOrStencil(attachment_format)) {
11378                     // using this over FormatIsColor() incase a multiplane and/or undef would sneak in
11379                     // "color" format is still an ambiguous term in spec (internal issue #2484)
11380                     skip |= LogError(
11381                         device, "VUID-VkAttachmentReference2-attachment-04754",
11382                         "%s: Layout for %s is %s but the attachment is a not a depth/stencil format (%s) so the layout must not "
11383                         "be VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "
11384                         "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, or VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL.",
11385                         function_name, error_type, string_VkImageLayout(reference.layout), string_VkFormat(attachment_format));
11386                 } else {
11387                     if ((reference.layout == VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL) ||
11388                         (reference.layout == VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL)) {
11389                         if (FormatIsDepthOnly(attachment_format)) {
11390                             skip |= LogError(
11391                                 device, "VUID-VkAttachmentReference2-attachment-04756",
11392                                 "%s: Layout for %s is %s but the attachment is a depth-only format (%s) so the layout must not "
11393                                 "be VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL.",
11394                                 function_name, error_type, string_VkImageLayout(reference.layout),
11395                                 string_VkFormat(attachment_format));
11396                         }
11397                     } else {
11398                         // DEPTH_ATTACHMENT_OPTIMAL || DEPTH_READ_ONLY_OPTIMAL
11399                         if (FormatIsStencilOnly(attachment_format)) {
11400                             skip |= LogError(
11401                                 device, "VUID-VkAttachmentReference2-attachment-04757",
11402                                 "%s: Layout for %s is %s but the attachment is a depth-only format (%s) so the layout must not "
11403                                 "be VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL.",
11404                                 function_name, error_type, string_VkImageLayout(reference.layout),
11405                                 string_VkFormat(attachment_format));
11406                         }
11407 
11408                         if (attachment_reference_stencil_layout) {
11409                             // This check doesn't rely on the aspect mask value
11410                             const VkImageLayout stencil_layout = attachment_reference_stencil_layout->stencilLayout;
11411                             // clang-format off
11412                             if (stencil_layout == VK_IMAGE_LAYOUT_UNDEFINED ||
11413                                 stencil_layout == VK_IMAGE_LAYOUT_PREINITIALIZED ||
11414                                 stencil_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ||
11415                                 stencil_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL ||
11416                                 stencil_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL ||
11417                                 stencil_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
11418                                 stencil_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ||
11419                                 stencil_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
11420                                 stencil_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
11421                                 stencil_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
11422                                 skip |= LogError(device, "VUID-VkAttachmentReferenceStencilLayout-stencilLayout-03318",
11423                                                     "%s: In %s with pNext chain instance VkAttachmentReferenceStencilLayout, "
11424                                                     "the stencilLayout (%s) must not be "
11425                                                     "VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PREINITIALIZED, "
11426                                                     "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "
11427                                                     "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, "
11428                                                     "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "
11429                                                     "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "
11430                                                     "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "
11431                                                     "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, "
11432                                                     "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, or "
11433                                                     "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.",
11434                                                     function_name, error_type, string_VkImageLayout(stencil_layout));
11435                             }
11436                             // clang-format on
11437                         } else if (FormatIsDepthAndStencil(attachment_format)) {
11438                             skip |= LogError(
11439                                 device, "VUID-VkAttachmentReference2-attachment-04755",
11440                                 "%s: Layout for %s is %s but the attachment is a depth and stencil format (%s) so if the layout is "
11441                                 "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL there needs "
11442                                 "to be a VkAttachmentReferenceStencilLayout in the pNext chain to set the seperate stencil layout "
11443                                 "because the separateDepthStencilLayouts feature is enabled.",
11444                                 function_name, error_type, string_VkImageLayout(reference.layout),
11445                                 string_VkFormat(attachment_format));
11446                         }
11447                     }
11448                 }
11449                 break;
11450 
11451             default:
11452                 break;
11453         }
11454     }
11455 
11456     return skip;
11457 }
11458 
ValidateRenderpassAttachmentUsage(RenderPassCreateVersion rp_version,const VkRenderPassCreateInfo2 * pCreateInfo,const char * function_name) const11459 bool CoreChecks::ValidateRenderpassAttachmentUsage(RenderPassCreateVersion rp_version, const VkRenderPassCreateInfo2 *pCreateInfo,
11460                                                    const char *function_name) const {
11461     bool skip = false;
11462     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
11463     const char *vuid;
11464 
11465     for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
11466         VkFormat format = pCreateInfo->pAttachments[i].format;
11467         if (pCreateInfo->pAttachments[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
11468             if ((FormatIsColor(format) || FormatHasDepth(format)) &&
11469                 pCreateInfo->pAttachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) {
11470                 skip |= LogWarning(device, kVUID_Core_DrawState_InvalidRenderpass,
11471                                    "%s: Render pass pAttachment[%u] has loadOp == VK_ATTACHMENT_LOAD_OP_LOAD and initialLayout == "
11472                                    "VK_IMAGE_LAYOUT_UNDEFINED.  This is probably not what you intended.  Consider using "
11473                                    "VK_ATTACHMENT_LOAD_OP_DONT_CARE instead if the image truely is undefined at the start of the "
11474                                    "render pass.",
11475                                    function_name, i);
11476             }
11477             if (FormatHasStencil(format) && pCreateInfo->pAttachments[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) {
11478                 skip |=
11479                     LogWarning(device, kVUID_Core_DrawState_InvalidRenderpass,
11480                                "%s: Render pass pAttachment[%u] has stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD and initialLayout "
11481                                "== VK_IMAGE_LAYOUT_UNDEFINED.  This is probably not what you intended.  Consider using "
11482                                "VK_ATTACHMENT_LOAD_OP_DONT_CARE instead if the image truely is undefined at the start of the "
11483                                "render pass.",
11484                                function_name, i);
11485             }
11486         }
11487     }
11488 
11489     // Track when we're observing the first use of an attachment
11490     std::vector<bool> attach_first_use(pCreateInfo->attachmentCount, true);
11491 
11492     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
11493         const VkSubpassDescription2 &subpass = pCreateInfo->pSubpasses[i];
11494         std::vector<uint8_t> attachment_uses(pCreateInfo->attachmentCount);
11495         std::vector<VkImageLayout> attachment_layouts(pCreateInfo->attachmentCount);
11496 
11497         // Track if attachments are used as input as well as another type
11498         layer_data::unordered_set<uint32_t> input_attachments;
11499 
11500         if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS &&
11501             subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI) {
11502             vuid = use_rp2 ? "VUID-VkSubpassDescription2-pipelineBindPoint-04953"
11503                            : "VUID-VkSubpassDescription-pipelineBindPoint-04952";
11504             skip |= LogError(device, vuid,
11505                              "%s: Pipeline bind point for pSubpasses[%d] must be VK_PIPELINE_BIND_POINT_GRAPHICS or "
11506                              "VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI.",
11507                              function_name, i);
11508         }
11509 
11510         // Check input attachments first
11511         // - so we can detect first-use-as-input for VU #00349
11512         // - if other color or depth/stencil is also input, it limits valid layouts
11513         for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
11514             auto const &attachment_ref = subpass.pInputAttachments[j];
11515             const uint32_t attachment_index = attachment_ref.attachment;
11516             const VkImageAspectFlags aspect_mask = attachment_ref.aspectMask;
11517             if (attachment_index != VK_ATTACHMENT_UNUSED) {
11518                 input_attachments.insert(attachment_index);
11519                 std::string error_type = "pSubpasses[" + std::to_string(i) + "].pInputAttachments[" + std::to_string(j) + "]";
11520                 skip |= ValidateAttachmentIndex(rp_version, attachment_index, pCreateInfo->attachmentCount, error_type.c_str(),
11521                                                 function_name);
11522 
11523                 if (aspect_mask & VK_IMAGE_ASPECT_METADATA_BIT) {
11524                     vuid = use_rp2 ? "VUID-VkSubpassDescription2-attachment-02801"
11525                                    : "VUID-VkInputAttachmentAspectReference-aspectMask-01964";
11526                     skip |= LogError(
11527                         device, vuid,
11528                         "%s: Aspect mask for input attachment reference %d in subpass %d includes VK_IMAGE_ASPECT_METADATA_BIT.",
11529                         function_name, j, i);
11530                 } else if (aspect_mask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
11531                                           VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
11532                     vuid = use_rp2 ? "VUID-VkSubpassDescription2-attachment-04563"
11533                                    : "VUID-VkInputAttachmentAspectReference-aspectMask-02250";
11534                     skip |= LogError(device, vuid,
11535                                      "%s: Aspect mask for input attachment reference %d in subpass %d includes "
11536                                      "VK_IMAGE_ASPECT_MEMORY_PLANE_*_BIT_EXT bit.",
11537                                      function_name, j, i);
11538                 }
11539 
11540                 // safe to dereference pCreateInfo->pAttachments[]
11541                 if (attachment_index < pCreateInfo->attachmentCount) {
11542                     const VkFormat attachment_format = pCreateInfo->pAttachments[attachment_index].format;
11543                     skip |= ValidateAttachmentReference(rp_version, attachment_ref, attachment_format, true, error_type.c_str(),
11544                                                         function_name);
11545 
11546                     skip |= AddAttachmentUse(rp_version, i, attachment_uses, attachment_layouts, attachment_index, ATTACHMENT_INPUT,
11547                                              attachment_ref.layout);
11548 
11549                     vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-attachment-02525" : "VUID-VkRenderPassCreateInfo-pNext-01963";
11550                     skip |= ValidateImageAspectMask(VK_NULL_HANDLE, attachment_format, aspect_mask, function_name, vuid);
11551 
11552                     if (attach_first_use[attachment_index]) {
11553                         skip |=
11554                             ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pInputAttachments[j].layout,
11555                                                                   attachment_index, pCreateInfo->pAttachments[attachment_index]);
11556 
11557                         bool used_as_depth = (subpass.pDepthStencilAttachment != NULL &&
11558                                               subpass.pDepthStencilAttachment->attachment == attachment_index);
11559                         bool used_as_color = false;
11560                         for (uint32_t k = 0; !used_as_depth && !used_as_color && k < subpass.colorAttachmentCount; ++k) {
11561                             used_as_color = (subpass.pColorAttachments[k].attachment == attachment_index);
11562                         }
11563                         if (!used_as_depth && !used_as_color &&
11564                             pCreateInfo->pAttachments[attachment_index].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
11565                             vuid = use_rp2 ? "VUID-VkSubpassDescription2-loadOp-03064" : "VUID-VkSubpassDescription-loadOp-00846";
11566                             skip |= LogError(device, vuid,
11567                                              "%s: attachment %u is first used as an input attachment in %s with loadOp set to "
11568                                              "VK_ATTACHMENT_LOAD_OP_CLEAR.",
11569                                              function_name, attachment_index, error_type.c_str());
11570                         }
11571                     }
11572                     attach_first_use[attachment_index] = false;
11573 
11574                     const VkFormatFeatureFlags valid_flags =
11575                         VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
11576                     const VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(attachment_format);
11577                     if ((format_features & valid_flags) == 0) {
11578                         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pInputAttachments-02897"
11579                                        : "VUID-VkSubpassDescription-pInputAttachments-02647";
11580                         skip |=
11581                             LogError(device, vuid,
11582                                      "%s: Input attachment %s format (%s) does not contain VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT "
11583                                      "| VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.",
11584                                      function_name, error_type.c_str(), string_VkFormat(attachment_format));
11585                     }
11586                 }
11587 
11588                 if (rp_version == RENDER_PASS_VERSION_2) {
11589                     // These are validated automatically as part of parameter validation for create renderpass 1
11590                     // as they are in a struct that only applies to input attachments - not so for v2.
11591 
11592                     // Check for 0
11593                     if (aspect_mask == 0) {
11594                         skip |= LogError(device, "VUID-VkSubpassDescription2-attachment-02800",
11595                                          "%s: Input attachment %s aspect mask must not be 0.", function_name, error_type.c_str());
11596                     } else {
11597                         const VkImageAspectFlags valid_bits =
11598                             (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT |
11599                              VK_IMAGE_ASPECT_METADATA_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT |
11600                              VK_IMAGE_ASPECT_PLANE_2_BIT | VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT |
11601                              VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT | VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT |
11602                              VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT);
11603 
11604                         // Check for valid aspect mask bits
11605                         if (aspect_mask & ~valid_bits) {
11606                             skip |= LogError(device, "VUID-VkSubpassDescription2-attachment-02799",
11607                                              "%s: Input attachment %s aspect mask (0x%" PRIx32 ")is invalid.", function_name,
11608                                              error_type.c_str(), aspect_mask);
11609                         }
11610                     }
11611                 }
11612 
11613                 // Validate layout
11614                 vuid = use_rp2 ? "VUID-VkSubpassDescription2-None-04439" : "VUID-VkSubpassDescription-None-04437";
11615                 switch (attachment_ref.layout) {
11616                     case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
11617                     case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
11618                     case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
11619                     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
11620                     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
11621                     case VK_IMAGE_LAYOUT_GENERAL:
11622                     case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR:
11623                     case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL:
11624                     case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL:
11625                         break;  // valid layouts
11626                     default:
11627                         skip |= LogError(device, vuid,
11628                                          "%s: %s layout is %s but input attachments must be "
11629                                          "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, "
11630                                          "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, "
11631                                          "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, "
11632                                          "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "
11633                                          "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, "
11634                                          "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "
11635                                          "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, or "
11636                                          "VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR",
11637                                          function_name, error_type.c_str(), string_VkImageLayout(attachment_ref.layout));
11638                         break;
11639                 }
11640             }
11641         }
11642 
11643         for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
11644             std::string error_type = "pSubpasses[" + std::to_string(i) + "].pPreserveAttachments[" + std::to_string(j) + "]";
11645             uint32_t attachment = subpass.pPreserveAttachments[j];
11646             if (attachment == VK_ATTACHMENT_UNUSED) {
11647                 vuid = use_rp2 ? "VUID-VkSubpassDescription2-attachment-03073" : "VUID-VkSubpassDescription-attachment-00853";
11648                 skip |= LogError(device, vuid, "%s:  Preserve attachment (%d) must not be VK_ATTACHMENT_UNUSED.", function_name, j);
11649             } else {
11650                 skip |= ValidateAttachmentIndex(rp_version, attachment, pCreateInfo->attachmentCount, error_type.c_str(),
11651                                                 function_name);
11652                 if (attachment < pCreateInfo->attachmentCount) {
11653                     skip |= AddAttachmentUse(rp_version, i, attachment_uses, attachment_layouts, attachment, ATTACHMENT_PRESERVE,
11654                                              VkImageLayout(0) /* preserve doesn't have any layout */);
11655                 }
11656             }
11657         }
11658 
11659         bool subpass_performs_resolve = false;
11660 
11661         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
11662             if (subpass.pResolveAttachments) {
11663                 std::string error_type = "pSubpasses[" + std::to_string(i) + "].pResolveAttachments[" + std::to_string(j) + "]";
11664                 auto const &attachment_ref = subpass.pResolveAttachments[j];
11665                 if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
11666                     skip |= ValidateAttachmentIndex(rp_version, attachment_ref.attachment, pCreateInfo->attachmentCount,
11667                                                     error_type.c_str(), function_name);
11668 
11669                     // safe to dereference pCreateInfo->pAttachments[]
11670                     if (attachment_ref.attachment < pCreateInfo->attachmentCount) {
11671                         const VkFormat attachment_format = pCreateInfo->pAttachments[attachment_ref.attachment].format;
11672                         skip |= ValidateAttachmentReference(rp_version, attachment_ref, attachment_format, false,
11673                                                             error_type.c_str(), function_name);
11674                         skip |= AddAttachmentUse(rp_version, i, attachment_uses, attachment_layouts, attachment_ref.attachment,
11675                                                  ATTACHMENT_RESOLVE, attachment_ref.layout);
11676 
11677                         subpass_performs_resolve = true;
11678 
11679                         if (pCreateInfo->pAttachments[attachment_ref.attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
11680                             vuid = use_rp2 ? "VUID-VkSubpassDescription2-pResolveAttachments-03067"
11681                                            : "VUID-VkSubpassDescription-pResolveAttachments-00849";
11682                             skip |= LogError(
11683                                 device, vuid,
11684                                 "%s: Subpass %u requests multisample resolve into attachment %u, which must "
11685                                 "have VK_SAMPLE_COUNT_1_BIT but has %s.",
11686                                 function_name, i, attachment_ref.attachment,
11687                                 string_VkSampleCountFlagBits(pCreateInfo->pAttachments[attachment_ref.attachment].samples));
11688                         }
11689 
11690                         const VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(attachment_format);
11691                         if ((format_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) {
11692                             vuid = use_rp2 ? "VUID-VkSubpassDescription2-pResolveAttachments-02899"
11693                                            : "VUID-VkSubpassDescription-pResolveAttachments-02649";
11694                             skip |= LogError(device, vuid,
11695                                              "%s: Resolve attachment %s format (%s) does not contain "
11696                                              "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT.",
11697                                              function_name, error_type.c_str(), string_VkFormat(attachment_format));
11698                         }
11699 
11700                         //  VK_QCOM_render_pass_shader_resolve check of resolve attachmnents
11701                         if ((subpass.flags & VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM) != 0) {
11702                             vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-flags-04907" : "VUID-VkSubpassDescription-flags-03341";
11703                             skip |= LogError(
11704                                 device, vuid,
11705                                 "%s: Subpass %u enables shader resolve, which requires every element of pResolve attachments"
11706                                 " must be VK_ATTACHMENT_UNUSED, but element %u contains a reference to attachment %u instead.",
11707                                 function_name, i, j, attachment_ref.attachment);
11708                         }
11709                     }
11710                 }
11711             }
11712         }
11713 
11714         if (subpass.pDepthStencilAttachment) {
11715             std::string error_type = "pSubpasses[" + std::to_string(i) + "].pDepthStencilAttachment";
11716             const uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
11717             const VkImageLayout image_layout = subpass.pDepthStencilAttachment->layout;
11718             if (attachment != VK_ATTACHMENT_UNUSED) {
11719                 skip |= ValidateAttachmentIndex(rp_version, attachment, pCreateInfo->attachmentCount, error_type.c_str(),
11720                                                 function_name);
11721 
11722                 // safe to dereference pCreateInfo->pAttachments[]
11723                 if (attachment < pCreateInfo->attachmentCount) {
11724                     const VkFormat attachment_format = pCreateInfo->pAttachments[attachment].format;
11725                     skip |= ValidateAttachmentReference(rp_version, *subpass.pDepthStencilAttachment, attachment_format, false,
11726                                                         error_type.c_str(), function_name);
11727                     skip |= AddAttachmentUse(rp_version, i, attachment_uses, attachment_layouts, attachment, ATTACHMENT_DEPTH,
11728                                              image_layout);
11729 
11730                     if (attach_first_use[attachment]) {
11731                         skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, image_layout, attachment,
11732                                                                       pCreateInfo->pAttachments[attachment]);
11733                     }
11734                     attach_first_use[attachment] = false;
11735 
11736                     const VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(attachment_format);
11737                     if ((format_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
11738                         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pDepthStencilAttachment-02900"
11739                                        : "VUID-VkSubpassDescription-pDepthStencilAttachment-02650";
11740                         skip |= LogError(device, vuid,
11741                                          "%s: Depth Stencil %s format (%s) does not contain "
11742                                          "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.",
11743                                          function_name, error_type.c_str(), string_VkFormat(attachment_format));
11744                     }
11745                 }
11746 
11747                 // Check for valid imageLayout
11748                 vuid = use_rp2 ? "VUID-VkSubpassDescription2-None-04439" : "VUID-VkSubpassDescription-None-04437";
11749                 switch (image_layout) {
11750                     case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
11751                     case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
11752                     case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
11753                     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
11754                     case VK_IMAGE_LAYOUT_GENERAL:
11755                         break;  // valid layouts
11756                     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
11757                     case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
11758                     case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL:
11759                     case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL:
11760                     case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL:
11761                     case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR:
11762                     case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR:
11763                         if (input_attachments.find(attachment) != input_attachments.end()) {
11764                             skip |= LogError(
11765                                 device, vuid,
11766                                 "%s: %s is also an input attachment so the layout (%s) must not be "
11767                                 "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, "
11768                                 "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, "
11769                                 "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR "
11770                                 "or VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR.",
11771                                 function_name, error_type.c_str(), string_VkImageLayout(image_layout));
11772                         }
11773                         break;
11774                     default:
11775                         skip |= LogError(device, vuid,
11776                                          "%s: %s layout is %s but depth/stencil attachments must be "
11777                                          "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "
11778                                          "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, "
11779                                          "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "
11780                                          "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, "
11781                                          "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, "
11782                                          "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, "
11783                                          "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, "
11784                                          "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, "
11785                                          "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "
11786                                          "VK_IMAGE_LAYOUT_GENERAL, "
11787                                          "VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR or"
11788                                          "VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR.",
11789                                          function_name, error_type.c_str(), string_VkImageLayout(image_layout));
11790                         break;
11791                 }
11792             }
11793         }
11794 
11795         uint32_t last_sample_count_attachment = VK_ATTACHMENT_UNUSED;
11796         for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
11797             std::string error_type = "pSubpasses[" + std::to_string(i) + "].pColorAttachments[" + std::to_string(j) + "]";
11798             auto const &attachment_ref = subpass.pColorAttachments[j];
11799             const uint32_t attachment_index = attachment_ref.attachment;
11800             if (attachment_index != VK_ATTACHMENT_UNUSED) {
11801                 skip |= ValidateAttachmentIndex(rp_version, attachment_index, pCreateInfo->attachmentCount, error_type.c_str(),
11802                                                 function_name);
11803 
11804                 // safe to dereference pCreateInfo->pAttachments[]
11805                 if (attachment_index < pCreateInfo->attachmentCount) {
11806                     const VkFormat attachment_format = pCreateInfo->pAttachments[attachment_index].format;
11807                     skip |= ValidateAttachmentReference(rp_version, attachment_ref, attachment_format, false, error_type.c_str(),
11808                                                         function_name);
11809                     skip |= AddAttachmentUse(rp_version, i, attachment_uses, attachment_layouts, attachment_index, ATTACHMENT_COLOR,
11810                                              attachment_ref.layout);
11811 
11812                     VkSampleCountFlagBits current_sample_count = pCreateInfo->pAttachments[attachment_index].samples;
11813                     if (last_sample_count_attachment != VK_ATTACHMENT_UNUSED) {
11814                         VkSampleCountFlagBits last_sample_count =
11815                             pCreateInfo->pAttachments[subpass.pColorAttachments[last_sample_count_attachment].attachment].samples;
11816                         if (current_sample_count != last_sample_count) {
11817                             vuid = use_rp2 ? "VUID-VkSubpassDescription2-pColorAttachments-03069"
11818                                            : "VUID-VkSubpassDescription-pColorAttachments-01417";
11819                             skip |= LogError(
11820                                 device, vuid,
11821                                 "%s: Subpass %u attempts to render to color attachments with inconsistent sample counts."
11822                                 "Color attachment ref %u has sample count %s, whereas previous color attachment ref %u has "
11823                                 "sample count %s.",
11824                                 function_name, i, j, string_VkSampleCountFlagBits(current_sample_count),
11825                                 last_sample_count_attachment, string_VkSampleCountFlagBits(last_sample_count));
11826                         }
11827                     }
11828                     last_sample_count_attachment = j;
11829 
11830                     if (subpass_performs_resolve && current_sample_count == VK_SAMPLE_COUNT_1_BIT) {
11831                         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pResolveAttachments-03066"
11832                                        : "VUID-VkSubpassDescription-pResolveAttachments-00848";
11833                         skip |= LogError(device, vuid,
11834                                          "%s: Subpass %u requests multisample resolve from attachment %u which has "
11835                                          "VK_SAMPLE_COUNT_1_BIT.",
11836                                          function_name, i, attachment_index);
11837                     }
11838 
11839                     if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED &&
11840                         subpass.pDepthStencilAttachment->attachment < pCreateInfo->attachmentCount) {
11841                         const auto depth_stencil_sample_count =
11842                             pCreateInfo->pAttachments[subpass.pDepthStencilAttachment->attachment].samples;
11843 
11844                         if (IsExtEnabled(device_extensions.vk_amd_mixed_attachment_samples)) {
11845                             if (current_sample_count > depth_stencil_sample_count) {
11846                                 vuid = use_rp2 ? "VUID-VkSubpassDescription2-pColorAttachments-03070"
11847                                                : "VUID-VkSubpassDescription-pColorAttachments-01506";
11848                                 skip |=
11849                                     LogError(device, vuid, "%s: %s has %s which is larger than depth/stencil attachment %s.",
11850                                              function_name, error_type.c_str(), string_VkSampleCountFlagBits(current_sample_count),
11851                                              string_VkSampleCountFlagBits(depth_stencil_sample_count));
11852                                 break;
11853                             }
11854                         }
11855 
11856                         if (!IsExtEnabled(device_extensions.vk_amd_mixed_attachment_samples) &&
11857                             !IsExtEnabled(device_extensions.vk_nv_framebuffer_mixed_samples) &&
11858                             current_sample_count != depth_stencil_sample_count) {
11859                             vuid = use_rp2 ? "VUID-VkSubpassDescription2-pDepthStencilAttachment-03071"
11860                                            : "VUID-VkSubpassDescription-pDepthStencilAttachment-01418";
11861                             skip |= LogError(device, vuid,
11862                                              "%s:  Subpass %u attempts to render to use a depth/stencil attachment with sample "
11863                                              "count that differs "
11864                                              "from color attachment %u."
11865                                              "The depth attachment ref has sample count %s, whereas color attachment ref %u has "
11866                                              "sample count %s.",
11867                                              function_name, i, j, string_VkSampleCountFlagBits(depth_stencil_sample_count), j,
11868                                              string_VkSampleCountFlagBits(current_sample_count));
11869                             break;
11870                         }
11871                     }
11872 
11873                     const VkFormatFeatureFlags format_features = GetPotentialFormatFeatures(attachment_format);
11874                     if ((format_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) {
11875                         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pColorAttachments-02898"
11876                                        : "VUID-VkSubpassDescription-pColorAttachments-02648";
11877                         skip |= LogError(device, vuid,
11878                                          "%s: Color attachment %s format (%s) does not contain "
11879                                          "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT.",
11880                                          function_name, error_type.c_str(), string_VkFormat(attachment_format));
11881                     }
11882 
11883                     if (attach_first_use[attachment_index]) {
11884                         skip |=
11885                             ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pColorAttachments[j].layout,
11886                                                                   attachment_index, pCreateInfo->pAttachments[attachment_index]);
11887                     }
11888                     attach_first_use[attachment_index] = false;
11889                 }
11890 
11891                 // Check for valid imageLayout
11892                 vuid = use_rp2 ? "VUID-VkSubpassDescription2-None-04439" : "VUID-VkSubpassDescription-None-04437";
11893                 switch (attachment_ref.layout) {
11894                     case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
11895                     case VK_IMAGE_LAYOUT_GENERAL:
11896                         break;  // valid layouts
11897                     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
11898                     case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR:
11899                         if (input_attachments.find(attachment_index) != input_attachments.end()) {
11900                             skip |= LogError(device, vuid,
11901                                              "%s: %s is also an input attachment so the layout (%s) must not be "
11902                                              "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR.",
11903                                              function_name, error_type.c_str(), string_VkImageLayout(attachment_ref.layout));
11904                         }
11905                         break;
11906                     default:
11907                         skip |= LogError(device, vuid,
11908                                          "%s: %s layout is %s but color attachments must be "
11909                                          "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "
11910                                          "VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR, "
11911                                          "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or "
11912                                          "VK_IMAGE_LAYOUT_GENERAL.",
11913                                          function_name, error_type.c_str(), string_VkImageLayout(attachment_ref.layout));
11914                         break;
11915                 }
11916             }
11917 
11918             if (subpass_performs_resolve && subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED &&
11919                 subpass.pResolveAttachments[j].attachment < pCreateInfo->attachmentCount) {
11920                 if (attachment_index == VK_ATTACHMENT_UNUSED) {
11921                     vuid = use_rp2 ? "VUID-VkSubpassDescription2-pResolveAttachments-03065"
11922                                    : "VUID-VkSubpassDescription-pResolveAttachments-00847";
11923                     skip |= LogError(device, vuid,
11924                                      "%s: Subpass %u requests multisample resolve from attachment %u which has "
11925                                      "attachment=VK_ATTACHMENT_UNUSED.",
11926                                      function_name, i, attachment_index);
11927                 } else {
11928                     const auto &color_desc = pCreateInfo->pAttachments[attachment_index];
11929                     const auto &resolve_desc = pCreateInfo->pAttachments[subpass.pResolveAttachments[j].attachment];
11930                     if (color_desc.format != resolve_desc.format) {
11931                         vuid = use_rp2 ? "VUID-VkSubpassDescription2-pResolveAttachments-03068"
11932                                        : "VUID-VkSubpassDescription-pResolveAttachments-00850";
11933                         skip |= LogError(device, vuid,
11934                                          "%s: %s resolves to an attachment with a "
11935                                          "different format. color format: %u, resolve format: %u.",
11936                                          function_name, error_type.c_str(), color_desc.format, resolve_desc.format);
11937                     }
11938                 }
11939             }
11940         }
11941     }
11942     return skip;
11943 }
11944 
ValidateCreateRenderPass(VkDevice device,RenderPassCreateVersion rp_version,const VkRenderPassCreateInfo2 * pCreateInfo,const char * function_name) const11945 bool CoreChecks::ValidateCreateRenderPass(VkDevice device, RenderPassCreateVersion rp_version,
11946                                           const VkRenderPassCreateInfo2 *pCreateInfo, const char *function_name) const {
11947     bool skip = false;
11948     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
11949     const char *vuid;
11950 
11951     skip |= ValidateRenderpassAttachmentUsage(rp_version, pCreateInfo, function_name);
11952 
11953     skip |= ValidateRenderPassDAG(rp_version, pCreateInfo);
11954 
11955     // Validate multiview correlation and view masks
11956     bool view_mask_zero = false;
11957     bool view_mask_non_zero = false;
11958 
11959     for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
11960         const VkSubpassDescription2 &subpass = pCreateInfo->pSubpasses[i];
11961         if (subpass.viewMask != 0) {
11962             view_mask_non_zero = true;
11963         } else {
11964             view_mask_zero = true;
11965         }
11966 
11967         if ((subpass.flags & VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX) != 0 &&
11968             (subpass.flags & VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX) == 0) {
11969             vuid = use_rp2 ? "VUID-VkSubpassDescription2-flags-03076" : "VUID-VkSubpassDescription-flags-00856";
11970             skip |= LogError(device, vuid,
11971                              "%s: The flags parameter of subpass description %u includes "
11972                              "VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX but does not also include "
11973                              "VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX.",
11974                              function_name, i);
11975         }
11976     }
11977 
11978     if (rp_version == RENDER_PASS_VERSION_2) {
11979         if (view_mask_non_zero && view_mask_zero) {
11980             skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-viewMask-03058",
11981                              "%s: Some view masks are non-zero whilst others are zero.", function_name);
11982         }
11983 
11984         if (view_mask_zero && pCreateInfo->correlatedViewMaskCount != 0) {
11985             skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-viewMask-03057",
11986                              "%s: Multiview is not enabled but correlation masks are still provided", function_name);
11987         }
11988     }
11989     uint32_t aggregated_cvms = 0;
11990     for (uint32_t i = 0; i < pCreateInfo->correlatedViewMaskCount; ++i) {
11991         if (aggregated_cvms & pCreateInfo->pCorrelatedViewMasks[i]) {
11992             vuid = use_rp2 ? "VUID-VkRenderPassCreateInfo2-pCorrelatedViewMasks-03056"
11993                            : "VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841";
11994             skip |=
11995                 LogError(device, vuid, "%s: pCorrelatedViewMasks[%u] contains a previously appearing view bit.", function_name, i);
11996         }
11997         aggregated_cvms |= pCreateInfo->pCorrelatedViewMasks[i];
11998     }
11999     LogObjectList objects(device);
12000 
12001     auto func_name = use_rp2 ? Func::vkCreateRenderPass2 : Func::vkCreateRenderPass;
12002     auto structure = use_rp2 ? Struct::VkSubpassDependency2 : Struct::VkSubpassDependency;
12003     for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
12004         auto const &dependency = pCreateInfo->pDependencies[i];
12005         Location loc(func_name, structure, Field::pDependencies, i);
12006         skip |= ValidateSubpassDependency(objects, loc, dependency);
12007     }
12008     return skip;
12009 }
12010 
PreCallValidateCreateRenderPass(VkDevice device,const VkRenderPassCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass) const12011 bool CoreChecks::PreCallValidateCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
12012                                                  const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) const {
12013     bool skip = false;
12014     // Handle extension structs from KHR_multiview and KHR_maintenance2 that can only be validated for RP1 (indices out of bounds)
12015     const VkRenderPassMultiviewCreateInfo *multiview_info = LvlFindInChain<VkRenderPassMultiviewCreateInfo>(pCreateInfo->pNext);
12016     if (multiview_info) {
12017         if (multiview_info->subpassCount && multiview_info->subpassCount != pCreateInfo->subpassCount) {
12018             skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pNext-01928",
12019                              "vkCreateRenderPass(): Subpass count is %u but multiview info has a subpass count of %u.",
12020                              pCreateInfo->subpassCount, multiview_info->subpassCount);
12021         } else if (multiview_info->dependencyCount && multiview_info->dependencyCount != pCreateInfo->dependencyCount) {
12022             skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pNext-01929",
12023                              "vkCreateRenderPass(): Dependency count is %u but multiview info has a dependency count of %u.",
12024                              pCreateInfo->dependencyCount, multiview_info->dependencyCount);
12025         }
12026         bool all_zero = true;
12027         bool all_not_zero = true;
12028         for (uint32_t i = 0; i < multiview_info->subpassCount; ++i) {
12029             all_zero &= multiview_info->pViewMasks[i] == 0;
12030             all_not_zero &= !(multiview_info->pViewMasks[i] == 0);
12031         }
12032         if (!all_zero && !all_not_zero) {
12033             skip |= LogError(
12034                 device, "VUID-VkRenderPassCreateInfo-pNext-02513",
12035                 "vkCreateRenderPass(): elements of VkRenderPassMultiviewCreateInfo pViewMasks must all be either 0 or not 0.");
12036         }
12037     }
12038     const VkRenderPassInputAttachmentAspectCreateInfo *input_attachment_aspect_info =
12039         LvlFindInChain<VkRenderPassInputAttachmentAspectCreateInfo>(pCreateInfo->pNext);
12040     if (input_attachment_aspect_info) {
12041         for (uint32_t i = 0; i < input_attachment_aspect_info->aspectReferenceCount; ++i) {
12042             uint32_t subpass = input_attachment_aspect_info->pAspectReferences[i].subpass;
12043             uint32_t attachment = input_attachment_aspect_info->pAspectReferences[i].inputAttachmentIndex;
12044             if (subpass >= pCreateInfo->subpassCount) {
12045                 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pNext-01926",
12046                                  "vkCreateRenderPass(): Subpass index %u specified by input attachment aspect info %u is greater "
12047                                  "than the subpass "
12048                                  "count of %u for this render pass.",
12049                                  subpass, i, pCreateInfo->subpassCount);
12050             } else if (pCreateInfo->pSubpasses && attachment >= pCreateInfo->pSubpasses[subpass].inputAttachmentCount) {
12051                 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-pNext-01927",
12052                                  "vkCreateRenderPass(): Input attachment index %u specified by input attachment aspect info %u is "
12053                                  "greater than the "
12054                                  "input attachment count of %u for this subpass.",
12055                                  attachment, i, pCreateInfo->pSubpasses[subpass].inputAttachmentCount);
12056             }
12057         }
12058     }
12059 
12060     // TODO - VK_EXT_fragment_density_map should be moved into generic ValidateCreateRenderPass() and given RP2 VUIDs
12061     const VkRenderPassFragmentDensityMapCreateInfoEXT *fragment_density_map_info =
12062         LvlFindInChain<VkRenderPassFragmentDensityMapCreateInfoEXT>(pCreateInfo->pNext);
12063     if (fragment_density_map_info) {
12064         if (fragment_density_map_info->fragmentDensityMapAttachment.attachment != VK_ATTACHMENT_UNUSED) {
12065             if (fragment_density_map_info->fragmentDensityMapAttachment.attachment >= pCreateInfo->attachmentCount) {
12066                 skip |= LogError(device, "VUID-VkRenderPassCreateInfo-fragmentDensityMapAttachment-06471",
12067                                  "vkCreateRenderPass(): fragmentDensityMapAttachment %u must be less than attachmentCount %u of "
12068                                  "for this render pass.",
12069                                  fragment_density_map_info->fragmentDensityMapAttachment.attachment, pCreateInfo->attachmentCount);
12070             } else {
12071                 if (!(fragment_density_map_info->fragmentDensityMapAttachment.layout ==
12072                           VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT ||
12073                       fragment_density_map_info->fragmentDensityMapAttachment.layout == VK_IMAGE_LAYOUT_GENERAL)) {
12074                     skip |= LogError(device, "VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02549",
12075                                      "vkCreateRenderPass(): Layout of fragmentDensityMapAttachment %u' must be equal to "
12076                                      "VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, or VK_IMAGE_LAYOUT_GENERAL.",
12077                                      fragment_density_map_info->fragmentDensityMapAttachment.attachment);
12078                 }
12079                 if (!(pCreateInfo->pAttachments[fragment_density_map_info->fragmentDensityMapAttachment.attachment].loadOp ==
12080                           VK_ATTACHMENT_LOAD_OP_LOAD ||
12081                       pCreateInfo->pAttachments[fragment_density_map_info->fragmentDensityMapAttachment.attachment].loadOp ==
12082                           VK_ATTACHMENT_LOAD_OP_DONT_CARE)) {
12083                     skip |= LogError(
12084                         device, "VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02550",
12085                         "vkCreateRenderPass(): FragmentDensityMapAttachment %u' must reference an attachment with a loadOp "
12086                         "equal to VK_ATTACHMENT_LOAD_OP_LOAD or VK_ATTACHMENT_LOAD_OP_DONT_CARE.",
12087                         fragment_density_map_info->fragmentDensityMapAttachment.attachment);
12088                 }
12089                 if (pCreateInfo->pAttachments[fragment_density_map_info->fragmentDensityMapAttachment.attachment].storeOp !=
12090                     VK_ATTACHMENT_STORE_OP_DONT_CARE) {
12091                     skip |= LogError(
12092                         device, "VUID-VkRenderPassFragmentDensityMapCreateInfoEXT-fragmentDensityMapAttachment-02551",
12093                         "vkCreateRenderPass(): FragmentDensityMapAttachment %u' must reference an attachment with a storeOp "
12094                         "equal to VK_ATTACHMENT_STORE_OP_DONT_CARE.",
12095                         fragment_density_map_info->fragmentDensityMapAttachment.attachment);
12096                 }
12097             }
12098         }
12099     }
12100 
12101     if (!skip) {
12102         safe_VkRenderPassCreateInfo2 create_info_2;
12103         ConvertVkRenderPassCreateInfoToV2KHR(*pCreateInfo, &create_info_2);
12104         skip |= ValidateCreateRenderPass(device, RENDER_PASS_VERSION_1, create_info_2.ptr(), "vkCreateRenderPass()");
12105     }
12106 
12107     return skip;
12108 }
12109 
12110 // VK_KHR_depth_stencil_resolve was added with a requirement on VK_KHR_create_renderpass2 so this will never be able to use
12111 // VkRenderPassCreateInfo
ValidateDepthStencilResolve(const VkRenderPassCreateInfo2 * pCreateInfo,const char * function_name) const12112 bool CoreChecks::ValidateDepthStencilResolve(const VkRenderPassCreateInfo2 *pCreateInfo, const char *function_name) const {
12113     bool skip = false;
12114 
12115     // If the pNext list of VkSubpassDescription2 includes a VkSubpassDescriptionDepthStencilResolve structure,
12116     // then that structure describes depth/stencil resolve operations for the subpass.
12117     for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
12118         const VkSubpassDescription2 &subpass = pCreateInfo->pSubpasses[i];
12119         const auto *resolve = LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(subpass.pNext);
12120 
12121         // All of the VUs are wrapped in the wording:
12122         // "If pDepthStencilResolveAttachment is not NULL"
12123         if (resolve == nullptr || resolve->pDepthStencilResolveAttachment == nullptr) {
12124             continue;
12125         }
12126 
12127         // The spec says
12128         // "If pDepthStencilAttachment is NULL, or if its attachment index is VK_ATTACHMENT_UNUSED, it indicates that no
12129         // depth/stencil attachment will be used in the subpass."
12130         if (subpass.pDepthStencilAttachment == nullptr) {
12131             continue;
12132         } else if (subpass.pDepthStencilAttachment->attachment == VK_ATTACHMENT_UNUSED) {
12133             // while should be ignored, this is an explicit VU and some drivers will crash if this is let through
12134             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03177",
12135                              "%s: Subpass %" PRIu32
12136                              " includes a VkSubpassDescriptionDepthStencilResolve "
12137                              "structure with resolve attachment %" PRIu32 ", but pDepthStencilAttachment=VK_ATTACHMENT_UNUSED.",
12138                              function_name, i, resolve->pDepthStencilResolveAttachment->attachment);
12139             continue;
12140         }
12141 
12142         const uint32_t ds_attachment = subpass.pDepthStencilAttachment->attachment;
12143         const uint32_t resolve_attachment = resolve->pDepthStencilResolveAttachment->attachment;
12144 
12145         // ValidateAttachmentIndex() should catch if this is invalid, but skip to avoid crashing
12146         if (ds_attachment >= pCreateInfo->attachmentCount) {
12147             continue;
12148         }
12149 
12150         // All VUs in VkSubpassDescriptionDepthStencilResolve are wrapped with language saying it is not unused
12151         if (resolve_attachment == VK_ATTACHMENT_UNUSED) {
12152             continue;
12153         }
12154 
12155         if (resolve_attachment >= pCreateInfo->attachmentCount) {
12156             skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-pSubpasses-06473",
12157                              "%s: pDepthStencilResolveAttachment %" PRIu32 " must be less than attachmentCount %" PRIu32
12158                              " of for this render pass.",
12159                              function_name, resolve_attachment, pCreateInfo->attachmentCount);
12160             // if the index is invalid need to skip everything else to prevent out of bounds index accesses crashing
12161             continue;
12162         }
12163 
12164         const VkFormat ds_attachment_format = pCreateInfo->pAttachments[ds_attachment].format;
12165         const VkFormat resolve_attachment_format = pCreateInfo->pAttachments[resolve_attachment].format;
12166 
12167         // "depthResolveMode is ignored if the VkFormat of the pDepthStencilResolveAttachment does not have a depth component"
12168         bool resolve_has_depth = FormatHasDepth(resolve_attachment_format);
12169         // "stencilResolveMode is ignored if the VkFormat of the pDepthStencilResolveAttachment does not have a stencil component"
12170         bool resolve_has_stencil = FormatHasStencil(resolve_attachment_format);
12171 
12172         if (resolve_has_depth) {
12173             if (!(resolve->depthResolveMode == VK_RESOLVE_MODE_NONE ||
12174                   resolve->depthResolveMode & phys_dev_props_core12.supportedDepthResolveModes)) {
12175                 skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-depthResolveMode-03183",
12176                                  "%s: Subpass %" PRIu32
12177                                  " includes a VkSubpassDescriptionDepthStencilResolve "
12178                                  "structure with invalid depthResolveMode (%s), must be VK_RESOLVE_MODE_NONE or a value from "
12179                                  "supportedDepthResolveModes (%s).",
12180                                  function_name, i, string_VkResolveModeFlagBits(resolve->depthResolveMode),
12181                                  string_VkResolveModeFlags(phys_dev_props_core12.supportedDepthResolveModes).c_str());
12182             }
12183         }
12184 
12185         if (resolve_has_stencil) {
12186             if (!(resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE ||
12187                   resolve->stencilResolveMode & phys_dev_props_core12.supportedStencilResolveModes)) {
12188                 skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-stencilResolveMode-03184",
12189                                  "%s: Subpass %" PRIu32
12190                                  " includes a VkSubpassDescriptionDepthStencilResolve "
12191                                  "structure with invalid stencilResolveMode (%s), must be VK_RESOLVE_MODE_NONE or a value from "
12192                                  "supportedStencilResolveModes (%s).",
12193                                  function_name, i, string_VkResolveModeFlagBits(resolve->stencilResolveMode),
12194                                  string_VkResolveModeFlags(phys_dev_props_core12.supportedStencilResolveModes).c_str());
12195             }
12196         }
12197 
12198         if (resolve_has_depth && resolve_has_stencil) {
12199             if (phys_dev_props_core12.independentResolve == VK_FALSE && phys_dev_props_core12.independentResolveNone == VK_FALSE &&
12200                 !(resolve->depthResolveMode == resolve->stencilResolveMode)) {
12201                 skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03185",
12202                                  "%s: Subpass %" PRIu32
12203                                  " includes a VkSubpassDescriptionDepthStencilResolve "
12204                                  "structure. The values of depthResolveMode (%s) and stencilResolveMode (%s) must be identical.",
12205                                  function_name, i, string_VkResolveModeFlagBits(resolve->depthResolveMode),
12206                                  string_VkResolveModeFlagBits(resolve->stencilResolveMode));
12207             }
12208 
12209             if (phys_dev_props_core12.independentResolve == VK_FALSE && phys_dev_props_core12.independentResolveNone == VK_TRUE &&
12210                 !(resolve->depthResolveMode == resolve->stencilResolveMode || resolve->depthResolveMode == VK_RESOLVE_MODE_NONE ||
12211                   resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE)) {
12212                 skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03186",
12213                                  "%s: Subpass %" PRIu32
12214                                  " includes a VkSubpassDescriptionDepthStencilResolve "
12215                                  "structure. The values of depthResolveMode (%s) and stencilResolveMode (%s) must be identical, or "
12216                                  "one of them must be VK_RESOLVE_MODE_NONE.",
12217                                  function_name, i, string_VkResolveModeFlagBits(resolve->depthResolveMode),
12218                                  string_VkResolveModeFlagBits(resolve->stencilResolveMode));
12219             }
12220         }
12221 
12222         // Same VU, but better error message if one of the resolves are ignored
12223         if (resolve_has_depth && !resolve_has_stencil && resolve->depthResolveMode == VK_RESOLVE_MODE_NONE) {
12224             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03178",
12225                              "%s: Subpass %" PRIu32
12226                              " includes a VkSubpassDescriptionDepthStencilResolve structure with resolve "
12227                              "attachment %" PRIu32
12228                              ", but the depth resolve mode is VK_RESOLVE_MODE_NONE (stencil resolve mode is "
12229                              "ignored due to format not having stencil component).",
12230                              function_name, i, resolve_attachment);
12231         } else if (!resolve_has_depth && resolve_has_stencil && resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE) {
12232             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03178",
12233                              "%s: Subpass %" PRIu32
12234                              " includes a VkSubpassDescriptionDepthStencilResolve structure with resolve "
12235                              "attachment %" PRIu32
12236                              ", but the stencil resolve mode is VK_RESOLVE_MODE_NONE (depth resolve mode is "
12237                              "ignored due to format not having depth component).",
12238                              function_name, i, resolve_attachment);
12239         } else if (resolve_has_depth && resolve_has_stencil && resolve->depthResolveMode == VK_RESOLVE_MODE_NONE &&
12240                    resolve->stencilResolveMode == VK_RESOLVE_MODE_NONE) {
12241             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03178",
12242                              "%s: Subpass %" PRIu32
12243                              " includes a VkSubpassDescriptionDepthStencilResolve structure with resolve "
12244                              "attachment %" PRIu32 ", but both depth and stencil resolve modes are VK_RESOLVE_MODE_NONE.",
12245                              function_name, i, resolve_attachment);
12246         }
12247 
12248         const uint32_t resolve_depth_size = FormatDepthSize(resolve_attachment_format);
12249         const uint32_t resolve_stencil_size = FormatStencilSize(resolve_attachment_format);
12250 
12251         if (resolve_depth_size > 0 &&
12252             ((FormatDepthSize(ds_attachment_format) != resolve_depth_size) ||
12253              (FormatDepthNumericalType(ds_attachment_format) != FormatDepthNumericalType(ds_attachment_format)))) {
12254             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03181",
12255                              "%s: Subpass %" PRIu32
12256                              " includes a VkSubpassDescriptionDepthStencilResolve "
12257                              "structure with resolve attachment %" PRIu32 " which has a depth component (size %" PRIu32
12258                              "). The depth component "
12259                              "of pDepthStencilAttachment must have the same number of bits (currently %" PRIu32
12260                              ") and the same numerical type.",
12261                              function_name, i, resolve_attachment, resolve_depth_size, FormatDepthSize(ds_attachment_format));
12262         }
12263 
12264         if (resolve_stencil_size > 0 &&
12265             ((FormatStencilSize(ds_attachment_format) != resolve_stencil_size) ||
12266              (FormatStencilNumericalType(ds_attachment_format) != FormatStencilNumericalType(resolve_attachment_format)))) {
12267             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03182",
12268                              "%s: Subpass %" PRIu32
12269                              " includes a VkSubpassDescriptionDepthStencilResolve "
12270                              "structure with resolve attachment %" PRIu32 " which has a stencil component (size %" PRIu32
12271                              "). The stencil component "
12272                              "of pDepthStencilAttachment must have the same number of bits (currently %" PRIu32
12273                              ") and the same numerical type.",
12274                              function_name, i, resolve_attachment, resolve_stencil_size, FormatStencilSize(ds_attachment_format));
12275         }
12276 
12277         if (pCreateInfo->pAttachments[ds_attachment].samples == VK_SAMPLE_COUNT_1_BIT) {
12278             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03179",
12279                              "%s: Subpass %" PRIu32
12280                              " includes a VkSubpassDescriptionDepthStencilResolve "
12281                              "structure with resolve attachment %" PRIu32
12282                              ". However pDepthStencilAttachment has sample count=VK_SAMPLE_COUNT_1_BIT.",
12283                              function_name, i, resolve_attachment);
12284         }
12285 
12286         if (pCreateInfo->pAttachments[resolve_attachment].samples != VK_SAMPLE_COUNT_1_BIT) {
12287             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-03180",
12288                              "%s: Subpass %" PRIu32
12289                              " includes a VkSubpassDescriptionDepthStencilResolve "
12290                              "structure with resolve attachment %" PRIu32 " which has sample count=VK_SAMPLE_COUNT_1_BIT.",
12291                              function_name, i, resolve_attachment);
12292         }
12293 
12294         const VkFormatFeatureFlags potential_format_features = GetPotentialFormatFeatures(resolve_attachment_format);
12295         if ((potential_format_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
12296             skip |= LogError(device, "VUID-VkSubpassDescriptionDepthStencilResolve-pDepthStencilResolveAttachment-02651",
12297                              "%s: Subpass %" PRIu32
12298                              " includes a VkSubpassDescriptionDepthStencilResolve "
12299                              "structure with resolve attachment %" PRIu32
12300                              " with a format (%s) whose features do not contain VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.",
12301                              function_name, i, resolve_attachment, string_VkFormat(resolve_attachment_format));
12302         }
12303 
12304         //  VK_QCOM_render_pass_shader_resolve check of depth/stencil attachmnent
12305         if ((subpass.flags & VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM) != 0) {
12306             skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-flags-04908",
12307                              "%s: Subpass %" PRIu32
12308                              " enables shader resolve, which requires the depth/stencil resolve attachment"
12309                              " must be VK_ATTACHMENT_UNUSED, but a reference to attachment %" PRIu32 " was found instead.",
12310                              function_name, i, resolve_attachment);
12311         }
12312     }
12313 
12314     return skip;
12315 }
12316 
ValidateCreateRenderPass2(VkDevice device,const VkRenderPassCreateInfo2 * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass,const char * function_name) const12317 bool CoreChecks::ValidateCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo,
12318                                            const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass,
12319                                            const char *function_name) const {
12320     bool skip = false;
12321 
12322     if (IsExtEnabled(device_extensions.vk_khr_depth_stencil_resolve)) {
12323         skip |= ValidateDepthStencilResolve(pCreateInfo, function_name);
12324     }
12325 
12326     skip |= ValidateFragmentShadingRateAttachments(device, pCreateInfo);
12327 
12328     safe_VkRenderPassCreateInfo2 create_info_2(pCreateInfo);
12329     skip |= ValidateCreateRenderPass(device, RENDER_PASS_VERSION_2, create_info_2.ptr(), function_name);
12330 
12331     return skip;
12332 }
12333 
ValidateFragmentShadingRateAttachments(VkDevice device,const VkRenderPassCreateInfo2 * pCreateInfo) const12334 bool CoreChecks::ValidateFragmentShadingRateAttachments(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo) const {
12335     bool skip = false;
12336 
12337     if (enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
12338         for (uint32_t attachment_description = 0; attachment_description < pCreateInfo->attachmentCount; ++attachment_description) {
12339             std::vector<uint32_t> used_as_fragment_shading_rate_attachment;
12340 
12341             // Prepass to find any use as a fragment shading rate attachment structures and validate them independently
12342             for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
12343                 const VkFragmentShadingRateAttachmentInfoKHR *fragment_shading_rate_attachment =
12344                     LvlFindInChain<VkFragmentShadingRateAttachmentInfoKHR>(pCreateInfo->pSubpasses[subpass].pNext);
12345 
12346                 if (fragment_shading_rate_attachment && fragment_shading_rate_attachment->pFragmentShadingRateAttachment) {
12347                     const VkAttachmentReference2 &attachment_reference =
12348                         *(fragment_shading_rate_attachment->pFragmentShadingRateAttachment);
12349                     if (attachment_reference.attachment == attachment_description) {
12350                         used_as_fragment_shading_rate_attachment.push_back(subpass);
12351                     }
12352 
12353                     if (((pCreateInfo->flags & VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM) != 0) &&
12354                         (attachment_reference.attachment != VK_ATTACHMENT_UNUSED)) {
12355                         skip |= LogError(device, "VUID-VkRenderPassCreateInfo2-flags-04521",
12356                                          "vkCreateRenderPass2: Render pass includes VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM but "
12357                                          "a fragment shading rate attachment is specified in subpass %u.",
12358                                          subpass);
12359                     }
12360 
12361                     if (attachment_reference.attachment != VK_ATTACHMENT_UNUSED) {
12362                         const VkFormatFeatureFlags potential_format_features =
12363                             GetPotentialFormatFeatures(pCreateInfo->pAttachments[attachment_reference.attachment].format);
12364 
12365                         if (!(potential_format_features & VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR)) {
12366                             skip |=
12367                                 LogError(device, "VUID-VkRenderPassCreateInfo2-pAttachments-04586",
12368                                          "vkCreateRenderPass2: Attachment description %u is used in subpass %u as a fragment "
12369                                          "shading rate attachment, but specifies format %s, which does not support "
12370                                          "VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR.",
12371                                          attachment_reference.attachment, subpass,
12372                                          string_VkFormat(pCreateInfo->pAttachments[attachment_reference.attachment].format));
12373                         }
12374 
12375                         if (attachment_reference.layout != VK_IMAGE_LAYOUT_GENERAL &&
12376                             attachment_reference.layout != VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR) {
12377                             skip |= LogError(
12378                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04524",
12379                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u specifies a layout of %s.",
12380                                 subpass, string_VkImageLayout(attachment_reference.layout));
12381                         }
12382 
12383                         if (!IsPowerOfTwo(fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width)) {
12384                             skip |=
12385                                 LogError(device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04525",
12386                                          "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a "
12387                                          "non-power-of-two texel width of %u.",
12388                                          subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width);
12389                         }
12390                         if (fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width <
12391                             phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.width) {
12392                             skip |= LogError(
12393                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04526",
12394                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a texel width of %u which "
12395                                 "is lower than the advertised minimum width %u.",
12396                                 subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width,
12397                                 phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.width);
12398                         }
12399                         if (fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width >
12400                             phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.width) {
12401                             skip |= LogError(
12402                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04527",
12403                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a texel width of %u which "
12404                                 "is higher than the advertised maximum width %u.",
12405                                 subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width,
12406                                 phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.width);
12407                         }
12408                         if (!IsPowerOfTwo(fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height)) {
12409                             skip |=
12410                                 LogError(device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04528",
12411                                          "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a "
12412                                          "non-power-of-two texel height of %u.",
12413                                          subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height);
12414                         }
12415                         if (fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height <
12416                             phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.height) {
12417                             skip |= LogError(
12418                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04529",
12419                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a texel height of %u "
12420                                 "which is lower than the advertised minimum height %u.",
12421                                 subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height,
12422                                 phys_dev_ext_props.fragment_shading_rate_props.minFragmentShadingRateAttachmentTexelSize.height);
12423                         }
12424                         if (fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height >
12425                             phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.height) {
12426                             skip |= LogError(
12427                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04530",
12428                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a texel height of %u "
12429                                 "which is higher than the advertised maximum height %u.",
12430                                 subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height,
12431                                 phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSize.height);
12432                         }
12433                         uint32_t aspect_ratio = fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width /
12434                                                 fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height;
12435                         uint32_t inverse_aspect_ratio = fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height /
12436                                                         fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width;
12437                         if (aspect_ratio >
12438                             phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSizeAspectRatio) {
12439                             skip |= LogError(
12440                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04531",
12441                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a texel size of %u by %u, "
12442                                 "which has an aspect ratio %u, which is higher than the advertised maximum aspect ratio %u.",
12443                                 subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width,
12444                                 fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height, aspect_ratio,
12445                                 phys_dev_ext_props.fragment_shading_rate_props
12446                                     .maxFragmentShadingRateAttachmentTexelSizeAspectRatio);
12447                         }
12448                         if (inverse_aspect_ratio >
12449                             phys_dev_ext_props.fragment_shading_rate_props.maxFragmentShadingRateAttachmentTexelSizeAspectRatio) {
12450                             skip |= LogError(
12451                                 device, "VUID-VkFragmentShadingRateAttachmentInfoKHR-pFragmentShadingRateAttachment-04532",
12452                                 "vkCreateRenderPass2: Fragment shading rate attachment in subpass %u has a texel size of %u by %u, "
12453                                 "which has an inverse aspect ratio of %u, which is higher than the advertised maximum aspect ratio "
12454                                 "%u.",
12455                                 subpass, fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.width,
12456                                 fragment_shading_rate_attachment->shadingRateAttachmentTexelSize.height, inverse_aspect_ratio,
12457                                 phys_dev_ext_props.fragment_shading_rate_props
12458                                     .maxFragmentShadingRateAttachmentTexelSizeAspectRatio);
12459                         }
12460                     }
12461                 }
12462             }
12463 
12464             // Lambda function turning a vector of integers into a string
12465             auto vector_to_string = [&](std::vector<uint32_t> vector) {
12466                 std::stringstream ss;
12467                 size_t size = vector.size();
12468                 for (size_t i = 0; i < used_as_fragment_shading_rate_attachment.size(); i++) {
12469                     if (size == 2 && i == 1) {
12470                         ss << " and ";
12471                     } else if (size > 2 && i == size - 2) {
12472                         ss << ", and ";
12473                     } else if (i != 0) {
12474                         ss << ", ";
12475                     }
12476                     ss << vector[i];
12477                 }
12478                 return ss.str();
12479             };
12480 
12481             // Search for other uses of the same attachment
12482             if (!used_as_fragment_shading_rate_attachment.empty()) {
12483                 for (uint32_t subpass = 0; subpass < pCreateInfo->subpassCount; ++subpass) {
12484                     const VkSubpassDescription2 &subpass_info = pCreateInfo->pSubpasses[subpass];
12485                     const VkSubpassDescriptionDepthStencilResolve *depth_stencil_resolve_attachment =
12486                         LvlFindInChain<VkSubpassDescriptionDepthStencilResolve>(subpass_info.pNext);
12487 
12488                     std::string fsr_attachment_subpasses_string = vector_to_string(used_as_fragment_shading_rate_attachment);
12489 
12490                     for (uint32_t attachment = 0; attachment < subpass_info.colorAttachmentCount; ++attachment) {
12491                         if (subpass_info.pColorAttachments[attachment].attachment == attachment_description) {
12492                             skip |= LogError(
12493                                 device, "VUID-VkRenderPassCreateInfo2-pAttachments-04585",
12494                                 "vkCreateRenderPass2: Attachment description %u is used as a fragment shading rate attachment in "
12495                                 "subpass(es) %s but also as color attachment %u in subpass %u",
12496                                 attachment_description, fsr_attachment_subpasses_string.c_str(), attachment, subpass);
12497                         }
12498                     }
12499                     for (uint32_t attachment = 0; attachment < subpass_info.colorAttachmentCount; ++attachment) {
12500                         if (subpass_info.pResolveAttachments &&
12501                             subpass_info.pResolveAttachments[attachment].attachment == attachment_description) {
12502                             skip |= LogError(
12503                                 device, "VUID-VkRenderPassCreateInfo2-pAttachments-04585",
12504                                 "vkCreateRenderPass2: Attachment description %u is used as a fragment shading rate attachment in "
12505                                 "subpass(es) %s but also as color resolve attachment %u in subpass %u",
12506                                 attachment_description, fsr_attachment_subpasses_string.c_str(), attachment, subpass);
12507                         }
12508                     }
12509                     for (uint32_t attachment = 0; attachment < subpass_info.inputAttachmentCount; ++attachment) {
12510                         if (subpass_info.pInputAttachments[attachment].attachment == attachment_description) {
12511                             skip |= LogError(
12512                                 device, "VUID-VkRenderPassCreateInfo2-pAttachments-04585",
12513                                 "vkCreateRenderPass2: Attachment description %u is used as a fragment shading rate attachment in "
12514                                 "subpass(es) %s but also as input attachment %u in subpass %u",
12515                                 attachment_description, fsr_attachment_subpasses_string.c_str(), attachment, subpass);
12516                         }
12517                     }
12518                     if (subpass_info.pDepthStencilAttachment) {
12519                         if (subpass_info.pDepthStencilAttachment->attachment == attachment_description) {
12520                             skip |= LogError(
12521                                 device, "VUID-VkRenderPassCreateInfo2-pAttachments-04585",
12522                                 "vkCreateRenderPass2: Attachment description %u is used as a fragment shading rate attachment in "
12523                                 "subpass(es) %s but also as the depth/stencil attachment in subpass %u",
12524                                 attachment_description, fsr_attachment_subpasses_string.c_str(), subpass);
12525                         }
12526                     }
12527                     if (depth_stencil_resolve_attachment && depth_stencil_resolve_attachment->pDepthStencilResolveAttachment) {
12528                         if (depth_stencil_resolve_attachment->pDepthStencilResolveAttachment->attachment ==
12529                             attachment_description) {
12530                             skip |= LogError(
12531                                 device, "VUID-VkRenderPassCreateInfo2-pAttachments-04585",
12532                                 "vkCreateRenderPass2: Attachment description %u is used as a fragment shading rate attachment in "
12533                                 "subpass(es) %s but also as the depth/stencil resolve attachment in subpass %u",
12534                                 attachment_description, fsr_attachment_subpasses_string.c_str(), subpass);
12535                         }
12536                     }
12537                 }
12538             }
12539         }
12540     }
12541 
12542     return skip;
12543 }
12544 
PreCallValidateCreateRenderPass2KHR(VkDevice device,const VkRenderPassCreateInfo2 * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass) const12545 bool CoreChecks::PreCallValidateCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo,
12546                                                      const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) const {
12547     return ValidateCreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass, "vkCreateRenderPass2KHR()");
12548 }
12549 
PreCallValidateCreateRenderPass2(VkDevice device,const VkRenderPassCreateInfo2 * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkRenderPass * pRenderPass) const12550 bool CoreChecks::PreCallValidateCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo,
12551                                                   const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) const {
12552     return ValidateCreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass, "vkCreateRenderPass2()");
12553 }
12554 
ValidatePrimaryCommandBuffer(const CMD_BUFFER_STATE * pCB,char const * cmd_name,const char * error_code) const12555 bool CoreChecks::ValidatePrimaryCommandBuffer(const CMD_BUFFER_STATE *pCB, char const *cmd_name, const char *error_code) const {
12556     bool skip = false;
12557     if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
12558         skip |= LogError(pCB->commandBuffer(), error_code, "Cannot execute command %s on a secondary command buffer.", cmd_name);
12559     }
12560     return skip;
12561 }
12562 
VerifyRenderAreaBounds(const VkRenderPassBeginInfo * pRenderPassBegin,const char * func_name) const12563 bool CoreChecks::VerifyRenderAreaBounds(const VkRenderPassBeginInfo *pRenderPassBegin, const char *func_name) const {
12564     bool skip = false;
12565 
12566     bool device_group = false;
12567     uint32_t device_group_area_count = 0;
12568     const VkDeviceGroupRenderPassBeginInfo *device_group_render_pass_begin_info =
12569         LvlFindInChain<VkDeviceGroupRenderPassBeginInfo>(pRenderPassBegin->pNext);
12570     if (IsExtEnabled(device_extensions.vk_khr_device_group)) {
12571         device_group = true;
12572         if (device_group_render_pass_begin_info) {
12573             device_group_area_count = device_group_render_pass_begin_info->deviceRenderAreaCount;
12574         }
12575     }
12576     auto framebuffer_state = Get<FRAMEBUFFER_STATE>(pRenderPassBegin->framebuffer);
12577     const auto *framebuffer_info = &framebuffer_state->createInfo;
12578     if (device_group && device_group_area_count > 0) {
12579         for (uint32_t i = 0; i < device_group_render_pass_begin_info->deviceRenderAreaCount; ++i) {
12580             const auto &deviceRenderArea = device_group_render_pass_begin_info->pDeviceRenderAreas[i];
12581             if (deviceRenderArea.offset.x < 0) {
12582                 skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkDeviceGroupRenderPassBeginInfo-offset-06166",
12583                                  "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, "
12584                                  "VkDeviceGroupRenderPassBeginInfo::pDeviceRenderAreas[%" PRIu32 "].offset.x is negative (%" PRIi32
12585                                  ").",
12586                                  func_name, i, deviceRenderArea.offset.x);
12587             }
12588             if (deviceRenderArea.offset.y < 0) {
12589                 skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkDeviceGroupRenderPassBeginInfo-offset-06167",
12590                                  "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, "
12591                                  "VkDeviceGroupRenderPassBeginInfo::pDeviceRenderAreas[%" PRIu32 "].offset.y is negative (%" PRIi32
12592                                  ").",
12593                                  func_name, i, deviceRenderArea.offset.y);
12594             }
12595             if ((deviceRenderArea.offset.x + deviceRenderArea.extent.width) > framebuffer_info->width) {
12596                 skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-pNext-02856",
12597                                  "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, "
12598                                  "VkDeviceGroupRenderPassBeginInfo::pDeviceRenderAreas[%" PRIu32 "] offset.x (%" PRIi32
12599                                  ") + extent.width (%" PRIi32 ") is greater than framebuffer width (%" PRIi32 ").",
12600                                  func_name, i, deviceRenderArea.offset.x, deviceRenderArea.extent.width, framebuffer_info->width);
12601             }
12602             if ((deviceRenderArea.offset.y + deviceRenderArea.extent.height) > framebuffer_info->height) {
12603                 skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-pNext-02857",
12604                                  "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, "
12605                                  "VkDeviceGroupRenderPassBeginInfo::pDeviceRenderAreas[%" PRIu32 "] offset.y (%" PRIi32
12606                                  ") + extent.height (%" PRIi32 ") is greater than framebuffer height (%" PRIi32 ").",
12607                                  func_name, i, deviceRenderArea.offset.y, deviceRenderArea.extent.height, framebuffer_info->height);
12608             }
12609         }
12610     } else {
12611         if (pRenderPassBegin->renderArea.offset.x < 0) {
12612             if (device_group) {
12613                 skip |=
12614                     LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-pNext-02850",
12615                              "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer and pNext "
12616                              "of VkRenderPassBeginInfo does not contain VkDeviceGroupRenderPassBeginInfo or its "
12617                              "deviceRenderAreaCount is 0, renderArea.offset.x is negative (%" PRIi32 ") .",
12618                              func_name, pRenderPassBegin->renderArea.offset.x);
12619             } else {
12620                 skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-renderArea-02846",
12621                                  "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, "
12622                                  "renderArea.offset.x is negative (%" PRIi32 ") .",
12623                                  func_name, pRenderPassBegin->renderArea.offset.x);
12624             }
12625         }
12626         if (pRenderPassBegin->renderArea.offset.y < 0) {
12627             if (device_group) {
12628                 skip |=
12629                     LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-pNext-02851",
12630                              "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer and pNext "
12631                              "of VkRenderPassBeginInfo does not contain VkDeviceGroupRenderPassBeginInfo or its "
12632                              "deviceRenderAreaCount is 0, renderArea.offset.y is negative (%" PRIi32 ") .",
12633                              func_name, pRenderPassBegin->renderArea.offset.y);
12634             } else {
12635                 skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-renderArea-02847",
12636                                  "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, "
12637                                  "renderArea.offset.y is negative (%" PRIi32 ") .",
12638                                  func_name, pRenderPassBegin->renderArea.offset.y);
12639             }
12640         }
12641         if ((pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > framebuffer_info->width) {
12642             if (device_group) {
12643                 skip |=
12644                     LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-pNext-02852",
12645                              "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer and pNext "
12646                              "of VkRenderPassBeginInfo does not contain VkDeviceGroupRenderPassBeginInfo or its "
12647                              "deviceRenderAreaCount is 0, renderArea.offset.x (%" PRIi32 ") + renderArea.extent.width (%" PRIi32
12648                              ") is greater than framebuffer width (%" PRIi32 ").",
12649                              func_name, pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.extent.width,
12650                              framebuffer_info->width);
12651             } else {
12652                 skip |= LogError(
12653                     pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-renderArea-02848",
12654                     "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, renderArea.offset.x "
12655                     "(%" PRIi32 ") + renderArea.extent.width (%" PRIi32 ") is greater than framebuffer width (%" PRIi32 ").",
12656                     func_name, pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.extent.width,
12657                     framebuffer_info->width);
12658             }
12659         }
12660         if ((pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > framebuffer_info->height) {
12661             if (device_group) {
12662                 skip |=
12663                     LogError(pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-pNext-02853",
12664                              "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer and pNext "
12665                              "of VkRenderPassBeginInfo does not contain VkDeviceGroupRenderPassBeginInfo or its "
12666                              "deviceRenderAreaCount is 0, renderArea.offset.y (%" PRIi32 ") + renderArea.extent.height (%" PRIi32
12667                              ") is greater than framebuffer height (%" PRIi32 ").",
12668                              func_name, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.height,
12669                              framebuffer_info->height);
12670             } else {
12671                 skip |= LogError(
12672                     pRenderPassBegin->renderPass, "VUID-VkRenderPassBeginInfo-renderArea-02849",
12673                     "%s: Cannot execute a render pass with renderArea not within the bound of the framebuffer, renderArea.offset.y "
12674                     "(%" PRIi32 ") + renderArea.extent.height (%" PRIi32 ") is greater than framebuffer height (%" PRIi32 ").",
12675                     func_name, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.height,
12676                     framebuffer_info->height);
12677             }
12678         }
12679     }
12680     return skip;
12681 }
12682 
VerifyFramebufferAndRenderPassImageViews(const VkRenderPassBeginInfo * pRenderPassBeginInfo,const char * func_name) const12683 bool CoreChecks::VerifyFramebufferAndRenderPassImageViews(const VkRenderPassBeginInfo *pRenderPassBeginInfo,
12684                                                           const char *func_name) const {
12685     bool skip = false;
12686     const VkRenderPassAttachmentBeginInfo *render_pass_attachment_begin_info =
12687         LvlFindInChain<VkRenderPassAttachmentBeginInfo>(pRenderPassBeginInfo->pNext);
12688 
12689     if (render_pass_attachment_begin_info && render_pass_attachment_begin_info->attachmentCount != 0) {
12690         auto framebuffer_state = Get<FRAMEBUFFER_STATE>(pRenderPassBeginInfo->framebuffer);
12691         const auto *framebuffer_create_info = &framebuffer_state->createInfo;
12692         const VkFramebufferAttachmentsCreateInfo *framebuffer_attachments_create_info =
12693             LvlFindInChain<VkFramebufferAttachmentsCreateInfo>(framebuffer_create_info->pNext);
12694         if ((framebuffer_create_info->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT) == 0) {
12695             skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03207",
12696                              "%s: Image views specified at render pass begin, but framebuffer not created with "
12697                              "VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT",
12698                              func_name);
12699         } else if (framebuffer_attachments_create_info) {
12700             if (framebuffer_attachments_create_info->attachmentImageInfoCount !=
12701                 render_pass_attachment_begin_info->attachmentCount) {
12702                 skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03208",
12703                                  "%s: %u image views specified at render pass begin, but framebuffer "
12704                                  "created expecting %u attachments",
12705                                  func_name, render_pass_attachment_begin_info->attachmentCount,
12706                                  framebuffer_attachments_create_info->attachmentImageInfoCount);
12707             } else {
12708                 auto render_pass_state = Get<RENDER_PASS_STATE>(pRenderPassBeginInfo->renderPass);
12709                 const auto *render_pass_create_info = &render_pass_state->createInfo;
12710                 for (uint32_t i = 0; i < render_pass_attachment_begin_info->attachmentCount; ++i) {
12711                     const auto image_view_state = Get<IMAGE_VIEW_STATE>(render_pass_attachment_begin_info->pAttachments[i]);
12712                     const VkImageViewCreateInfo *image_view_create_info = &image_view_state->create_info;
12713                     const auto &subresource_range = image_view_state->normalized_subresource_range;
12714                     const VkFramebufferAttachmentImageInfo *framebuffer_attachment_image_info =
12715                         &framebuffer_attachments_create_info->pAttachmentImageInfos[i];
12716                     const auto *image_create_info = &image_view_state->image_state->createInfo;
12717 
12718                     if (framebuffer_attachment_image_info->flags != image_create_info->flags) {
12719                         skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03209",
12720                                          "%s: Image view #%u created from an image with flags set as 0x%X, "
12721                                          "but image info #%u used to create the framebuffer had flags set as 0x%X",
12722                                          func_name, i, image_create_info->flags, i, framebuffer_attachment_image_info->flags);
12723                     }
12724 
12725                     if (framebuffer_attachment_image_info->usage != image_view_state->inherited_usage) {
12726                         // Give clearer message if this error is due to the "inherited" part or not
12727                         if (image_create_info->usage == image_view_state->inherited_usage) {
12728                             skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-04627",
12729                                              "%s: Image view #%u created from an image with usage set as 0x%X, "
12730                                              "but image info #%u used to create the framebuffer had usage set as 0x%X",
12731                                              func_name, i, image_create_info->usage, i, framebuffer_attachment_image_info->usage);
12732                         } else {
12733                             skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-04627",
12734                                              "%s: Image view #%u created from an image with usage set as 0x%X but using "
12735                                              "VkImageViewUsageCreateInfo the inherited usage is the subset 0x%X "
12736                                              "and the image info #%u used to create the framebuffer had usage set as 0x%X",
12737                                              func_name, i, image_create_info->usage, image_view_state->inherited_usage, i,
12738                                              framebuffer_attachment_image_info->usage);
12739                         }
12740                     }
12741 
12742                     const auto view_width = image_create_info->extent.width >> subresource_range.baseMipLevel;
12743                     if (framebuffer_attachment_image_info->width != view_width) {
12744                         skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03211",
12745                                          "%s: For VkRenderPassAttachmentBeginInfo::pAttachments[%" PRIu32
12746                                          "], VkImageView width (%" PRIu32 ") at mip level %" PRIu32 " (%" PRIu32
12747                                          ") != VkFramebufferAttachmentsCreateInfo::pAttachments[%" PRIu32 "]::width (%" PRIu32 ").",
12748                                          func_name, i, image_create_info->extent.width, subresource_range.baseMipLevel, view_width,
12749                                          i, framebuffer_attachment_image_info->width);
12750                     }
12751 
12752                     const bool is_1d = (image_view_create_info->viewType == VK_IMAGE_VIEW_TYPE_1D) ||
12753                                        (image_view_create_info->viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY);
12754                     const auto view_height = (!is_1d) ? image_create_info->extent.height >> subresource_range.baseMipLevel
12755                                                       : image_create_info->extent.height;
12756                     if (framebuffer_attachment_image_info->height != view_height) {
12757                         skip |=
12758                             LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03212",
12759                                      "%s: For VkRenderPassAttachmentBeginInfo::pAttachments[%" PRIu32
12760                                      "], VkImageView height (%" PRIu32 ") at mip level %" PRIu32 " (%" PRIu32
12761                                      ") != VkFramebufferAttachmentsCreateInfo::pAttachments[%" PRIu32 "]::height (%" PRIu32 ").",
12762                                      func_name, i, image_create_info->extent.height, subresource_range.baseMipLevel, view_height, i,
12763                                      framebuffer_attachment_image_info->height);
12764                     }
12765 
12766                     if (framebuffer_attachment_image_info->layerCount != subresource_range.layerCount) {
12767                         skip |=
12768                             LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03213",
12769                                      "%s: Image view #%u created with a subresource range with a layerCount of %u, "
12770                                      "but image info #%u used to create the framebuffer had layerCount set as %u",
12771                                      func_name, i, subresource_range.layerCount, i, framebuffer_attachment_image_info->layerCount);
12772                     }
12773 
12774                     const VkImageFormatListCreateInfo *image_format_list_create_info =
12775                         LvlFindInChain<VkImageFormatListCreateInfo>(image_create_info->pNext);
12776                     if (image_format_list_create_info) {
12777                         if (image_format_list_create_info->viewFormatCount != framebuffer_attachment_image_info->viewFormatCount) {
12778                             skip |= LogError(
12779                                 pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03214",
12780                                 "VkRenderPassBeginInfo: Image view #%u created with an image with a viewFormatCount of %u, "
12781                                 "but image info #%u used to create the framebuffer had viewFormatCount set as %u",
12782                                 i, image_format_list_create_info->viewFormatCount, i,
12783                                 framebuffer_attachment_image_info->viewFormatCount);
12784                         }
12785 
12786                         for (uint32_t j = 0; j < image_format_list_create_info->viewFormatCount; ++j) {
12787                             bool format_found = false;
12788                             for (uint32_t k = 0; k < framebuffer_attachment_image_info->viewFormatCount; ++k) {
12789                                 if (image_format_list_create_info->pViewFormats[j] ==
12790                                     framebuffer_attachment_image_info->pViewFormats[k]) {
12791                                     format_found = true;
12792                                 }
12793                             }
12794                             if (!format_found) {
12795                                 skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03215",
12796                                                  "VkRenderPassBeginInfo: Image view #%u created with an image including the format "
12797                                                  "%s in its view format list, "
12798                                                  "but image info #%u used to create the framebuffer does not include this format",
12799                                                  i, string_VkFormat(image_format_list_create_info->pViewFormats[j]), i);
12800                             }
12801                         }
12802                     }
12803 
12804                     if (render_pass_create_info->pAttachments[i].format != image_view_create_info->format) {
12805                         skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03216",
12806                                          "%s: Image view #%u created with a format of %s, "
12807                                          "but render pass attachment description #%u created with a format of %s",
12808                                          func_name, i, string_VkFormat(image_view_create_info->format), i,
12809                                          string_VkFormat(render_pass_create_info->pAttachments[i].format));
12810                     }
12811 
12812                     if (render_pass_create_info->pAttachments[i].samples != image_create_info->samples) {
12813                         skip |= LogError(pRenderPassBeginInfo->renderPass, "VUID-VkRenderPassBeginInfo-framebuffer-03217",
12814                                          "%s: Image view #%u created with an image with %s samples, "
12815                                          "but render pass attachment description #%u created with %s samples",
12816                                          func_name, i, string_VkSampleCountFlagBits(image_create_info->samples), i,
12817                                          string_VkSampleCountFlagBits(render_pass_create_info->pAttachments[i].samples));
12818                     }
12819 
12820                     if (subresource_range.levelCount != 1) {
12821                         skip |= LogError(render_pass_attachment_begin_info->pAttachments[i],
12822                                          "VUID-VkRenderPassAttachmentBeginInfo-pAttachments-03218",
12823                                          "%s: Image view #%u created with multiple (%u) mip levels.", func_name, i,
12824                                          subresource_range.levelCount);
12825                     }
12826 
12827                     if (IsIdentitySwizzle(image_view_create_info->components) == false) {
12828                         skip |= LogError(
12829                             render_pass_attachment_begin_info->pAttachments[i],
12830                             "VUID-VkRenderPassAttachmentBeginInfo-pAttachments-03219",
12831                             "%s: Image view #%u created with non-identity swizzle. All "
12832                             "framebuffer attachments must have been created with the identity swizzle. Here are the actual "
12833                             "swizzle values:\n"
12834                             "r swizzle = %s\n"
12835                             "g swizzle = %s\n"
12836                             "b swizzle = %s\n"
12837                             "a swizzle = %s\n",
12838                             func_name, i, string_VkComponentSwizzle(image_view_create_info->components.r),
12839                             string_VkComponentSwizzle(image_view_create_info->components.g),
12840                             string_VkComponentSwizzle(image_view_create_info->components.b),
12841                             string_VkComponentSwizzle(image_view_create_info->components.a));
12842                     }
12843 
12844                     if (image_view_create_info->viewType == VK_IMAGE_VIEW_TYPE_3D) {
12845                         skip |= LogError(render_pass_attachment_begin_info->pAttachments[i],
12846                                          "VUID-VkRenderPassAttachmentBeginInfo-pAttachments-04114",
12847                                          "%s: Image view #%u created with type VK_IMAGE_VIEW_TYPE_3D", func_name, i);
12848                     }
12849                 }
12850             }
12851         }
12852     }
12853 
12854     return skip;
12855 }
12856 
12857 // If this is a stencil format, make sure the stencil[Load|Store]Op flag is checked, while if it is a depth/color attachment the
12858 // [load|store]Op flag must be checked
12859 // TODO: The memory valid flag in DEVICE_MEMORY_STATE should probably be split to track the validity of stencil memory separately.
12860 template <typename T>
FormatSpecificLoadAndStoreOpSettings(VkFormat format,T color_depth_op,T stencil_op,T op)12861 static bool FormatSpecificLoadAndStoreOpSettings(VkFormat format, T color_depth_op, T stencil_op, T op) {
12862     if (color_depth_op != op && stencil_op != op) {
12863         return false;
12864     }
12865     bool check_color_depth_load_op = !FormatIsStencilOnly(format);
12866     bool check_stencil_load_op = FormatIsDepthAndStencil(format) || !check_color_depth_load_op;
12867 
12868     return ((check_color_depth_load_op && (color_depth_op == op)) || (check_stencil_load_op && (stencil_op == op)));
12869 }
12870 
ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer,RenderPassCreateVersion rp_version,const VkRenderPassBeginInfo * pRenderPassBegin,CMD_TYPE cmd_type) const12871 bool CoreChecks::ValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, RenderPassCreateVersion rp_version,
12872                                             const VkRenderPassBeginInfo *pRenderPassBegin, CMD_TYPE cmd_type) const {
12873     bool skip = false;
12874     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
12875     const char *function_name = CommandTypeString(cmd_type);
12876     assert(cb_state);
12877     if (pRenderPassBegin) {
12878         auto rp_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
12879         auto fb_state = Get<FRAMEBUFFER_STATE>(pRenderPassBegin->framebuffer);
12880 
12881         if (rp_state) {
12882             uint32_t clear_op_size = 0;  // Make sure pClearValues is at least as large as last LOAD_OP_CLEAR
12883 
12884             // Handle extension struct from EXT_sample_locations
12885             const VkRenderPassSampleLocationsBeginInfoEXT *sample_locations_begin_info =
12886                 LvlFindInChain<VkRenderPassSampleLocationsBeginInfoEXT>(pRenderPassBegin->pNext);
12887             if (sample_locations_begin_info) {
12888                 for (uint32_t i = 0; i < sample_locations_begin_info->attachmentInitialSampleLocationsCount; ++i) {
12889                     const VkAttachmentSampleLocationsEXT &sample_location =
12890                         sample_locations_begin_info->pAttachmentInitialSampleLocations[i];
12891                     skip |= ValidateSampleLocationsInfo(&sample_location.sampleLocationsInfo, function_name);
12892                     if (sample_location.attachmentIndex >= rp_state->createInfo.attachmentCount) {
12893                         skip |= LogError(device, "VUID-VkAttachmentSampleLocationsEXT-attachmentIndex-01531",
12894                                          "%s: Attachment index %u specified by attachment sample locations %u is greater than the "
12895                                          "attachment count of %u for the render pass being begun.",
12896                                          function_name, sample_location.attachmentIndex, i, rp_state->createInfo.attachmentCount);
12897                     }
12898                 }
12899 
12900                 for (uint32_t i = 0; i < sample_locations_begin_info->postSubpassSampleLocationsCount; ++i) {
12901                     const VkSubpassSampleLocationsEXT &sample_location =
12902                         sample_locations_begin_info->pPostSubpassSampleLocations[i];
12903                     skip |= ValidateSampleLocationsInfo(&sample_location.sampleLocationsInfo, function_name);
12904                     if (sample_location.subpassIndex >= rp_state->createInfo.subpassCount) {
12905                         skip |= LogError(
12906                             device, "VUID-VkSubpassSampleLocationsEXT-subpassIndex-01532",
12907                             "%s: Subpass index %u specified by subpass sample locations %u is greater than the subpass count "
12908                             "of %u for the render pass being begun.",
12909                             function_name, sample_location.subpassIndex, i, rp_state->createInfo.subpassCount);
12910                     }
12911                 }
12912             }
12913 
12914             for (uint32_t i = 0; i < rp_state->createInfo.attachmentCount; ++i) {
12915                 auto attachment = &rp_state->createInfo.pAttachments[i];
12916                 if (FormatSpecificLoadAndStoreOpSettings(attachment->format, attachment->loadOp, attachment->stencilLoadOp,
12917                                                          VK_ATTACHMENT_LOAD_OP_CLEAR)) {
12918                     clear_op_size = static_cast<uint32_t>(i) + 1;
12919 
12920                     if (FormatHasDepth(attachment->format) && pRenderPassBegin->pClearValues) {
12921                         skip |= ValidateClearDepthStencilValue(commandBuffer, pRenderPassBegin->pClearValues[i].depthStencil,
12922                                                                function_name);
12923                     }
12924                 }
12925             }
12926 
12927             if (clear_op_size > pRenderPassBegin->clearValueCount) {
12928                 skip |=
12929                     LogError(rp_state->renderPass(), "VUID-VkRenderPassBeginInfo-clearValueCount-00902",
12930                              "In %s the VkRenderPassBeginInfo struct has a clearValueCount of %u but there "
12931                              "must be at least %u entries in pClearValues array to account for the highest index attachment in "
12932                              "%s that uses VK_ATTACHMENT_LOAD_OP_CLEAR is %u. Note that the pClearValues array is indexed by "
12933                              "attachment number so even if some pClearValues entries between 0 and %u correspond to attachments "
12934                              "that aren't cleared they will be ignored.",
12935                              function_name, pRenderPassBegin->clearValueCount, clear_op_size,
12936                              report_data->FormatHandle(rp_state->renderPass()).c_str(), clear_op_size, clear_op_size - 1);
12937             }
12938             skip |= VerifyFramebufferAndRenderPassImageViews(pRenderPassBegin, function_name);
12939             skip |= VerifyRenderAreaBounds(pRenderPassBegin, function_name);
12940             skip |= VerifyFramebufferAndRenderPassLayouts(rp_version, cb_state.get(), pRenderPassBegin, fb_state.get());
12941             if (fb_state->rp_state->renderPass() != rp_state->renderPass()) {
12942                 skip |= ValidateRenderPassCompatibility("render pass", rp_state.get(), "framebuffer", fb_state->rp_state.get(),
12943                                                         function_name, "VUID-VkRenderPassBeginInfo-renderPass-00904");
12944             }
12945 
12946             skip |= ValidateDependencies(fb_state.get(), rp_state.get());
12947 
12948             skip |= ValidateCmd(cb_state.get(), cmd_type);
12949         }
12950     }
12951 
12952     auto chained_device_group_struct = LvlFindInChain<VkDeviceGroupRenderPassBeginInfo>(pRenderPassBegin->pNext);
12953     if (chained_device_group_struct) {
12954         skip |= ValidateDeviceMaskToPhysicalDeviceCount(chained_device_group_struct->deviceMask, pRenderPassBegin->renderPass,
12955                                                         "VUID-VkDeviceGroupRenderPassBeginInfo-deviceMask-00905");
12956         skip |= ValidateDeviceMaskToZero(chained_device_group_struct->deviceMask, pRenderPassBegin->renderPass,
12957                                          "VUID-VkDeviceGroupRenderPassBeginInfo-deviceMask-00906");
12958         skip |=
12959             ValidateDeviceMaskToCommandBuffer(cb_state.get(), chained_device_group_struct->deviceMask, pRenderPassBegin->renderPass,
12960                                               "VUID-VkDeviceGroupRenderPassBeginInfo-deviceMask-00907");
12961 
12962         if (chained_device_group_struct->deviceRenderAreaCount != 0 &&
12963             chained_device_group_struct->deviceRenderAreaCount != physical_device_count) {
12964             skip |= LogError(pRenderPassBegin->renderPass, "VUID-VkDeviceGroupRenderPassBeginInfo-deviceRenderAreaCount-00908",
12965                              "%s: deviceRenderAreaCount[%" PRIu32 "] is invaild. Physical device count is %" PRIu32 ".",
12966                              function_name, chained_device_group_struct->deviceRenderAreaCount, physical_device_count);
12967         }
12968     }
12969     return skip;
12970 }
12971 
PreCallValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,VkSubpassContents contents) const12972 bool CoreChecks::PreCallValidateCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
12973                                                    VkSubpassContents contents) const {
12974     bool skip = ValidateCmdBeginRenderPass(commandBuffer, RENDER_PASS_VERSION_1, pRenderPassBegin, CMD_BEGINRENDERPASS);
12975     return skip;
12976 }
12977 
PreCallValidateCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,const VkSubpassBeginInfo * pSubpassBeginInfo) const12978 bool CoreChecks::PreCallValidateCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
12979                                                        const VkSubpassBeginInfo *pSubpassBeginInfo) const {
12980     bool skip = ValidateCmdBeginRenderPass(commandBuffer, RENDER_PASS_VERSION_2, pRenderPassBegin, CMD_BEGINRENDERPASS2KHR);
12981     return skip;
12982 }
12983 
PreCallValidateCmdBeginRenderPass2(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,const VkSubpassBeginInfo * pSubpassBeginInfo) const12984 bool CoreChecks::PreCallValidateCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
12985                                                     const VkSubpassBeginInfo *pSubpassBeginInfo) const {
12986     bool skip = ValidateCmdBeginRenderPass(commandBuffer, RENDER_PASS_VERSION_2, pRenderPassBegin, CMD_BEGINRENDERPASS2);
12987     return skip;
12988 }
12989 
RecordCmdBeginRenderPassLayouts(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,const VkSubpassContents contents)12990 void CoreChecks::RecordCmdBeginRenderPassLayouts(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
12991                                                  const VkSubpassContents contents) {
12992     if (!pRenderPassBegin) {
12993         return;
12994     }
12995     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
12996     auto render_pass_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
12997     auto framebuffer = Get<FRAMEBUFFER_STATE>(pRenderPassBegin->framebuffer);
12998     if (render_pass_state) {
12999         // transition attachments to the correct layouts for beginning of renderPass and first subpass
13000         TransitionBeginRenderPassLayouts(cb_state.get(), render_pass_state.get(), framebuffer.get());
13001     }
13002 }
13003 
PreCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,VkSubpassContents contents)13004 void CoreChecks::PreCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
13005                                                  VkSubpassContents contents) {
13006     StateTracker::PreCallRecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
13007     RecordCmdBeginRenderPassLayouts(commandBuffer, pRenderPassBegin, contents);
13008 }
13009 
PreCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,const VkSubpassBeginInfo * pSubpassBeginInfo)13010 void CoreChecks::PreCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
13011                                                      const VkSubpassBeginInfo *pSubpassBeginInfo) {
13012     StateTracker::PreCallRecordCmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
13013     RecordCmdBeginRenderPassLayouts(commandBuffer, pRenderPassBegin, pSubpassBeginInfo->contents);
13014 }
13015 
PreCallRecordCmdBeginRenderPass2(VkCommandBuffer commandBuffer,const VkRenderPassBeginInfo * pRenderPassBegin,const VkSubpassBeginInfo * pSubpassBeginInfo)13016 void CoreChecks::PreCallRecordCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
13017                                                   const VkSubpassBeginInfo *pSubpassBeginInfo) {
13018     StateTracker::PreCallRecordCmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
13019     RecordCmdBeginRenderPassLayouts(commandBuffer, pRenderPassBegin, pSubpassBeginInfo->contents);
13020 }
13021 
ValidateCmdNextSubpass(RenderPassCreateVersion rp_version,VkCommandBuffer commandBuffer,CMD_TYPE cmd_type) const13022 bool CoreChecks::ValidateCmdNextSubpass(RenderPassCreateVersion rp_version, VkCommandBuffer commandBuffer,
13023                                         CMD_TYPE cmd_type) const {
13024     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
13025     assert(cb_state);
13026     bool skip = false;
13027     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
13028     const char *vuid;
13029     const char *function_name = CommandTypeString(cmd_type);
13030 
13031     skip |= ValidateCmd(cb_state.get(), cmd_type);
13032 
13033     auto subpass_count = cb_state->activeRenderPass->createInfo.subpassCount;
13034     if (cb_state->activeSubpass == subpass_count - 1) {
13035         vuid = use_rp2 ? "VUID-vkCmdNextSubpass2-None-03102" : "VUID-vkCmdNextSubpass-None-00909";
13036         skip |= LogError(commandBuffer, vuid, "%s: Attempted to advance beyond final subpass.", function_name);
13037     }
13038     return skip;
13039 }
13040 
PreCallValidateCmdNextSubpass(VkCommandBuffer commandBuffer,VkSubpassContents contents) const13041 bool CoreChecks::PreCallValidateCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) const {
13042     return ValidateCmdNextSubpass(RENDER_PASS_VERSION_1, commandBuffer, CMD_NEXTSUBPASS);
13043 }
13044 
PreCallValidateCmdNextSubpass2KHR(VkCommandBuffer commandBuffer,const VkSubpassBeginInfo * pSubpassBeginInfo,const VkSubpassEndInfo * pSubpassEndInfo) const13045 bool CoreChecks::PreCallValidateCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
13046                                                    const VkSubpassEndInfo *pSubpassEndInfo) const {
13047     return ValidateCmdNextSubpass(RENDER_PASS_VERSION_2, commandBuffer, CMD_NEXTSUBPASS2KHR);
13048 }
13049 
PreCallValidateCmdNextSubpass2(VkCommandBuffer commandBuffer,const VkSubpassBeginInfo * pSubpassBeginInfo,const VkSubpassEndInfo * pSubpassEndInfo) const13050 bool CoreChecks::PreCallValidateCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
13051                                                 const VkSubpassEndInfo *pSubpassEndInfo) const {
13052     return ValidateCmdNextSubpass(RENDER_PASS_VERSION_2, commandBuffer, CMD_NEXTSUBPASS2);
13053 }
13054 
RecordCmdNextSubpassLayouts(VkCommandBuffer commandBuffer,VkSubpassContents contents)13055 void CoreChecks::RecordCmdNextSubpassLayouts(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
13056     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
13057     auto framebuffer = Get<FRAMEBUFFER_STATE>(cb_state->activeRenderPassBeginInfo.framebuffer);
13058     TransitionSubpassLayouts(cb_state.get(), cb_state->activeRenderPass.get(), cb_state->activeSubpass, framebuffer.get());
13059 }
13060 
PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer,VkSubpassContents contents)13061 void CoreChecks::PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
13062     StateTracker::PostCallRecordCmdNextSubpass(commandBuffer, contents);
13063     RecordCmdNextSubpassLayouts(commandBuffer, contents);
13064 }
13065 
PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer,const VkSubpassBeginInfo * pSubpassBeginInfo,const VkSubpassEndInfo * pSubpassEndInfo)13066 void CoreChecks::PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
13067                                                   const VkSubpassEndInfo *pSubpassEndInfo) {
13068     StateTracker::PostCallRecordCmdNextSubpass2KHR(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
13069     RecordCmdNextSubpassLayouts(commandBuffer, pSubpassBeginInfo->contents);
13070 }
13071 
PostCallRecordCmdNextSubpass2(VkCommandBuffer commandBuffer,const VkSubpassBeginInfo * pSubpassBeginInfo,const VkSubpassEndInfo * pSubpassEndInfo)13072 void CoreChecks::PostCallRecordCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
13073                                                const VkSubpassEndInfo *pSubpassEndInfo) {
13074     StateTracker::PostCallRecordCmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
13075     RecordCmdNextSubpassLayouts(commandBuffer, pSubpassBeginInfo->contents);
13076 }
13077 
ValidateCmdEndRenderPass(RenderPassCreateVersion rp_version,VkCommandBuffer commandBuffer,CMD_TYPE cmd_type) const13078 bool CoreChecks::ValidateCmdEndRenderPass(RenderPassCreateVersion rp_version, VkCommandBuffer commandBuffer,
13079                                           CMD_TYPE cmd_type) const {
13080     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
13081     assert(cb_state);
13082     bool skip = false;
13083     const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
13084     const char *vuid;
13085     const char *function_name = CommandTypeString(cmd_type);
13086 
13087     RENDER_PASS_STATE *rp_state = cb_state->activeRenderPass.get();
13088     if (rp_state) {
13089         if (cb_state->activeSubpass != rp_state->createInfo.subpassCount - 1) {
13090             vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2-None-03103" : "VUID-vkCmdEndRenderPass-None-00910";
13091             skip |= LogError(commandBuffer, vuid, "%s: Called before reaching final subpass.", function_name);
13092         }
13093 
13094         if (rp_state->use_dynamic_rendering) {
13095             vuid = use_rp2 ? "VUID-vkCmdEndRenderPass2-None-06171" : "VUID-vkCmdEndRenderPass-None-06170";
13096             skip |= LogError(commandBuffer, vuid,
13097                              "%s: Called when the render pass instance was begun with vkCmdBeginRenderingKHR().", function_name);
13098         }
13099     }
13100 
13101     skip |= ValidateCmd(cb_state.get(), cmd_type);
13102     return skip;
13103 }
13104 
PreCallValidateCmdEndRenderPass(VkCommandBuffer commandBuffer) const13105 bool CoreChecks::PreCallValidateCmdEndRenderPass(VkCommandBuffer commandBuffer) const {
13106     bool skip = ValidateCmdEndRenderPass(RENDER_PASS_VERSION_1, commandBuffer, CMD_ENDRENDERPASS);
13107     return skip;
13108 }
13109 
PreCallValidateCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer,const VkSubpassEndInfo * pSubpassEndInfo) const13110 bool CoreChecks::PreCallValidateCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) const {
13111     bool skip = ValidateCmdEndRenderPass(RENDER_PASS_VERSION_2, commandBuffer, CMD_ENDRENDERPASS2KHR);
13112     return skip;
13113 }
13114 
PreCallValidateCmdEndRenderPass2(VkCommandBuffer commandBuffer,const VkSubpassEndInfo * pSubpassEndInfo) const13115 bool CoreChecks::PreCallValidateCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) const {
13116     bool skip = ValidateCmdEndRenderPass(RENDER_PASS_VERSION_2, commandBuffer, CMD_ENDRENDERPASS2);
13117     return skip;
13118 }
13119 
RecordCmdEndRenderPassLayouts(VkCommandBuffer commandBuffer)13120 void CoreChecks::RecordCmdEndRenderPassLayouts(VkCommandBuffer commandBuffer) {
13121     auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
13122     TransitionFinalSubpassLayouts(cb_state.get(), cb_state->activeRenderPassBeginInfo.ptr(), cb_state->activeFramebuffer.get());
13123 }
13124 
PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer)13125 void CoreChecks::PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer) {
13126     // Record the end at the CoreLevel to ensure StateTracker cleanup doesn't step on anything we need.
13127     RecordCmdEndRenderPassLayouts(commandBuffer);
13128     StateTracker::PostCallRecordCmdEndRenderPass(commandBuffer);
13129 }
13130 
PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer,const VkSubpassEndInfo * pSubpassEndInfo)13131 void CoreChecks::PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
13132     // Record the end at the CoreLevel to ensure StateTracker cleanup doesn't step on anything we need.
13133     RecordCmdEndRenderPassLayouts(commandBuffer);
13134     StateTracker::PostCallRecordCmdEndRenderPass2KHR(commandBuffer, pSubpassEndInfo);
13135 }
13136 
PostCallRecordCmdEndRenderPass2(VkCommandBuffer commandBuffer,const VkSubpassEndInfo * pSubpassEndInfo)13137 void CoreChecks::PostCallRecordCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
13138     RecordCmdEndRenderPassLayouts(commandBuffer);
13139     StateTracker::PostCallRecordCmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
13140 }
13141 
ValidateFramebuffer(VkCommandBuffer primaryBuffer,const CMD_BUFFER_STATE * pCB,VkCommandBuffer secondaryBuffer,const CMD_BUFFER_STATE * pSubCB,const char * caller) const13142 bool CoreChecks::ValidateFramebuffer(VkCommandBuffer primaryBuffer, const CMD_BUFFER_STATE *pCB, VkCommandBuffer secondaryBuffer,
13143                                      const CMD_BUFFER_STATE *pSubCB, const char *caller) const {
13144     bool skip = false;
13145     if (!pSubCB->beginInfo.pInheritanceInfo) {
13146         return skip;
13147     }
13148     VkFramebuffer primary_fb = pCB->activeFramebuffer ? pCB->activeFramebuffer->framebuffer() : VK_NULL_HANDLE;
13149     VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
13150     if (secondary_fb != VK_NULL_HANDLE) {
13151         if (primary_fb != secondary_fb) {
13152             LogObjectList objlist(primaryBuffer);
13153             objlist.add(secondaryBuffer);
13154             objlist.add(secondary_fb);
13155             objlist.add(primary_fb);
13156             skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-pCommandBuffers-00099",
13157                              "vkCmdExecuteCommands() called w/ invalid secondary %s which has a %s"
13158                              " that is not the same as the primary command buffer's current active %s.",
13159                              report_data->FormatHandle(secondaryBuffer).c_str(), report_data->FormatHandle(secondary_fb).c_str(),
13160                              report_data->FormatHandle(primary_fb).c_str());
13161         }
13162         auto fb = Get<FRAMEBUFFER_STATE>(secondary_fb);
13163         if (!fb) {
13164             LogObjectList objlist(primaryBuffer);
13165             objlist.add(secondaryBuffer);
13166             objlist.add(secondary_fb);
13167             skip |= LogError(objlist, kVUID_Core_DrawState_InvalidSecondaryCommandBuffer,
13168                              "vkCmdExecuteCommands() called w/ invalid %s which has invalid %s.",
13169                              report_data->FormatHandle(secondaryBuffer).c_str(), report_data->FormatHandle(secondary_fb).c_str());
13170             return skip;
13171         }
13172     }
13173     return skip;
13174 }
13175 
ValidateSecondaryCommandBufferState(const CMD_BUFFER_STATE * pCB,const CMD_BUFFER_STATE * pSubCB) const13176 bool CoreChecks::ValidateSecondaryCommandBufferState(const CMD_BUFFER_STATE *pCB, const CMD_BUFFER_STATE *pSubCB) const {
13177     bool skip = false;
13178     layer_data::unordered_set<int> active_types;
13179     if (!disabled[query_validation]) {
13180         for (const auto &query_object : pCB->activeQueries) {
13181             auto query_pool_state = Get<QUERY_POOL_STATE>(query_object.pool);
13182             if (query_pool_state) {
13183                 if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
13184                     pSubCB->beginInfo.pInheritanceInfo) {
13185                     VkQueryPipelineStatisticFlags cmd_buf_statistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
13186                     if ((cmd_buf_statistics & query_pool_state->createInfo.pipelineStatistics) != cmd_buf_statistics) {
13187                         LogObjectList objlist(pCB->commandBuffer());
13188                         objlist.add(query_object.pool);
13189                         skip |= LogError(
13190                             objlist, "VUID-vkCmdExecuteCommands-commandBuffer-00104",
13191                             "vkCmdExecuteCommands() called w/ invalid %s which has invalid active %s"
13192                             ". Pipeline statistics is being queried so the command buffer must have all bits set on the queryPool.",
13193                             report_data->FormatHandle(pCB->commandBuffer()).c_str(),
13194                             report_data->FormatHandle(query_object.pool).c_str());
13195                     }
13196                 }
13197                 active_types.insert(query_pool_state->createInfo.queryType);
13198             }
13199         }
13200         for (const auto &query_object : pSubCB->startedQueries) {
13201             auto query_pool_state = Get<QUERY_POOL_STATE>(query_object.pool);
13202             if (query_pool_state && active_types.count(query_pool_state->createInfo.queryType)) {
13203                 LogObjectList objlist(pCB->commandBuffer());
13204                 objlist.add(query_object.pool);
13205                 skip |= LogError(objlist, kVUID_Core_DrawState_InvalidSecondaryCommandBuffer,
13206                                  "vkCmdExecuteCommands() called w/ invalid %s which has invalid active %s"
13207                                  " of type %d but a query of that type has been started on secondary %s.",
13208                                  report_data->FormatHandle(pCB->commandBuffer()).c_str(),
13209                                  report_data->FormatHandle(query_object.pool).c_str(), query_pool_state->createInfo.queryType,
13210                                  report_data->FormatHandle(pSubCB->commandBuffer()).c_str());
13211             }
13212         }
13213     }
13214     const auto primary_pool = pCB->command_pool;
13215     const auto secondary_pool = pSubCB->command_pool;
13216     if (primary_pool && secondary_pool && (primary_pool->queueFamilyIndex != secondary_pool->queueFamilyIndex)) {
13217         LogObjectList objlist(pSubCB->commandBuffer());
13218         objlist.add(pCB->commandBuffer());
13219         skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-pCommandBuffers-00094",
13220                          "vkCmdExecuteCommands(): Primary %s created in queue family %d has secondary "
13221                          "%s created in queue family %d.",
13222                          report_data->FormatHandle(pCB->commandBuffer()).c_str(), primary_pool->queueFamilyIndex,
13223                          report_data->FormatHandle(pSubCB->commandBuffer()).c_str(), secondary_pool->queueFamilyIndex);
13224     }
13225 
13226     return skip;
13227 }
13228 
13229 // Object that simulates the inherited viewport/scissor state as the device executes the called secondary command buffers.
13230 // Visit the calling primary command buffer first, then the called secondaries in order.
13231 // Contact David Zhao Akeley <dakeley@nvidia.com> for clarifications and bug fixes.
13232 class CoreChecks::ViewportScissorInheritanceTracker {
13233     static_assert(4 == sizeof(CMD_BUFFER_STATE::viewportMask), "Adjust max_viewports to match viewportMask bit width");
13234     static constexpr uint32_t kMaxViewports = 32, kNotTrashed = uint32_t(-2), kTrashedByPrimary = uint32_t(-1);
13235 
13236     const ValidationObject &validation_;
13237     const CMD_BUFFER_STATE *primary_state_ = nullptr;
13238     uint32_t viewport_mask_;
13239     uint32_t scissor_mask_;
13240     uint32_t viewport_trashed_by_[kMaxViewports];  // filled in VisitPrimary.
13241     uint32_t scissor_trashed_by_[kMaxViewports];
13242     VkViewport viewports_to_inherit_[kMaxViewports];
13243     uint32_t viewport_count_to_inherit_;  // 0 if viewport count (EXT state) has never been defined (but not trashed)
13244     uint32_t scissor_count_to_inherit_;   // 0 if scissor count (EXT state) has never been defined (but not trashed)
13245     uint32_t viewport_count_trashed_by_;
13246     uint32_t scissor_count_trashed_by_;
13247 
13248   public:
ViewportScissorInheritanceTracker(const ValidationObject & validation)13249     ViewportScissorInheritanceTracker(const ValidationObject &validation) : validation_(validation) {}
13250 
VisitPrimary(const CMD_BUFFER_STATE * primary_state)13251     bool VisitPrimary(const CMD_BUFFER_STATE *primary_state) {
13252         assert(!primary_state_);
13253         primary_state_ = primary_state;
13254 
13255         viewport_mask_ = primary_state->viewportMask | primary_state->viewportWithCountMask;
13256         scissor_mask_ = primary_state->scissorMask | primary_state->scissorWithCountMask;
13257 
13258         for (uint32_t n = 0; n < kMaxViewports; ++n) {
13259             uint32_t bit = uint32_t(1) << n;
13260             viewport_trashed_by_[n] = primary_state->trashedViewportMask & bit ? kTrashedByPrimary : kNotTrashed;
13261             scissor_trashed_by_[n] = primary_state->trashedScissorMask & bit ? kTrashedByPrimary : kNotTrashed;
13262             if (viewport_mask_ & bit) {
13263                 viewports_to_inherit_[n] = primary_state->dynamicViewports[n];
13264             }
13265         }
13266 
13267         viewport_count_to_inherit_ = primary_state->viewportWithCountCount;
13268         scissor_count_to_inherit_ = primary_state->scissorWithCountCount;
13269         viewport_count_trashed_by_ = primary_state->trashedViewportCount ? kTrashedByPrimary : kNotTrashed;
13270         scissor_count_trashed_by_ = primary_state->trashedScissorCount ? kTrashedByPrimary : kNotTrashed;
13271         return false;
13272     }
13273 
VisitSecondary(uint32_t cmd_buffer_idx,const CMD_BUFFER_STATE * secondary_state)13274     bool VisitSecondary(uint32_t cmd_buffer_idx, const CMD_BUFFER_STATE *secondary_state) {
13275         bool skip = false;
13276         if (secondary_state->inheritedViewportDepths.empty()) {
13277             skip |= VisitSecondaryNoInheritance(cmd_buffer_idx, secondary_state);
13278         } else {
13279             skip |= VisitSecondaryInheritance(cmd_buffer_idx, secondary_state);
13280         }
13281 
13282         // See note at end of VisitSecondaryNoInheritance.
13283         if (secondary_state->trashedViewportCount) {
13284             viewport_count_trashed_by_ = cmd_buffer_idx;
13285         }
13286         if (secondary_state->trashedScissorCount) {
13287             scissor_count_trashed_by_ = cmd_buffer_idx;
13288         }
13289         return skip;
13290     }
13291 
13292   private:
13293     // Track state inheritance as specified by VK_NV_inherited_scissor_viewport, including states
13294     // overwritten to undefined value by bound pipelines with non-dynamic state.
VisitSecondaryNoInheritance(uint32_t cmd_buffer_idx,const CMD_BUFFER_STATE * secondary_state)13295     bool VisitSecondaryNoInheritance(uint32_t cmd_buffer_idx, const CMD_BUFFER_STATE *secondary_state) {
13296         viewport_mask_ |= secondary_state->viewportMask | secondary_state->viewportWithCountMask;
13297         scissor_mask_ |= secondary_state->scissorMask | secondary_state->scissorWithCountMask;
13298 
13299         for (uint32_t n = 0; n < kMaxViewports; ++n) {
13300             uint32_t bit = uint32_t(1) << n;
13301             if ((secondary_state->viewportMask | secondary_state->viewportWithCountMask) & bit) {
13302                 viewports_to_inherit_[n] = secondary_state->dynamicViewports[n];
13303                 viewport_trashed_by_[n] = kNotTrashed;
13304             }
13305             if ((secondary_state->scissorMask | secondary_state->scissorWithCountMask) & bit) {
13306                 scissor_trashed_by_[n] = kNotTrashed;
13307             }
13308             if (secondary_state->viewportWithCountCount != 0) {
13309                 viewport_count_to_inherit_ = secondary_state->viewportWithCountCount;
13310                 viewport_count_trashed_by_ = kNotTrashed;
13311             }
13312             if (secondary_state->scissorWithCountCount != 0) {
13313                 scissor_count_to_inherit_ = secondary_state->scissorWithCountCount;
13314                 scissor_count_trashed_by_ = kNotTrashed;
13315             }
13316             // Order of above vs below matters here.
13317             if (secondary_state->trashedViewportMask & bit) {
13318                 viewport_trashed_by_[n] = cmd_buffer_idx;
13319             }
13320             if (secondary_state->trashedScissorMask & bit) {
13321                 scissor_trashed_by_[n] = cmd_buffer_idx;
13322             }
13323             // Check trashing dynamic viewport/scissor count in VisitSecondary (at end) as even secondary command buffers enabling
13324             // viewport/scissor state inheritance may define this state statically in bound graphics pipelines.
13325         }
13326         return false;
13327     }
13328 
13329     // Validate needed inherited state as specified by VK_NV_inherited_scissor_viewport.
VisitSecondaryInheritance(uint32_t cmd_buffer_idx,const CMD_BUFFER_STATE * secondary_state)13330     bool VisitSecondaryInheritance(uint32_t cmd_buffer_idx, const CMD_BUFFER_STATE *secondary_state) {
13331         bool skip = false;
13332         uint32_t check_viewport_count = 0, check_scissor_count = 0;
13333 
13334         // Common code for reporting missing inherited state (for a myriad of reasons).
13335         auto check_missing_inherit = [&](uint32_t was_ever_defined, uint32_t trashed_by, VkDynamicState state, uint32_t index = 0,
13336                                          uint32_t static_use_count = 0, const VkViewport *inherited_viewport = nullptr,
13337                                          const VkViewport *expected_viewport_depth = nullptr) {
13338             if (was_ever_defined && trashed_by == kNotTrashed) {
13339                 if (state != VK_DYNAMIC_STATE_VIEWPORT) return false;
13340 
13341                 assert(inherited_viewport != nullptr && expected_viewport_depth != nullptr);
13342                 if (inherited_viewport->minDepth != expected_viewport_depth->minDepth ||
13343                     inherited_viewport->maxDepth != expected_viewport_depth->maxDepth) {
13344                     return validation_.LogError(
13345                         primary_state_->commandBuffer(), "VUID-vkCmdDraw-commandBuffer-02701",
13346                         "vkCmdExecuteCommands(): Draw commands in pCommandBuffers[%u] (%s) consume inherited viewport %u %s"
13347                         "but this state was not inherited as its depth range [%f, %f] does not match "
13348                         "pViewportDepths[%u] = [%f, %f]",
13349                         unsigned(cmd_buffer_idx), validation_.report_data->FormatHandle(secondary_state->commandBuffer()).c_str(),
13350                         unsigned(index), index >= static_use_count ? "(with count) " : "", inherited_viewport->minDepth,
13351                         inherited_viewport->maxDepth, unsigned(cmd_buffer_idx), expected_viewport_depth->minDepth,
13352                         expected_viewport_depth->maxDepth);
13353                     // akeley98 note: This VUID is not ideal; however, there isn't a more relevant VUID as
13354                     // it isn't illegal in itself to have mismatched inherited viewport depths.
13355                     // The error only occurs upon attempting to consume the viewport.
13356                 } else {
13357                     return false;
13358                 }
13359             }
13360 
13361             const char *state_name;
13362             bool format_index = false;
13363 
13364             switch (state) {
13365                 case VK_DYNAMIC_STATE_SCISSOR:
13366                     state_name = "scissor";
13367                     format_index = true;
13368                     break;
13369                 case VK_DYNAMIC_STATE_VIEWPORT:
13370                     state_name = "viewport";
13371                     format_index = true;
13372                     break;
13373                 case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT:
13374                     state_name = "dynamic viewport count";
13375                     break;
13376                 case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT:
13377                     state_name = "dynamic scissor count";
13378                     break;
13379                 default:
13380                     assert(0);
13381                     state_name = "<unknown state, report bug>";
13382                     break;
13383             }
13384 
13385             std::stringstream ss;
13386             ss << "vkCmdExecuteCommands(): Draw commands in pCommandBuffers[" << cmd_buffer_idx << "] ("
13387                << validation_.report_data->FormatHandle(secondary_state->commandBuffer()).c_str() << ") consume inherited "
13388                << state_name << " ";
13389             if (format_index) {
13390                 if (index >= static_use_count) {
13391                     ss << "(with count) ";
13392                 }
13393                 ss << index << " ";
13394             }
13395             ss << "but this state ";
13396             if (!was_ever_defined) {
13397                 ss << "was never defined.";
13398             } else if (trashed_by == kTrashedByPrimary) {
13399                 ss << "was left undefined after vkCmdExecuteCommands or vkCmdBindPipeline (with non-dynamic state) in "
13400                       "the calling primary command buffer.";
13401             } else {
13402                 ss << "was left undefined after vkCmdBindPipeline (with non-dynamic state) in pCommandBuffers[" << trashed_by
13403                    << "].";
13404             }
13405             return validation_.LogError(primary_state_->commandBuffer(), "VUID-vkCmdDraw-commandBuffer-02701", "%s", ss.str().c_str());
13406         };
13407 
13408         // Check if secondary command buffer uses viewport/scissor-with-count state, and validate this state if so.
13409         if (secondary_state->usedDynamicViewportCount) {
13410             if (viewport_count_to_inherit_ == 0 || viewport_count_trashed_by_ != kNotTrashed) {
13411                 skip |= check_missing_inherit(viewport_count_to_inherit_, viewport_count_trashed_by_,
13412                                               VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
13413             } else {
13414                 check_viewport_count = viewport_count_to_inherit_;
13415             }
13416         }
13417         if (secondary_state->usedDynamicScissorCount) {
13418             if (scissor_count_to_inherit_ == 0 || scissor_count_trashed_by_ != kNotTrashed) {
13419                 skip |= check_missing_inherit(scissor_count_to_inherit_, scissor_count_trashed_by_,
13420                                               VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
13421             } else {
13422                 check_scissor_count = scissor_count_to_inherit_;
13423             }
13424         }
13425 
13426         // Check the maximum of (viewports used by pipelines with static viewport count, "" dynamic viewport count)
13427         // but limit to length of inheritedViewportDepths array and uint32_t bit width (validation layer limit).
13428         check_viewport_count = std::min(std::min(kMaxViewports, uint32_t(secondary_state->inheritedViewportDepths.size())),
13429                                         std::max(check_viewport_count, secondary_state->usedViewportScissorCount));
13430         check_scissor_count = std::min(kMaxViewports, std::max(check_scissor_count, secondary_state->usedViewportScissorCount));
13431 
13432         if (secondary_state->usedDynamicViewportCount &&
13433             viewport_count_to_inherit_ > secondary_state->inheritedViewportDepths.size()) {
13434             skip |= validation_.LogError(
13435                 primary_state_->commandBuffer(), "VUID-vkCmdDraw-commandBuffer-02701",
13436                 "vkCmdExecuteCommands(): "
13437                 "Draw commands in pCommandBuffers[%u] (%s) consume inherited dynamic viewport with count state "
13438                 "but the dynamic viewport count (%u) exceeds the inheritance limit (viewportDepthCount=%u).",
13439                 unsigned(cmd_buffer_idx), validation_.report_data->FormatHandle(secondary_state->commandBuffer()).c_str(),
13440                 unsigned(viewport_count_to_inherit_), unsigned(secondary_state->inheritedViewportDepths.size()));
13441         }
13442 
13443         for (uint32_t n = 0; n < check_viewport_count; ++n) {
13444             skip |= check_missing_inherit(viewport_mask_ & uint32_t(1) << n, viewport_trashed_by_[n], VK_DYNAMIC_STATE_VIEWPORT, n,
13445                                           secondary_state->usedViewportScissorCount, &viewports_to_inherit_[n],
13446                                           &secondary_state->inheritedViewportDepths[n]);
13447         }
13448 
13449         for (uint32_t n = 0; n < check_scissor_count; ++n) {
13450             skip |= check_missing_inherit(scissor_mask_ & uint32_t(1) << n, scissor_trashed_by_[n], VK_DYNAMIC_STATE_SCISSOR, n,
13451                                           secondary_state->usedViewportScissorCount);
13452         }
13453         return skip;
13454     }
13455 };
13456 
13457 constexpr uint32_t CoreChecks::ViewportScissorInheritanceTracker::kMaxViewports;
13458 constexpr uint32_t CoreChecks::ViewportScissorInheritanceTracker::kNotTrashed;
13459 constexpr uint32_t CoreChecks::ViewportScissorInheritanceTracker::kTrashedByPrimary;
13460 
PreCallValidateCmdExecuteCommands(VkCommandBuffer commandBuffer,uint32_t commandBuffersCount,const VkCommandBuffer * pCommandBuffers) const13461 bool CoreChecks::PreCallValidateCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount,
13462                                                    const VkCommandBuffer *pCommandBuffers) const {
13463     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
13464     assert(cb_state);
13465     bool skip = false;
13466     layer_data::unordered_set<const CMD_BUFFER_STATE *> linked_command_buffers;
13467     ViewportScissorInheritanceTracker viewport_scissor_inheritance{*this};
13468 
13469     if (enabled_features.inherited_viewport_scissor_features.inheritedViewportScissor2D)
13470     {
13471         skip |= viewport_scissor_inheritance.VisitPrimary(cb_state.get());
13472     }
13473 
13474     bool active_occlusion_query = false;
13475     for (const auto& active_query : cb_state->activeQueries) {
13476         const auto query_pool_state = Get<QUERY_POOL_STATE>(active_query.pool);
13477         if (query_pool_state->createInfo.queryType == VK_QUERY_TYPE_OCCLUSION) {
13478             active_occlusion_query = true;
13479             break;
13480         }
13481     }
13482 
13483     if (cb_state->activeRenderPass) {
13484         if ((cb_state->activeRenderPass->use_dynamic_rendering == false) &&
13485             (cb_state->activeSubpassContents != VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS)) {
13486             skip |= LogError(commandBuffer, "VUID-vkCmdExecuteCommands-contents-06018",
13487                              "vkCmdExecuteCommands(): contents must be set to VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS "
13488                              "when calling vkCmdExecuteCommands() within a render pass instance begun with "
13489                              "vkCmdBeginRenderPass().");
13490         }
13491 
13492         if ((cb_state->activeRenderPass->use_dynamic_rendering == true) &&
13493             !(cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.flags &
13494               VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR)) {
13495             skip |= LogError(commandBuffer, "VUID-vkCmdExecuteCommands-flags-06024",
13496                              "vkCmdExecuteCommands(): VkRenderingInfoKHR::flags must include "
13497                              "VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR when calling vkCmdExecuteCommands() within a "
13498                              "render pass instance begun with vkCmdBeginRenderingKHR().");
13499         }
13500     }
13501 
13502     for (uint32_t i = 0; i < commandBuffersCount; i++) {
13503         const auto sub_cb_state = Get<CMD_BUFFER_STATE>(pCommandBuffers[i]);
13504         assert(sub_cb_state);
13505 
13506         if (enabled_features.inherited_viewport_scissor_features.inheritedViewportScissor2D)
13507         {
13508             skip |= viewport_scissor_inheritance.VisitSecondary(i, sub_cb_state.get());
13509         }
13510 
13511         if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == sub_cb_state->createInfo.level) {
13512             skip |= LogError(pCommandBuffers[i], "VUID-vkCmdExecuteCommands-pCommandBuffers-00088",
13513                              "vkCmdExecuteCommands() called w/ Primary %s in element %u of pCommandBuffers array. All "
13514                              "cmd buffers in pCommandBuffers array must be secondary.",
13515                              report_data->FormatHandle(pCommandBuffers[i]).c_str(), i);
13516         } else if (VK_COMMAND_BUFFER_LEVEL_SECONDARY == sub_cb_state->createInfo.level) {
13517             if (sub_cb_state->beginInfo.pInheritanceInfo != nullptr) {
13518                 const auto secondary_rp_state = Get<RENDER_PASS_STATE>(sub_cb_state->beginInfo.pInheritanceInfo->renderPass);
13519                 if (cb_state->activeRenderPass &&
13520                     !(sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
13521                     LogObjectList objlist(pCommandBuffers[i]);
13522                     objlist.add(cb_state->activeRenderPass->renderPass());
13523                     skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-pCommandBuffers-00096",
13524                                      "vkCmdExecuteCommands(): Secondary %s is executed within a %s "
13525                                      "instance scope, but the Secondary Command Buffer does not have the "
13526                                      "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set in VkCommandBufferBeginInfo::flags when "
13527                                      "the vkBeginCommandBuffer() was called.",
13528                                      report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13529                                      report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str());
13530                 } else if (!cb_state->activeRenderPass &&
13531                            (sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
13532                     skip |= LogError(pCommandBuffers[i], "VUID-vkCmdExecuteCommands-pCommandBuffers-00100",
13533                                      "vkCmdExecuteCommands(): Secondary %s is executed outside a render pass "
13534                                      "instance scope, but the Secondary Command Buffer does have the "
13535                                      "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set in VkCommandBufferBeginInfo::flags when "
13536                                      "the vkBeginCommandBuffer() was called.",
13537                                      report_data->FormatHandle(pCommandBuffers[i]).c_str());
13538                 } else if (cb_state->activeRenderPass && (cb_state->activeRenderPass->use_dynamic_rendering == false) &&
13539                            (sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
13540                     // Make sure render pass is compatible with parent command buffer pass if has continue
13541                     if (cb_state->activeRenderPass->renderPass() != secondary_rp_state->renderPass()) {
13542                         skip |= ValidateRenderPassCompatibility(
13543                             "primary command buffer", cb_state->activeRenderPass.get(), "secondary command buffer",
13544                             secondary_rp_state.get(), "vkCmdExecuteCommands()", "VUID-vkCmdExecuteCommands-pBeginInfo-06020");
13545                     }
13546                     //  If framebuffer for secondary CB is not NULL, then it must match active FB from primaryCB
13547                     skip |= ValidateFramebuffer(commandBuffer, cb_state.get(), pCommandBuffers[i], sub_cb_state.get(),
13548                                                 "vkCmdExecuteCommands()");
13549                     if (!sub_cb_state->cmd_execute_commands_functions.empty()) {
13550                         //  Inherit primary's activeFramebuffer and while running validate functions
13551                         for (auto &function : sub_cb_state->cmd_execute_commands_functions) {
13552                             skip |= function(*sub_cb_state, cb_state.get(), cb_state->activeFramebuffer.get());
13553                         }
13554                     }
13555                 }
13556 
13557                 if (cb_state->activeRenderPass && (cb_state->activeRenderPass->use_dynamic_rendering == false) &&
13558                     (cb_state->activeSubpass != sub_cb_state->beginInfo.pInheritanceInfo->subpass)) {
13559                     LogObjectList objlist(pCommandBuffers[i]);
13560                     objlist.add(cb_state->activeRenderPass->renderPass());
13561                     skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-pCommandBuffers-06019",
13562                                      "vkCmdExecuteCommands(): Secondary %s is executed within a %s "
13563                                      "instance scope begun by vkCmdBeginRenderPass(), but "
13564                                      "VkCommandBufferInheritanceInfo::subpass (%u) does not "
13565                                      "match the current subpass (%u).",
13566                                      report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13567                                      report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str(),
13568                                      sub_cb_state->beginInfo.pInheritanceInfo->subpass, cb_state->activeSubpass);
13569                 } else if (cb_state->activeRenderPass && (cb_state->activeRenderPass->use_dynamic_rendering == true)) {
13570                     if (sub_cb_state->beginInfo.pInheritanceInfo->renderPass != VK_NULL_HANDLE) {
13571                         LogObjectList objlist(pCommandBuffers[i]);
13572                         objlist.add(cb_state->activeRenderPass->renderPass());
13573                         skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-pBeginInfo-06025",
13574                                          "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13575                                          "by vkCmdBeginRenderingKHR(), but "
13576                                          "VkCommandBufferInheritanceInfo::pInheritanceInfo::renderPass is not VK_NULL_HANDLE.",
13577                                          report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13578                                          report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str());
13579                     }
13580 
13581                     if (sub_cb_state->activeRenderPass->use_dynamic_rendering_inherited) {
13582                         if (sub_cb_state->activeRenderPass->inheritance_rendering_info.flags !=
13583                             (cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.flags &
13584                              ~VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR)) {
13585                             LogObjectList objlist(pCommandBuffers[i]);
13586                             objlist.add(cb_state->activeRenderPass->renderPass());
13587                             skip |= LogError(
13588                                 objlist, "VUID-vkCmdExecuteCommands-flags-06026",
13589                                 "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13590                                 "by vkCmdBeginRenderingKHR(), but VkCommandBufferInheritanceRenderingInfoKHR::flags (%u) does "
13591                                 "not match VkRenderingInfoKHR::flags (%u), excluding "
13592                                 "VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR.",
13593                                 report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13594                                 report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str(),
13595                                 sub_cb_state->activeRenderPass->inheritance_rendering_info.flags,
13596                                 cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.flags);
13597                         }
13598 
13599                         if (sub_cb_state->activeRenderPass->inheritance_rendering_info.colorAttachmentCount !=
13600                             cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount) {
13601                             LogObjectList objlist(pCommandBuffers[i]);
13602                             objlist.add(cb_state->activeRenderPass->renderPass());
13603                             skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-colorAttachmentCount-06027",
13604                                              "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13605                                              "by vkCmdBeginRenderingKHR(), but "
13606                                              "VkCommandBufferInheritanceRenderingInfoKHR::colorAttachmentCount (%u) does "
13607                                              "not match VkRenderingInfoKHR::colorAttachmentCount (%u).",
13608                                              report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13609                                              report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str(),
13610                                              sub_cb_state->activeRenderPass->inheritance_rendering_info.colorAttachmentCount,
13611                                              cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount);
13612                         }
13613 
13614                         for (uint32_t index = 0;
13615                              index < cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.colorAttachmentCount;
13616                              index++) {
13617                             if (cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pColorAttachments[index]
13618                                     .imageView !=
13619                                 VK_NULL_HANDLE) {
13620                                 auto image_view_state = Get<IMAGE_VIEW_STATE>(
13621                                     cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pColorAttachments[index]
13622                                         .imageView);
13623 
13624                                 if (image_view_state->create_info.format !=
13625                                     sub_cb_state->activeRenderPass->inheritance_rendering_info.pColorAttachmentFormats[index]) {
13626                                     LogObjectList objlist(pCommandBuffers[i]);
13627                                     objlist.add(cb_state->activeRenderPass->renderPass());
13628                                     skip |= LogError(
13629                                         objlist, "VUID-vkCmdExecuteCommands-imageView-06028",
13630                                         "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13631                                         "by vkCmdBeginRenderingKHR(), but "
13632                                         "VkCommandBufferInheritanceRenderingInfoKHR::pColorAttachmentFormats at index (%u) does "
13633                                         "not match the format of the imageView in VkRenderingInfoKHR::pColorAttachments.",
13634                                         report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13635                                         report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str(), index);
13636                                 }
13637                             }
13638                         }
13639 
13640                         if ((cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pDepthAttachment != nullptr) &&
13641                             cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pDepthAttachment->imageView !=
13642                                 VK_NULL_HANDLE) {
13643                             auto image_view_state = Get<IMAGE_VIEW_STATE>(
13644                                 cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pDepthAttachment->imageView);
13645 
13646                             if (image_view_state->create_info.format !=
13647                                 sub_cb_state->activeRenderPass->inheritance_rendering_info.depthAttachmentFormat) {
13648                                 LogObjectList objlist(pCommandBuffers[i]);
13649                                 objlist.add(cb_state->activeRenderPass->renderPass());
13650                                 skip |=
13651                                     LogError(objlist, "VUID-vkCmdExecuteCommands-pDepthAttachment-06029",
13652                                              "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13653                                              "by vkCmdBeginRenderingKHR(), but "
13654                                              "VkCommandBufferInheritanceRenderingInfoKHR::depthAttachmentFormat does "
13655                                              "not match the format of the imageView in VkRenderingInfoKHR::pDepthAttachment.",
13656                                              report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13657                                              report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str());
13658                             }
13659                         }
13660 
13661                         if ((cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pStencilAttachment != nullptr) &&
13662                             cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pStencilAttachment->imageView !=
13663                                 VK_NULL_HANDLE) {
13664                             auto image_view_state = Get<IMAGE_VIEW_STATE>(
13665                                 cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.pStencilAttachment->imageView);
13666 
13667                             if (image_view_state->create_info.format !=
13668                                 sub_cb_state->activeRenderPass->inheritance_rendering_info.stencilAttachmentFormat) {
13669                                 LogObjectList objlist(pCommandBuffers[i]);
13670                                 objlist.add(cb_state->activeRenderPass->renderPass());
13671                                 skip |=
13672                                     LogError(objlist, "VUID-vkCmdExecuteCommands-pStencilAttachment-06030",
13673                                              "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13674                                              "by vkCmdBeginRenderingKHR(), but "
13675                                              "VkCommandBufferInheritanceRenderingInfoKHR::stencilAttachmentFormat does "
13676                                              "not match the format of the imageView in VkRenderingInfoKHR::pStencilAttachment.",
13677                                              report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13678                                              report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str());
13679                             }
13680                         }
13681 
13682                         if (cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.viewMask !=
13683                             sub_cb_state->activeRenderPass->inheritance_rendering_info.viewMask) {
13684                             LogObjectList objlist(pCommandBuffers[i]);
13685                             objlist.add(cb_state->activeRenderPass->renderPass());
13686                             skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-viewMask-06031",
13687                                              "vkCmdExecuteCommands(): Secondary %s is executed within a %s instance scope begun "
13688                                              "by vkCmdBeginRenderingKHR(), but "
13689                                              "VkCommandBufferInheritanceRenderingInfoKHR::viewMask (%u) does "
13690                                              "not match VkRenderingInfoKHR::viewMask (%u).",
13691                                              report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13692                                              report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str(),
13693                                              sub_cb_state->activeRenderPass->inheritance_rendering_info.viewMask,
13694                                              cb_state->activeRenderPass->dynamic_rendering_begin_rendering_info.viewMask);
13695                         }
13696                     }
13697                 }
13698             }
13699         }
13700 
13701         // TODO(mlentine): Move more logic into this method
13702         skip |= ValidateSecondaryCommandBufferState(cb_state.get(), sub_cb_state.get());
13703         skip |= ValidateCommandBufferState(sub_cb_state.get(), "vkCmdExecuteCommands()", 0,
13704                                            "VUID-vkCmdExecuteCommands-pCommandBuffers-00089");
13705         if (!(sub_cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
13706             if (sub_cb_state->InUse()) {
13707                 skip |= LogError(
13708                     cb_state->commandBuffer(), "VUID-vkCmdExecuteCommands-pCommandBuffers-00091",
13709                     "vkCmdExecuteCommands(): Cannot execute pending %s without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
13710                     report_data->FormatHandle(sub_cb_state->commandBuffer()).c_str());
13711             }
13712             // We use an const_cast, because one cannot query a container keyed on a non-const pointer using a const pointer
13713             if (cb_state->linkedCommandBuffers.count(const_cast<CMD_BUFFER_STATE *>(sub_cb_state.get()))) {
13714                 LogObjectList objlist(cb_state->commandBuffer());
13715                 objlist.add(sub_cb_state->commandBuffer());
13716                 skip |= LogError(objlist, "VUID-vkCmdExecuteCommands-pCommandBuffers-00092",
13717                                  "vkCmdExecuteCommands(): Cannot execute %s without VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
13718                                  "set if previously executed in %s",
13719                                  report_data->FormatHandle(sub_cb_state->commandBuffer()).c_str(),
13720                                  report_data->FormatHandle(cb_state->commandBuffer()).c_str());
13721             }
13722 
13723             const auto insert_pair = linked_command_buffers.insert(sub_cb_state.get());
13724             if (!insert_pair.second) {
13725                 skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdExecuteCommands-pCommandBuffers-00093",
13726                                  "vkCmdExecuteCommands(): Cannot duplicate %s in pCommandBuffers without "
13727                                  "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set.",
13728                                  report_data->FormatHandle(cb_state->commandBuffer()).c_str());
13729             }
13730 
13731             if (cb_state->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
13732                 // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
13733                 LogObjectList objlist(pCommandBuffers[i]);
13734                 objlist.add(cb_state->commandBuffer());
13735                 skip |= LogWarning(objlist, kVUID_Core_DrawState_InvalidCommandBufferSimultaneousUse,
13736                                    "vkCmdExecuteCommands(): Secondary %s does not have "
13737                                    "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary "
13738                                    "%s to be treated as if it does not have "
13739                                    "VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set, even though it does.",
13740                                    report_data->FormatHandle(pCommandBuffers[i]).c_str(),
13741                                    report_data->FormatHandle(cb_state->commandBuffer()).c_str());
13742             }
13743         }
13744         if (!cb_state->activeQueries.empty() && !enabled_features.core.inheritedQueries) {
13745             skip |= LogError(pCommandBuffers[i], "VUID-vkCmdExecuteCommands-commandBuffer-00101",
13746                              "vkCmdExecuteCommands(): Secondary %s cannot be submitted with a query in flight and "
13747                              "inherited queries not supported on this device.",
13748                              report_data->FormatHandle(pCommandBuffers[i]).c_str());
13749         }
13750         // Validate initial layout uses vs. the primary cmd buffer state
13751         // Novel Valid usage: "UNASSIGNED-vkCmdExecuteCommands-commandBuffer-00001"
13752         // initial layout usage of secondary command buffers resources must match parent command buffer
13753         const auto const_cb_state = std::static_pointer_cast<const CMD_BUFFER_STATE>(cb_state);
13754         for (const auto &sub_layout_map_entry : sub_cb_state->image_layout_map) {
13755             const auto *image_state = sub_layout_map_entry.first;
13756             const auto image = image_state->image();
13757 
13758             const auto *cb_subres_map = const_cb_state->GetImageSubresourceLayoutMap(*image_state);
13759             // Const getter can be null in which case we have nothing to check against for this image...
13760             if (!cb_subres_map) continue;
13761 
13762             const auto *sub_cb_subres_map = &sub_layout_map_entry.second;
13763             // Validate the initial_uses, that they match the current state of the primary cb, or absent a current state,
13764             // that the match any initial_layout.
13765             for (const auto &subres_layout : *sub_cb_subres_map) {
13766                 const auto &sub_layout = subres_layout.initial_layout;
13767                 const auto &subresource = subres_layout.subresource;
13768                 if (VK_IMAGE_LAYOUT_UNDEFINED == sub_layout) continue;  // secondary doesn't care about current or initial
13769 
13770                 // Look up the layout to compared to the intial layout of the sub command buffer (current else initial)
13771                 const auto *cb_layouts = cb_subres_map->GetSubresourceLayouts(subresource);
13772                 auto cb_layout = cb_layouts ? cb_layouts->current_layout : kInvalidLayout;
13773                 const char *layout_type = "current";
13774                 if (cb_layout == kInvalidLayout) {
13775                     cb_layout = cb_layouts ? cb_layouts->initial_layout : kInvalidLayout;
13776                     layout_type = "initial";
13777                 }
13778                 if ((cb_layout != kInvalidLayout) && (cb_layout != sub_layout)) {
13779                     skip |= LogError(pCommandBuffers[i], "UNASSIGNED-vkCmdExecuteCommands-commandBuffer-00001",
13780                                      "%s: Executed secondary command buffer using %s (subresource: aspectMask 0x%X array layer %u, "
13781                                      "mip level %u) which expects layout %s--instead, image %s layout is %s.",
13782                                      "vkCmdExecuteCommands():", report_data->FormatHandle(image).c_str(), subresource.aspectMask,
13783                                      subresource.arrayLayer, subresource.mipLevel, string_VkImageLayout(sub_layout), layout_type,
13784                                      string_VkImageLayout(cb_layout));
13785                 }
13786             }
13787         }
13788 
13789         // All commands buffers involved must be protected or unprotected
13790         if ((cb_state->unprotected == false) && (sub_cb_state->unprotected == true)) {
13791             LogObjectList objlist(cb_state->commandBuffer());
13792             objlist.add(sub_cb_state->commandBuffer());
13793             skip |= LogError(
13794                 objlist, "VUID-vkCmdExecuteCommands-commandBuffer-01820",
13795                 "vkCmdExecuteCommands(): command buffer %s is protected while secondary command buffer %s is a unprotected",
13796                 report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
13797                 report_data->FormatHandle(sub_cb_state->commandBuffer()).c_str());
13798         } else if ((cb_state->unprotected == true) && (sub_cb_state->unprotected == false)) {
13799             LogObjectList objlist(cb_state->commandBuffer());
13800             objlist.add(sub_cb_state->commandBuffer());
13801             skip |= LogError(
13802                 objlist, "VUID-vkCmdExecuteCommands-commandBuffer-01821",
13803                 "vkCmdExecuteCommands(): command buffer %s is unprotected while secondary command buffer %s is a protected",
13804                 report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
13805                 report_data->FormatHandle(sub_cb_state->commandBuffer()).c_str());
13806         }
13807         if (active_occlusion_query && sub_cb_state->inheritanceInfo.occlusionQueryEnable != VK_TRUE) {
13808             skip |= LogError(pCommandBuffers[i], "VUID-vkCmdExecuteCommands-commandBuffer-00102",
13809                              "vkCmdExecuteCommands(): command buffer %s has an active occlusion query, but secondary command "
13810                              "buffer %s was recorded with VkCommandBufferInheritanceInfo::occlusionQueryEnable set to VK_FALSE",
13811                              report_data->FormatHandle(cb_state->commandBuffer()).c_str(),
13812                              report_data->FormatHandle(sub_cb_state->commandBuffer()).c_str());
13813         }
13814     }
13815 
13816     skip |= ValidateCmd(cb_state.get(), CMD_EXECUTECOMMANDS);
13817     return skip;
13818 }
13819 
PreCallValidateMapMemory(VkDevice device,VkDeviceMemory mem,VkDeviceSize offset,VkDeviceSize size,VkFlags flags,void ** ppData) const13820 bool CoreChecks::PreCallValidateMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size,
13821                                           VkFlags flags, void **ppData) const {
13822     bool skip = false;
13823     const auto mem_info = Get<DEVICE_MEMORY_STATE>(mem);
13824     if (mem_info) {
13825         if ((phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
13826              VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
13827             skip = LogError(mem, "VUID-vkMapMemory-memory-00682",
13828                             "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: %s.",
13829                             report_data->FormatHandle(mem).c_str());
13830         }
13831 
13832         if (mem_info->multi_instance) {
13833             skip = LogError(mem, "VUID-vkMapMemory-memory-00683",
13834                             "Memory (%s) must not have been allocated with multiple instances -- either by supplying a deviceMask "
13835                             "with more than one bit set, or by allocation from a heap with the MULTI_INSTANCE heap flag set.",
13836                             report_data->FormatHandle(mem).c_str());
13837         }
13838 
13839         skip |= ValidateMapMemRange(mem_info.get(), offset, size);
13840     }
13841     return skip;
13842 }
13843 
PreCallValidateUnmapMemory(VkDevice device,VkDeviceMemory mem) const13844 bool CoreChecks::PreCallValidateUnmapMemory(VkDevice device, VkDeviceMemory mem) const {
13845     bool skip = false;
13846     const auto mem_info = Get<DEVICE_MEMORY_STATE>(mem);
13847     if (mem_info && !mem_info->mapped_range.size) {
13848         // Valid Usage: memory must currently be mapped
13849         skip |= LogError(mem, "VUID-vkUnmapMemory-memory-00689", "Unmapping Memory without memory being mapped: %s.",
13850                          report_data->FormatHandle(mem).c_str());
13851     }
13852     return skip;
13853 }
13854 
ValidateMemoryIsMapped(const char * funcName,uint32_t memRangeCount,const VkMappedMemoryRange * pMemRanges) const13855 bool CoreChecks::ValidateMemoryIsMapped(const char *funcName, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) const {
13856     bool skip = false;
13857     for (uint32_t i = 0; i < memRangeCount; ++i) {
13858         auto mem_info = Get<DEVICE_MEMORY_STATE>(pMemRanges[i].memory);
13859         if (mem_info) {
13860             // Makes sure the memory is already mapped
13861             if (mem_info->mapped_range.size == 0) {
13862                 skip = LogError(pMemRanges[i].memory, "VUID-VkMappedMemoryRange-memory-00684",
13863                                 "%s: Attempting to use memory (%s) that is not currently host mapped.", funcName,
13864                                 report_data->FormatHandle(pMemRanges[i].memory).c_str());
13865             }
13866 
13867             if (pMemRanges[i].size == VK_WHOLE_SIZE) {
13868                 if (mem_info->mapped_range.offset > pMemRanges[i].offset) {
13869                     skip |= LogError(pMemRanges[i].memory, "VUID-VkMappedMemoryRange-size-00686",
13870                                      "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER
13871                                      ") is less than Memory Object's offset (" PRINTF_SIZE_T_SPECIFIER ").",
13872                                      funcName, static_cast<size_t>(pMemRanges[i].offset),
13873                                      static_cast<size_t>(mem_info->mapped_range.offset));
13874                 }
13875             } else {
13876                 const uint64_t data_end = (mem_info->mapped_range.size == VK_WHOLE_SIZE)
13877                                               ? mem_info->alloc_info.allocationSize
13878                                               : (mem_info->mapped_range.offset + mem_info->mapped_range.size);
13879                 if ((mem_info->mapped_range.offset > pMemRanges[i].offset) ||
13880                     (data_end < (pMemRanges[i].offset + pMemRanges[i].size))) {
13881                     skip |= LogError(pMemRanges[i].memory, "VUID-VkMappedMemoryRange-size-00685",
13882                                      "%s: Flush/Invalidate size or offset (" PRINTF_SIZE_T_SPECIFIER ", " PRINTF_SIZE_T_SPECIFIER
13883                                      ") exceed the Memory Object's upper-bound (" PRINTF_SIZE_T_SPECIFIER ").",
13884                                      funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
13885                                      static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(data_end));
13886                 }
13887             }
13888         }
13889     }
13890     return skip;
13891 }
13892 
ValidateMappedMemoryRangeDeviceLimits(const char * func_name,uint32_t mem_range_count,const VkMappedMemoryRange * mem_ranges) const13893 bool CoreChecks::ValidateMappedMemoryRangeDeviceLimits(const char *func_name, uint32_t mem_range_count,
13894                                                        const VkMappedMemoryRange *mem_ranges) const {
13895     bool skip = false;
13896     for (uint32_t i = 0; i < mem_range_count; ++i) {
13897         const uint64_t atom_size = phys_dev_props.limits.nonCoherentAtomSize;
13898         const VkDeviceSize offset = mem_ranges[i].offset;
13899         const VkDeviceSize size = mem_ranges[i].size;
13900 
13901         if (SafeModulo(offset, atom_size) != 0) {
13902             skip |= LogError(mem_ranges->memory, "VUID-VkMappedMemoryRange-offset-00687",
13903                              "%s: Offset in pMemRanges[%d] is 0x%" PRIxLEAST64
13904                              ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64 ").",
13905                              func_name, i, offset, atom_size);
13906         }
13907         auto mem_info = Get<DEVICE_MEMORY_STATE>(mem_ranges[i].memory);
13908         if (mem_info) {
13909             const auto allocation_size = mem_info->alloc_info.allocationSize;
13910             if (size == VK_WHOLE_SIZE) {
13911                 const auto mapping_offset = mem_info->mapped_range.offset;
13912                 const auto mapping_size = mem_info->mapped_range.size;
13913                 const auto mapping_end = ((mapping_size == VK_WHOLE_SIZE) ? allocation_size : mapping_offset + mapping_size);
13914                 if (SafeModulo(mapping_end, atom_size) != 0 && mapping_end != allocation_size) {
13915                     skip |= LogError(mem_ranges->memory, "VUID-VkMappedMemoryRange-size-01389",
13916                                      "%s: Size in pMemRanges[%d] is VK_WHOLE_SIZE and the mapping end (0x%" PRIxLEAST64
13917                                      " = 0x%" PRIxLEAST64 " + 0x%" PRIxLEAST64
13918                                      ") not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64
13919                                      ") and not equal to the end of the memory object (0x%" PRIxLEAST64 ").",
13920                                      func_name, i, mapping_end, mapping_offset, mapping_size, atom_size, allocation_size);
13921                 }
13922             } else {
13923                 const auto range_end = size + offset;
13924                 if (range_end != allocation_size && SafeModulo(size, atom_size) != 0) {
13925                     skip |= LogError(mem_ranges->memory, "VUID-VkMappedMemoryRange-size-01390",
13926                                      "%s: Size in pMemRanges[%d] is 0x%" PRIxLEAST64
13927                                      ", which is not a multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize (0x%" PRIxLEAST64
13928                                      ") and offset + size (0x%" PRIxLEAST64 " + 0x%" PRIxLEAST64 " = 0x%" PRIxLEAST64
13929                                      ") not equal to the memory size (0x%" PRIxLEAST64 ").",
13930                                      func_name, i, size, atom_size, offset, size, range_end, allocation_size);
13931                 }
13932             }
13933         }
13934     }
13935     return skip;
13936 }
13937 
PreCallValidateFlushMappedMemoryRanges(VkDevice device,uint32_t memRangeCount,const VkMappedMemoryRange * pMemRanges) const13938 bool CoreChecks::PreCallValidateFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
13939                                                         const VkMappedMemoryRange *pMemRanges) const {
13940     bool skip = false;
13941     skip |= ValidateMappedMemoryRangeDeviceLimits("vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
13942     skip |= ValidateMemoryIsMapped("vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
13943     return skip;
13944 }
13945 
PreCallValidateInvalidateMappedMemoryRanges(VkDevice device,uint32_t memRangeCount,const VkMappedMemoryRange * pMemRanges) const13946 bool CoreChecks::PreCallValidateInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount,
13947                                                              const VkMappedMemoryRange *pMemRanges) const {
13948     bool skip = false;
13949     skip |= ValidateMappedMemoryRangeDeviceLimits("vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
13950     skip |= ValidateMemoryIsMapped("vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
13951     return skip;
13952 }
13953 
PreCallValidateGetDeviceMemoryCommitment(VkDevice device,VkDeviceMemory mem,VkDeviceSize * pCommittedMem) const13954 bool CoreChecks::PreCallValidateGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory mem, VkDeviceSize *pCommittedMem) const {
13955     bool skip = false;
13956     const auto mem_info = Get<DEVICE_MEMORY_STATE>(mem);
13957 
13958     if (mem_info) {
13959         if ((phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
13960              VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) == 0) {
13961             skip = LogError(mem, "VUID-vkGetDeviceMemoryCommitment-memory-00690",
13962                             "vkGetDeviceMemoryCommitment(): Querying commitment for memory without "
13963                             "VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT set: %s.",
13964                             report_data->FormatHandle(mem).c_str());
13965         }
13966     }
13967     return skip;
13968 }
13969 
ValidateBindImageMemory(uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos,const char * api_name) const13970 bool CoreChecks::ValidateBindImageMemory(uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos,
13971                                          const char *api_name) const {
13972     bool skip = false;
13973 
13974     bool bind_image_mem_2 = strcmp(api_name, "vkBindImageMemory()") != 0;
13975     char error_prefix[128];
13976     strcpy(error_prefix, api_name);
13977 
13978     // Track all image sub resources if they are bound for bind_image_mem_2
13979     // uint32_t[3] is which index in pBindInfos for max 3 planes
13980     // Non disjoint images act as a single plane
13981     layer_data::unordered_map<VkImage, std::array<uint32_t, 3>> resources_bound;
13982 
13983     for (uint32_t i = 0; i < bindInfoCount; i++) {
13984         if (bind_image_mem_2 == true) {
13985             sprintf(error_prefix, "%s pBindInfos[%u]", api_name, i);
13986         }
13987 
13988         const VkBindImageMemoryInfo &bind_info = pBindInfos[i];
13989         const auto image_state = Get<IMAGE_STATE>(bind_info.image);
13990         if (image_state) {
13991             // Track objects tied to memory
13992             skip |= ValidateSetMemBinding(bind_info.memory, *image_state, error_prefix);
13993 
13994             const auto plane_info = LvlFindInChain<VkBindImagePlaneMemoryInfo>(bind_info.pNext);
13995             const auto mem_info = Get<DEVICE_MEMORY_STATE>(bind_info.memory);
13996 
13997             // Need extra check for disjoint flag incase called without bindImage2 and don't want false positive errors
13998             // no 'else' case as if that happens another VUID is already being triggered for it being invalid
13999             if ((plane_info == nullptr) && (image_state->disjoint == false)) {
14000                 // Check non-disjoint images VkMemoryRequirements
14001 
14002                 // All validation using the image_state->requirements for external AHB is check in android only section
14003                 if (image_state->IsExternalAHB() == false) {
14004                     const VkMemoryRequirements &mem_req = image_state->requirements[0];
14005 
14006                     // Validate memory requirements alignment
14007                     if (SafeModulo(bind_info.memoryOffset, mem_req.alignment) != 0) {
14008                         const char *validation_error;
14009                         if (bind_image_mem_2 == false) {
14010                             validation_error = "VUID-vkBindImageMemory-memoryOffset-01048";
14011                         } else if (IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)) {
14012                             validation_error = "VUID-VkBindImageMemoryInfo-pNext-01616";
14013                         } else {
14014                             validation_error = "VUID-VkBindImageMemoryInfo-memoryOffset-01613";
14015                         }
14016                         skip |=
14017                             LogError(bind_info.image, validation_error,
14018                                      "%s: memoryOffset is 0x%" PRIxLEAST64
14019                                      " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
14020                                      ", returned from a call to vkGetImageMemoryRequirements with image.",
14021                                      error_prefix, bind_info.memoryOffset, mem_req.alignment);
14022                     }
14023 
14024                     if (mem_info) {
14025                         safe_VkMemoryAllocateInfo alloc_info = mem_info->alloc_info;
14026                         // Validate memory requirements size
14027                         if (mem_req.size > alloc_info.allocationSize - bind_info.memoryOffset) {
14028                             const char *validation_error;
14029                             if (bind_image_mem_2 == false) {
14030                                 validation_error = "VUID-vkBindImageMemory-size-01049";
14031                             } else if (IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)) {
14032                                 validation_error = "VUID-VkBindImageMemoryInfo-pNext-01617";
14033                             } else {
14034                                 validation_error = "VUID-VkBindImageMemoryInfo-memory-01614";
14035                             }
14036                             skip |= LogError(bind_info.image, validation_error,
14037                                              "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64
14038                                              " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64
14039                                              ", returned from a call to vkGetImageMemoryRequirements with image.",
14040                                              error_prefix, alloc_info.allocationSize - bind_info.memoryOffset, mem_req.size);
14041                         }
14042 
14043                         // Validate memory type used
14044                         {
14045                             const char *validation_error;
14046                             if (bind_image_mem_2 == false) {
14047                                 validation_error = "VUID-vkBindImageMemory-memory-01047";
14048                             } else if (IsExtEnabled(device_extensions.vk_khr_sampler_ycbcr_conversion)) {
14049                                 validation_error = "VUID-VkBindImageMemoryInfo-pNext-01615";
14050                             } else {
14051                                 validation_error = "VUID-VkBindImageMemoryInfo-memory-01612";
14052                             }
14053                             skip |= ValidateMemoryTypes(mem_info.get(), mem_req.memoryTypeBits, error_prefix, validation_error);
14054                         }
14055                     }
14056                 }
14057 
14058                 if (bind_image_mem_2 == true) {
14059                     // since its a non-disjoint image, finding VkImage in map is a duplicate
14060                     auto it = resources_bound.find(image_state->image());
14061                     if (it == resources_bound.end()) {
14062                         std::array<uint32_t, 3> bound_index = {i, UINT32_MAX, UINT32_MAX};
14063                         resources_bound.emplace(image_state->image(), bound_index);
14064                     } else {
14065                         skip |= LogError(
14066                             bind_info.image, "VUID-vkBindImageMemory2-pBindInfos-04006",
14067                             "%s: The same non-disjoint image resource is being bound twice at pBindInfos[%d] and pBindInfos[%d]",
14068                             error_prefix, it->second[0], i);
14069                     }
14070                 }
14071             } else if ((plane_info != nullptr) && (image_state->disjoint == true)) {
14072                 // Check disjoint images VkMemoryRequirements for given plane
14073                 int plane = 0;
14074 
14075                 // All validation using the image_state->plane*_requirements for external AHB is check in android only section
14076                 if (image_state->IsExternalAHB() == false) {
14077                     const VkImageAspectFlagBits aspect = plane_info->planeAspect;
14078                     switch (aspect) {
14079                         case VK_IMAGE_ASPECT_PLANE_0_BIT:
14080                             plane = 0;
14081                             break;
14082                         case VK_IMAGE_ASPECT_PLANE_1_BIT:
14083                             plane = 1;
14084                             break;
14085                         case VK_IMAGE_ASPECT_PLANE_2_BIT:
14086                             plane = 2;
14087                             break;
14088                         default:
14089                             assert(false);  // parameter validation should have caught this
14090                             break;
14091                     }
14092                     const VkMemoryRequirements &disjoint_mem_req = image_state->requirements[plane];
14093 
14094                     // Validate memory requirements alignment
14095                     if (SafeModulo(bind_info.memoryOffset, disjoint_mem_req.alignment) != 0) {
14096                         skip |= LogError(
14097                             bind_info.image, "VUID-VkBindImageMemoryInfo-pNext-01620",
14098                             "%s: memoryOffset is 0x%" PRIxLEAST64
14099                             " but must be an integer multiple of the VkMemoryRequirements::alignment value 0x%" PRIxLEAST64
14100                             ", returned from a call to vkGetImageMemoryRequirements2 with disjoint image for aspect plane %s.",
14101                             error_prefix, bind_info.memoryOffset, disjoint_mem_req.alignment, string_VkImageAspectFlagBits(aspect));
14102                     }
14103 
14104                     if (mem_info) {
14105                         safe_VkMemoryAllocateInfo alloc_info = mem_info->alloc_info;
14106 
14107                         // Validate memory requirements size
14108                         if (disjoint_mem_req.size > alloc_info.allocationSize - bind_info.memoryOffset) {
14109                             skip |= LogError(
14110                                 bind_info.image, "VUID-VkBindImageMemoryInfo-pNext-01621",
14111                                 "%s: memory size minus memoryOffset is 0x%" PRIxLEAST64
14112                                 " but must be at least as large as VkMemoryRequirements::size value 0x%" PRIxLEAST64
14113                                 ", returned from a call to vkGetImageMemoryRequirements with disjoint image for aspect plane %s.",
14114                                 error_prefix, alloc_info.allocationSize - bind_info.memoryOffset, disjoint_mem_req.size,
14115                                 string_VkImageAspectFlagBits(aspect));
14116                         }
14117 
14118                         // Validate memory type used
14119                         {
14120                             skip |= ValidateMemoryTypes(mem_info.get(), disjoint_mem_req.memoryTypeBits, error_prefix,
14121                                                         "VUID-VkBindImageMemoryInfo-pNext-01619");
14122                         }
14123                     }
14124                 }
14125 
14126                 auto it = resources_bound.find(image_state->image());
14127                 if (it == resources_bound.end()) {
14128                     std::array<uint32_t, 3> bound_index = {UINT32_MAX, UINT32_MAX, UINT32_MAX};
14129                     bound_index[plane] = i;
14130                     resources_bound.emplace(image_state->image(), bound_index);
14131                 } else {
14132                     if (it->second[plane] == UINT32_MAX) {
14133                         it->second[plane] = i;
14134                     } else {
14135                         skip |= LogError(bind_info.image, "VUID-vkBindImageMemory2-pBindInfos-04006",
14136                                          "%s: The same disjoint image sub-resource for plane %d is being bound twice at "
14137                                          "pBindInfos[%d] and pBindInfos[%d]",
14138                                          error_prefix, plane, it->second[plane], i);
14139                     }
14140                 }
14141             }
14142 
14143             if (mem_info) {
14144                 // Validate bound memory range information
14145                 // if memory is exported to an AHB then the mem_info->allocationSize must be zero and this check is not needed
14146                 if ((mem_info->IsExport() == false) ||
14147                     ((mem_info->export_handle_type_flags & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) ==
14148                      0)) {
14149                     skip |= ValidateInsertImageMemoryRange(bind_info.image, mem_info.get(), bind_info.memoryOffset, error_prefix);
14150                 }
14151 
14152                 // Validate dedicated allocation
14153                 if (mem_info->IsDedicatedImage()) {
14154                     if (enabled_features.dedicated_allocation_image_aliasing_features.dedicatedAllocationImageAliasing) {
14155                         const auto current_image_state = Get<IMAGE_STATE>(bind_info.image);
14156                         if ((bind_info.memoryOffset != 0) || !current_image_state ||
14157                             !current_image_state->IsCreateInfoDedicatedAllocationImageAliasingCompatible(
14158                                 mem_info->dedicated->create_info.image)) {
14159                             const char *validation_error;
14160                             if (bind_image_mem_2 == false) {
14161                                 validation_error = "VUID-vkBindImageMemory-memory-02629";
14162                             } else {
14163                                 validation_error = "VUID-VkBindImageMemoryInfo-memory-02629";
14164                             }
14165                             LogObjectList objlist(bind_info.image);
14166                             objlist.add(bind_info.memory);
14167                             objlist.add(mem_info->dedicated->handle);
14168                             skip |= LogError(
14169                                 objlist, validation_error,
14170                                 "%s: for dedicated memory allocation %s, VkMemoryDedicatedAllocateInfo:: %s must compatible "
14171                                 "with %s and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
14172                                 error_prefix, report_data->FormatHandle(bind_info.memory).c_str(),
14173                                 report_data->FormatHandle(mem_info->dedicated->handle).c_str(),
14174                                 report_data->FormatHandle(bind_info.image).c_str(), bind_info.memoryOffset);
14175                         }
14176                     } else {
14177                         if ((bind_info.memoryOffset != 0) || (mem_info->dedicated->handle.Cast<VkImage>() != bind_info.image)) {
14178                             const char *validation_error;
14179                             if (bind_image_mem_2 == false) {
14180                                 validation_error = "VUID-vkBindImageMemory-memory-01509";
14181                             } else {
14182                                 validation_error = "VUID-VkBindImageMemoryInfo-memory-01509";
14183                             }
14184                             LogObjectList objlist(bind_info.image);
14185                             objlist.add(bind_info.memory);
14186                             objlist.add(mem_info->dedicated->handle);
14187                             skip |=
14188                                 LogError(objlist, validation_error,
14189                                          "%s: for dedicated memory allocation %s, VkMemoryDedicatedAllocateInfo:: %s must be equal "
14190                                          "to %s and memoryOffset 0x%" PRIxLEAST64 " must be zero.",
14191                                          error_prefix, report_data->FormatHandle(bind_info.memory).c_str(),
14192                                          report_data->FormatHandle(mem_info->dedicated->handle).c_str(),
14193                                          report_data->FormatHandle(bind_info.image).c_str(), bind_info.memoryOffset);
14194                         }
14195                     }
14196                 }
14197 
14198                 // Validate export memory handles
14199                 if ((mem_info->export_handle_type_flags != 0) &&
14200                     ((mem_info->export_handle_type_flags & image_state->external_memory_handle) == 0)) {
14201                     const char *vuid =
14202                         bind_image_mem_2 ? "VUID-VkBindImageMemoryInfo-memory-02728" : "VUID-vkBindImageMemory-memory-02728";
14203                     LogObjectList objlist(bind_info.image);
14204                     objlist.add(bind_info.memory);
14205                     skip |= LogError(objlist, vuid,
14206                                      "%s: The VkDeviceMemory (%s) has an external handleType of %s which does not include at least "
14207                                      "one handle from VkImage (%s) handleType %s.",
14208                                      error_prefix, report_data->FormatHandle(bind_info.memory).c_str(),
14209                                      string_VkExternalMemoryHandleTypeFlags(mem_info->export_handle_type_flags).c_str(),
14210                                      report_data->FormatHandle(bind_info.image).c_str(),
14211                                      string_VkExternalMemoryHandleTypeFlags(image_state->external_memory_handle).c_str());
14212                 }
14213 
14214                 // Validate import memory handles
14215                 if (mem_info->IsImportAHB() == true) {
14216                     skip |= ValidateImageImportedHandleANDROID(api_name, image_state->external_memory_handle, bind_info.memory,
14217                                                                bind_info.image);
14218                 } else if (mem_info->IsImport() == true) {
14219                     if ((mem_info->import_handle_type_flags & image_state->external_memory_handle) == 0) {
14220                         const char *vuid = nullptr;
14221                         if ((bind_image_mem_2) &&
14222                             IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
14223                             vuid = "VUID-VkBindImageMemoryInfo-memory-02989";
14224                         } else if ((!bind_image_mem_2) &&
14225                                    IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
14226                             vuid = "VUID-vkBindImageMemory-memory-02989";
14227                         } else if ((bind_image_mem_2) &&
14228                                    !IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
14229                             vuid = "VUID-VkBindImageMemoryInfo-memory-02729";
14230                         } else if ((!bind_image_mem_2) &&
14231                                    !IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)) {
14232                             vuid = "VUID-vkBindImageMemory-memory-02729";
14233                         }
14234                         LogObjectList objlist(bind_info.image);
14235                         objlist.add(bind_info.memory);
14236                         skip |= LogError(objlist, vuid,
14237                                          "%s: The VkDeviceMemory (%s) was created with an import operation with handleType of %s "
14238                                          "which is not set in the VkImage (%s) VkExternalMemoryImageCreateInfo::handleType (%s)",
14239                                          api_name, report_data->FormatHandle(bind_info.memory).c_str(),
14240                                          string_VkExternalMemoryHandleTypeFlags(mem_info->import_handle_type_flags).c_str(),
14241                                          report_data->FormatHandle(bind_info.image).c_str(),
14242                                          string_VkExternalMemoryHandleTypeFlags(image_state->external_memory_handle).c_str());
14243                     }
14244                 }
14245 
14246                 // Validate mix of protected buffer and memory
14247                 if ((image_state->unprotected == false) && (mem_info->unprotected == true)) {
14248                     const char *vuid =
14249                         bind_image_mem_2 ? "VUID-VkBindImageMemoryInfo-None-01901" : "VUID-vkBindImageMemory-None-01901";
14250                     LogObjectList objlist(bind_info.image);
14251                     objlist.add(bind_info.memory);
14252                     skip |= LogError(objlist, vuid,
14253                                      "%s: The VkDeviceMemory (%s) was not created with protected memory but the VkImage (%s) was "
14254                                      "set to use protected memory.",
14255                                      api_name, report_data->FormatHandle(bind_info.memory).c_str(),
14256                                      report_data->FormatHandle(bind_info.image).c_str());
14257                 } else if ((image_state->unprotected == true) && (mem_info->unprotected == false)) {
14258                     const char *vuid =
14259                         bind_image_mem_2 ? "VUID-VkBindImageMemoryInfo-None-01902" : "VUID-vkBindImageMemory-None-01902";
14260                     LogObjectList objlist(bind_info.image);
14261                     objlist.add(bind_info.memory);
14262                     skip |= LogError(objlist, vuid,
14263                                      "%s: The VkDeviceMemory (%s) was created with protected memory but the VkImage (%s) was not "
14264                                      "set to use protected memory.",
14265                                      api_name, report_data->FormatHandle(bind_info.memory).c_str(),
14266                                      report_data->FormatHandle(bind_info.image).c_str());
14267                 }
14268             }
14269 
14270             const auto swapchain_info = LvlFindInChain<VkBindImageMemorySwapchainInfoKHR>(bind_info.pNext);
14271             if (swapchain_info) {
14272                 if (bind_info.memory != VK_NULL_HANDLE) {
14273                     skip |= LogError(bind_info.image, "VUID-VkBindImageMemoryInfo-pNext-01631", "%s: %s is not VK_NULL_HANDLE.",
14274                                      error_prefix, report_data->FormatHandle(bind_info.memory).c_str());
14275                 }
14276                 if (image_state->create_from_swapchain != swapchain_info->swapchain) {
14277                     LogObjectList objlist(image_state->image());
14278                     objlist.add(image_state->create_from_swapchain);
14279                     objlist.add(swapchain_info->swapchain);
14280                     skip |= LogError(
14281                         objlist, kVUID_Core_BindImageMemory_Swapchain,
14282                         "%s: %s is created by %s, but the image is bound by %s. The image should be created and bound by the same "
14283                         "swapchain",
14284                         error_prefix, report_data->FormatHandle(image_state->image()).c_str(),
14285                         report_data->FormatHandle(image_state->create_from_swapchain).c_str(),
14286                         report_data->FormatHandle(swapchain_info->swapchain).c_str());
14287                 }
14288                 const auto swapchain_state = Get<SWAPCHAIN_NODE>(swapchain_info->swapchain);
14289                 if (swapchain_state && swapchain_state->images.size() <= swapchain_info->imageIndex) {
14290                     skip |= LogError(bind_info.image, "VUID-VkBindImageMemorySwapchainInfoKHR-imageIndex-01644",
14291                                      "%s: imageIndex (%i) is out of bounds of %s images (size: %i)", error_prefix,
14292                                      swapchain_info->imageIndex, report_data->FormatHandle(swapchain_info->swapchain).c_str(),
14293                                      static_cast<int>(swapchain_state->images.size()));
14294                 }
14295             } else {
14296                 if (image_state->create_from_swapchain) {
14297                     skip |= LogError(bind_info.image, "VUID-VkBindImageMemoryInfo-image-01630",
14298                                      "%s: pNext of VkBindImageMemoryInfo doesn't include VkBindImageMemorySwapchainInfoKHR.",
14299                                      error_prefix);
14300                 }
14301                 if (!mem_info) {
14302                     skip |= LogError(bind_info.image, "VUID-VkBindImageMemoryInfo-pNext-01632", "%s: %s is invalid.", error_prefix,
14303                                      report_data->FormatHandle(bind_info.memory).c_str());
14304                 }
14305             }
14306 
14307             const auto bind_image_memory_device_group_info = LvlFindInChain<VkBindImageMemoryDeviceGroupInfo>(bind_info.pNext);
14308             if (bind_image_memory_device_group_info && bind_image_memory_device_group_info->splitInstanceBindRegionCount != 0) {
14309                 if (!(image_state->createInfo.flags & VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT)) {
14310                     skip |= LogError(bind_info.image, "VUID-VkBindImageMemoryInfo-pNext-01627",
14311                                      "%s: pNext of VkBindImageMemoryInfo contains VkBindImageMemoryDeviceGroupInfo with "
14312                                      "splitInstanceBindRegionCount (%" PRIi32
14313                                      ") not equal to 0 and %s is not created with "
14314                                      "VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT.",
14315                                      error_prefix, bind_image_memory_device_group_info->splitInstanceBindRegionCount,
14316                                      report_data->FormatHandle(image_state->image()).c_str());
14317                 }
14318                 uint32_t phy_dev_square = 1;
14319                 if (device_group_create_info.physicalDeviceCount > 0) {
14320                     phy_dev_square = device_group_create_info.physicalDeviceCount * device_group_create_info.physicalDeviceCount;
14321                 }
14322                 if (bind_image_memory_device_group_info->splitInstanceBindRegionCount != phy_dev_square) {
14323                     skip |= LogError(
14324                         bind_info.image, "VUID-VkBindImageMemoryDeviceGroupInfo-splitInstanceBindRegionCount-01636",
14325                         "%s: pNext of VkBindImageMemoryInfo contains VkBindImageMemoryDeviceGroupInfo with "
14326                         "splitInstanceBindRegionCount (%" PRIi32
14327                         ") which is not 0 and different from the number of physical devices in the logical device squared (%" PRIu32
14328                         ").",
14329                         error_prefix, bind_image_memory_device_group_info->splitInstanceBindRegionCount, phy_dev_square);
14330                 }
14331             }
14332 
14333             if (plane_info) {
14334                 // Checks for disjoint bit in image
14335                 if (image_state->disjoint == false) {
14336                     skip |= LogError(
14337                         bind_info.image, "VUID-VkBindImageMemoryInfo-pNext-01618",
14338                         "%s: pNext of VkBindImageMemoryInfo contains VkBindImagePlaneMemoryInfo and %s is not created with "
14339                         "VK_IMAGE_CREATE_DISJOINT_BIT.",
14340                         error_prefix, report_data->FormatHandle(image_state->image()).c_str());
14341                 }
14342 
14343                 // Make sure planeAspect is only a single, valid plane
14344                 uint32_t planes = FormatPlaneCount(image_state->createInfo.format);
14345                 VkImageAspectFlags aspect = plane_info->planeAspect;
14346                 if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT)) {
14347                     skip |= LogError(
14348                         bind_info.image, "VUID-VkBindImagePlaneMemoryInfo-planeAspect-02283",
14349                         "%s: Image %s VkBindImagePlaneMemoryInfo::planeAspect is %s but can only be VK_IMAGE_ASPECT_PLANE_0_BIT"
14350                         "or VK_IMAGE_ASPECT_PLANE_1_BIT.",
14351                         error_prefix, report_data->FormatHandle(image_state->image()).c_str(),
14352                         string_VkImageAspectFlags(aspect).c_str());
14353                 }
14354                 if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT) &&
14355                     (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT)) {
14356                     skip |= LogError(
14357                         bind_info.image, "VUID-VkBindImagePlaneMemoryInfo-planeAspect-02283",
14358                         "%s: Image %s VkBindImagePlaneMemoryInfo::planeAspect is %s but can only be VK_IMAGE_ASPECT_PLANE_0_BIT"
14359                         "or VK_IMAGE_ASPECT_PLANE_1_BIT or VK_IMAGE_ASPECT_PLANE_2_BIT.",
14360                         error_prefix, report_data->FormatHandle(image_state->image()).c_str(),
14361                         string_VkImageAspectFlags(aspect).c_str());
14362                 }
14363             }
14364         }
14365 
14366         const auto bind_image_memory_device_group = LvlFindInChain<VkBindImageMemoryDeviceGroupInfo>(bind_info.pNext);
14367         if (bind_image_memory_device_group) {
14368             if (bind_image_memory_device_group->deviceIndexCount > 0 &&
14369                 bind_image_memory_device_group->splitInstanceBindRegionCount > 0) {
14370                 skip |= LogError(bind_info.image, "VUID-VkBindImageMemoryDeviceGroupInfo-deviceIndexCount-01633",
14371                                  "%s: VkBindImageMemoryDeviceGroupInfo in pNext of pBindInfos[%" PRIu32
14372                                  "] has both deviceIndexCount and splitInstanceBindRegionCount greater than 0.",
14373                                  error_prefix, i);
14374             }
14375         }
14376     }
14377 
14378     // Check to make sure all disjoint planes were bound
14379     for (auto &resource : resources_bound) {
14380         const auto image_state = Get<IMAGE_STATE>(resource.first);
14381         if (image_state->disjoint == true) {
14382             uint32_t total_planes = FormatPlaneCount(image_state->createInfo.format);
14383             for (uint32_t i = 0; i < total_planes; i++) {
14384                 if (resource.second[i] == UINT32_MAX) {
14385                     skip |= LogError(resource.first, "VUID-vkBindImageMemory2-pBindInfos-02858",
14386                                      "%s: Plane %u of the disjoint image was not bound. All %d planes need to bound individually "
14387                                      "in separate pBindInfos in a single call.",
14388                                      api_name, i, total_planes);
14389                 }
14390             }
14391         }
14392     }
14393 
14394     return skip;
14395 }
14396 
PreCallValidateBindImageMemory(VkDevice device,VkImage image,VkDeviceMemory mem,VkDeviceSize memoryOffset) const14397 bool CoreChecks::PreCallValidateBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem,
14398                                                 VkDeviceSize memoryOffset) const {
14399     bool skip = false;
14400     const auto image_state = Get<IMAGE_STATE>(image);
14401     if (image_state) {
14402         // Checks for no disjoint bit
14403         if (image_state->disjoint == true) {
14404             skip |=
14405                 LogError(image, "VUID-vkBindImageMemory-image-01608",
14406                          "%s must not have been created with the VK_IMAGE_CREATE_DISJOINT_BIT (need to use vkBindImageMemory2).",
14407                          report_data->FormatHandle(image).c_str());
14408         }
14409     }
14410 
14411     auto bind_info = LvlInitStruct<VkBindImageMemoryInfo>();
14412     bind_info.image = image;
14413     bind_info.memory = mem;
14414     bind_info.memoryOffset = memoryOffset;
14415     skip |= ValidateBindImageMemory(1, &bind_info, "vkBindImageMemory()");
14416     return skip;
14417 }
14418 
PreCallValidateBindImageMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos) const14419 bool CoreChecks::PreCallValidateBindImageMemory2(VkDevice device, uint32_t bindInfoCount,
14420                                                  const VkBindImageMemoryInfo *pBindInfos) const {
14421     return ValidateBindImageMemory(bindInfoCount, pBindInfos, "vkBindImageMemory2()");
14422 }
14423 
PreCallValidateBindImageMemory2KHR(VkDevice device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos) const14424 bool CoreChecks::PreCallValidateBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount,
14425                                                     const VkBindImageMemoryInfo *pBindInfos) const {
14426     return ValidateBindImageMemory(bindInfoCount, pBindInfos, "vkBindImageMemory2KHR()");
14427 }
14428 
PreCallValidateSetEvent(VkDevice device,VkEvent event) const14429 bool CoreChecks::PreCallValidateSetEvent(VkDevice device, VkEvent event) const {
14430     bool skip = false;
14431     const auto event_state = Get<EVENT_STATE>(event);
14432     if (event_state) {
14433         if (event_state->write_in_use) {
14434             skip |=
14435                 LogError(event, kVUID_Core_DrawState_QueueForwardProgress,
14436                          "vkSetEvent(): %s that is already in use by a command buffer.", report_data->FormatHandle(event).c_str());
14437         }
14438         if (event_state->flags & VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR) {
14439             skip |= LogError(event, "VUID-vkSetEvent-event-03941",
14440                              "vkSetEvent(): %s was created with VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR.",
14441                              report_data->FormatHandle(event).c_str());
14442         }
14443     }
14444     return skip;
14445 }
14446 
PreCallValidateResetEvent(VkDevice device,VkEvent event) const14447 bool CoreChecks::PreCallValidateResetEvent(VkDevice device, VkEvent event) const {
14448     bool skip = false;
14449     const auto event_state = Get<EVENT_STATE>(event);
14450     if (event_state) {
14451         if (event_state->flags & VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR) {
14452             skip |= LogError(event, "VUID-vkResetEvent-event-03823",
14453                              "vkResetEvent(): %s was created with VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR.",
14454                              report_data->FormatHandle(event).c_str());
14455         }
14456     }
14457     return skip;
14458 }
14459 
PreCallValidateGetEventStatus(VkDevice device,VkEvent event) const14460 bool CoreChecks::PreCallValidateGetEventStatus(VkDevice device, VkEvent event) const {
14461     bool skip = false;
14462     const auto event_state = Get<EVENT_STATE>(event);
14463     if (event_state) {
14464         if (event_state->flags & VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR) {
14465             skip |= LogError(event, "VUID-vkGetEventStatus-event-03940",
14466                              "vkGetEventStatus(): %s was created with VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR.",
14467                              report_data->FormatHandle(event).c_str());
14468         }
14469     }
14470     return skip;
14471 }
14472 
ValidateSparseMemoryBind(const VkSparseMemoryBind * bind,const char * func_name,const char * parameter_name) const14473 bool CoreChecks::ValidateSparseMemoryBind(const VkSparseMemoryBind *bind, const char *func_name, const char *parameter_name) const {
14474     bool skip = false;
14475     if (bind) {
14476         const auto mem_info = Get<DEVICE_MEMORY_STATE>(bind->memory);
14477         if (mem_info) {
14478             if (phys_dev_mem_props.memoryTypes[mem_info->alloc_info.memoryTypeIndex].propertyFlags &
14479                 VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
14480                 skip |=
14481                     LogError(bind->memory, "VUID-VkSparseMemoryBind-memory-01097",
14482                              "%s: %s memory type has VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT bit set.", func_name, parameter_name);
14483             }
14484         }
14485     }
14486     return skip;
14487 }
14488 
PreCallValidateQueueBindSparse(VkQueue queue,uint32_t bindInfoCount,const VkBindSparseInfo * pBindInfo,VkFence fence) const14489 bool CoreChecks::PreCallValidateQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo,
14490                                                 VkFence fence) const {
14491     const auto queue_data = Get<QUEUE_STATE>(queue);
14492     const auto fence_state = Get<FENCE_STATE>(fence);
14493     bool skip = ValidateFenceForSubmit(fence_state.get(), "VUID-vkQueueBindSparse-fence-01114",
14494                                        "VUID-vkQueueBindSparse-fence-01113", "VkQueueBindSparse()");
14495     if (skip) {
14496         return true;
14497     }
14498 
14499     const auto queue_flags = physical_device_state->queue_family_properties[queue_data->queueFamilyIndex].queueFlags;
14500     if (!(queue_flags & VK_QUEUE_SPARSE_BINDING_BIT)) {
14501         skip |= LogError(queue, "VUID-vkQueueBindSparse-queuetype",
14502                          "vkQueueBindSparse(): a non-memory-management capable queue -- VK_QUEUE_SPARSE_BINDING_BIT not set.");
14503     }
14504 
14505     layer_data::unordered_set<VkSemaphore> signaled_semaphores;
14506     layer_data::unordered_set<VkSemaphore> unsignaled_semaphores;
14507     layer_data::unordered_set<VkSemaphore> internal_semaphores;
14508     auto *vuid_error = IsExtEnabled(device_extensions.vk_khr_timeline_semaphore) ? "VUID-vkQueueBindSparse-pWaitSemaphores-03245"
14509                                                                                  : kVUID_Core_DrawState_QueueForwardProgress;
14510     for (uint32_t bind_idx = 0; bind_idx < bindInfoCount; ++bind_idx) {
14511         const VkBindSparseInfo &bind_info = pBindInfo[bind_idx];
14512 
14513         auto timeline_semaphore_submit_info = LvlFindInChain<VkTimelineSemaphoreSubmitInfo>(pBindInfo->pNext);
14514         std::vector<SEMAPHORE_WAIT> semaphore_waits;
14515         std::vector<VkSemaphore> semaphore_signals;
14516         for (uint32_t i = 0; i < bind_info.waitSemaphoreCount; ++i) {
14517             VkSemaphore semaphore = bind_info.pWaitSemaphores[i];
14518             const auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
14519             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE && !timeline_semaphore_submit_info) {
14520                 skip |= LogError(semaphore, "VUID-VkBindSparseInfo-pWaitSemaphores-03246",
14521                                  "VkQueueBindSparse: pBindInfo[%u].pWaitSemaphores[%u] (%s) is a timeline semaphore, but "
14522                                  "pBindInfo[%u] does not include an instance of VkTimelineSemaphoreSubmitInfo",
14523                                  bind_idx, i, report_data->FormatHandle(semaphore).c_str(), bind_idx);
14524             }
14525             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE && timeline_semaphore_submit_info &&
14526                 bind_info.waitSemaphoreCount != timeline_semaphore_submit_info->waitSemaphoreValueCount) {
14527                 skip |= LogError(semaphore, "VUID-VkBindSparseInfo-pNext-03247",
14528                                  "VkQueueBindSparse: pBindInfo[%u].pWaitSemaphores[%u] (%s) is a timeline semaphore, it contains "
14529                                  "an instance of VkTimelineSemaphoreSubmitInfo, but waitSemaphoreValueCount (%u) is different "
14530                                  "than pBindInfo[%u].waitSemaphoreCount (%u)",
14531                                  bind_idx, i, report_data->FormatHandle(semaphore).c_str(),
14532                                  timeline_semaphore_submit_info->waitSemaphoreValueCount, bind_idx, bind_info.waitSemaphoreCount);
14533             }
14534             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_BINARY &&
14535                 (semaphore_state->scope == kSyncScopeInternal || internal_semaphores.count(semaphore))) {
14536                 if (unsignaled_semaphores.count(semaphore) ||
14537                     (!(signaled_semaphores.count(semaphore)) && !(semaphore_state->signaled) && !SemaphoreWasSignaled(semaphore))) {
14538                     LogObjectList objlist(semaphore);
14539                     objlist.add(queue);
14540                     skip |= LogError(
14541                         objlist,
14542                         semaphore_state->scope == kSyncScopeInternal ? vuid_error : kVUID_Core_DrawState_QueueForwardProgress,
14543                         "vkQueueBindSparse(): Queue %s is waiting on pBindInfo[%u].pWaitSemaphores[%u] (%s) that has no way to be "
14544                         "signaled.",
14545                         report_data->FormatHandle(queue).c_str(), bind_idx, i, report_data->FormatHandle(semaphore).c_str());
14546                 } else {
14547                     signaled_semaphores.erase(semaphore);
14548                     unsignaled_semaphores.insert(semaphore);
14549                 }
14550             }
14551             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_BINARY &&
14552                 semaphore_state->scope == kSyncScopeExternalTemporary) {
14553                 internal_semaphores.insert(semaphore);
14554             }
14555         }
14556 
14557         for (uint32_t i = 0; i < bind_info.signalSemaphoreCount; ++i) {
14558             VkSemaphore semaphore = bind_info.pSignalSemaphores[i];
14559             const auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
14560             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE && !timeline_semaphore_submit_info) {
14561                 skip |= LogError(semaphore, "VUID-VkBindSparseInfo-pWaitSemaphores-03246",
14562                                  "VkQueueBindSparse: pBindInfo[%u].pSignalSemaphores[%u] (%s) is a timeline semaphore, but "
14563                                  "pBindInfo[%u] does not include an instance of VkTimelineSemaphoreSubmitInfo",
14564                                  bind_idx, i, report_data->FormatHandle(semaphore).c_str(), bind_idx);
14565             }
14566             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE && timeline_semaphore_submit_info &&
14567                 timeline_semaphore_submit_info->pSignalSemaphoreValues[i] <= semaphore_state->payload) {
14568                 LogObjectList objlist(semaphore);
14569                 objlist.add(queue);
14570                 skip |= LogError(objlist, "VUID-VkBindSparseInfo-pSignalSemaphores-03249",
14571                                  "VkQueueBindSparse: signal value (0x%" PRIx64
14572                                  ") in %s must be greater than current timeline semaphore %s value (0x%" PRIx64
14573                                  ") in pBindInfo[%u].pSignalSemaphores[%u]",
14574                                  semaphore_state->payload, report_data->FormatHandle(queue).c_str(),
14575                                  report_data->FormatHandle(semaphore).c_str(),
14576                                  timeline_semaphore_submit_info->pSignalSemaphoreValues[i], bind_idx, i);
14577             }
14578             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE && timeline_semaphore_submit_info &&
14579                 bind_info.signalSemaphoreCount != timeline_semaphore_submit_info->signalSemaphoreValueCount) {
14580                 skip |=
14581                     LogError(semaphore, "VUID-VkBindSparseInfo-pNext-03248",
14582                              "VkQueueBindSparse: pBindInfo[%u].pSignalSemaphores[%u] (%s) is a timeline semaphore, it contains "
14583                              "an instance of VkTimelineSemaphoreSubmitInfo, but signalSemaphoreValueCount (%u) is different "
14584                              "than pBindInfo[%u].signalSemaphoreCount (%u)",
14585                              bind_idx, i, report_data->FormatHandle(semaphore).c_str(),
14586                              timeline_semaphore_submit_info->signalSemaphoreValueCount, bind_idx, bind_info.signalSemaphoreCount);
14587             }
14588             if (semaphore_state && semaphore_state->type == VK_SEMAPHORE_TYPE_BINARY &&
14589                 semaphore_state->scope == kSyncScopeInternal) {
14590                 if (signaled_semaphores.count(semaphore) ||
14591                     (!(unsignaled_semaphores.count(semaphore)) && semaphore_state->signaled)) {
14592                     LogObjectList objlist(semaphore);
14593                     objlist.add(queue);
14594                     objlist.add(semaphore_state->signaler.queue->Handle());
14595                     skip |= LogError(objlist, kVUID_Core_DrawState_QueueForwardProgress,
14596                                      "vkQueueBindSparse(): %s is signaling pBindInfo[%u].pSignalSemaphores[%u] (%s) that was "
14597                                      "previously signaled by %s but has not since been waited on by any queue.",
14598                                      report_data->FormatHandle(queue).c_str(), bind_idx, i,
14599                                      report_data->FormatHandle(semaphore).c_str(),
14600                                      report_data->FormatHandle(semaphore_state->signaler.queue->Handle()).c_str());
14601                 } else {
14602                     unsignaled_semaphores.erase(semaphore);
14603                     signaled_semaphores.insert(semaphore);
14604                 }
14605             }
14606         }
14607 
14608         if (bind_info.pBufferBinds) {
14609             for (uint32_t buffer_idx = 0; buffer_idx < bind_info.bufferBindCount; ++buffer_idx) {
14610                 const VkSparseBufferMemoryBindInfo &buffer_bind = bind_info.pBufferBinds[buffer_idx];
14611                 if (buffer_bind.pBinds) {
14612                     for (uint32_t buffer_bind_idx = 0; buffer_bind_idx < buffer_bind.bindCount; ++buffer_bind_idx) {
14613                         const VkSparseMemoryBind &memory_bind = buffer_bind.pBinds[buffer_bind_idx];
14614                         std::stringstream parameter_name;
14615                         parameter_name << "pBindInfo[" << bind_idx << "].pBufferBinds[" << buffer_idx << " ].pBinds["
14616                                        << buffer_bind_idx << "]";
14617                         ValidateSparseMemoryBind(&memory_bind, "vkQueueBindSparse()", parameter_name.str().c_str());
14618                         const auto mem_info = Get<DEVICE_MEMORY_STATE>(memory_bind.memory);
14619                         if (mem_info) {
14620                             if (memory_bind.memoryOffset >= mem_info->alloc_info.allocationSize) {
14621                                 skip |=
14622                                     LogError(buffer_bind.buffer, "VUID-VkSparseMemoryBind-memoryOffset-01101",
14623                                              "vkQueueBindSparse(): pBindInfo[%u].pBufferBinds[%u]: memoryOffset is not less than "
14624                                              "the size of memory",
14625                                              bind_idx, buffer_idx);
14626                             }
14627                         }
14628                     }
14629                 }
14630             }
14631         }
14632 
14633         if (bind_info.pImageOpaqueBinds) {
14634             for (uint32_t image_opaque_idx = 0; image_opaque_idx < bind_info.bufferBindCount; ++image_opaque_idx) {
14635                 const VkSparseImageOpaqueMemoryBindInfo &image_opaque_bind = bind_info.pImageOpaqueBinds[image_opaque_idx];
14636                 if (image_opaque_bind.pBinds) {
14637                     for (uint32_t image_opaque_bind_idx = 0; image_opaque_bind_idx < image_opaque_bind.bindCount;
14638                          ++image_opaque_bind_idx) {
14639                         const VkSparseMemoryBind &memory_bind = image_opaque_bind.pBinds[image_opaque_bind_idx];
14640                         std::stringstream parameter_name;
14641                         parameter_name << "pBindInfo[" << bind_idx << "].pImageOpaqueBinds[" << image_opaque_idx << " ].pBinds["
14642                                        << image_opaque_bind_idx << "]";
14643                         ValidateSparseMemoryBind(&memory_bind, "vkQueueBindSparse()", parameter_name.str().c_str());
14644                         const auto mem_info = Get<DEVICE_MEMORY_STATE>(memory_bind.memory);
14645                         if (mem_info) {
14646                             if (memory_bind.memoryOffset >= mem_info->alloc_info.allocationSize) {
14647                                 skip |= LogError(
14648                                     image_opaque_bind.image, "VUID-VkSparseMemoryBind-memoryOffset-01101",
14649                                     "vkQueueBindSparse(): pBindInfo[%u].pImageOpaqueBinds[%u]: memoryOffset is not less than "
14650                                     "the size of memory",
14651                                     bind_idx, image_opaque_idx);
14652                             }
14653                         }
14654                     }
14655                 }
14656             }
14657         }
14658 
14659         if (bind_info.pImageBinds) {
14660             for (uint32_t image_idx = 0; image_idx < bind_info.imageBindCount; ++image_idx) {
14661                 const VkSparseImageMemoryBindInfo &image_bind = bind_info.pImageBinds[image_idx];
14662                 const auto image_state = Get<IMAGE_STATE>(image_bind.image);
14663 
14664                 if (image_state && !(image_state->createInfo.flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)) {
14665                     skip |= LogError(image_bind.image, "VUID-VkSparseImageMemoryBindInfo-image-02901",
14666                                      "vkQueueBindSparse(): pBindInfo[%u].pImageBinds[%u]: image must have been created with "
14667                                      "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT set",
14668                                      bind_idx, image_idx);
14669                 }
14670 
14671                 if (image_bind.pBinds) {
14672                     for (uint32_t image_bind_idx = 0; image_bind_idx < image_bind.bindCount; ++image_bind_idx) {
14673                         const VkSparseImageMemoryBind &memory_bind = image_bind.pBinds[image_bind_idx];
14674                         const auto mem_info = Get<DEVICE_MEMORY_STATE>(memory_bind.memory);
14675                         if (mem_info) {
14676                             if (memory_bind.memoryOffset >= mem_info->alloc_info.allocationSize) {
14677                                 skip |=
14678                                     LogError(image_bind.image, "VUID-VkSparseMemoryBind-memoryOffset-01101",
14679                                              "vkQueueBindSparse(): pBindInfo[%u].pImageBinds[%u]: memoryOffset is not less than "
14680                                              "the size of memory",
14681                                              bind_idx, image_idx);
14682                             }
14683                         }
14684 
14685                         if (image_state) {
14686                             if (memory_bind.subresource.mipLevel >= image_state->createInfo.mipLevels) {
14687                                 skip |= LogError(image_bind.image, "VUID-VkSparseImageMemoryBindInfo-subresource-01722",
14688                                          "vkQueueBindSparse(): pBindInfo[%" PRIu32 "].pImageBinds[%" PRIu32
14689                                          "].subresource.mipLevel (%" PRIu32 ") is not less than mipLevels (%" PRIu32
14690                                          ") of image pBindInfo[%" PRIu32 "].pImageBinds[%" PRIu32 "].image.",
14691                                          bind_idx, image_idx, memory_bind.subresource.mipLevel, image_state->createInfo.mipLevels,
14692                                          bind_idx, image_idx);
14693                             }
14694                             if (memory_bind.subresource.arrayLayer >= image_state->createInfo.arrayLayers) {
14695                                 skip |= LogError(image_bind.image, "VUID-VkSparseImageMemoryBindInfo-subresource-01723",
14696                                          "vkQueueBindSparse(): pBindInfo[%" PRIu32 "].pImageBinds[%" PRIu32
14697                                          "].subresource.arrayLayer (%" PRIu32 ") is not less than arrayLayers (%" PRIu32
14698                                          ") of image pBindInfo[%" PRIu32 "].pImageBinds[%" PRIu32 "].image.",
14699                                          bind_idx, image_idx, memory_bind.subresource.arrayLayer,
14700                                          image_state->createInfo.arrayLayers,
14701                                          bind_idx, image_idx);
14702                             }
14703                         }
14704                     }
14705                 }
14706             }
14707         }
14708     }
14709 
14710     if (skip) return skip;
14711 
14712     // Now verify maxTimelineSemaphoreValueDifference
14713     for (uint32_t bind_idx = 0; bind_idx < bindInfoCount; ++bind_idx) {
14714         Location outer_loc(Func::vkQueueBindSparse, Struct::VkBindSparseInfo);
14715         const VkBindSparseInfo *bind_info = &pBindInfo[bind_idx];
14716         auto *info = LvlFindInChain<VkTimelineSemaphoreSubmitInfo>(bind_info->pNext);
14717         if (info) {
14718             // If there are any timeline semaphores, this condition gets checked before the early return above
14719             if (info->waitSemaphoreValueCount) {
14720                 for (uint32_t i = 0; i < bind_info->waitSemaphoreCount; ++i) {
14721                     auto loc = outer_loc.dot(Field::pWaitSemaphoreValues, i);
14722                     VkSemaphore semaphore = bind_info->pWaitSemaphores[i];
14723                     skip |= ValidateMaxTimelineSemaphoreValueDifference(loc, semaphore, info->pWaitSemaphoreValues[i]);
14724                 }
14725             }
14726             // If there are any timeline semaphores, this condition gets checked before the early return above
14727             if (info->signalSemaphoreValueCount) {
14728                 for (uint32_t i = 0; i < bind_info->signalSemaphoreCount; ++i) {
14729                     auto loc = outer_loc.dot(Field::pSignalSemaphoreValues, i);
14730                     VkSemaphore semaphore = bind_info->pSignalSemaphores[i];
14731                     skip |= ValidateMaxTimelineSemaphoreValueDifference(loc, semaphore, info->pSignalSemaphoreValues[i]);
14732                 }
14733             }
14734         }
14735     }
14736 
14737     return skip;
14738 }
14739 
ValidateSignalSemaphore(VkDevice device,const VkSemaphoreSignalInfo * pSignalInfo,const char * api_name) const14740 bool CoreChecks::ValidateSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo, const char *api_name) const {
14741     bool skip = false;
14742     const auto semaphore_state = Get<SEMAPHORE_STATE>(pSignalInfo->semaphore);
14743     if (semaphore_state && semaphore_state->type != VK_SEMAPHORE_TYPE_TIMELINE) {
14744         skip |= LogError(pSignalInfo->semaphore, "VUID-VkSemaphoreSignalInfo-semaphore-03257",
14745                          "%s(): semaphore %s must be of VK_SEMAPHORE_TYPE_TIMELINE type", api_name,
14746                          report_data->FormatHandle(pSignalInfo->semaphore).c_str());
14747         return skip;
14748     }
14749     if (semaphore_state && semaphore_state->payload >= pSignalInfo->value) {
14750         skip |= LogError(pSignalInfo->semaphore, "VUID-VkSemaphoreSignalInfo-value-03258",
14751                          "%s(): value must be greater than current semaphore %s value", api_name,
14752                          report_data->FormatHandle(pSignalInfo->semaphore).c_str());
14753     }
14754     ForEach<QUEUE_STATE>([this, &skip, api_name, pSignalInfo](const QUEUE_STATE &queue_state) {
14755         for (const auto &submission : queue_state.submissions) {
14756             for (const auto &signal_semaphore : submission.signal_semaphores) {
14757                 if (signal_semaphore.semaphore->semaphore() == pSignalInfo->semaphore &&
14758                     pSignalInfo->value >= signal_semaphore.payload) {
14759                     skip |= LogError(pSignalInfo->semaphore, "VUID-VkSemaphoreSignalInfo-value-03259",
14760                                      "%s(): value must be greater than value of pending signal operation "
14761                                      "for semaphore %s",
14762                                      api_name, report_data->FormatHandle(pSignalInfo->semaphore).c_str());
14763                 }
14764             }
14765         }
14766     });
14767 
14768     if (!skip) {
14769         Location loc(Func::vkSignalSemaphore, Struct::VkSemaphoreSignalInfo, Field::value);
14770         skip |= ValidateMaxTimelineSemaphoreValueDifference(loc, pSignalInfo->semaphore, pSignalInfo->value);
14771     }
14772 
14773     return skip;
14774 }
14775 
PreCallValidateSignalSemaphore(VkDevice device,const VkSemaphoreSignalInfo * pSignalInfo) const14776 bool CoreChecks::PreCallValidateSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo) const {
14777     return ValidateSignalSemaphore(device, pSignalInfo, "vkSignalSemaphore");
14778 }
14779 
PreCallValidateSignalSemaphoreKHR(VkDevice device,const VkSemaphoreSignalInfo * pSignalInfo) const14780 bool CoreChecks::PreCallValidateSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo) const {
14781     return ValidateSignalSemaphore(device, pSignalInfo, "vkSignalSemaphoreKHR");
14782 }
14783 
ValidateImportSemaphore(VkSemaphore semaphore,const char * caller_name) const14784 bool CoreChecks::ValidateImportSemaphore(VkSemaphore semaphore, const char *caller_name) const {
14785     bool skip = false;
14786     const auto sema_node = Get<SEMAPHORE_STATE>(semaphore);
14787     if (sema_node) {
14788         skip |= ValidateObjectNotInUse(sema_node.get(), caller_name, kVUIDUndefined);
14789     }
14790     return skip;
14791 }
14792 
14793 #ifdef VK_USE_PLATFORM_WIN32_KHR
PreCallValidateImportSemaphoreWin32HandleKHR(VkDevice device,const VkImportSemaphoreWin32HandleInfoKHR * pImportSemaphoreWin32HandleInfo) const14794 bool CoreChecks::PreCallValidateImportSemaphoreWin32HandleKHR(
14795     VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo) const {
14796     return ValidateImportSemaphore(pImportSemaphoreWin32HandleInfo->semaphore, "vkImportSemaphoreWin32HandleKHR");
14797 }
14798 
14799 #endif  // VK_USE_PLATFORM_WIN32_KHR
14800 
PreCallValidateImportSemaphoreFdKHR(VkDevice device,const VkImportSemaphoreFdInfoKHR * pImportSemaphoreFdInfo) const14801 bool CoreChecks::PreCallValidateImportSemaphoreFdKHR(VkDevice device,
14802                                                      const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo) const {
14803     return ValidateImportSemaphore(pImportSemaphoreFdInfo->semaphore, "vkImportSemaphoreFdKHR");
14804 }
14805 
ValidateImportFence(VkFence fence,const char * vuid,const char * caller_name) const14806 bool CoreChecks::ValidateImportFence(VkFence fence, const char *vuid, const char *caller_name) const {
14807     const auto fence_node = Get<FENCE_STATE>(fence);
14808     bool skip = false;
14809     if (fence_node && fence_node->scope == kSyncScopeInternal && fence_node->state == FENCE_INFLIGHT) {
14810         skip |=
14811             LogError(fence, vuid, "%s: Fence %s that is currently in use.", caller_name, report_data->FormatHandle(fence).c_str());
14812     }
14813     return skip;
14814 }
14815 
14816 #ifdef VK_USE_PLATFORM_WIN32_KHR
PreCallValidateImportFenceWin32HandleKHR(VkDevice device,const VkImportFenceWin32HandleInfoKHR * pImportFenceWin32HandleInfo) const14817 bool CoreChecks::PreCallValidateImportFenceWin32HandleKHR(
14818     VkDevice device, const VkImportFenceWin32HandleInfoKHR *pImportFenceWin32HandleInfo) const {
14819     return ValidateImportFence(pImportFenceWin32HandleInfo->fence, "VUID-vkImportFenceWin32HandleKHR-fence-04448",
14820                                "vkImportFenceWin32HandleKHR()");
14821 }
14822 #endif  // VK_USE_PLATFORM_WIN32_KHR
14823 
PreCallValidateImportFenceFdKHR(VkDevice device,const VkImportFenceFdInfoKHR * pImportFenceFdInfo) const14824 bool CoreChecks::PreCallValidateImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *pImportFenceFdInfo) const {
14825     return ValidateImportFence(pImportFenceFdInfo->fence, "VUID-vkImportFenceFdKHR-fence-01463", "vkImportFenceFdKHR()");
14826 }
14827 
GetSwapchainImpliedImageCreateInfo(VkSwapchainCreateInfoKHR const * pCreateInfo)14828 static VkImageCreateInfo GetSwapchainImpliedImageCreateInfo(VkSwapchainCreateInfoKHR const *pCreateInfo) {
14829     auto result = LvlInitStruct<VkImageCreateInfo>();
14830 
14831     if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR) {
14832         result.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
14833     }
14834     if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) result.flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
14835     if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
14836         result.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT;
14837     }
14838 
14839     result.imageType = VK_IMAGE_TYPE_2D;
14840     result.format = pCreateInfo->imageFormat;
14841     result.extent.width = pCreateInfo->imageExtent.width;
14842     result.extent.height = pCreateInfo->imageExtent.height;
14843     result.extent.depth = 1;
14844     result.mipLevels = 1;
14845     result.arrayLayers = pCreateInfo->imageArrayLayers;
14846     result.samples = VK_SAMPLE_COUNT_1_BIT;
14847     result.tiling = VK_IMAGE_TILING_OPTIMAL;
14848     result.usage = pCreateInfo->imageUsage;
14849     result.sharingMode = pCreateInfo->imageSharingMode;
14850     result.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount;
14851     result.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices;
14852     result.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
14853 
14854     return result;
14855 }
14856 
ValidateCreateSwapchain(const char * func_name,VkSwapchainCreateInfoKHR const * pCreateInfo,const SURFACE_STATE * surface_state,const SWAPCHAIN_NODE * old_swapchain_state) const14857 bool CoreChecks::ValidateCreateSwapchain(const char *func_name, VkSwapchainCreateInfoKHR const *pCreateInfo,
14858                                          const SURFACE_STATE *surface_state, const SWAPCHAIN_NODE *old_swapchain_state) const {
14859     // All physical devices and queue families are required to be able to present to any native window on Android; require the
14860     // application to have established support on any other platform.
14861     if (!instance_extensions.vk_khr_android_surface) {
14862         // restrict search only to queue families of VkDeviceQueueCreateInfos, not the whole physical device
14863         bool is_supported = AnyOf<QUEUE_STATE>([this, surface_state](const QUEUE_STATE &queue_state) {
14864             return surface_state->GetQueueSupport(physical_device, queue_state.queueFamilyIndex);
14865         });
14866 
14867         if (!is_supported) {
14868             LogObjectList objs(device);
14869             objs.add(surface_state->Handle());
14870             if (LogError(objs, "VUID-VkSwapchainCreateInfoKHR-surface-01270",
14871                     "%s: pCreateInfo->surface is not supported for presentation by this device.", func_name)) {
14872                 return true;
14873             }
14874         }
14875     }
14876 
14877     if (old_swapchain_state) {
14878         if (old_swapchain_state->createInfo.surface != pCreateInfo->surface) {
14879             if (LogError(pCreateInfo->oldSwapchain, "VUID-VkSwapchainCreateInfoKHR-oldSwapchain-01933",
14880                          "%s: pCreateInfo->oldSwapchain's surface is not pCreateInfo->surface", func_name)) {
14881                 return true;
14882             }
14883         }
14884         if (old_swapchain_state->retired) {
14885             if (LogError(pCreateInfo->oldSwapchain, "VUID-VkSwapchainCreateInfoKHR-oldSwapchain-01933",
14886                          "%s: pCreateInfo->oldSwapchain is retired", func_name)) {
14887                 return true;
14888             }
14889         }
14890     }
14891 
14892     if ((pCreateInfo->imageExtent.width == 0) || (pCreateInfo->imageExtent.height == 0)) {
14893         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageExtent-01689",
14894                      "%s: pCreateInfo->imageExtent = (%d, %d) which is illegal.", func_name, pCreateInfo->imageExtent.width,
14895                      pCreateInfo->imageExtent.height)) {
14896             return true;
14897         }
14898     }
14899 
14900     VkSurfaceCapabilitiesKHR capabilities{};
14901     DispatchGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_state->PhysDev(), pCreateInfo->surface, &capabilities);
14902     bool skip = false;
14903     VkSurfaceTransformFlagBitsKHR current_transform = capabilities.currentTransform;
14904     if ((pCreateInfo->preTransform & current_transform) != pCreateInfo->preTransform) {
14905         skip |= LogPerformanceWarning(physical_device, kVUID_Core_Swapchain_PreTransform,
14906                                       "%s: pCreateInfo->preTransform (%s) doesn't match the currentTransform (%s) returned by "
14907                                       "vkGetPhysicalDeviceSurfaceCapabilitiesKHR, the presentation engine will transform the image "
14908                                       "content as part of the presentation operation.",
14909                                       func_name, string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform),
14910                                       string_VkSurfaceTransformFlagBitsKHR(current_transform));
14911     }
14912 
14913     const VkPresentModeKHR present_mode = pCreateInfo->presentMode;
14914     const bool shared_present_mode = (VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == present_mode ||
14915                                       VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == present_mode);
14916 
14917     // Validate pCreateInfo->minImageCount against VkSurfaceCapabilitiesKHR::{min|max}ImageCount:
14918     // Shared Present Mode must have a minImageCount of 1
14919     if ((pCreateInfo->minImageCount < capabilities.minImageCount) && !shared_present_mode) {
14920         const char *vuid = IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)
14921                                ? "VUID-VkSwapchainCreateInfoKHR-presentMode-02839"
14922                                : "VUID-VkSwapchainCreateInfoKHR-minImageCount-01271";
14923         if (LogError(device, vuid,
14924                      "%s called with minImageCount = %d, which is outside the bounds returned by "
14925                      "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d).",
14926                      func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount)) {
14927             return true;
14928         }
14929     }
14930 
14931     if ((capabilities.maxImageCount > 0) && (pCreateInfo->minImageCount > capabilities.maxImageCount)) {
14932         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-minImageCount-01272",
14933                      "%s called with minImageCount = %d, which is outside the bounds returned by "
14934                      "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() (i.e. minImageCount = %d, maxImageCount = %d).",
14935                      func_name, pCreateInfo->minImageCount, capabilities.minImageCount, capabilities.maxImageCount)) {
14936             return true;
14937         }
14938     }
14939 
14940     // Validate pCreateInfo->imageExtent against VkSurfaceCapabilitiesKHR::{current|min|max}ImageExtent:
14941     if ((pCreateInfo->imageExtent.width < capabilities.minImageExtent.width) ||
14942         (pCreateInfo->imageExtent.width > capabilities.maxImageExtent.width) ||
14943         (pCreateInfo->imageExtent.height < capabilities.minImageExtent.height) ||
14944         (pCreateInfo->imageExtent.height > capabilities.maxImageExtent.height)) {
14945         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageExtent-01274",
14946                      "%s called with imageExtent = (%d,%d), which is outside the bounds returned by "
14947                      "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): currentExtent = (%d,%d), minImageExtent = (%d,%d), "
14948                      "maxImageExtent = (%d,%d).",
14949                      func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height, capabilities.currentExtent.width,
14950                      capabilities.currentExtent.height, capabilities.minImageExtent.width, capabilities.minImageExtent.height,
14951                      capabilities.maxImageExtent.width, capabilities.maxImageExtent.height)) {
14952             return true;
14953         }
14954     }
14955     // pCreateInfo->preTransform should have exactly one bit set, and that bit must also be set in
14956     // VkSurfaceCapabilitiesKHR::supportedTransforms.
14957     if (!pCreateInfo->preTransform || (pCreateInfo->preTransform & (pCreateInfo->preTransform - 1)) ||
14958         !(pCreateInfo->preTransform & capabilities.supportedTransforms)) {
14959         // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
14960         // it up a little at a time, and then log it:
14961         std::string error_string = "";
14962         char str[1024];
14963         // Here's the first part of the message:
14964         sprintf(str, "%s called with a non-supported pCreateInfo->preTransform (i.e. %s).  Supported values are:\n", func_name,
14965                 string_VkSurfaceTransformFlagBitsKHR(pCreateInfo->preTransform));
14966         error_string += str;
14967         for (int i = 0; i < 32; i++) {
14968             // Build up the rest of the message:
14969             if ((1 << i) & capabilities.supportedTransforms) {
14970                 const char *new_str = string_VkSurfaceTransformFlagBitsKHR(static_cast<VkSurfaceTransformFlagBitsKHR>(1 << i));
14971                 sprintf(str, "    %s\n", new_str);
14972                 error_string += str;
14973             }
14974         }
14975         // Log the message that we've built up:
14976         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-preTransform-01279", "%s.", error_string.c_str())) return true;
14977     }
14978 
14979     // pCreateInfo->compositeAlpha should have exactly one bit set, and that bit must also be set in
14980     // VkSurfaceCapabilitiesKHR::supportedCompositeAlpha
14981     if (!pCreateInfo->compositeAlpha || (pCreateInfo->compositeAlpha & (pCreateInfo->compositeAlpha - 1)) ||
14982         !((pCreateInfo->compositeAlpha) & capabilities.supportedCompositeAlpha)) {
14983         // This is an error situation; one for which we'd like to give the developer a helpful, multi-line error message.  Build
14984         // it up a little at a time, and then log it:
14985         std::string error_string = "";
14986         char str[1024];
14987         // Here's the first part of the message:
14988         sprintf(str, "%s called with a non-supported pCreateInfo->compositeAlpha (i.e. %s).  Supported values are:\n", func_name,
14989                 string_VkCompositeAlphaFlagBitsKHR(pCreateInfo->compositeAlpha));
14990         error_string += str;
14991         for (int i = 0; i < 32; i++) {
14992             // Build up the rest of the message:
14993             if ((1 << i) & capabilities.supportedCompositeAlpha) {
14994                 const char *new_str = string_VkCompositeAlphaFlagBitsKHR(static_cast<VkCompositeAlphaFlagBitsKHR>(1 << i));
14995                 sprintf(str, "    %s\n", new_str);
14996                 error_string += str;
14997             }
14998         }
14999         // Log the message that we've built up:
15000         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280", "%s.", error_string.c_str())) return true;
15001     }
15002     // Validate pCreateInfo->imageArrayLayers against VkSurfaceCapabilitiesKHR::maxImageArrayLayers:
15003     if (pCreateInfo->imageArrayLayers > capabilities.maxImageArrayLayers) {
15004         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275",
15005                      "%s called with a non-supported imageArrayLayers (i.e. %d).  Maximum value is %d.", func_name,
15006                      pCreateInfo->imageArrayLayers, capabilities.maxImageArrayLayers)) {
15007             return true;
15008         }
15009     }
15010     const VkImageUsageFlags image_usage = pCreateInfo->imageUsage;
15011     // Validate pCreateInfo->imageUsage against VkSurfaceCapabilitiesKHR::supportedUsageFlags:
15012     // Shared Present Mode uses different set of capabilities to check imageUsage support
15013     if ((image_usage != (image_usage & capabilities.supportedUsageFlags)) && !shared_present_mode) {
15014         const char *vuid = IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)
15015                                ? "VUID-VkSwapchainCreateInfoKHR-presentMode-01427"
15016                                : "VUID-VkSwapchainCreateInfoKHR-imageUsage-01276";
15017         if (LogError(device, vuid,
15018                      "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits are 0x%08x.",
15019                      func_name, image_usage, capabilities.supportedUsageFlags)) {
15020             return true;
15021         }
15022     }
15023 
15024     if (IsExtEnabled(device_extensions.vk_khr_surface_protected_capabilities) &&
15025         (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR)) {
15026         VkPhysicalDeviceSurfaceInfo2KHR surface_info = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR};
15027         surface_info.surface = pCreateInfo->surface;
15028         VkSurfaceProtectedCapabilitiesKHR surface_protected_capabilities = {VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR};
15029         VkSurfaceCapabilities2KHR surface_capabilities = {VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR};
15030         surface_capabilities.pNext = &surface_protected_capabilities;
15031         DispatchGetPhysicalDeviceSurfaceCapabilities2KHR(physical_device_state->PhysDev(), &surface_info, &surface_capabilities);
15032 
15033         if (!surface_protected_capabilities.supportsProtected) {
15034             if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-flags-03187",
15035                          "%s: pCreateInfo->flags contains VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR but the surface "
15036                          "capabilities does not have VkSurfaceProtectedCapabilitiesKHR.supportsProtected set to VK_TRUE.",
15037                          func_name)) {
15038                 return true;
15039             }
15040         }
15041     }
15042 
15043     // Validate pCreateInfo values with the results of vkGetPhysicalDeviceSurfaceFormatsKHR():
15044     {
15045         // Validate pCreateInfo->imageFormat against VkSurfaceFormatKHR::format:
15046         bool found_format = false;
15047         bool found_color_space = false;
15048         bool found_match = false;
15049         const auto formats = surface_state->GetFormats(physical_device);
15050         for (const auto &format : formats) {
15051             if (pCreateInfo->imageFormat == format.format) {
15052                 // Validate pCreateInfo->imageColorSpace against VkSurfaceFormatKHR::colorSpace:
15053                 found_format = true;
15054                 if (pCreateInfo->imageColorSpace == format.colorSpace) {
15055                     found_match = true;
15056                     break;
15057                 }
15058             } else {
15059                 if (pCreateInfo->imageColorSpace == format.colorSpace) {
15060                     found_color_space = true;
15061                 }
15062             }
15063         }
15064         if (!found_match) {
15065             if (!found_format) {
15066                 if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01273",
15067                              "%s called with a non-supported pCreateInfo->imageFormat (%s).", func_name,
15068                              string_VkFormat(pCreateInfo->imageFormat))) {
15069                     return true;
15070                 }
15071             }
15072             if (!found_color_space) {
15073                 if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01273",
15074                              "%s called with a non-supported pCreateInfo->imageColorSpace (%s).", func_name,
15075                              string_VkColorSpaceKHR(pCreateInfo->imageColorSpace))) {
15076                     return true;
15077                 }
15078             }
15079         }
15080     }
15081 
15082     // Validate pCreateInfo->presentMode against vkGetPhysicalDeviceSurfacePresentModesKHR():
15083     auto present_modes = surface_state->GetPresentModes(physical_device);
15084     bool found_match = std::find(present_modes.begin(), present_modes.end(), present_mode) != present_modes.end();
15085     if (!found_match) {
15086         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-presentMode-01281",
15087                      "%s called with a non-supported presentMode (i.e. %s).", func_name, string_VkPresentModeKHR(present_mode))) {
15088             return true;
15089         }
15090     }
15091 
15092     // Validate state for shared presentable case
15093     if (shared_present_mode) {
15094         if (!IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)) {
15095             if (LogError(
15096                     device, kVUID_Core_DrawState_ExtensionNotEnabled,
15097                     "%s called with presentMode %s which requires the VK_KHR_shared_presentable_image extension, which has not "
15098                     "been enabled.",
15099                     func_name, string_VkPresentModeKHR(present_mode))) {
15100                 return true;
15101             }
15102         } else if (pCreateInfo->minImageCount != 1) {
15103             if (LogError(
15104                     device, "VUID-VkSwapchainCreateInfoKHR-minImageCount-01383",
15105                     "%s called with presentMode %s, but minImageCount value is %d. For shared presentable image, minImageCount "
15106                     "must be 1.",
15107                     func_name, string_VkPresentModeKHR(present_mode), pCreateInfo->minImageCount)) {
15108                 return true;
15109             }
15110         }
15111 
15112         VkSharedPresentSurfaceCapabilitiesKHR shared_present_capabilities = LvlInitStruct<VkSharedPresentSurfaceCapabilitiesKHR>();
15113         VkSurfaceCapabilities2KHR capabilities2 = LvlInitStruct<VkSurfaceCapabilities2KHR>(&shared_present_capabilities);
15114         VkPhysicalDeviceSurfaceInfo2KHR surface_info = LvlInitStruct<VkPhysicalDeviceSurfaceInfo2KHR>();
15115         surface_info.surface = pCreateInfo->surface;
15116         DispatchGetPhysicalDeviceSurfaceCapabilities2KHR(physical_device_state->PhysDev(), &surface_info, &capabilities2);
15117 
15118         if (image_usage != (image_usage & shared_present_capabilities.sharedPresentSupportedUsageFlags)) {
15119             if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageUsage-01384",
15120                          "%s called with a non-supported pCreateInfo->imageUsage (i.e. 0x%08x).  Supported flag bits for %s "
15121                          "present mode are 0x%08x.",
15122                          func_name, image_usage, string_VkPresentModeKHR(pCreateInfo->presentMode),
15123                          shared_present_capabilities.sharedPresentSupportedUsageFlags)) {
15124                 return true;
15125             }
15126         }
15127     }
15128 
15129     if ((pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) && pCreateInfo->pQueueFamilyIndices) {
15130         bool skip1 = ValidatePhysicalDeviceQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices,
15131                                                          "vkCreateBuffer", "pCreateInfo->pQueueFamilyIndices",
15132                                                          "VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428");
15133         if (skip1) return true;
15134     }
15135 
15136     // Validate pCreateInfo->imageUsage against GetPhysicalDeviceFormatProperties
15137     const VkFormatProperties format_properties = GetPDFormatProperties(pCreateInfo->imageFormat);
15138     const VkFormatFeatureFlags tiling_features = format_properties.optimalTilingFeatures;
15139 
15140     if (tiling_features == 0) {
15141         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15142                      "%s: pCreateInfo->imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL has no supported format features on this "
15143                      "physical device.",
15144                      func_name, string_VkFormat(pCreateInfo->imageFormat))) {
15145             return true;
15146         }
15147     } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
15148         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15149                      "%s: pCreateInfo->imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes "
15150                      "VK_IMAGE_USAGE_SAMPLED_BIT.",
15151                      func_name, string_VkFormat(pCreateInfo->imageFormat))) {
15152             return true;
15153         }
15154     } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
15155         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15156                      "%s: pCreateInfo->imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes "
15157                      "VK_IMAGE_USAGE_STORAGE_BIT.",
15158                      func_name, string_VkFormat(pCreateInfo->imageFormat))) {
15159             return true;
15160         }
15161     } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
15162         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15163                      "%s: pCreateInfo->imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes "
15164                      "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.",
15165                      func_name, string_VkFormat(pCreateInfo->imageFormat))) {
15166             return true;
15167         }
15168     } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
15169                !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
15170         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15171                      "%s: pCreateInfo->imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes "
15172                      "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT.",
15173                      func_name, string_VkFormat(pCreateInfo->imageFormat))) {
15174             return true;
15175         }
15176     } else if ((image_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
15177                !(tiling_features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))) {
15178         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15179                      "%s: pCreateInfo->imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes "
15180                      "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT or VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT.",
15181                      func_name, string_VkFormat(pCreateInfo->imageFormat))) {
15182             return true;
15183         }
15184     }
15185 
15186     const VkImageCreateInfo image_create_info = GetSwapchainImpliedImageCreateInfo(pCreateInfo);
15187     VkImageFormatProperties image_properties = {};
15188     const VkResult image_properties_result = DispatchGetPhysicalDeviceImageFormatProperties(
15189         physical_device, image_create_info.format, image_create_info.imageType, image_create_info.tiling, image_create_info.usage,
15190         image_create_info.flags, &image_properties);
15191 
15192     if (image_properties_result != VK_SUCCESS) {
15193         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15194                      "vkGetPhysicalDeviceImageFormatProperties() unexpectedly failed, "
15195                      "when called for %s validation with following params: "
15196                      "format: %s, imageType: %s, "
15197                      "tiling: %s, usage: %s, "
15198                      "flags: %s.",
15199                      func_name, string_VkFormat(image_create_info.format), string_VkImageType(image_create_info.imageType),
15200                      string_VkImageTiling(image_create_info.tiling), string_VkImageUsageFlags(image_create_info.usage).c_str(),
15201                      string_VkImageCreateFlags(image_create_info.flags).c_str())) {
15202             return true;
15203         }
15204     }
15205 
15206     // Validate pCreateInfo->imageArrayLayers against VkImageFormatProperties::maxArrayLayers
15207     if (pCreateInfo->imageArrayLayers > image_properties.maxArrayLayers) {
15208         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15209                      "%s called with a non-supported imageArrayLayers (i.e. %d). "
15210                      "Maximum value returned by vkGetPhysicalDeviceImageFormatProperties() is %d "
15211                      "for imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL",
15212                      func_name, pCreateInfo->imageArrayLayers, image_properties.maxArrayLayers,
15213                      string_VkFormat(pCreateInfo->imageFormat))) {
15214             return true;
15215         }
15216     }
15217 
15218     // Validate pCreateInfo->imageExtent against VkImageFormatProperties::maxExtent
15219     if ((pCreateInfo->imageExtent.width > image_properties.maxExtent.width) ||
15220         (pCreateInfo->imageExtent.height > image_properties.maxExtent.height)) {
15221         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-imageFormat-01778",
15222                      "%s called with imageExtent = (%d,%d), which is bigger than max extent (%d,%d)"
15223                      "returned by vkGetPhysicalDeviceImageFormatProperties(): "
15224                      "for imageFormat %s with tiling VK_IMAGE_TILING_OPTIMAL",
15225                      func_name, pCreateInfo->imageExtent.width, pCreateInfo->imageExtent.height, image_properties.maxExtent.width,
15226                      image_properties.maxExtent.height, string_VkFormat(pCreateInfo->imageFormat))) {
15227             return true;
15228         }
15229     }
15230 
15231     if ((pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR) &&
15232         device_group_create_info.physicalDeviceCount == 1) {
15233         if (LogError(device, "VUID-VkSwapchainCreateInfoKHR-physicalDeviceCount-01429",
15234                      "%s called with flags containing VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR"
15235                      "but logical device was created with VkDeviceGroupDeviceCreateInfo::physicalDeviceCount equal to 1",
15236                      func_name)) {
15237             return true;
15238         }
15239     }
15240     return skip;
15241 }
15242 
PreCallValidateCreateSwapchainKHR(VkDevice device,const VkSwapchainCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSwapchainKHR * pSwapchain) const15243 bool CoreChecks::PreCallValidateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
15244                                                    const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) const {
15245     const auto surface_state = Get<SURFACE_STATE>(pCreateInfo->surface);
15246     const auto old_swapchain_state = Get<SWAPCHAIN_NODE>(pCreateInfo->oldSwapchain);
15247     return ValidateCreateSwapchain("vkCreateSwapchainKHR()", pCreateInfo, surface_state.get(), old_swapchain_state.get());
15248 }
15249 
PreCallRecordDestroySwapchainKHR(VkDevice device,VkSwapchainKHR swapchain,const VkAllocationCallbacks * pAllocator)15250 void CoreChecks::PreCallRecordDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
15251                                                   const VkAllocationCallbacks *pAllocator) {
15252     if (swapchain) {
15253         auto swapchain_data = Get<SWAPCHAIN_NODE>(swapchain);
15254         if (swapchain_data) {
15255             for (const auto &swapchain_image : swapchain_data->images) {
15256                 if (!swapchain_image.image_state) continue;
15257                 imageLayoutMap.erase(swapchain_image.image_state);
15258                 qfo_release_image_barrier_map.erase(swapchain_image.image_state->image());
15259             }
15260         }
15261     }
15262     StateTracker::PreCallRecordDestroySwapchainKHR(device, swapchain, pAllocator);
15263 }
15264 
PostCallRecordGetSwapchainImagesKHR(VkDevice device,VkSwapchainKHR swapchain,uint32_t * pSwapchainImageCount,VkImage * pSwapchainImages,VkResult result)15265 void CoreChecks::PostCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
15266                                                      VkImage *pSwapchainImages, VkResult result) {
15267     // This function will run twice. The first is to get pSwapchainImageCount. The second is to get pSwapchainImages.
15268     // The first time in StateTracker::PostCallRecordGetSwapchainImagesKHR only generates the container's size.
15269     // The second time in StateTracker::PostCallRecordGetSwapchainImagesKHR will create VKImage and IMAGE_STATE.
15270 
15271     // So GlobalImageLayoutMap saving new IMAGE_STATEs has to run in the second time.
15272     // pSwapchainImages is not nullptr and it needs to wait until StateTracker::PostCallRecordGetSwapchainImagesKHR.
15273 
15274     uint32_t new_swapchain_image_index = 0;
15275     if (((result == VK_SUCCESS) || (result == VK_INCOMPLETE)) && pSwapchainImages) {
15276         auto swapchain_state = Get<SWAPCHAIN_NODE>(swapchain);
15277         const auto image_vector_size = swapchain_state->images.size();
15278 
15279         for (; new_swapchain_image_index < *pSwapchainImageCount; ++new_swapchain_image_index) {
15280             if ((new_swapchain_image_index >= image_vector_size) ||
15281                 !swapchain_state->images[new_swapchain_image_index].image_state) {
15282                 break;
15283             };
15284         }
15285     }
15286     StateTracker::PostCallRecordGetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages, result);
15287 
15288     if (((result == VK_SUCCESS) || (result == VK_INCOMPLETE)) && pSwapchainImages) {
15289         for (; new_swapchain_image_index < *pSwapchainImageCount; ++new_swapchain_image_index) {
15290             auto image_state = Get<IMAGE_STATE>(pSwapchainImages[new_swapchain_image_index]);
15291             AddInitialLayoutintoImageLayoutMap(*image_state, imageLayoutMap);
15292         }
15293     }
15294 }
15295 
PreCallValidateQueuePresentKHR(VkQueue queue,const VkPresentInfoKHR * pPresentInfo) const15296 bool CoreChecks::PreCallValidateQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) const {
15297     bool skip = false;
15298     const auto queue_state = Get<QUEUE_STATE>(queue);
15299 
15300     for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
15301         const auto semaphore_state = Get<SEMAPHORE_STATE>(pPresentInfo->pWaitSemaphores[i]);
15302         if (semaphore_state && semaphore_state->type != VK_SEMAPHORE_TYPE_BINARY) {
15303             skip |= LogError(pPresentInfo->pWaitSemaphores[i], "VUID-vkQueuePresentKHR-pWaitSemaphores-03267",
15304                              "vkQueuePresentKHR: pWaitSemaphores[%u] (%s) is not a VK_SEMAPHORE_TYPE_BINARY", i,
15305                              report_data->FormatHandle(pPresentInfo->pWaitSemaphores[i]).c_str());
15306         }
15307         if (semaphore_state && !semaphore_state->signaled && !SemaphoreWasSignaled(pPresentInfo->pWaitSemaphores[i])) {
15308             LogObjectList objlist(queue);
15309             objlist.add(pPresentInfo->pWaitSemaphores[i]);
15310             skip |= LogError(objlist, "VUID-vkQueuePresentKHR-pWaitSemaphores-03268",
15311                              "vkQueuePresentKHR: Queue %s is waiting on pWaitSemaphores[%u] (%s) that has no way to be signaled.",
15312                              report_data->FormatHandle(queue).c_str(), i,
15313                              report_data->FormatHandle(pPresentInfo->pWaitSemaphores[i]).c_str());
15314         }
15315     }
15316 
15317     for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
15318         const auto swapchain_data = Get<SWAPCHAIN_NODE>(pPresentInfo->pSwapchains[i]);
15319         if (swapchain_data) {
15320             // VU currently is 2-in-1, covers being a valid index and valid layout
15321             const char *validation_error = IsExtEnabled(device_extensions.vk_khr_shared_presentable_image)
15322                                                ? "VUID-VkPresentInfoKHR-pImageIndices-01430"
15323                                                : "VUID-VkPresentInfoKHR-pImageIndices-01296";
15324 
15325             // Check if index is even possible to be acquired to give better error message
15326             if (pPresentInfo->pImageIndices[i] >= swapchain_data->images.size()) {
15327                 skip |= LogError(
15328                     pPresentInfo->pSwapchains[i], validation_error,
15329                     "vkQueuePresentKHR: pSwapchains[%u] image index is too large (%u). There are only %u images in this swapchain.",
15330                     i, pPresentInfo->pImageIndices[i], static_cast<uint32_t>(swapchain_data->images.size()));
15331             } else if (!swapchain_data->images[pPresentInfo->pImageIndices[i]].image_state ||
15332                        !swapchain_data->images[pPresentInfo->pImageIndices[i]].acquired) {
15333                 skip |= LogError(pPresentInfo->pSwapchains[i], validation_error,
15334                                  "vkQueuePresentKHR: pSwapchains[%" PRIu32 "] image at index %" PRIu32
15335                                  " was not acquired from the swapchain.",
15336                                  i, pPresentInfo->pImageIndices[i]);
15337             } else {
15338                 const auto *image_state = swapchain_data->images[pPresentInfo->pImageIndices[i]].image_state;
15339                 assert(image_state);
15340 
15341                 vector<VkImageLayout> layouts;
15342                 if (FindLayouts(*image_state, layouts)) {
15343                     for (auto layout : layouts) {
15344                         if ((layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) &&
15345                             (!IsExtEnabled(device_extensions.vk_khr_shared_presentable_image) ||
15346                              (layout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR))) {
15347                             skip |= LogError(queue, validation_error,
15348                                              "vkQueuePresentKHR(): pSwapchains[%u] images passed to present must be in layout "
15349                                              "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or "
15350                                              "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in %s.",
15351                                              i, string_VkImageLayout(layout));
15352                         }
15353                     }
15354                 }
15355                 const auto *display_present_info = LvlFindInChain<VkDisplayPresentInfoKHR>(pPresentInfo->pNext);
15356                 if (display_present_info) {
15357                     if (display_present_info->srcRect.offset.x < 0 || display_present_info->srcRect.offset.y < 0 ||
15358                         display_present_info->srcRect.offset.x + display_present_info->srcRect.extent.width >
15359                             image_state->createInfo.extent.width ||
15360                         display_present_info->srcRect.offset.y + display_present_info->srcRect.extent.height >
15361                             image_state->createInfo.extent.height) {
15362                         skip |= LogError(queue, "VUID-VkDisplayPresentInfoKHR-srcRect-01257",
15363                                          "vkQueuePresentKHR(): VkDisplayPresentInfoKHR::srcRect (offset (%" PRIu32 ", %" PRIu32
15364                                          "), extent (%" PRIu32 ", %" PRIu32
15365                                          ")) in the pNext chain of VkPresentInfoKHR is not a subset of the image begin presented "
15366                                          "(extent (%" PRIu32 ", %" PRIu32 ")).",
15367                                          display_present_info->srcRect.offset.x, display_present_info->srcRect.offset.y,
15368                                          display_present_info->srcRect.extent.width, display_present_info->srcRect.extent.height,
15369                                          image_state->createInfo.extent.width, image_state->createInfo.extent.height);
15370                     }
15371                 }
15372             }
15373 
15374             // All physical devices and queue families are required to be able to present to any native window on Android
15375             if (!instance_extensions.vk_khr_android_surface) {
15376                 const auto surface_state = Get<SURFACE_STATE>(swapchain_data->createInfo.surface);
15377                 if (!surface_state->GetQueueSupport(physical_device, queue_state->queueFamilyIndex)) {
15378                     skip |= LogError(
15379                         pPresentInfo->pSwapchains[i], "VUID-vkQueuePresentKHR-pSwapchains-01292",
15380                         "vkQueuePresentKHR: Presenting pSwapchains[%u] image on queue that cannot present to this surface.", i);
15381                 }
15382             }
15383         }
15384     }
15385     if (pPresentInfo->pNext) {
15386         // Verify ext struct
15387         const auto *present_regions = LvlFindInChain<VkPresentRegionsKHR>(pPresentInfo->pNext);
15388         if (present_regions) {
15389             for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
15390                 const auto swapchain_data = Get<SWAPCHAIN_NODE>(pPresentInfo->pSwapchains[i]);
15391                 assert(swapchain_data);
15392                 VkPresentRegionKHR region = present_regions->pRegions[i];
15393                 for (uint32_t j = 0; j < region.rectangleCount; ++j) {
15394                     VkRectLayerKHR rect = region.pRectangles[j];
15395                     // Swap offsets and extents for 90 or 270 degree preTransform rotation
15396                     if (swapchain_data->createInfo.preTransform &
15397                         (VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
15398                          VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
15399                          VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR)) {
15400                         std::swap(rect.offset.x, rect.offset.y);
15401                         std::swap(rect.extent.width, rect.extent.height);
15402                     }
15403                     if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
15404                         skip |=
15405                             LogError(pPresentInfo->pSwapchains[i], "VUID-VkRectLayerKHR-offset-04864",
15406                                      "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], "
15407                                      "the sum of offset.x (%i) and extent.width (%i) after applying preTransform (%s) is greater "
15408                                      "than the corresponding swapchain's imageExtent.width (%i).",
15409                                      i, j, rect.offset.x, rect.extent.width,
15410                                      string_VkSurfaceTransformFlagBitsKHR(swapchain_data->createInfo.preTransform),
15411                                      swapchain_data->createInfo.imageExtent.width);
15412                     }
15413                     if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
15414                         skip |=
15415                             LogError(pPresentInfo->pSwapchains[i], "VUID-VkRectLayerKHR-offset-04864",
15416                                      "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], "
15417                                      "the sum of offset.y (%i) and extent.height (%i) after applying preTransform (%s) is greater "
15418                                      "than the corresponding swapchain's imageExtent.height (%i).",
15419                                      i, j, rect.offset.y, rect.extent.height,
15420                                      string_VkSurfaceTransformFlagBitsKHR(swapchain_data->createInfo.preTransform),
15421                                      swapchain_data->createInfo.imageExtent.height);
15422                     }
15423                     if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
15424                         skip |= LogError(
15425                             pPresentInfo->pSwapchains[i], "VUID-VkRectLayerKHR-layer-01262",
15426                             "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the layer "
15427                             "(%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
15428                             i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
15429                     }
15430                 }
15431             }
15432         }
15433 
15434         const auto *present_times_info = LvlFindInChain<VkPresentTimesInfoGOOGLE>(pPresentInfo->pNext);
15435         if (present_times_info) {
15436             if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
15437                 skip |=
15438                     LogError(pPresentInfo->pSwapchains[0], "VUID-VkPresentTimesInfoGOOGLE-swapchainCount-01247",
15439                              "vkQueuePresentKHR(): VkPresentTimesInfoGOOGLE.swapchainCount is %i but pPresentInfo->swapchainCount "
15440                              "is %i. For VkPresentTimesInfoGOOGLE down pNext chain of VkPresentInfoKHR, "
15441                              "VkPresentTimesInfoGOOGLE.swapchainCount must equal VkPresentInfoKHR.swapchainCount.",
15442                              present_times_info->swapchainCount, pPresentInfo->swapchainCount);
15443             }
15444         }
15445 
15446         const auto *present_id_info = LvlFindInChain<VkPresentIdKHR>(pPresentInfo->pNext);
15447         if (present_id_info) {
15448             if (!enabled_features.present_id_features.presentId) {
15449                 for (uint32_t i = 0; i < present_id_info->swapchainCount; i++) {
15450                     if (present_id_info->pPresentIds[i] != 0) {
15451                         skip |=
15452                             LogError(pPresentInfo->pSwapchains[0], "VUID-VkPresentInfoKHR-pNext-06235",
15453                                      "vkQueuePresentKHR(): presentId feature is not enabled and VkPresentIdKHR::pPresentId[%" PRIu32
15454                                      "] = %" PRIu64 " when only NULL values are allowed",
15455                                      i, present_id_info->pPresentIds[i]);
15456                     }
15457                 }
15458             }
15459             if (pPresentInfo->swapchainCount != present_id_info->swapchainCount) {
15460                 skip |= LogError(pPresentInfo->pSwapchains[0], "VUID-VkPresentIdKHR-swapchainCount-04998",
15461                                  "vkQueuePresentKHR(): VkPresentIdKHR.swapchainCount is %" PRIu32
15462                                  " but pPresentInfo->swapchainCount is %" PRIu32
15463                                  ". VkPresentIdKHR.swapchainCount must be the same value as VkPresentInfoKHR::swapchainCount",
15464                                  present_id_info->swapchainCount, pPresentInfo->swapchainCount);
15465             }
15466             for (uint32_t i = 0; i < present_id_info->swapchainCount; i++) {
15467                 const auto swapchain_state = Get<SWAPCHAIN_NODE>(pPresentInfo->pSwapchains[i]);
15468                 if ((present_id_info->pPresentIds[i] != 0) &&
15469                     (present_id_info->pPresentIds[i] <= swapchain_state->max_present_id)) {
15470                     skip |= LogError(pPresentInfo->pSwapchains[i], "VUID-VkPresentIdKHR-presentIds-04999",
15471                                      "vkQueuePresentKHR(): VkPresentIdKHR.pPresentId[%" PRIu32 "] is %" PRIu64
15472                                      " and the largest presentId sent for this swapchain is %" PRIu64
15473                                      ". Each presentIds entry must be greater than any previous presentIds entry passed for the "
15474                                      "associated pSwapchains entry",
15475                                      i, present_id_info->pPresentIds[i], swapchain_state->max_present_id);
15476                 }
15477             }
15478         }
15479     }
15480 
15481     return skip;
15482 }
15483 
PreCallValidateCreateSharedSwapchainsKHR(VkDevice device,uint32_t swapchainCount,const VkSwapchainCreateInfoKHR * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkSwapchainKHR * pSwapchains) const15484 bool CoreChecks::PreCallValidateCreateSharedSwapchainsKHR(VkDevice device, uint32_t swapchainCount,
15485                                                           const VkSwapchainCreateInfoKHR *pCreateInfos,
15486                                                           const VkAllocationCallbacks *pAllocator,
15487                                                           VkSwapchainKHR *pSwapchains) const {
15488     bool skip = false;
15489     if (pCreateInfos) {
15490         for (uint32_t i = 0; i < swapchainCount; i++) {
15491             const auto surface_state = Get<SURFACE_STATE>(pCreateInfos[i].surface);
15492             const auto old_swapchain_state = Get<SWAPCHAIN_NODE>(pCreateInfos[i].oldSwapchain);
15493             std::stringstream func_name;
15494             func_name << "vkCreateSharedSwapchainsKHR[" << swapchainCount << "]()";
15495             skip |=
15496                 ValidateCreateSwapchain(func_name.str().c_str(), &pCreateInfos[i], surface_state.get(), old_swapchain_state.get());
15497         }
15498     }
15499     return skip;
15500 }
15501 
ValidateAcquireNextImage(VkDevice device,const AcquireVersion version,VkSwapchainKHR swapchain,uint64_t timeout,VkSemaphore semaphore,VkFence fence,uint32_t * pImageIndex,const char * func_name,const char * semaphore_type_vuid) const15502 bool CoreChecks::ValidateAcquireNextImage(VkDevice device, const AcquireVersion version, VkSwapchainKHR swapchain, uint64_t timeout,
15503                                           VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex, const char *func_name,
15504                                           const char *semaphore_type_vuid) const {
15505     bool skip = false;
15506 
15507     auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
15508     if (semaphore_state && semaphore_state->type != VK_SEMAPHORE_TYPE_BINARY) {
15509         skip |= LogError(semaphore, semaphore_type_vuid, "%s: %s is not a VK_SEMAPHORE_TYPE_BINARY", func_name,
15510                          report_data->FormatHandle(semaphore).c_str());
15511     }
15512     if (semaphore_state && semaphore_state->scope == kSyncScopeInternal && semaphore_state->signaled) {
15513         const char *vuid = version == ACQUIRE_VERSION_2 ? "VUID-VkAcquireNextImageInfoKHR-semaphore-01288"
15514                                                         : "VUID-vkAcquireNextImageKHR-semaphore-01286";
15515         skip |= LogError(semaphore, vuid, "%s: Semaphore must not be currently signaled or in a wait state.", func_name);
15516     }
15517 
15518     auto fence_state = Get<FENCE_STATE>(fence);
15519     if (fence_state) {
15520         skip |= ValidateFenceForSubmit(fence_state.get(), "VUID-vkAcquireNextImageKHR-fence-01287",
15521                                        "VUID-vkAcquireNextImageKHR-fence-01287", "vkAcquireNextImageKHR()");
15522     }
15523 
15524     const auto swapchain_data = Get<SWAPCHAIN_NODE>(swapchain);
15525     if (swapchain_data) {
15526         if (swapchain_data->retired) {
15527             const char *vuid = version == ACQUIRE_VERSION_2 ? "VUID-VkAcquireNextImageInfoKHR-swapchain-01675"
15528                                                             : "VUID-vkAcquireNextImageKHR-swapchain-01285";
15529             skip |= LogError(swapchain, vuid,
15530                              "%s: This swapchain has been retired. The application can still present any images it "
15531                              "has acquired, but cannot acquire any more.",
15532                              func_name);
15533         }
15534 
15535         const uint32_t acquired_images = swapchain_data->acquired_images;
15536         const uint32_t swapchain_image_count = static_cast<uint32_t>(swapchain_data->images.size());
15537         auto caps = swapchain_data->surface->GetCapabilities(physical_device);
15538         const auto min_image_count = caps.minImageCount;
15539         const bool too_many_already_acquired = acquired_images > swapchain_image_count - min_image_count;
15540         if (timeout == UINT64_MAX && too_many_already_acquired) {
15541             const char *vuid = version == ACQUIRE_VERSION_2 ? "VUID-vkAcquireNextImage2KHR-swapchain-01803"
15542                                                             : "VUID-vkAcquireNextImageKHR-swapchain-01802";
15543             const uint32_t acquirable = swapchain_image_count - min_image_count + 1;
15544             skip |= LogError(swapchain, vuid,
15545                              "%s: Application has already previously acquired %" PRIu32 " image%s from swapchain. Only %" PRIu32
15546                              " %s available to be acquired using a timeout of UINT64_MAX (given the swapchain has %" PRIu32
15547                              ", and VkSurfaceCapabilitiesKHR::minImageCount is %" PRIu32 ").",
15548                              func_name, acquired_images, acquired_images > 1 ? "s" : "", acquirable, acquirable > 1 ? "are" : "is",
15549                              swapchain_image_count, min_image_count);
15550         }
15551     }
15552     return skip;
15553 }
15554 
PreCallValidateAcquireNextImageKHR(VkDevice device,VkSwapchainKHR swapchain,uint64_t timeout,VkSemaphore semaphore,VkFence fence,uint32_t * pImageIndex) const15555 bool CoreChecks::PreCallValidateAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
15556                                                     VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) const {
15557     return ValidateAcquireNextImage(device, ACQUIRE_VERSION_1, swapchain, timeout, semaphore, fence, pImageIndex,
15558                                     "vkAcquireNextImageKHR", "VUID-vkAcquireNextImageKHR-semaphore-03265");
15559 }
15560 
PreCallValidateAcquireNextImage2KHR(VkDevice device,const VkAcquireNextImageInfoKHR * pAcquireInfo,uint32_t * pImageIndex) const15561 bool CoreChecks::PreCallValidateAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo,
15562                                                      uint32_t *pImageIndex) const {
15563     bool skip = false;
15564     skip |= ValidateDeviceMaskToPhysicalDeviceCount(pAcquireInfo->deviceMask, pAcquireInfo->swapchain,
15565                                                     "VUID-VkAcquireNextImageInfoKHR-deviceMask-01290");
15566     skip |= ValidateDeviceMaskToZero(pAcquireInfo->deviceMask, pAcquireInfo->swapchain,
15567                                      "VUID-VkAcquireNextImageInfoKHR-deviceMask-01291");
15568     skip |= ValidateAcquireNextImage(device, ACQUIRE_VERSION_2, pAcquireInfo->swapchain, pAcquireInfo->timeout,
15569                                      pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex, "vkAcquireNextImage2KHR",
15570                                      "VUID-VkAcquireNextImageInfoKHR-semaphore-03266");
15571     return skip;
15572 }
15573 
PreCallValidateWaitForPresentKHR(VkDevice device,VkSwapchainKHR swapchain,uint64_t presentId,uint64_t timeout) const15574 bool CoreChecks::PreCallValidateWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout) const {
15575     bool skip = false;
15576     if (!enabled_features.present_wait_features.presentWait) {
15577         skip |= LogError(swapchain, "VUID-vkWaitForPresentKHR-presentWait-06234",
15578             "vkWaitForPresentKHR(): VkWaitForPresent called but presentWait feature is not enabled");
15579     }
15580     const auto swapchain_state = Get<SWAPCHAIN_NODE>(swapchain);
15581     if (swapchain_state) {
15582         if (swapchain_state->retired) {
15583             skip |= LogError(swapchain, "VUID-vkWaitForPresentKHR-swapchain-04997",
15584                 "vkWaitForPresentKHR() called with a retired swapchain.");
15585         }
15586     }
15587     return skip;
15588 }
15589 
PreCallValidateDestroySurfaceKHR(VkInstance instance,VkSurfaceKHR surface,const VkAllocationCallbacks * pAllocator) const15590 bool CoreChecks::PreCallValidateDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
15591                                                   const VkAllocationCallbacks *pAllocator) const {
15592     const auto surface_state = Get<SURFACE_STATE>(surface);
15593     bool skip = false;
15594     if ((surface_state) && (surface_state->swapchain)) {
15595         skip |= LogError(instance, "VUID-vkDestroySurfaceKHR-surface-01266",
15596                          "vkDestroySurfaceKHR() called before its associated VkSwapchainKHR was destroyed.");
15597     }
15598     return skip;
15599 }
15600 
15601 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
PreCallValidateGetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,struct wl_display * display) const15602 bool CoreChecks::PreCallValidateGetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice,
15603                                                                                uint32_t queueFamilyIndex,
15604                                                                                struct wl_display *display) const {
15605     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
15606     return ValidateQueueFamilyIndex(pd_state.get(), queueFamilyIndex,
15607                                     "VUID-vkGetPhysicalDeviceWaylandPresentationSupportKHR-queueFamilyIndex-01306",
15608                                     "vkGetPhysicalDeviceWaylandPresentationSupportKHR", "queueFamilyIndex");
15609 }
15610 #endif  // VK_USE_PLATFORM_WAYLAND_KHR
15611 
15612 #ifdef VK_USE_PLATFORM_WIN32_KHR
PreCallValidateGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex) const15613 bool CoreChecks::PreCallValidateGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
15614                                                                              uint32_t queueFamilyIndex) const {
15615     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
15616     return ValidateQueueFamilyIndex(pd_state.get(), queueFamilyIndex,
15617                                     "VUID-vkGetPhysicalDeviceWin32PresentationSupportKHR-queueFamilyIndex-01309",
15618                                     "vkGetPhysicalDeviceWin32PresentationSupportKHR", "queueFamilyIndex");
15619 }
15620 #endif  // VK_USE_PLATFORM_WIN32_KHR
15621 
15622 #ifdef VK_USE_PLATFORM_XCB_KHR
PreCallValidateGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,xcb_connection_t * connection,xcb_visualid_t visual_id) const15623 bool CoreChecks::PreCallValidateGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice,
15624                                                                            uint32_t queueFamilyIndex, xcb_connection_t *connection,
15625                                                                            xcb_visualid_t visual_id) const {
15626     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
15627     return ValidateQueueFamilyIndex(pd_state.get(), queueFamilyIndex,
15628                                     "VUID-vkGetPhysicalDeviceXcbPresentationSupportKHR-queueFamilyIndex-01312",
15629                                     "vkGetPhysicalDeviceXcbPresentationSupportKHR", "queueFamilyIndex");
15630 }
15631 #endif  // VK_USE_PLATFORM_XCB_KHR
15632 
15633 #ifdef VK_USE_PLATFORM_XLIB_KHR
PreCallValidateGetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,Display * dpy,VisualID visualID) const15634 bool CoreChecks::PreCallValidateGetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice,
15635                                                                             uint32_t queueFamilyIndex, Display *dpy,
15636                                                                             VisualID visualID) const {
15637     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
15638     return ValidateQueueFamilyIndex(pd_state.get(), queueFamilyIndex,
15639                                     "VUID-vkGetPhysicalDeviceXlibPresentationSupportKHR-queueFamilyIndex-01315",
15640                                     "vkGetPhysicalDeviceXlibPresentationSupportKHR", "queueFamilyIndex");
15641 }
15642 #endif  // VK_USE_PLATFORM_XLIB_KHR
15643 
PreCallValidateGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex,VkSurfaceKHR surface,VkBool32 * pSupported) const15644 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex,
15645                                                                    VkSurfaceKHR surface, VkBool32 *pSupported) const {
15646     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
15647     return ValidateQueueFamilyIndex(pd_state.get(), queueFamilyIndex,
15648                                     "VUID-vkGetPhysicalDeviceSurfaceSupportKHR-queueFamilyIndex-01269",
15649                                     "vkGetPhysicalDeviceSurfaceSupportKHR", "queueFamilyIndex");
15650 }
15651 
ValidateDescriptorUpdateTemplate(const char * func_name,const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo) const15652 bool CoreChecks::ValidateDescriptorUpdateTemplate(const char *func_name,
15653                                                   const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo) const {
15654     bool skip = false;
15655     const auto layout = Get<cvdescriptorset::DescriptorSetLayout>(pCreateInfo->descriptorSetLayout);
15656     if (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET == pCreateInfo->templateType && !layout) {
15657         skip |= LogError(pCreateInfo->descriptorSetLayout, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00350",
15658                          "%s: Invalid pCreateInfo->descriptorSetLayout (%s)", func_name,
15659                          report_data->FormatHandle(pCreateInfo->descriptorSetLayout).c_str());
15660     } else if (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR == pCreateInfo->templateType) {
15661         auto bind_point = pCreateInfo->pipelineBindPoint;
15662         bool valid_bp = (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) || (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) ||
15663                         (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR);
15664         if (!valid_bp) {
15665             skip |=
15666                 LogError(device, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00351",
15667                          "%s: Invalid pCreateInfo->pipelineBindPoint (%" PRIu32 ").", func_name, static_cast<uint32_t>(bind_point));
15668         }
15669         const auto pipeline_layout = Get<PIPELINE_LAYOUT_STATE>(pCreateInfo->pipelineLayout);
15670         if (!pipeline_layout) {
15671             skip |= LogError(pCreateInfo->pipelineLayout, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00352",
15672                              "%s: Invalid pCreateInfo->pipelineLayout (%s)", func_name,
15673                              report_data->FormatHandle(pCreateInfo->pipelineLayout).c_str());
15674         } else {
15675             const uint32_t pd_set = pCreateInfo->set;
15676             if ((pd_set >= pipeline_layout->set_layouts.size()) || !pipeline_layout->set_layouts[pd_set] ||
15677                 !pipeline_layout->set_layouts[pd_set]->IsPushDescriptor()) {
15678                 skip |= LogError(pCreateInfo->pipelineLayout, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-00353",
15679                                  "%s: pCreateInfo->set (%" PRIu32
15680                                  ") does not refer to the push descriptor set layout for pCreateInfo->pipelineLayout (%s).",
15681                                  func_name, pd_set, report_data->FormatHandle(pCreateInfo->pipelineLayout).c_str());
15682             }
15683         }
15684     } else if (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET == pCreateInfo->templateType) {
15685         for (const auto &binding : layout->GetBindings()) {
15686             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
15687                 skip |= LogError(
15688                     device, "VUID-VkDescriptorUpdateTemplateCreateInfo-templateType-04615",
15689                     "%s: pCreateInfo->templateType is VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, but "
15690                     "pCreateInfo->descriptorSetLayout contains a binding with descriptor type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE.",
15691                     func_name);
15692             }
15693         }
15694     }
15695     for (uint32_t i = 0; i < pCreateInfo->descriptorUpdateEntryCount; ++i) {
15696         const auto &descriptor_update = pCreateInfo->pDescriptorUpdateEntries[i];
15697         if (descriptor_update.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
15698             if (descriptor_update.dstArrayElement & 3) {
15699                 skip |= LogError(pCreateInfo->pipelineLayout, "VUID-VkDescriptorUpdateTemplateEntry-descriptor-02226",
15700                                  "%s: pCreateInfo->pDescriptorUpdateEntries[%" PRIu32
15701                                  "] has descriptorType VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, but dstArrayElement (%" PRIu32 ") is not a "
15702                                  "multiple of 4).",
15703                                  func_name, i, descriptor_update.dstArrayElement);
15704             }
15705             if (descriptor_update.descriptorCount & 3) {
15706                 skip |= LogError(pCreateInfo->pipelineLayout, "VUID-VkDescriptorUpdateTemplateEntry-descriptor-02227",
15707                                  "%s: pCreateInfo->pDescriptorUpdateEntries[%" PRIu32
15708                                  "] has descriptorType VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, but descriptorCount (%" PRIu32 ")is not a "
15709                                  "multiple of 4).",
15710                                  func_name, i, descriptor_update.descriptorCount);
15711             }
15712         }
15713     }
15714     return skip;
15715 }
15716 
PreCallValidateCreateDescriptorUpdateTemplate(VkDevice device,const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate) const15717 bool CoreChecks::PreCallValidateCreateDescriptorUpdateTemplate(VkDevice device,
15718                                                                const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo,
15719                                                                const VkAllocationCallbacks *pAllocator,
15720                                                                VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate) const {
15721     bool skip = ValidateDescriptorUpdateTemplate("vkCreateDescriptorUpdateTemplate()", pCreateInfo);
15722     return skip;
15723 }
15724 
PreCallValidateCreateDescriptorUpdateTemplateKHR(VkDevice device,const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate) const15725 bool CoreChecks::PreCallValidateCreateDescriptorUpdateTemplateKHR(VkDevice device,
15726                                                                   const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo,
15727                                                                   const VkAllocationCallbacks *pAllocator,
15728                                                                   VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate) const {
15729     bool skip = ValidateDescriptorUpdateTemplate("vkCreateDescriptorUpdateTemplateKHR()", pCreateInfo);
15730     return skip;
15731 }
15732 
ValidateUpdateDescriptorSetWithTemplate(VkDescriptorSet descriptorSet,VkDescriptorUpdateTemplate descriptorUpdateTemplate,const void * pData) const15733 bool CoreChecks::ValidateUpdateDescriptorSetWithTemplate(VkDescriptorSet descriptorSet,
15734                                                          VkDescriptorUpdateTemplate descriptorUpdateTemplate,
15735                                                          const void *pData) const {
15736     bool skip = false;
15737     const auto template_state = Get<UPDATE_TEMPLATE_STATE>(descriptorUpdateTemplate);
15738     // Object tracker will report errors for invalid descriptorUpdateTemplate values, avoiding a crash in release builds
15739     // but retaining the assert as template support is new enough to want to investigate these in debug builds.
15740     assert(template_state);
15741     // TODO: Validate template push descriptor updates
15742     if (template_state->create_info.templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET) {
15743         skip = ValidateUpdateDescriptorSetsWithTemplateKHR(descriptorSet, template_state.get(), pData);
15744     }
15745     return skip;
15746 }
15747 
PreCallValidateUpdateDescriptorSetWithTemplate(VkDevice device,VkDescriptorSet descriptorSet,VkDescriptorUpdateTemplate descriptorUpdateTemplate,const void * pData) const15748 bool CoreChecks::PreCallValidateUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet,
15749                                                                 VkDescriptorUpdateTemplate descriptorUpdateTemplate,
15750                                                                 const void *pData) const {
15751     return ValidateUpdateDescriptorSetWithTemplate(descriptorSet, descriptorUpdateTemplate, pData);
15752 }
15753 
PreCallValidateUpdateDescriptorSetWithTemplateKHR(VkDevice device,VkDescriptorSet descriptorSet,VkDescriptorUpdateTemplate descriptorUpdateTemplate,const void * pData) const15754 bool CoreChecks::PreCallValidateUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet,
15755                                                                    VkDescriptorUpdateTemplate descriptorUpdateTemplate,
15756                                                                    const void *pData) const {
15757     return ValidateUpdateDescriptorSetWithTemplate(descriptorSet, descriptorUpdateTemplate, pData);
15758 }
15759 
PreCallValidateCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,VkDescriptorUpdateTemplate descriptorUpdateTemplate,VkPipelineLayout layout,uint32_t set,const void * pData) const15760 bool CoreChecks::PreCallValidateCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer,
15761                                                                     VkDescriptorUpdateTemplate descriptorUpdateTemplate,
15762                                                                     VkPipelineLayout layout, uint32_t set,
15763                                                                     const void *pData) const {
15764     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
15765     assert(cb_state);
15766     const char *const func_name = "vkPushDescriptorSetWithTemplateKHR()";
15767     bool skip = false;
15768     skip |= ValidateCmd(cb_state.get(), CMD_PUSHDESCRIPTORSETWITHTEMPLATEKHR);
15769 
15770     const auto layout_data = Get<PIPELINE_LAYOUT_STATE>(layout);
15771     const auto dsl = layout_data ? layout_data->GetDsl(set) : nullptr;
15772     // Validate the set index points to a push descriptor set and is in range
15773     if (dsl) {
15774         if (!dsl->IsPushDescriptor()) {
15775             skip = LogError(layout, "VUID-vkCmdPushDescriptorSetKHR-set-00365",
15776                             "%s: Set index %" PRIu32 " does not match push descriptor set layout index for %s.", func_name, set,
15777                             report_data->FormatHandle(layout).c_str());
15778         }
15779     } else if (layout_data && (set >= layout_data->set_layouts.size())) {
15780         skip = LogError(layout, "VUID-vkCmdPushDescriptorSetKHR-set-00364",
15781                         "%s: Set index %" PRIu32 " is outside of range for %s (set < %" PRIu32 ").", func_name, set,
15782                         report_data->FormatHandle(layout).c_str(), static_cast<uint32_t>(layout_data->set_layouts.size()));
15783     }
15784 
15785     const auto template_state = Get<UPDATE_TEMPLATE_STATE>(descriptorUpdateTemplate);
15786     if (template_state) {
15787         const auto &template_ci = template_state->create_info;
15788         static const std::map<VkPipelineBindPoint, std::string> bind_errors = {
15789             std::make_pair(VK_PIPELINE_BIND_POINT_GRAPHICS, "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-00366"),
15790             std::make_pair(VK_PIPELINE_BIND_POINT_COMPUTE, "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-00366"),
15791             std::make_pair(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
15792                            "VUID-vkCmdPushDescriptorSetWithTemplateKHR-commandBuffer-00366")};
15793         skip |= ValidatePipelineBindPoint(cb_state.get(), template_ci.pipelineBindPoint, func_name, bind_errors);
15794 
15795         if (template_ci.templateType != VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR) {
15796             skip |= LogError(cb_state->commandBuffer(), kVUID_Core_PushDescriptorUpdate_TemplateType,
15797                              "%s: descriptorUpdateTemplate %s was not created with flag "
15798                              "VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR.",
15799                              func_name, report_data->FormatHandle(descriptorUpdateTemplate).c_str());
15800         }
15801         if (template_ci.set != set) {
15802             skip |= LogError(cb_state->commandBuffer(), kVUID_Core_PushDescriptorUpdate_Template_SetMismatched,
15803                              "%s: descriptorUpdateTemplate %s created with set %" PRIu32
15804                              " does not match command parameter set %" PRIu32 ".",
15805                              func_name, report_data->FormatHandle(descriptorUpdateTemplate).c_str(), template_ci.set, set);
15806         }
15807         const auto template_layout = Get<PIPELINE_LAYOUT_STATE>(template_ci.pipelineLayout);
15808         if (!CompatForSet(set, layout_data.get(), template_layout.get())) {
15809             LogObjectList objlist(cb_state->commandBuffer());
15810             objlist.add(descriptorUpdateTemplate);
15811             objlist.add(template_ci.pipelineLayout);
15812             objlist.add(layout);
15813             skip |= LogError(objlist, kVUID_Core_PushDescriptorUpdate_Template_LayoutMismatched,
15814                              "%s: descriptorUpdateTemplate %s created with %s is incompatible with command parameter "
15815                              "%s for set %" PRIu32,
15816                              func_name, report_data->FormatHandle(descriptorUpdateTemplate).c_str(),
15817                              report_data->FormatHandle(template_ci.pipelineLayout).c_str(),
15818                              report_data->FormatHandle(layout).c_str(), set);
15819         }
15820     }
15821 
15822     if (dsl && template_state) {
15823         // Create an empty proxy in order to use the existing descriptor set update validation
15824         cvdescriptorset::DescriptorSet proxy_ds(VK_NULL_HANDLE, nullptr, dsl, 0, this);
15825         // Decode the template into a set of write updates
15826         cvdescriptorset::DecodedTemplateUpdate decoded_template(this, VK_NULL_HANDLE, template_state.get(), pData,
15827                                                                 dsl->GetDescriptorSetLayout());
15828         // Validate the decoded update against the proxy_ds
15829         skip |= ValidatePushDescriptorsUpdate(&proxy_ds, static_cast<uint32_t>(decoded_template.desc_writes.size()),
15830                                               decoded_template.desc_writes.data(), func_name);
15831     }
15832 
15833     return skip;
15834 }
15835 
ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(VkPhysicalDevice physicalDevice,uint32_t planeIndex,const char * api_name) const15836 bool CoreChecks::ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
15837                                                                          const char *api_name) const {
15838     bool skip = false;
15839     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
15840     if (pd_state->vkGetPhysicalDeviceDisplayPlanePropertiesKHR_called) {
15841         if (planeIndex >= pd_state->display_plane_property_count) {
15842             skip |= LogError(physicalDevice, "VUID-vkGetDisplayPlaneSupportedDisplaysKHR-planeIndex-01249",
15843                              "%s(): planeIndex (%u) must be in the range [0, %d] that was returned by "
15844                              "vkGetPhysicalDeviceDisplayPlanePropertiesKHR "
15845                              "or vkGetPhysicalDeviceDisplayPlaneProperties2KHR. Do you have the plane index hardcoded?",
15846                              api_name, planeIndex, pd_state->display_plane_property_count - 1);
15847         }
15848     }
15849 
15850     return skip;
15851 }
15852 
PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice,uint32_t planeIndex,uint32_t * pDisplayCount,VkDisplayKHR * pDisplays) const15853 bool CoreChecks::PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
15854                                                                     uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) const {
15855     bool skip = false;
15856     skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(physicalDevice, planeIndex,
15857                                                                     "vkGetDisplayPlaneSupportedDisplaysKHR");
15858     return skip;
15859 }
15860 
PreCallValidateGetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice,VkDisplayModeKHR mode,uint32_t planeIndex,VkDisplayPlaneCapabilitiesKHR * pCapabilities) const15861 bool CoreChecks::PreCallValidateGetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode,
15862                                                                uint32_t planeIndex,
15863                                                                VkDisplayPlaneCapabilitiesKHR *pCapabilities) const {
15864     bool skip = false;
15865     skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(physicalDevice, planeIndex, "vkGetDisplayPlaneCapabilitiesKHR");
15866     return skip;
15867 }
15868 
PreCallValidateGetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,const VkDisplayPlaneInfo2KHR * pDisplayPlaneInfo,VkDisplayPlaneCapabilities2KHR * pCapabilities) const15869 bool CoreChecks::PreCallValidateGetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,
15870                                                                 const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
15871                                                                 VkDisplayPlaneCapabilities2KHR *pCapabilities) const {
15872     bool skip = false;
15873     skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(physicalDevice, pDisplayPlaneInfo->planeIndex,
15874                                                                     "vkGetDisplayPlaneCapabilities2KHR");
15875     return skip;
15876 }
15877 
PreCallValidateCreateDisplayPlaneSurfaceKHR(VkInstance instance,const VkDisplaySurfaceCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface) const15878 bool CoreChecks::PreCallValidateCreateDisplayPlaneSurfaceKHR(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
15879                                                              const VkAllocationCallbacks *pAllocator,
15880                                                              VkSurfaceKHR *pSurface) const {
15881     bool skip = false;
15882     const VkDisplayModeKHR display_mode = pCreateInfo->displayMode;
15883     const uint32_t plane_index = pCreateInfo->planeIndex;
15884 
15885     if (pCreateInfo->alphaMode == VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR) {
15886         const float global_alpha = pCreateInfo->globalAlpha;
15887         if ((global_alpha > 1.0f) || (global_alpha < 0.0f)) {
15888             skip |= LogError(
15889                 display_mode, "VUID-VkDisplaySurfaceCreateInfoKHR-alphaMode-01254",
15890                 "vkCreateDisplayPlaneSurfaceKHR(): alphaMode is VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR but globalAlpha is %f.",
15891                 global_alpha);
15892         }
15893     }
15894 
15895     const auto dm_state = Get<DISPLAY_MODE_STATE>(display_mode);
15896     if (dm_state != nullptr) {
15897         // Get physical device from VkDisplayModeKHR state tracking
15898         const VkPhysicalDevice physical_device = dm_state->physical_device;
15899         const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physical_device);
15900         VkPhysicalDeviceProperties device_properties = {};
15901         DispatchGetPhysicalDeviceProperties(physical_device, &device_properties);
15902 
15903         const uint32_t width = pCreateInfo->imageExtent.width;
15904         const uint32_t height = pCreateInfo->imageExtent.height;
15905         if (width >= device_properties.limits.maxImageDimension2D) {
15906             skip |= LogError(display_mode, "VUID-VkDisplaySurfaceCreateInfoKHR-width-01256",
15907                              "vkCreateDisplayPlaneSurfaceKHR(): width (%" PRIu32
15908                              ") exceeds device limit maxImageDimension2D (%" PRIu32 ").",
15909                              width, device_properties.limits.maxImageDimension2D);
15910         }
15911         if (height >= device_properties.limits.maxImageDimension2D) {
15912             skip |= LogError(display_mode, "VUID-VkDisplaySurfaceCreateInfoKHR-width-01256",
15913                              "vkCreateDisplayPlaneSurfaceKHR(): height (%" PRIu32
15914                              ") exceeds device limit maxImageDimension2D (%" PRIu32 ").",
15915                              height, device_properties.limits.maxImageDimension2D);
15916         }
15917 
15918         if (pd_state->vkGetPhysicalDeviceDisplayPlanePropertiesKHR_called) {
15919             if (plane_index >= pd_state->display_plane_property_count) {
15920                 skip |=
15921                     LogError(display_mode, "VUID-VkDisplaySurfaceCreateInfoKHR-planeIndex-01252",
15922                              "vkCreateDisplayPlaneSurfaceKHR(): planeIndex (%u) must be in the range [0, %d] that was returned by "
15923                              "vkGetPhysicalDeviceDisplayPlanePropertiesKHR "
15924                              "or vkGetPhysicalDeviceDisplayPlaneProperties2KHR. Do you have the plane index hardcoded?",
15925                              plane_index, pd_state->display_plane_property_count - 1);
15926             } else {
15927                 // call here once we know the plane index used is a valid plane index
15928                 VkDisplayPlaneCapabilitiesKHR plane_capabilities;
15929                 DispatchGetDisplayPlaneCapabilitiesKHR(physical_device, display_mode, plane_index, &plane_capabilities);
15930 
15931                 if ((pCreateInfo->alphaMode & plane_capabilities.supportedAlpha) == 0) {
15932                     skip |= LogError(display_mode, "VUID-VkDisplaySurfaceCreateInfoKHR-alphaMode-01255",
15933                                      "vkCreateDisplayPlaneSurfaceKHR(): alphaMode is %s but planeIndex %u supportedAlpha (0x%x) "
15934                                      "does not support the mode.",
15935                                      string_VkDisplayPlaneAlphaFlagBitsKHR(pCreateInfo->alphaMode), plane_index,
15936                                      plane_capabilities.supportedAlpha);
15937                 }
15938             }
15939         }
15940     }
15941 
15942     return skip;
15943 }
15944 
PreCallValidateCmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer,const VkDebugMarkerMarkerInfoEXT * pMarkerInfo) const15945 bool CoreChecks::PreCallValidateCmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer,
15946                                                        const VkDebugMarkerMarkerInfoEXT *pMarkerInfo) const {
15947     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
15948     assert(cb_state);
15949     return ValidateCmd(cb_state.get(), CMD_DEBUGMARKERBEGINEXT);
15950 }
15951 
PreCallValidateCmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer) const15952 bool CoreChecks::PreCallValidateCmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer) const {
15953     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
15954     assert(cb_state);
15955     return ValidateCmd(cb_state.get(), CMD_DEBUGMARKERENDEXT);
15956 }
15957 
PreCallValidateCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t query,VkQueryControlFlags flags,uint32_t index) const15958 bool CoreChecks::PreCallValidateCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query,
15959                                                         VkQueryControlFlags flags, uint32_t index) const {
15960     if (disabled[query_validation]) return false;
15961     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
15962     assert(cb_state);
15963     QueryObject query_obj(queryPool, query, index);
15964     const char *cmd_name = "vkCmdBeginQueryIndexedEXT()";
15965     struct BeginQueryIndexedVuids : ValidateBeginQueryVuids {
15966         BeginQueryIndexedVuids() : ValidateBeginQueryVuids() {
15967             vuid_queue_flags = "VUID-vkCmdBeginQueryIndexedEXT-commandBuffer-cmdpool";
15968             vuid_queue_feedback = "VUID-vkCmdBeginQueryIndexedEXT-queryType-02338";
15969             vuid_queue_occlusion = "VUID-vkCmdBeginQueryIndexedEXT-queryType-00803";
15970             vuid_precise = "VUID-vkCmdBeginQueryIndexedEXT-queryType-00800";
15971             vuid_query_count = "VUID-vkCmdBeginQueryIndexedEXT-query-00802";
15972             vuid_profile_lock = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03223";
15973             vuid_scope_not_first = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03224";
15974             vuid_scope_in_rp = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-03225";
15975             vuid_dup_query_type = "VUID-vkCmdBeginQueryIndexedEXT-queryPool-04753";
15976             vuid_protected_cb = "VUID-vkCmdBeginQueryIndexedEXT-commandBuffer-01885";
15977         }
15978     };
15979     BeginQueryIndexedVuids vuids;
15980     bool skip = ValidateBeginQuery(cb_state.get(), query_obj, flags, index, CMD_BEGINQUERYINDEXEDEXT, &vuids);
15981 
15982     // Extension specific VU's
15983     auto query_pool_state = Get<QUERY_POOL_STATE>(query_obj.pool);
15984     const auto &query_pool_ci = query_pool_state->createInfo;
15985     if (query_pool_ci.queryType == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
15986         if (IsExtEnabled(device_extensions.vk_ext_transform_feedback) &&
15987             (index >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams)) {
15988             skip |= LogError(
15989                 cb_state->commandBuffer(), "VUID-vkCmdBeginQueryIndexedEXT-queryType-02339",
15990                 "%s: index %" PRIu32
15991                 " must be less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams %" PRIu32 ".",
15992                 cmd_name, index, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
15993         }
15994     } else if (index != 0) {
15995         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdBeginQueryIndexedEXT-queryType-02340",
15996                          "%s: index %" PRIu32
15997                          " must be zero if %s was not created with type VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT.",
15998                          cmd_name, index, report_data->FormatHandle(queryPool).c_str());
15999     }
16000     return skip;
16001 }
16002 
PreCallRecordCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t query,VkQueryControlFlags flags,uint32_t index)16003 void CoreChecks::PreCallRecordCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query,
16004                                                       VkQueryControlFlags flags, uint32_t index) {
16005     if (disabled[query_validation]) return;
16006     QueryObject query_obj = {queryPool, query, index};
16007     EnqueueVerifyBeginQuery(commandBuffer, query_obj, "vkCmdBeginQueryIndexedEXT()");
16008 }
16009 
PreCallRecordCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t query,uint32_t index)16010 void CoreChecks::PreCallRecordCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query,
16011                                                     uint32_t index) {
16012     if (disabled[query_validation]) return;
16013     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16014     QueryObject query_obj = {queryPool, query, index};
16015     query_obj.endCommandIndex = cb_state->commandCount - 1;
16016     EnqueueVerifyEndQuery(commandBuffer, query_obj);
16017 }
16018 
PreCallValidateCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer,VkQueryPool queryPool,uint32_t query,uint32_t index) const16019 bool CoreChecks::PreCallValidateCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query,
16020                                                       uint32_t index) const {
16021     if (disabled[query_validation]) return false;
16022     QueryObject query_obj = {queryPool, query, index};
16023     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16024     assert(cb_state);
16025     struct EndQueryIndexedVuids : ValidateEndQueryVuids {
16026         EndQueryIndexedVuids() : ValidateEndQueryVuids() {
16027             vuid_queue_flags = "VUID-vkCmdEndQueryIndexedEXT-commandBuffer-cmdpool";
16028             vuid_active_queries = "VUID-vkCmdEndQueryIndexedEXT-None-02342";
16029             vuid_protected_cb = "VUID-vkCmdEndQueryIndexedEXT-commandBuffer-02344";
16030         }
16031     };
16032     EndQueryIndexedVuids vuids;
16033     bool skip = false;
16034     skip |= ValidateCmdEndQuery(cb_state.get(), query_obj, index, CMD_ENDQUERYINDEXEDEXT, &vuids);
16035 
16036     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
16037     if (query_pool_state) {
16038         const auto &query_pool_ci = query_pool_state->createInfo;
16039         const uint32_t available_query_count = query_pool_state->createInfo.queryCount;
16040         if (query >= available_query_count) {
16041             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdEndQueryIndexedEXT-query-02343",
16042                              "vkCmdEndQueryIndexedEXT(): query index (%" PRIu32
16043                              ") is greater or equal to the queryPool size (%" PRIu32 ").",
16044                              index, available_query_count);
16045         }
16046         if (query_pool_ci.queryType == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
16047             if (IsExtEnabled(device_extensions.vk_ext_transform_feedback) &&
16048                 (index >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams)) {
16049                 skip |= LogError(
16050                     cb_state->commandBuffer(), "VUID-vkCmdEndQueryIndexedEXT-queryType-02346",
16051                     "vkCmdEndQueryIndexedEXT(): index %" PRIu32
16052                     " must be less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams %" PRIu32 ".",
16053                     index, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
16054             }
16055         } else if (index != 0) {
16056             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdEndQueryIndexedEXT-queryType-02347",
16057                              "vkCmdEndQueryIndexedEXT(): index %" PRIu32
16058                              " must be zero if %s was not created with type VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT.",
16059                              index, report_data->FormatHandle(queryPool).c_str());
16060         }
16061     }
16062 
16063     return skip;
16064 }
16065 
PreCallValidateCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer,uint32_t firstDiscardRectangle,uint32_t discardRectangleCount,const VkRect2D * pDiscardRectangles) const16066 bool CoreChecks::PreCallValidateCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle,
16067                                                           uint32_t discardRectangleCount,
16068                                                           const VkRect2D *pDiscardRectangles) const {
16069     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16070     bool skip = false;
16071     // Minimal validation for command buffer state
16072     skip |= ValidateCmd(cb_state.get(), CMD_SETDISCARDRECTANGLEEXT);
16073     skip |= ForbidInheritedViewportScissor(
16074         commandBuffer, cb_state.get(), "VUID-vkCmdSetDiscardRectangleEXT-viewportScissor2D-04788", "vkCmdSetDiscardRectangleEXT");
16075     for (uint32_t i = 0; i < discardRectangleCount; ++i) {
16076         if (pDiscardRectangles[i].offset.x < 0) {
16077             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetDiscardRectangleEXT-x-00587",
16078                              "vkCmdSetDiscardRectangleEXT(): pDiscardRectangles[%" PRIu32 "].x (%" PRIi32 ") is negative.", i,
16079                              pDiscardRectangles[i].offset.x);
16080         }
16081         if (pDiscardRectangles[i].offset.y < 0) {
16082             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetDiscardRectangleEXT-x-00587",
16083                              "vkCmdSetDiscardRectangleEXT(): pDiscardRectangles[%" PRIu32 "].y (%" PRIi32 ") is negative.", i,
16084                              pDiscardRectangles[i].offset.y);
16085         }
16086     }
16087     if (firstDiscardRectangle + discardRectangleCount > phys_dev_ext_props.discard_rectangle_props.maxDiscardRectangles) {
16088         skip |=
16089             LogError(cb_state->commandBuffer(), "VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585",
16090                      "vkCmdSetDiscardRectangleEXT(): firstDiscardRectangle (%" PRIu32 ") + discardRectangleCount (%" PRIu32
16091                      ") is not less than VkPhysicalDeviceDiscardRectanglePropertiesEXT::maxDiscardRectangles (%" PRIu32 ".",
16092                      firstDiscardRectangle, discardRectangleCount, phys_dev_ext_props.discard_rectangle_props.maxDiscardRectangles);
16093     }
16094     return skip;
16095 }
16096 
PreCallValidateCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer,const VkSampleLocationsInfoEXT * pSampleLocationsInfo) const16097 bool CoreChecks::PreCallValidateCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer,
16098                                                          const VkSampleLocationsInfoEXT *pSampleLocationsInfo) const {
16099     bool skip = false;
16100     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16101     // Minimal validation for command buffer state
16102     skip |= ValidateCmd(cb_state.get(), CMD_SETSAMPLELOCATIONSEXT);
16103     skip |= ValidateSampleLocationsInfo(pSampleLocationsInfo, "vkCmdSetSampleLocationsEXT");
16104 
16105     const auto lv_bind_point = ConvertToLvlBindPoint(VK_PIPELINE_BIND_POINT_GRAPHICS);
16106     const auto *pipe = cb_state->lastBound[lv_bind_point].pipeline_state;
16107     if (pipe != nullptr) {
16108         // Check same error with different log messages
16109         const safe_VkPipelineMultisampleStateCreateInfo *multisample_state = pipe->create_info.graphics.pMultisampleState;
16110         if (multisample_state == nullptr) {
16111             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetSampleLocationsEXT-sampleLocationsPerPixel-01529",
16112                              "vkCmdSetSampleLocationsEXT(): pSampleLocationsInfo->sampleLocationsPerPixel must be equal to "
16113                              "rasterizationSamples, but the bound graphics pipeline was created without a multisample state");
16114         } else if (multisample_state->rasterizationSamples != pSampleLocationsInfo->sampleLocationsPerPixel) {
16115             skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetSampleLocationsEXT-sampleLocationsPerPixel-01529",
16116                              "vkCmdSetSampleLocationsEXT(): pSampleLocationsInfo->sampleLocationsPerPixel (%s) is not equal to "
16117                              "the last bound pipeline's rasterizationSamples (%s)",
16118                              string_VkSampleCountFlagBits(pSampleLocationsInfo->sampleLocationsPerPixel),
16119                              string_VkSampleCountFlagBits(multisample_state->rasterizationSamples));
16120         }
16121     }
16122 
16123     return skip;
16124 }
16125 
ValidateCreateSamplerYcbcrConversion(const char * func_name,const VkSamplerYcbcrConversionCreateInfo * create_info) const16126 bool CoreChecks::ValidateCreateSamplerYcbcrConversion(const char *func_name,
16127                                                       const VkSamplerYcbcrConversionCreateInfo *create_info) const {
16128     bool skip = false;
16129     const VkFormat conversion_format = create_info->format;
16130 
16131     // Need to check for external format conversion first as it allows for non-UNORM format
16132     bool external_format = false;
16133 #ifdef VK_USE_PLATFORM_ANDROID_KHR
16134     const VkExternalFormatANDROID *ext_format_android = LvlFindInChain<VkExternalFormatANDROID>(create_info->pNext);
16135     if ((nullptr != ext_format_android) && (0 != ext_format_android->externalFormat)) {
16136         external_format = true;
16137         if (VK_FORMAT_UNDEFINED != create_info->format) {
16138             return LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01904",
16139                             "%s: CreateInfo format is not VK_FORMAT_UNDEFINED while "
16140                             "there is a chained VkExternalFormatANDROID struct with a non-zero externalFormat.",
16141                             func_name);
16142         }
16143     }
16144 #endif  // VK_USE_PLATFORM_ANDROID_KHR
16145 
16146     if ((external_format == false) && (FormatIsUNORM(conversion_format) == false)) {
16147         const char *vuid = IsExtEnabled(device_extensions.vk_android_external_memory_android_hardware_buffer)
16148                                ? "VUID-VkSamplerYcbcrConversionCreateInfo-format-04061"
16149                                : "VUID-VkSamplerYcbcrConversionCreateInfo-format-04060";
16150         skip |=
16151             LogError(device, vuid,
16152                      "%s: CreateInfo format (%s) is not an UNORM format and there is no external format conversion being created.",
16153                      func_name, string_VkFormat(conversion_format));
16154     }
16155 
16156     // Gets VkFormatFeatureFlags according to Sampler Ycbcr Conversion Format Features
16157     // (vkspec.html#potential-format-features)
16158     VkFormatFeatureFlags format_features = VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM;
16159     if (conversion_format == VK_FORMAT_UNDEFINED) {
16160 #ifdef VK_USE_PLATFORM_ANDROID_KHR
16161         // only check for external format inside VK_FORMAT_UNDEFINED check to prevent unnecessary extra errors from no format
16162         // features being supported
16163         if (external_format == true) {
16164             auto it = ahb_ext_formats_map.find(ext_format_android->externalFormat);
16165             if (it != ahb_ext_formats_map.end()) {
16166                 format_features = it->second;
16167             }
16168         }
16169 #endif  // VK_USE_PLATFORM_ANDROID_KHR
16170     } else {
16171         format_features = GetPotentialFormatFeatures(conversion_format);
16172     }
16173 
16174     // Check all VUID that are based off of VkFormatFeatureFlags
16175     // These can't be in StatelessValidation due to needing possible External AHB state for feature support
16176     if (((format_features & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0) &&
16177         ((format_features & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0)) {
16178         skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-format-01650",
16179                          "%s: Format %s does not support either VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or "
16180                          "VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT",
16181                          func_name, string_VkFormat(conversion_format));
16182     }
16183     if ((format_features & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0) {
16184         if (FormatIsXChromaSubsampled(conversion_format) && create_info->xChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN) {
16185             skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01651",
16186                              "%s: Format %s does not support VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT so xChromaOffset can't "
16187                              "be VK_CHROMA_LOCATION_COSITED_EVEN",
16188                              func_name, string_VkFormat(conversion_format));
16189         }
16190         if (FormatIsYChromaSubsampled(conversion_format) && create_info->yChromaOffset == VK_CHROMA_LOCATION_COSITED_EVEN) {
16191             skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01651",
16192                              "%s: Format %s does not support VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT so yChromaOffset can't "
16193                              "be VK_CHROMA_LOCATION_COSITED_EVEN",
16194                              func_name, string_VkFormat(conversion_format));
16195         }
16196     }
16197     if ((format_features & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0) {
16198         if (FormatIsXChromaSubsampled(conversion_format) && create_info->xChromaOffset == VK_CHROMA_LOCATION_MIDPOINT) {
16199             skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01652",
16200                              "%s: Format %s does not support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT so xChromaOffset can't "
16201                              "be VK_CHROMA_LOCATION_MIDPOINT",
16202                              func_name, string_VkFormat(conversion_format));
16203         }
16204         if (FormatIsYChromaSubsampled(conversion_format) && create_info->yChromaOffset == VK_CHROMA_LOCATION_MIDPOINT) {
16205             skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01652",
16206                              "%s: Format %s does not support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT so yChromaOffset can't "
16207                              "be VK_CHROMA_LOCATION_MIDPOINT",
16208                              func_name, string_VkFormat(conversion_format));
16209         }
16210     }
16211     if (((format_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT) == 0) &&
16212         (create_info->forceExplicitReconstruction == VK_TRUE)) {
16213         skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-forceExplicitReconstruction-01656",
16214                          "%s: Format %s does not support "
16215                          "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT so "
16216                          "forceExplicitReconstruction must be VK_FALSE",
16217                          func_name, string_VkFormat(conversion_format));
16218     }
16219     if (((format_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0) &&
16220         (create_info->chromaFilter == VK_FILTER_LINEAR)) {
16221         skip |= LogError(device, "VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-01657",
16222                          "%s: Format %s does not support VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT so "
16223                          "chromaFilter must not be VK_FILTER_LINEAR",
16224                          func_name, string_VkFormat(conversion_format));
16225     }
16226 
16227     return skip;
16228 }
16229 
PreCallValidateCreateSamplerYcbcrConversion(VkDevice device,const VkSamplerYcbcrConversionCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSamplerYcbcrConversion * pYcbcrConversion) const16230 bool CoreChecks::PreCallValidateCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
16231                                                              const VkAllocationCallbacks *pAllocator,
16232                                                              VkSamplerYcbcrConversion *pYcbcrConversion) const {
16233     return ValidateCreateSamplerYcbcrConversion("vkCreateSamplerYcbcrConversion()", pCreateInfo);
16234 }
16235 
PreCallValidateCreateSamplerYcbcrConversionKHR(VkDevice device,const VkSamplerYcbcrConversionCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSamplerYcbcrConversion * pYcbcrConversion) const16236 bool CoreChecks::PreCallValidateCreateSamplerYcbcrConversionKHR(VkDevice device,
16237                                                                 const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
16238                                                                 const VkAllocationCallbacks *pAllocator,
16239                                                                 VkSamplerYcbcrConversion *pYcbcrConversion) const {
16240     return ValidateCreateSamplerYcbcrConversion("vkCreateSamplerYcbcrConversionKHR()", pCreateInfo);
16241 }
16242 
PreCallValidateCreateSampler(VkDevice device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler) const16243 bool CoreChecks::PreCallValidateCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
16244                                               const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) const {
16245     bool skip = false;
16246 
16247     auto num_samplers = Count<SAMPLER_STATE>();
16248     if (num_samplers >= phys_dev_props.limits.maxSamplerAllocationCount) {
16249         skip |= LogError(
16250             device, "VUID-vkCreateSampler-maxSamplerAllocationCount-04110",
16251             "vkCreateSampler(): Number of currently valid sampler objects (%zu) is not less than the maximum allowed (%u).",
16252             num_samplers, phys_dev_props.limits.maxSamplerAllocationCount);
16253     }
16254 
16255     if (enabled_features.core11.samplerYcbcrConversion == VK_TRUE) {
16256         const VkSamplerYcbcrConversionInfo *conversion_info = LvlFindInChain<VkSamplerYcbcrConversionInfo>(pCreateInfo->pNext);
16257         if (conversion_info != nullptr) {
16258             const VkSamplerYcbcrConversion sampler_ycbcr_conversion = conversion_info->conversion;
16259             const auto ycbcr_state = Get<SAMPLER_YCBCR_CONVERSION_STATE>(sampler_ycbcr_conversion);
16260             if ((ycbcr_state->format_features &
16261                  VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0) {
16262                 const VkFilter chroma_filter = ycbcr_state->chromaFilter;
16263                 if (pCreateInfo->minFilter != chroma_filter) {
16264                     skip |= LogError(
16265                         device, "VUID-VkSamplerCreateInfo-minFilter-01645",
16266                         "VkCreateSampler: VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT is "
16267                         "not supported for SamplerYcbcrConversion's (%s) format %s so minFilter (%s) needs to be equal to "
16268                         "chromaFilter (%s)",
16269                         report_data->FormatHandle(sampler_ycbcr_conversion).c_str(), string_VkFormat(ycbcr_state->format),
16270                         string_VkFilter(pCreateInfo->minFilter), string_VkFilter(chroma_filter));
16271                 }
16272                 if (pCreateInfo->magFilter != chroma_filter) {
16273                     skip |= LogError(
16274                         device, "VUID-VkSamplerCreateInfo-minFilter-01645",
16275                         "VkCreateSampler: VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT is "
16276                         "not supported for SamplerYcbcrConversion's (%s) format %s so minFilter (%s) needs to be equal to "
16277                         "chromaFilter (%s)",
16278                         report_data->FormatHandle(sampler_ycbcr_conversion).c_str(), string_VkFormat(ycbcr_state->format),
16279                         string_VkFilter(pCreateInfo->minFilter), string_VkFilter(chroma_filter));
16280                 }
16281             }
16282             // At this point there is a known sampler YCbCr conversion enabled
16283             const auto *sampler_reduction = LvlFindInChain<VkSamplerReductionModeCreateInfo>(pCreateInfo->pNext);
16284             if (sampler_reduction != nullptr) {
16285                 if (sampler_reduction->reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE) {
16286                     skip |= LogError(device, "VUID-VkSamplerCreateInfo-None-01647",
16287                                      "A sampler YCbCr Conversion is being used creating this sampler so the sampler reduction mode "
16288                                      "must be VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE.");
16289                 }
16290             }
16291         }
16292     }
16293 
16294     if (pCreateInfo->borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT ||
16295         pCreateInfo->borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT) {
16296         if (!enabled_features.custom_border_color_features.customBorderColors) {
16297             skip |=
16298                 LogError(device, "VUID-VkSamplerCreateInfo-customBorderColors-04085",
16299                          "vkCreateSampler(): A custom border color was specified without enabling the custom border color feature");
16300         }
16301         auto custom_create_info = LvlFindInChain<VkSamplerCustomBorderColorCreateInfoEXT>(pCreateInfo->pNext);
16302         if (custom_create_info) {
16303             if (custom_create_info->format == VK_FORMAT_UNDEFINED &&
16304                 !enabled_features.custom_border_color_features.customBorderColorWithoutFormat) {
16305                 skip |= LogError(device, "VUID-VkSamplerCustomBorderColorCreateInfoEXT-format-04014",
16306                                  "vkCreateSampler(): A custom border color was specified as VK_FORMAT_UNDEFINED without the "
16307                                  "customBorderColorWithoutFormat feature being enabled");
16308             }
16309         }
16310         if (custom_border_color_sampler_count >= phys_dev_ext_props.custom_border_color_props.maxCustomBorderColorSamplers) {
16311             skip |= LogError(device, "VUID-VkSamplerCreateInfo-None-04012",
16312                              "vkCreateSampler(): Creating a sampler with a custom border color will exceed the "
16313                              "maxCustomBorderColorSamplers limit of %d",
16314                              phys_dev_ext_props.custom_border_color_props.maxCustomBorderColorSamplers);
16315         }
16316     }
16317 
16318     if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
16319         if ((VK_FALSE == enabled_features.portability_subset_features.samplerMipLodBias) && pCreateInfo->mipLodBias != 0) {
16320             skip |= LogError(device, "VUID-VkSamplerCreateInfo-samplerMipLodBias-04467",
16321                              "vkCreateSampler (portability error): mip LOD bias not supported.");
16322         }
16323     }
16324 
16325     // If any of addressModeU, addressModeV or addressModeW are VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, the
16326     // VK_KHR_sampler_mirror_clamp_to_edge extension or promoted feature must be enabled
16327     if ((device_extensions.vk_khr_sampler_mirror_clamp_to_edge != kEnabledByCreateinfo) &&
16328         (enabled_features.core12.samplerMirrorClampToEdge == VK_FALSE)) {
16329         // Use 'else' because getting 3 large error messages is redundant and assume developer, if set all 3, will notice and fix
16330         // all at once
16331         if (pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) {
16332             skip |=
16333                 LogError(device, "VUID-VkSamplerCreateInfo-addressModeU-01079",
16334                          "vkCreateSampler(): addressModeU is set to VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE but the "
16335                          "VK_KHR_sampler_mirror_clamp_to_edge extension or samplerMirrorClampToEdge feature has not been enabled.");
16336         } else if (pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) {
16337             skip |=
16338                 LogError(device, "VUID-VkSamplerCreateInfo-addressModeU-01079",
16339                          "vkCreateSampler(): addressModeV is set to VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE but the "
16340                          "VK_KHR_sampler_mirror_clamp_to_edge extension or samplerMirrorClampToEdge feature has not been enabled.");
16341         } else if (pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) {
16342             skip |=
16343                 LogError(device, "VUID-VkSamplerCreateInfo-addressModeU-01079",
16344                          "vkCreateSampler(): addressModeW is set to VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE but the "
16345                          "VK_KHR_sampler_mirror_clamp_to_edge extension or samplerMirrorClampToEdge feature has not been enabled.");
16346         }
16347     }
16348 
16349     return skip;
16350 }
16351 
ValidateGetBufferDeviceAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo,const char * apiName) const16352 bool CoreChecks::ValidateGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo,
16353                                                 const char *apiName) const {
16354     bool skip = false;
16355 
16356     if (!enabled_features.core12.bufferDeviceAddress && !enabled_features.buffer_device_address_ext_features.bufferDeviceAddress) {
16357         skip |= LogError(pInfo->buffer, "VUID-vkGetBufferDeviceAddress-bufferDeviceAddress-03324",
16358                          "%s: The bufferDeviceAddress feature must: be enabled.", apiName);
16359     }
16360 
16361     if (physical_device_count > 1 && !enabled_features.core12.bufferDeviceAddressMultiDevice &&
16362         !enabled_features.buffer_device_address_ext_features.bufferDeviceAddressMultiDevice) {
16363         skip |= LogError(pInfo->buffer, "VUID-vkGetBufferDeviceAddress-device-03325",
16364                          "%s: If device was created with multiple physical devices, then the "
16365                          "bufferDeviceAddressMultiDevice feature must: be enabled.",
16366                          apiName);
16367     }
16368 
16369     const auto buffer_state = Get<BUFFER_STATE>(pInfo->buffer);
16370     if (buffer_state) {
16371         if (!(buffer_state->createInfo.flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT)) {
16372             skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), apiName, "VUID-VkBufferDeviceAddressInfo-buffer-02600");
16373         }
16374 
16375         skip |= ValidateBufferUsageFlags(buffer_state.get(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, true,
16376                                          "VUID-VkBufferDeviceAddressInfo-buffer-02601", apiName,
16377                                          "VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT");
16378     }
16379 
16380     return skip;
16381 }
16382 
PreCallValidateGetBufferDeviceAddressEXT(VkDevice device,const VkBufferDeviceAddressInfo * pInfo) const16383 bool CoreChecks::PreCallValidateGetBufferDeviceAddressEXT(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) const {
16384     return ValidateGetBufferDeviceAddress(device, static_cast<const VkBufferDeviceAddressInfo *>(pInfo),
16385                                           "vkGetBufferDeviceAddressEXT");
16386 }
16387 
PreCallValidateGetBufferDeviceAddressKHR(VkDevice device,const VkBufferDeviceAddressInfo * pInfo) const16388 bool CoreChecks::PreCallValidateGetBufferDeviceAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) const {
16389     return ValidateGetBufferDeviceAddress(device, static_cast<const VkBufferDeviceAddressInfo *>(pInfo),
16390                                           "vkGetBufferDeviceAddressKHR");
16391 }
16392 
PreCallValidateGetBufferDeviceAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo) const16393 bool CoreChecks::PreCallValidateGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) const {
16394     return ValidateGetBufferDeviceAddress(device, static_cast<const VkBufferDeviceAddressInfo *>(pInfo),
16395                                           "vkGetBufferDeviceAddress");
16396 }
16397 
ValidateGetBufferOpaqueCaptureAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo,const char * apiName) const16398 bool CoreChecks::ValidateGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo,
16399                                                        const char *apiName) const {
16400     bool skip = false;
16401 
16402     if (!enabled_features.core12.bufferDeviceAddress) {
16403         skip |= LogError(pInfo->buffer, "VUID-vkGetBufferOpaqueCaptureAddress-None-03326",
16404                          "%s(): The bufferDeviceAddress feature must: be enabled.", apiName);
16405     }
16406 
16407     if (physical_device_count > 1 && !enabled_features.core12.bufferDeviceAddressMultiDevice) {
16408         skip |= LogError(pInfo->buffer, "VUID-vkGetBufferOpaqueCaptureAddress-device-03327",
16409                          "%s(): If device was created with multiple physical devices, then the "
16410                          "bufferDeviceAddressMultiDevice feature must: be enabled.",
16411                          apiName);
16412     }
16413     return skip;
16414 }
16415 
PreCallValidateGetBufferOpaqueCaptureAddressKHR(VkDevice device,const VkBufferDeviceAddressInfo * pInfo) const16416 bool CoreChecks::PreCallValidateGetBufferOpaqueCaptureAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) const {
16417     return ValidateGetBufferOpaqueCaptureAddress(device, static_cast<const VkBufferDeviceAddressInfo *>(pInfo),
16418                                                  "vkGetBufferOpaqueCaptureAddressKHR");
16419 }
16420 
PreCallValidateGetBufferOpaqueCaptureAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo) const16421 bool CoreChecks::PreCallValidateGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) const {
16422     return ValidateGetBufferOpaqueCaptureAddress(device, static_cast<const VkBufferDeviceAddressInfo *>(pInfo),
16423                                                  "vkGetBufferOpaqueCaptureAddress");
16424 }
16425 
ValidateGetDeviceMemoryOpaqueCaptureAddress(VkDevice device,const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo,const char * apiName) const16426 bool CoreChecks::ValidateGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo,
16427                                                              const char *apiName) const {
16428     bool skip = false;
16429 
16430     if (!enabled_features.core12.bufferDeviceAddress) {
16431         skip |= LogError(pInfo->memory, "VUID-vkGetDeviceMemoryOpaqueCaptureAddress-None-03334",
16432                          "%s(): The bufferDeviceAddress feature must: be enabled.", apiName);
16433     }
16434 
16435     if (physical_device_count > 1 && !enabled_features.core12.bufferDeviceAddressMultiDevice) {
16436         skip |= LogError(pInfo->memory, "VUID-vkGetDeviceMemoryOpaqueCaptureAddress-device-03335",
16437                          "%s(): If device was created with multiple physical devices, then the "
16438                          "bufferDeviceAddressMultiDevice feature must: be enabled.",
16439                          apiName);
16440     }
16441 
16442     const auto mem_info = Get<DEVICE_MEMORY_STATE>(pInfo->memory);
16443     if (mem_info) {
16444         auto chained_flags_struct = LvlFindInChain<VkMemoryAllocateFlagsInfo>(mem_info->alloc_info.pNext);
16445         if (!chained_flags_struct || !(chained_flags_struct->flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT)) {
16446             skip |= LogError(pInfo->memory, "VUID-VkDeviceMemoryOpaqueCaptureAddressInfo-memory-03336",
16447                              "%s(): memory must have been allocated with VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT.", apiName);
16448         }
16449     }
16450 
16451     return skip;
16452 }
16453 
PreCallValidateGetDeviceMemoryOpaqueCaptureAddressKHR(VkDevice device,const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo) const16454 bool CoreChecks::PreCallValidateGetDeviceMemoryOpaqueCaptureAddressKHR(VkDevice device,
16455                                                                        const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo) const {
16456     return ValidateGetDeviceMemoryOpaqueCaptureAddress(device, static_cast<const VkDeviceMemoryOpaqueCaptureAddressInfo *>(pInfo),
16457                                                        "vkGetDeviceMemoryOpaqueCaptureAddressKHR");
16458 }
16459 
PreCallValidateGetDeviceMemoryOpaqueCaptureAddress(VkDevice device,const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo) const16460 bool CoreChecks::PreCallValidateGetDeviceMemoryOpaqueCaptureAddress(VkDevice device,
16461                                                                     const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo) const {
16462     return ValidateGetDeviceMemoryOpaqueCaptureAddress(device, static_cast<const VkDeviceMemoryOpaqueCaptureAddressInfo *>(pInfo),
16463                                                        "vkGetDeviceMemoryOpaqueCaptureAddress");
16464 }
16465 
ValidateQueryRange(VkDevice device,VkQueryPool queryPool,uint32_t totalCount,uint32_t firstQuery,uint32_t queryCount,const char * vuid_badfirst,const char * vuid_badrange,const char * apiName) const16466 bool CoreChecks::ValidateQueryRange(VkDevice device, VkQueryPool queryPool, uint32_t totalCount, uint32_t firstQuery,
16467                                     uint32_t queryCount, const char *vuid_badfirst, const char *vuid_badrange,
16468                                     const char *apiName) const {
16469     bool skip = false;
16470 
16471     if (firstQuery >= totalCount) {
16472         skip |= LogError(device, vuid_badfirst,
16473                          "%s(): firstQuery (%" PRIu32 ") greater than or equal to query pool count (%" PRIu32 ") for %s", apiName,
16474                          firstQuery, totalCount, report_data->FormatHandle(queryPool).c_str());
16475     }
16476 
16477     if ((firstQuery + queryCount) > totalCount) {
16478         skip |= LogError(device, vuid_badrange,
16479                          "%s(): Query range [%" PRIu32 ", %" PRIu32 ") goes beyond query pool count (%" PRIu32 ") for %s", apiName,
16480                          firstQuery, firstQuery + queryCount, totalCount, report_data->FormatHandle(queryPool).c_str());
16481     }
16482 
16483     return skip;
16484 }
16485 
ValidateResetQueryPool(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,const char * apiName) const16486 bool CoreChecks::ValidateResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
16487                                         const char *apiName) const {
16488     if (disabled[query_validation]) return false;
16489 
16490     bool skip = false;
16491 
16492     if (!enabled_features.core12.hostQueryReset) {
16493         skip |= LogError(device, "VUID-vkResetQueryPool-None-02665", "%s(): Host query reset not enabled for device", apiName);
16494     }
16495 
16496     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
16497     if (query_pool_state) {
16498         skip |= ValidateQueryRange(device, queryPool, query_pool_state->createInfo.queryCount, firstQuery, queryCount,
16499                                    "VUID-vkResetQueryPool-firstQuery-02666", "VUID-vkResetQueryPool-firstQuery-02667", apiName);
16500     }
16501 
16502     return skip;
16503 }
16504 
PreCallValidateResetQueryPoolEXT(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount) const16505 bool CoreChecks::PreCallValidateResetQueryPoolEXT(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
16506                                                   uint32_t queryCount) const {
16507     return ValidateResetQueryPool(device, queryPool, firstQuery, queryCount, "vkResetQueryPoolEXT");
16508 }
16509 
PreCallValidateResetQueryPool(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount) const16510 bool CoreChecks::PreCallValidateResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
16511                                                uint32_t queryCount) const {
16512     return ValidateResetQueryPool(device, queryPool, firstQuery, queryCount, "vkResetQueryPool");
16513 }
16514 
CoreLayerCreateValidationCacheEXT(VkDevice device,const VkValidationCacheCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkValidationCacheEXT * pValidationCache)16515 VkResult CoreChecks::CoreLayerCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT *pCreateInfo,
16516                                                        const VkAllocationCallbacks *pAllocator,
16517                                                        VkValidationCacheEXT *pValidationCache) {
16518     *pValidationCache = ValidationCache::Create(pCreateInfo);
16519     return *pValidationCache ? VK_SUCCESS : VK_ERROR_INITIALIZATION_FAILED;
16520 }
16521 
CoreLayerDestroyValidationCacheEXT(VkDevice device,VkValidationCacheEXT validationCache,const VkAllocationCallbacks * pAllocator)16522 void CoreChecks::CoreLayerDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache,
16523                                                     const VkAllocationCallbacks *pAllocator) {
16524     delete CastFromHandle<ValidationCache *>(validationCache);
16525 }
16526 
CoreLayerGetValidationCacheDataEXT(VkDevice device,VkValidationCacheEXT validationCache,size_t * pDataSize,void * pData)16527 VkResult CoreChecks::CoreLayerGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t *pDataSize,
16528                                                         void *pData) {
16529     size_t in_size = *pDataSize;
16530     CastFromHandle<ValidationCache *>(validationCache)->Write(pDataSize, pData);
16531     return (pData && *pDataSize != in_size) ? VK_INCOMPLETE : VK_SUCCESS;
16532 }
16533 
CoreLayerMergeValidationCachesEXT(VkDevice device,VkValidationCacheEXT dstCache,uint32_t srcCacheCount,const VkValidationCacheEXT * pSrcCaches)16534 VkResult CoreChecks::CoreLayerMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount,
16535                                                        const VkValidationCacheEXT *pSrcCaches) {
16536     bool skip = false;
16537     auto dst = CastFromHandle<ValidationCache *>(dstCache);
16538     VkResult result = VK_SUCCESS;
16539     for (uint32_t i = 0; i < srcCacheCount; i++) {
16540         auto src = CastFromHandle<const ValidationCache *>(pSrcCaches[i]);
16541         if (src == dst) {
16542             skip |= LogError(device, "VUID-vkMergeValidationCachesEXT-dstCache-01536",
16543                              "vkMergeValidationCachesEXT: dstCache (0x%" PRIx64 ") must not appear in pSrcCaches array.",
16544                              HandleToUint64(dstCache));
16545             result = VK_ERROR_VALIDATION_FAILED_EXT;
16546         }
16547         if (!skip) {
16548             dst->Merge(src);
16549         }
16550     }
16551 
16552     return result;
16553 }
16554 
ValidateCmdSetDeviceMask(VkCommandBuffer commandBuffer,uint32_t deviceMask,CMD_TYPE cmd_type) const16555 bool CoreChecks::ValidateCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask, CMD_TYPE cmd_type) const {
16556     bool skip = false;
16557     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16558     skip |= ValidateCmd(cb_state.get(), cmd_type);
16559     skip |= ValidateDeviceMaskToPhysicalDeviceCount(deviceMask, commandBuffer, "VUID-vkCmdSetDeviceMask-deviceMask-00108");
16560     skip |= ValidateDeviceMaskToZero(deviceMask, commandBuffer, "VUID-vkCmdSetDeviceMask-deviceMask-00109");
16561     skip |=
16562         ValidateDeviceMaskToCommandBuffer(cb_state.get(), deviceMask, commandBuffer, "VUID-vkCmdSetDeviceMask-deviceMask-00110");
16563     if (cb_state->activeRenderPass) {
16564         skip |= ValidateDeviceMaskToRenderPass(cb_state.get(), deviceMask, "VUID-vkCmdSetDeviceMask-deviceMask-00111");
16565     }
16566     return skip;
16567 }
16568 
PreCallValidateCmdSetDeviceMask(VkCommandBuffer commandBuffer,uint32_t deviceMask) const16569 bool CoreChecks::PreCallValidateCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) const {
16570     return ValidateCmdSetDeviceMask(commandBuffer, deviceMask, CMD_SETDEVICEMASK);
16571 }
16572 
PreCallValidateCmdSetDeviceMaskKHR(VkCommandBuffer commandBuffer,uint32_t deviceMask) const16573 bool CoreChecks::PreCallValidateCmdSetDeviceMaskKHR(VkCommandBuffer commandBuffer, uint32_t deviceMask) const {
16574     return ValidateCmdSetDeviceMask(commandBuffer, deviceMask, CMD_SETDEVICEMASKKHR);
16575 }
16576 
ValidateGetSemaphoreCounterValue(VkDevice device,VkSemaphore semaphore,uint64_t * pValue,const char * apiName) const16577 bool CoreChecks::ValidateGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t *pValue,
16578                                                   const char *apiName) const {
16579     bool skip = false;
16580     const auto semaphore_state = Get<SEMAPHORE_STATE>(semaphore);
16581     if (semaphore_state && semaphore_state->type != VK_SEMAPHORE_TYPE_TIMELINE) {
16582         skip |= LogError(semaphore, "VUID-vkGetSemaphoreCounterValue-semaphore-03255",
16583                          "%s(): semaphore %s must be of VK_SEMAPHORE_TYPE_TIMELINE type", apiName,
16584                          report_data->FormatHandle(semaphore).c_str());
16585     }
16586     return skip;
16587 }
16588 
PreCallValidateGetSemaphoreCounterValueKHR(VkDevice device,VkSemaphore semaphore,uint64_t * pValue) const16589 bool CoreChecks::PreCallValidateGetSemaphoreCounterValueKHR(VkDevice device, VkSemaphore semaphore, uint64_t *pValue) const {
16590     return ValidateGetSemaphoreCounterValue(device, semaphore, pValue, "vkGetSemaphoreCounterValueKHR");
16591 }
PreCallValidateGetSemaphoreCounterValue(VkDevice device,VkSemaphore semaphore,uint64_t * pValue) const16592 bool CoreChecks::PreCallValidateGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t *pValue) const {
16593     return ValidateGetSemaphoreCounterValue(device, semaphore, pValue, "vkGetSemaphoreCounterValue");
16594 }
ValidateQueryPoolStride(const std::string & vuid_not_64,const std::string & vuid_64,const VkDeviceSize stride,const char * parameter_name,const uint64_t parameter_value,const VkQueryResultFlags flags) const16595 bool CoreChecks::ValidateQueryPoolStride(const std::string &vuid_not_64, const std::string &vuid_64, const VkDeviceSize stride,
16596                                          const char *parameter_name, const uint64_t parameter_value,
16597                                          const VkQueryResultFlags flags) const {
16598     bool skip = false;
16599     if (flags & VK_QUERY_RESULT_64_BIT) {
16600         static const int condition_multiples = 0b0111;
16601         if ((stride & condition_multiples) || (parameter_value & condition_multiples)) {
16602             skip |= LogError(device, vuid_64, "stride %" PRIx64 " or %s %" PRIx64 " is invalid.", stride, parameter_name,
16603                              parameter_value);
16604         }
16605     } else {
16606         static const int condition_multiples = 0b0011;
16607         if ((stride & condition_multiples) || (parameter_value & condition_multiples)) {
16608             skip |= LogError(device, vuid_not_64, "stride %" PRIx64 " or %s %" PRIx64 " is invalid.", stride, parameter_name,
16609                              parameter_value);
16610         }
16611     }
16612     return skip;
16613 }
16614 
ValidateCmdDrawStrideWithStruct(VkCommandBuffer commandBuffer,const std::string & vuid,const uint32_t stride,const char * struct_name,const uint32_t struct_size) const16615 bool CoreChecks::ValidateCmdDrawStrideWithStruct(VkCommandBuffer commandBuffer, const std::string &vuid, const uint32_t stride,
16616                                                  const char *struct_name, const uint32_t struct_size) const {
16617     bool skip = false;
16618     static const int condition_multiples = 0b0011;
16619     if ((stride & condition_multiples) || (stride < struct_size)) {
16620         skip |= LogError(commandBuffer, vuid, "stride %d is invalid or less than sizeof(%s) %d.", stride, struct_name, struct_size);
16621     }
16622     return skip;
16623 }
16624 
ValidateCmdDrawStrideWithBuffer(VkCommandBuffer commandBuffer,const std::string & vuid,const uint32_t stride,const char * struct_name,const uint32_t struct_size,const uint32_t drawCount,const VkDeviceSize offset,const BUFFER_STATE * buffer_state) const16625 bool CoreChecks::ValidateCmdDrawStrideWithBuffer(VkCommandBuffer commandBuffer, const std::string &vuid, const uint32_t stride,
16626                                                  const char *struct_name, const uint32_t struct_size, const uint32_t drawCount,
16627                                                  const VkDeviceSize offset, const BUFFER_STATE *buffer_state) const {
16628     bool skip = false;
16629     uint64_t validation_value = stride * (drawCount - 1) + offset + struct_size;
16630     if (validation_value > buffer_state->createInfo.size) {
16631         skip |= LogError(commandBuffer, vuid,
16632                          "stride[%d] * (drawCount[%d] - 1) + offset[%" PRIx64 "] + sizeof(%s)[%d] = %" PRIx64
16633                          " is greater than the size[%" PRIx64 "] of %s.",
16634                          stride, drawCount, offset, struct_name, struct_size, validation_value, buffer_state->createInfo.size,
16635                          report_data->FormatHandle(buffer_state->buffer()).c_str());
16636     }
16637     return skip;
16638 }
16639 
PreCallValidateReleaseProfilingLockKHR(VkDevice device) const16640 bool CoreChecks::PreCallValidateReleaseProfilingLockKHR(VkDevice device) const {
16641     bool skip = false;
16642 
16643     if (!performance_lock_acquired) {
16644         skip |= LogError(device, "VUID-vkReleaseProfilingLockKHR-device-03235",
16645                          "vkReleaseProfilingLockKHR(): The profiling lock of device must have been held via a previous successful "
16646                          "call to vkAcquireProfilingLockKHR.");
16647     }
16648 
16649     return skip;
16650 }
16651 
PreCallValidateCmdSetCheckpointNV(VkCommandBuffer commandBuffer,const void * pCheckpointMarker) const16652 bool CoreChecks::PreCallValidateCmdSetCheckpointNV(VkCommandBuffer commandBuffer, const void *pCheckpointMarker) const {
16653     {
16654         const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16655         assert(cb_state);
16656         bool skip = false;
16657         skip |= ValidateCmd(cb_state.get(), CMD_SETCHECKPOINTNV);
16658         return skip;
16659     }
16660 }
16661 
PreCallValidateWriteAccelerationStructuresPropertiesKHR(VkDevice device,uint32_t accelerationStructureCount,const VkAccelerationStructureKHR * pAccelerationStructures,VkQueryType queryType,size_t dataSize,void * pData,size_t stride) const16662 bool CoreChecks::PreCallValidateWriteAccelerationStructuresPropertiesKHR(VkDevice device, uint32_t accelerationStructureCount,
16663                                                                          const VkAccelerationStructureKHR *pAccelerationStructures,
16664                                                                          VkQueryType queryType, size_t dataSize, void *pData,
16665                                                                          size_t stride) const {
16666     bool skip = false;
16667     for (uint32_t i = 0; i < accelerationStructureCount; ++i) {
16668         const auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pAccelerationStructures[i]);
16669         const auto &as_info = as_state->build_info_khr;
16670         if (queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR) {
16671             if (!(as_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) {
16672                 skip |= LogError(device, "VUID-vkWriteAccelerationStructuresPropertiesKHR-accelerationStructures-03431",
16673                                  "vkWriteAccelerationStructuresPropertiesKHR: All acceleration structures (%s) in "
16674                                  "pAccelerationStructures must have been built with"
16675                                  "VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR if queryType is "
16676                                  "VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR.",
16677                                  report_data->FormatHandle(as_state->acceleration_structure()).c_str());
16678             }
16679         }
16680     }
16681     return skip;
16682 }
16683 
PreCallValidateCmdWriteAccelerationStructuresPropertiesKHR(VkCommandBuffer commandBuffer,uint32_t accelerationStructureCount,const VkAccelerationStructureKHR * pAccelerationStructures,VkQueryType queryType,VkQueryPool queryPool,uint32_t firstQuery) const16684 bool CoreChecks::PreCallValidateCmdWriteAccelerationStructuresPropertiesKHR(
16685     VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures,
16686     VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery) const {
16687     bool skip = false;
16688     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16689     skip |= ValidateCmd(cb_state.get(), CMD_WRITEACCELERATIONSTRUCTURESPROPERTIESKHR);
16690     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
16691     const auto &query_pool_ci = query_pool_state->createInfo;
16692     if (query_pool_ci.queryType != queryType) {
16693         skip |= LogError(
16694             device, "VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-queryPool-02493",
16695             "vkCmdWriteAccelerationStructuresPropertiesKHR: queryPool must have been created with a queryType matching queryType.");
16696     }
16697     for (uint32_t i = 0; i < accelerationStructureCount; ++i) {
16698         if (queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR) {
16699             const auto as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pAccelerationStructures[i]);
16700             if (!(as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) {
16701                 skip |= LogError(
16702                     device, "VUID-vkCmdWriteAccelerationStructuresPropertiesKHR-accelerationStructures-03431",
16703                     "vkCmdWriteAccelerationStructuresPropertiesKHR: All acceleration structures in pAccelerationStructures "
16704                     "must have been built with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR if queryType is "
16705                     "VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR.");
16706             }
16707         }
16708     }
16709     return skip;
16710 }
16711 
PreCallValidateCmdWriteAccelerationStructuresPropertiesNV(VkCommandBuffer commandBuffer,uint32_t accelerationStructureCount,const VkAccelerationStructureNV * pAccelerationStructures,VkQueryType queryType,VkQueryPool queryPool,uint32_t firstQuery) const16712 bool CoreChecks::PreCallValidateCmdWriteAccelerationStructuresPropertiesNV(VkCommandBuffer commandBuffer,
16713                                                                            uint32_t accelerationStructureCount,
16714                                                                            const VkAccelerationStructureNV *pAccelerationStructures,
16715                                                                            VkQueryType queryType, VkQueryPool queryPool,
16716                                                                            uint32_t firstQuery) const {
16717     bool skip = false;
16718     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16719     skip |= ValidateCmd(cb_state.get(), CMD_WRITEACCELERATIONSTRUCTURESPROPERTIESNV);
16720     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
16721     const auto &query_pool_ci = query_pool_state->createInfo;
16722     if (query_pool_ci.queryType != queryType) {
16723         skip |= LogError(
16724             device, "VUID-vkCmdWriteAccelerationStructuresPropertiesNV-queryPool-03755",
16725             "vkCmdWriteAccelerationStructuresPropertiesNV: queryPool must have been created with a queryType matching queryType.");
16726     }
16727     for (uint32_t i = 0; i < accelerationStructureCount; ++i) {
16728         if (queryType == VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV) {
16729             const auto as_state = Get<ACCELERATION_STRUCTURE_STATE>(pAccelerationStructures[i]);
16730             if (!(as_state->build_info.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) {
16731                 skip |=
16732                     LogError(device, "VUID-vkCmdWriteAccelerationStructuresPropertiesNV-pAccelerationStructures-06215",
16733                              "vkCmdWriteAccelerationStructuresPropertiesNV: All acceleration structures in pAccelerationStructures "
16734                              "must have been built with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR if queryType is "
16735                              "VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV.");
16736             }
16737         }
16738     }
16739     return skip;
16740 }
16741 
CalcTotalShaderGroupCount(const PIPELINE_STATE * pipelineState) const16742 uint32_t CoreChecks::CalcTotalShaderGroupCount(const PIPELINE_STATE *pipelineState) const {
16743     const auto &create_info = pipelineState->create_info.raytracing;
16744     uint32_t total = create_info.groupCount;
16745 
16746     if (create_info.pLibraryInfo) {
16747         for (uint32_t i = 0; i < create_info.pLibraryInfo->libraryCount; ++i) {
16748             const auto library_pipeline_state = Get<PIPELINE_STATE>(create_info.pLibraryInfo->pLibraries[i]);
16749             total += CalcTotalShaderGroupCount(library_pipeline_state.get());
16750         }
16751     }
16752 
16753     return total;
16754 }
16755 
PreCallValidateGetRayTracingShaderGroupHandlesKHR(VkDevice device,VkPipeline pipeline,uint32_t firstGroup,uint32_t groupCount,size_t dataSize,void * pData) const16756 bool CoreChecks::PreCallValidateGetRayTracingShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup,
16757                                                                    uint32_t groupCount, size_t dataSize, void *pData) const {
16758     bool skip = false;
16759     const auto pipeline_state = Get<PIPELINE_STATE>(pipeline);
16760     if (pipeline_state->GetPipelineCreateFlags() & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) {
16761         skip |= LogError(
16762             device, "VUID-vkGetRayTracingShaderGroupHandlesKHR-pipeline-03482",
16763             "vkGetRayTracingShaderGroupHandlesKHR: pipeline must have not been created with VK_PIPELINE_CREATE_LIBRARY_BIT_KHR.");
16764     }
16765     if (dataSize < (phys_dev_ext_props.ray_tracing_propsKHR.shaderGroupHandleSize * groupCount)) {
16766         skip |= LogError(device, "VUID-vkGetRayTracingShaderGroupHandlesKHR-dataSize-02420",
16767                          "vkGetRayTracingShaderGroupHandlesKHR: dataSize (%zu) must be at least "
16768                          "VkPhysicalDeviceRayTracingPipelinePropertiesKHR::shaderGroupHandleSize * groupCount.",
16769                          dataSize);
16770     }
16771 
16772     uint32_t total_group_count = CalcTotalShaderGroupCount(pipeline_state.get());
16773 
16774     if (firstGroup >= total_group_count) {
16775         skip |=
16776             LogError(device, "VUID-vkGetRayTracingShaderGroupHandlesKHR-firstGroup-04050",
16777                      "vkGetRayTracingShaderGroupHandlesKHR: firstGroup must be less than the number of shader groups in pipeline.");
16778     }
16779     if ((firstGroup + groupCount) > total_group_count) {
16780         skip |= LogError(
16781             device, "VUID-vkGetRayTracingShaderGroupHandlesKHR-firstGroup-02419",
16782             "vkGetRayTracingShaderGroupHandlesKHR: The sum of firstGroup and groupCount must be less than or equal the number "
16783             "of shader groups in pipeline.");
16784     }
16785     return skip;
16786 }
PreCallValidateGetRayTracingCaptureReplayShaderGroupHandlesKHR(VkDevice device,VkPipeline pipeline,uint32_t firstGroup,uint32_t groupCount,size_t dataSize,void * pData) const16787 bool CoreChecks::PreCallValidateGetRayTracingCaptureReplayShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline,
16788                                                                                 uint32_t firstGroup, uint32_t groupCount,
16789                                                                                 size_t dataSize, void *pData) const {
16790     bool skip = false;
16791     if (dataSize < (phys_dev_ext_props.ray_tracing_propsKHR.shaderGroupHandleCaptureReplaySize * groupCount)) {
16792         skip |= LogError(device, "VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-dataSize-03484",
16793                          "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR: dataSize (%zu) must be at least "
16794                          "VkPhysicalDeviceRayTracingPipelinePropertiesKHR::shaderGroupHandleCaptureReplaySize * groupCount.",
16795                          dataSize);
16796     }
16797     const auto pipeline_state = Get<PIPELINE_STATE>(pipeline);
16798     if (!pipeline_state) {
16799         return skip;
16800     }
16801     const auto &create_info = pipeline_state->create_info.raytracing;
16802     if (firstGroup >= create_info.groupCount) {
16803         skip |= LogError(device, "VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-firstGroup-04051",
16804                          "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR: firstGroup must be less than the number of shader "
16805                          "groups in pipeline.");
16806     }
16807     if ((firstGroup + groupCount) > create_info.groupCount) {
16808         skip |= LogError(device, "VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-firstGroup-03483",
16809                          "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR: The sum of firstGroup and groupCount must be less "
16810                          "than or equal to the number of shader groups in pipeline.");
16811     }
16812     if (!(create_info.flags & VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR)) {
16813         skip |= LogError(device, "VUID-vkGetRayTracingCaptureReplayShaderGroupHandlesKHR-pipeline-03607",
16814                          "pipeline must have been created with a flags that included "
16815                          "VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR.");
16816     }
16817     return skip;
16818 }
16819 
PreCallValidateCmdBuildAccelerationStructuresIndirectKHR(VkCommandBuffer commandBuffer,uint32_t infoCount,const VkAccelerationStructureBuildGeometryInfoKHR * pInfos,const VkDeviceAddress * pIndirectDeviceAddresses,const uint32_t * pIndirectStrides,const uint32_t * const * ppMaxPrimitiveCounts) const16820 bool CoreChecks::PreCallValidateCmdBuildAccelerationStructuresIndirectKHR(VkCommandBuffer commandBuffer, uint32_t infoCount,
16821                                                                           const VkAccelerationStructureBuildGeometryInfoKHR *pInfos,
16822                                                                           const VkDeviceAddress *pIndirectDeviceAddresses,
16823                                                                           const uint32_t *pIndirectStrides,
16824                                                                           const uint32_t *const *ppMaxPrimitiveCounts) const {
16825     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16826     assert(cb_state);
16827     bool skip = false;
16828     skip |= ValidateCmd(cb_state.get(), CMD_BUILDACCELERATIONSTRUCTURESINDIRECTKHR);
16829     skip |= ValidateCmdRayQueryState(cb_state.get(), CMD_BUILDACCELERATIONSTRUCTURESINDIRECTKHR,
16830                                      VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR);
16831     for (uint32_t i = 0; i < infoCount; ++i) {
16832         const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].srcAccelerationStructure);
16833         const auto dst_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfos[i].dstAccelerationStructure);
16834         if (pInfos[i].mode == VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR) {
16835             if (src_as_state == nullptr || !src_as_state->built ||
16836                 !(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR)) {
16837                 skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03667",
16838                                  "vkCmdBuildAccelerationStructuresIndirectKHR(): For each element of pInfos, if its mode member is "
16839                                  "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its srcAccelerationStructure member must have "
16840                                  "been built before with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR set in "
16841                                  "VkAccelerationStructureBuildGeometryInfoKHR::flags.");
16842             }
16843             if (pInfos[i].geometryCount != src_as_state->build_info_khr.geometryCount) {
16844                 skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03758",
16845                                  "vkCmdBuildAccelerationStructuresIndirectKHR(): For each element of pInfos, if its mode member is "
16846                                  "VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR,"
16847                                  " its geometryCount member must have the same value which was specified when "
16848                                  "srcAccelerationStructure was last built.");
16849             }
16850             if (pInfos[i].flags != src_as_state->build_info_khr.flags) {
16851                 skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03759",
16852                                  "vkCmdBuildAccelerationStructuresIndirectKHR(): For each element of pInfos, if its mode member is"
16853                                  " VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its flags member must have the same value which"
16854                                  " was specified when srcAccelerationStructure was last built.");
16855             }
16856             if (pInfos[i].type != src_as_state->build_info_khr.type) {
16857                 skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03760",
16858                                  "vkCmdBuildAccelerationStructuresIndirectKHR(): For each element of pInfos, if its mode member is"
16859                                  " VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR, its type member must have the same value which"
16860                                  " was specified when srcAccelerationStructure was last built.");
16861             }
16862         }
16863         if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) {
16864             if (!dst_as_state ||
16865                 (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR &&
16866                  dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) {
16867                 skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03700",
16868                                  "vkCmdBuildAccelerationStructuresIndirectKHR(): For each element of pInfos, if its type member is "
16869                                  "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, its dstAccelerationStructure member must have "
16870                                  "been created with a value of VkAccelerationStructureCreateInfoKHR::type equal to either "
16871                                  "VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.");
16872             }
16873         }
16874         if (pInfos[i].type == VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) {
16875             if (!dst_as_state ||
16876                 (dst_as_state && dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR &&
16877                  dst_as_state->create_infoKHR.type != VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR)) {
16878                 skip |= LogError(device, "VUID-vkCmdBuildAccelerationStructuresIndirectKHR-pInfos-03699",
16879                                  "vkCmdBuildAccelerationStructuresIndirectKHR():For each element of pInfos, if its type member is "
16880                                  "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, its dstAccelerationStructure member must have been "
16881                                  "created with a value of VkAccelerationStructureCreateInfoKHR::type equal to either "
16882                                  "VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR or VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR.");
16883             }
16884         }
16885     }
16886     return skip;
16887 }
16888 
ValidateCopyAccelerationStructureInfoKHR(const VkCopyAccelerationStructureInfoKHR * pInfo,const char * api_name) const16889 bool CoreChecks::ValidateCopyAccelerationStructureInfoKHR(const VkCopyAccelerationStructureInfoKHR *pInfo,
16890                                                           const char *api_name) const {
16891     bool skip = false;
16892     if (pInfo->mode == VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR) {
16893         const auto src_as_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src);
16894         if (!(src_as_state->build_info_khr.flags & VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR)) {
16895             skip |= LogError(device, "VUID-VkCopyAccelerationStructureInfoKHR-src-03411",
16896                              "(%s): src must have been built with VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR"
16897                              "if mode is VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR.",
16898                              api_name);
16899         }
16900     }
16901     const auto src_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src);
16902     if (src_accel_state) {
16903         const auto buffer_state = Get<BUFFER_STATE>(src_accel_state->create_infoKHR.buffer);
16904         skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), api_name, "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03718");
16905     }
16906     const auto dst_accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->dst);
16907     if (dst_accel_state) {
16908         const auto buffer_state = Get<BUFFER_STATE>(dst_accel_state->create_infoKHR.buffer);
16909         skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), api_name, "VUID-VkCopyAccelerationStructureInfoKHR-buffer-03719");
16910     }
16911     return skip;
16912 }
16913 
PreCallValidateCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer,const VkCopyAccelerationStructureInfoKHR * pInfo) const16914 bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer,
16915                                                                 const VkCopyAccelerationStructureInfoKHR *pInfo) const {
16916     bool skip = false;
16917     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16918     assert(cb_state);
16919     skip |= ValidateCmd(cb_state.get(), CMD_COPYACCELERATIONSTRUCTUREKHR);
16920     skip |= ValidateCopyAccelerationStructureInfoKHR(pInfo, "vkCmdCopyAccelerationStructureKHR");
16921     return skip;
16922 }
16923 
PreCallValidateCopyAccelerationStructureKHR(VkDevice device,VkDeferredOperationKHR deferredOperation,const VkCopyAccelerationStructureInfoKHR * pInfo) const16924 bool CoreChecks::PreCallValidateCopyAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation,
16925                                                              const VkCopyAccelerationStructureInfoKHR *pInfo) const {
16926     bool skip = false;
16927     skip |= ValidateCopyAccelerationStructureInfoKHR(pInfo, "vkCopyAccelerationStructureKHR");
16928     return skip;
16929 }
PreCallValidateCmdCopyAccelerationStructureToMemoryKHR(VkCommandBuffer commandBuffer,const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo) const16930 bool CoreChecks::PreCallValidateCmdCopyAccelerationStructureToMemoryKHR(
16931     VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo) const {
16932     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16933     assert(cb_state);
16934     bool skip = false;
16935     skip |= ValidateCmd(cb_state.get(), CMD_COPYACCELERATIONSTRUCTURETOMEMORYKHR);
16936 
16937     const auto accel_state = Get<ACCELERATION_STRUCTURE_STATE_KHR>(pInfo->src);
16938     if (accel_state) {
16939         const auto buffer_state = Get<BUFFER_STATE>(accel_state->create_infoKHR.buffer);
16940         skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), "vkCmdCopyAccelerationStructureToMemoryKHR",
16941                                               "VUID-vkCmdCopyAccelerationStructureToMemoryKHR-None-03559");
16942     }
16943     return skip;
16944 }
16945 
PreCallValidateCmdCopyMemoryToAccelerationStructureKHR(VkCommandBuffer commandBuffer,const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo) const16946 bool CoreChecks::PreCallValidateCmdCopyMemoryToAccelerationStructureKHR(
16947     VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo) const {
16948     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16949     assert(cb_state);
16950     bool skip = false;
16951     skip |= ValidateCmd(cb_state.get(), CMD_COPYMEMORYTOACCELERATIONSTRUCTUREKHR);
16952     return skip;
16953 }
16954 
PreCallValidateCmdBindTransformFeedbackBuffersEXT(VkCommandBuffer commandBuffer,uint32_t firstBinding,uint32_t bindingCount,const VkBuffer * pBuffers,const VkDeviceSize * pOffsets,const VkDeviceSize * pSizes) const16955 bool CoreChecks::PreCallValidateCmdBindTransformFeedbackBuffersEXT(VkCommandBuffer commandBuffer, uint32_t firstBinding,
16956                                                                    uint32_t bindingCount, const VkBuffer *pBuffers,
16957                                                                    const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes) const {
16958     bool skip = false;
16959     char const *const cmd_name = "CmdBindTransformFeedbackBuffersEXT";
16960     if (!enabled_features.transform_feedback_features.transformFeedback) {
16961         skip |= LogError(commandBuffer, "VUID-vkCmdBindTransformFeedbackBuffersEXT-transformFeedback-02355",
16962                          "%s: transformFeedback feature is not enabled.", cmd_name);
16963     }
16964 
16965     {
16966         const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
16967         if (cb_state->transform_feedback_active) {
16968             skip |= LogError(commandBuffer, "VUID-vkCmdBindTransformFeedbackBuffersEXT-None-02365",
16969                              "%s: transform feedback is active.", cmd_name);
16970         }
16971     }
16972 
16973     for (uint32_t i = 0; i < bindingCount; ++i) {
16974         const auto buffer_state = Get<BUFFER_STATE>(pBuffers[i]);
16975         assert(buffer_state != nullptr);
16976 
16977         if (pOffsets[i] >= buffer_state->createInfo.size) {
16978             skip |= LogError(buffer_state->buffer(), "VUID-vkCmdBindTransformFeedbackBuffersEXT-pOffsets-02358",
16979                              "%s: pOffset[%" PRIu32 "](0x%" PRIxLEAST64
16980                              ") is greater than or equal to the size of pBuffers[%" PRIu32 "](0x%" PRIxLEAST64 ").",
16981                              cmd_name, i, pOffsets[i], i, buffer_state->createInfo.size);
16982         }
16983 
16984         if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT) == 0) {
16985             skip |= LogError(buffer_state->buffer(), "VUID-vkCmdBindTransformFeedbackBuffersEXT-pBuffers-02360",
16986                              "%s: pBuffers[%" PRIu32 "] (%s)"
16987                              " was not created with the VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT flag.",
16988                              cmd_name, i, report_data->FormatHandle(pBuffers[i]).c_str());
16989         }
16990 
16991         // pSizes is optional and may be nullptr. Also might be VK_WHOLE_SIZE which VU don't apply
16992         if ((pSizes != nullptr) && (pSizes[i] != VK_WHOLE_SIZE)) {
16993             // only report one to prevent redundant error if the size is larger since adding offset will be as well
16994             if (pSizes[i] > buffer_state->createInfo.size) {
16995                 skip |= LogError(buffer_state->buffer(), "VUID-vkCmdBindTransformFeedbackBuffersEXT-pSizes-02362",
16996                                  "%s: pSizes[%" PRIu32 "](0x%" PRIxLEAST64 ") is greater than the size of pBuffers[%" PRIu32
16997                                  "](0x%" PRIxLEAST64 ").",
16998                                  cmd_name, i, pSizes[i], i, buffer_state->createInfo.size);
16999             } else if (pOffsets[i] + pSizes[i] > buffer_state->createInfo.size) {
17000                 skip |= LogError(buffer_state->buffer(), "VUID-vkCmdBindTransformFeedbackBuffersEXT-pOffsets-02363",
17001                                  "%s: The sum of pOffsets[%" PRIu32 "](Ox%" PRIxLEAST64 ") and pSizes[%" PRIu32 "](0x%" PRIxLEAST64
17002                                  ") is greater than the size of pBuffers[%" PRIu32 "](0x%" PRIxLEAST64 ").",
17003                                  cmd_name, i, pOffsets[i], i, pSizes[i], i, buffer_state->createInfo.size);
17004             }
17005         }
17006 
17007         skip |=
17008             ValidateMemoryIsBoundToBuffer(buffer_state.get(), cmd_name, "VUID-vkCmdBindTransformFeedbackBuffersEXT-pBuffers-02364");
17009     }
17010 
17011     return skip;
17012 }
17013 
PreCallValidateCmdBeginTransformFeedbackEXT(VkCommandBuffer commandBuffer,uint32_t firstCounterBuffer,uint32_t counterBufferCount,const VkBuffer * pCounterBuffers,const VkDeviceSize * pCounterBufferOffsets) const17014 bool CoreChecks::PreCallValidateCmdBeginTransformFeedbackEXT(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer,
17015                                                              uint32_t counterBufferCount, const VkBuffer *pCounterBuffers,
17016                                                              const VkDeviceSize *pCounterBufferOffsets) const {
17017     bool skip = false;
17018     char const *const cmd_name = "CmdBeginTransformFeedbackEXT";
17019     if (!enabled_features.transform_feedback_features.transformFeedback) {
17020         skip |= LogError(commandBuffer, "VUID-vkCmdBeginTransformFeedbackEXT-transformFeedback-02366",
17021                          "%s: transformFeedback feature is not enabled.", cmd_name);
17022     }
17023 
17024     {
17025         const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17026         if (cb_state) {
17027             if (cb_state->transform_feedback_active) {
17028                 skip |= LogError(commandBuffer, "VUID-vkCmdBeginTransformFeedbackEXT-None-02367",
17029                                  "%s: transform feedback is active.", cmd_name);
17030             }
17031             if (cb_state->activeRenderPass) {
17032                 const auto &rp_ci = cb_state->activeRenderPass->createInfo;
17033                 for (uint32_t i = 0; i < rp_ci.subpassCount; ++i) {
17034                     // When a subpass uses a non-zero view mask, multiview functionality is considered to be enabled
17035                     if (rp_ci.pSubpasses[i].viewMask > 0) {
17036                         skip |= LogError(commandBuffer, "VUID-vkCmdBeginTransformFeedbackEXT-None-02373",
17037                                          "%s: active render pass (%s) has multiview enabled.", cmd_name,
17038                                          report_data->FormatHandle(cb_state->activeRenderPass->renderPass()).c_str());
17039                         break;
17040                     }
17041                 }
17042             }
17043         }
17044     }
17045 
17046     // pCounterBuffers and pCounterBufferOffsets are optional and may be nullptr. Additionaly, pCounterBufferOffsets must be nullptr
17047     // if pCounterBuffers is nullptr.
17048     if (pCounterBuffers == nullptr) {
17049         if (pCounterBufferOffsets != nullptr) {
17050             skip |= LogError(commandBuffer, "VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffer-02371",
17051                              "%s: pCounterBuffers is NULL and pCounterBufferOffsets is not NULL.", cmd_name);
17052         }
17053     } else {
17054         for (uint32_t i = 0; i < counterBufferCount; ++i) {
17055             if (pCounterBuffers[i] != VK_NULL_HANDLE) {
17056                 const auto buffer_state = Get<BUFFER_STATE>(pCounterBuffers[i]);
17057                 assert(buffer_state != nullptr);
17058 
17059                 if (pCounterBufferOffsets != nullptr && pCounterBufferOffsets[i] + 4 > buffer_state->createInfo.size) {
17060                     skip |=
17061                         LogError(buffer_state->buffer(), "VUID-vkCmdBeginTransformFeedbackEXT-pCounterBufferOffsets-02370",
17062                                  "%s: pCounterBuffers[%" PRIu32 "](%s) is not large enough to hold 4 bytes at pCounterBufferOffsets[%" PRIu32 "](0x%" PRIx64 ").",
17063                              cmd_name, i, report_data->FormatHandle(pCounterBuffers[i]).c_str(), i, pCounterBufferOffsets[i]);
17064                 }
17065 
17066                 if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT) == 0) {
17067                     skip |= LogError(buffer_state->buffer(), "VUID-vkCmdBeginTransformFeedbackEXT-pCounterBuffers-02372",
17068                                      "%s: pCounterBuffers[%" PRIu32 "] (%s) was not created with the VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT flag.",
17069                                      cmd_name, i, report_data->FormatHandle(pCounterBuffers[i]).c_str());
17070                 }
17071             }
17072         }
17073     }
17074 
17075     return skip;
17076 }
17077 
PreCallValidateCmdEndTransformFeedbackEXT(VkCommandBuffer commandBuffer,uint32_t firstCounterBuffer,uint32_t counterBufferCount,const VkBuffer * pCounterBuffers,const VkDeviceSize * pCounterBufferOffsets) const17078 bool CoreChecks::PreCallValidateCmdEndTransformFeedbackEXT(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer,
17079                                                            uint32_t counterBufferCount, const VkBuffer *pCounterBuffers,
17080                                                            const VkDeviceSize *pCounterBufferOffsets) const {
17081     bool skip = false;
17082     char const *const cmd_name = "CmdEndTransformFeedbackEXT";
17083     if (!enabled_features.transform_feedback_features.transformFeedback) {
17084         skip |= LogError(commandBuffer, "VUID-vkCmdEndTransformFeedbackEXT-transformFeedback-02374",
17085                          "%s: transformFeedback feature is not enabled.", cmd_name);
17086     }
17087 
17088     {
17089         const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17090         if (!cb_state->transform_feedback_active) {
17091             skip |= LogError(commandBuffer, "VUID-vkCmdEndTransformFeedbackEXT-None-02375", "%s: transform feedback is not active.",
17092                              cmd_name);
17093         }
17094     }
17095 
17096     // pCounterBuffers and pCounterBufferOffsets are optional and may be nullptr. Additionaly, pCounterBufferOffsets must be nullptr
17097     // if pCounterBuffers is nullptr.
17098     if (pCounterBuffers == nullptr) {
17099         if (pCounterBufferOffsets != nullptr) {
17100             skip |= LogError(commandBuffer, "VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffer-02379",
17101                              "%s: pCounterBuffers is NULL and pCounterBufferOffsets is not NULL.", cmd_name);
17102         }
17103     } else {
17104         for (uint32_t i = 0; i < counterBufferCount; ++i) {
17105             if (pCounterBuffers[i] != VK_NULL_HANDLE) {
17106                 const auto buffer_state = Get<BUFFER_STATE>(pCounterBuffers[i]);
17107                 assert(buffer_state != nullptr);
17108 
17109                 if (pCounterBufferOffsets != nullptr && pCounterBufferOffsets[i] + 4 > buffer_state->createInfo.size) {
17110                     skip |=
17111                         LogError(buffer_state->buffer(), "VUID-vkCmdEndTransformFeedbackEXT-pCounterBufferOffsets-02378",
17112                                  "%s: pCounterBuffers[%" PRIu32 "](%s) is not large enough to hold 4 bytes at pCounterBufferOffsets[%" PRIu32 "](0x%" PRIx64 ").",
17113                                  cmd_name, i, report_data->FormatHandle(pCounterBuffers[i]).c_str(), i, pCounterBufferOffsets[i]);
17114                 }
17115 
17116                 if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT) == 0) {
17117                     skip |= LogError(buffer_state->buffer(), "VUID-vkCmdEndTransformFeedbackEXT-pCounterBuffers-02380",
17118                                      "%s: pCounterBuffers[%" PRIu32 "] (%s) was not created with the VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT flag.",
17119                                      cmd_name, i, report_data->FormatHandle(pCounterBuffers[i]).c_str());
17120                 }
17121             }
17122         }
17123     }
17124 
17125     return skip;
17126 }
17127 
PreCallValidateCmdSetLogicOpEXT(VkCommandBuffer commandBuffer,VkLogicOp logicOp) const17128 bool CoreChecks::PreCallValidateCmdSetLogicOpEXT(VkCommandBuffer commandBuffer, VkLogicOp logicOp) const {
17129     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17130     bool skip = false;
17131     skip |= ValidateCmd(cb_state.get(), CMD_SETLOGICOPEXT);
17132 
17133     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2LogicOp) {
17134         skip |= LogError(commandBuffer, "VUID-vkCmdSetLogicOpEXT-None-04867",
17135                          "vkCmdSetLogicOpEXT: extendedDynamicState feature is not enabled.");
17136     }
17137     return skip;
17138 }
17139 
PreCallValidateCmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer,uint32_t patchControlPoints) const17140 bool CoreChecks::PreCallValidateCmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer, uint32_t patchControlPoints) const {
17141     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17142     bool skip = false;
17143     skip |= ValidateCmd(cb_state.get(), CMD_SETPATCHCONTROLPOINTSEXT);
17144 
17145     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2PatchControlPoints) {
17146         skip |= LogError(commandBuffer, "VUID-vkCmdSetPatchControlPointsEXT-None-04873",
17147                          "vkCmdSetPatchControlPointsEXT: extendedDynamicState feature is not enabled.");
17148     }
17149     if (patchControlPoints > phys_dev_props.limits.maxTessellationPatchSize) {
17150         skip |= LogError(commandBuffer, "VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874",
17151                          "vkCmdSetPatchControlPointsEXT: The value of patchControlPoints must be less than "
17152                          "VkPhysicalDeviceLimits::maxTessellationPatchSize");
17153     }
17154     return skip;
17155 }
17156 
PreCallValidateCmdSetRasterizerDiscardEnableEXT(VkCommandBuffer commandBuffer,VkBool32 rasterizerDiscardEnable) const17157 bool CoreChecks::PreCallValidateCmdSetRasterizerDiscardEnableEXT(VkCommandBuffer commandBuffer,
17158                                                                  VkBool32 rasterizerDiscardEnable) const {
17159     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17160     bool skip = false;
17161     skip |= ValidateCmd(cb_state.get(), CMD_SETRASTERIZERDISCARDENABLEEXT);
17162 
17163     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2) {
17164         skip |= LogError(commandBuffer, "VUID-vkCmdSetRasterizerDiscardEnableEXT-None-04871",
17165                          "vkCmdSetRasterizerDiscardEnableEXT: extendedDynamicState feature is not enabled.");
17166     }
17167 
17168     return skip;
17169 }
17170 
PreCallValidateCmdSetDepthBiasEnableEXT(VkCommandBuffer commandBuffer,VkBool32 depthBiasEnable) const17171 bool CoreChecks::PreCallValidateCmdSetDepthBiasEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable) const {
17172     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17173     bool skip = false;
17174     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHBIASENABLEEXT);
17175 
17176     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2) {
17177         skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthBiasEnableEXT-None-04872",
17178                          "vkCmdSetDepthBiasEnableEXT: extendedDynamicState feature is not enabled.");
17179     }
17180 
17181     return skip;
17182 }
17183 
PreCallValidateCmdSetPrimitiveRestartEnableEXT(VkCommandBuffer commandBuffer,VkBool32 primitiveRestartEnable) const17184 bool CoreChecks::PreCallValidateCmdSetPrimitiveRestartEnableEXT(VkCommandBuffer commandBuffer,
17185                                                                 VkBool32 primitiveRestartEnable) const {
17186     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17187     bool skip = false;
17188     skip |= ValidateCmd(cb_state.get(), CMD_SETPRIMITIVERESTARTENABLEEXT);
17189 
17190     if (!enabled_features.extended_dynamic_state2_features.extendedDynamicState2) {
17191         skip |= LogError(commandBuffer, "VUID-vkCmdSetPrimitiveRestartEnableEXT-None-04866",
17192                          "vkCmdSetPrimitiveRestartEnableEXT: extendedDynamicState feature is not enabled.");
17193     }
17194 
17195     return skip;
17196 }
17197 
PreCallValidateCmdSetCullModeEXT(VkCommandBuffer commandBuffer,VkCullModeFlags cullMode) const17198 bool CoreChecks::PreCallValidateCmdSetCullModeEXT(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode) const {
17199     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17200     bool skip = false;
17201     skip |= ValidateCmd(cb_state.get(), CMD_SETCULLMODEEXT);
17202 
17203     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17204         skip |= LogError(commandBuffer, "VUID-vkCmdSetCullModeEXT-None-03384",
17205                          "vkCmdSetCullModeEXT: extendedDynamicState feature is not enabled.");
17206     }
17207 
17208     return skip;
17209 }
17210 
PreCallValidateCmdSetFrontFaceEXT(VkCommandBuffer commandBuffer,VkFrontFace frontFace) const17211 bool CoreChecks::PreCallValidateCmdSetFrontFaceEXT(VkCommandBuffer commandBuffer, VkFrontFace frontFace) const {
17212     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17213     bool skip = false;
17214     skip |= ValidateCmd(cb_state.get(), CMD_SETFRONTFACEEXT);
17215 
17216     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17217         skip |= LogError(commandBuffer, "VUID-vkCmdSetFrontFaceEXT-None-03383",
17218                          "vkCmdSetFrontFaceEXT: extendedDynamicState feature is not enabled.");
17219     }
17220 
17221     return skip;
17222 }
17223 
PreCallValidateCmdSetPrimitiveTopologyEXT(VkCommandBuffer commandBuffer,VkPrimitiveTopology primitiveTopology) const17224 bool CoreChecks::PreCallValidateCmdSetPrimitiveTopologyEXT(VkCommandBuffer commandBuffer,
17225                                                            VkPrimitiveTopology primitiveTopology) const {
17226     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17227     bool skip = false;
17228     skip |= ValidateCmd(cb_state.get(), CMD_SETPRIMITIVETOPOLOGYEXT);
17229 
17230     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17231         skip |= LogError(commandBuffer, "VUID-vkCmdSetPrimitiveTopologyEXT-None-03347",
17232                          "vkCmdSetPrimitiveTopologyEXT: extendedDynamicState feature is not enabled.");
17233     }
17234 
17235     return skip;
17236 }
17237 
PreCallValidateCmdSetViewportWithCountEXT(VkCommandBuffer commandBuffer,uint32_t viewportCount,const VkViewport * pViewports) const17238 bool CoreChecks::PreCallValidateCmdSetViewportWithCountEXT(VkCommandBuffer commandBuffer, uint32_t viewportCount,
17239                                                            const VkViewport *pViewports) const {
17240     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17241     bool skip = false;
17242     skip |= ValidateCmd(cb_state.get(), CMD_SETVIEWPORTWITHCOUNTEXT);
17243 
17244     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17245         skip |= LogError(commandBuffer, "VUID-vkCmdSetViewportWithCountEXT-None-03393",
17246                          "vkCmdSetViewportWithCountEXT: extendedDynamicState feature is not enabled.");
17247     }
17248     skip |= ForbidInheritedViewportScissor(commandBuffer, cb_state.get(), "VUID-vkCmdSetViewportWithCountEXT-commandBuffer-04819",
17249                                            "vkCmdSetViewportWithCountEXT");
17250 
17251     return skip;
17252 }
17253 
PreCallValidateCmdSetScissorWithCountEXT(VkCommandBuffer commandBuffer,uint32_t scissorCount,const VkRect2D * pScissors) const17254 bool CoreChecks::PreCallValidateCmdSetScissorWithCountEXT(VkCommandBuffer commandBuffer, uint32_t scissorCount,
17255                                                           const VkRect2D *pScissors) const {
17256     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17257     bool skip = false;
17258     skip |= ValidateCmd(cb_state.get(), CMD_SETSCISSORWITHCOUNTEXT);
17259 
17260     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17261         skip |= LogError(commandBuffer, "VUID-vkCmdSetScissorWithCountEXT-None-03396",
17262                          "vkCmdSetScissorWithCountEXT: extendedDynamicState feature is not enabled.");
17263     }
17264     skip |= ForbidInheritedViewportScissor(commandBuffer, cb_state.get(), "VUID-vkCmdSetScissorWithCountEXT-commandBuffer-04820",
17265                                            "vkCmdSetScissorWithCountEXT");
17266 
17267     return skip;
17268 }
17269 
PreCallValidateCmdBindVertexBuffers2EXT(VkCommandBuffer commandBuffer,uint32_t firstBinding,uint32_t bindingCount,const VkBuffer * pBuffers,const VkDeviceSize * pOffsets,const VkDeviceSize * pSizes,const VkDeviceSize * pStrides) const17270 bool CoreChecks::PreCallValidateCmdBindVertexBuffers2EXT(VkCommandBuffer commandBuffer, uint32_t firstBinding,
17271                                                          uint32_t bindingCount, const VkBuffer *pBuffers,
17272                                                          const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes,
17273                                                          const VkDeviceSize *pStrides) const {
17274     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17275     assert(cb_state);
17276 
17277     bool skip = false;
17278     skip |= ValidateCmd(cb_state.get(), CMD_BINDVERTEXBUFFERS2EXT);
17279     for (uint32_t i = 0; i < bindingCount; ++i) {
17280         const auto buffer_state = Get<BUFFER_STATE>(pBuffers[i]);
17281         if (buffer_state) {
17282             skip |= ValidateBufferUsageFlags(buffer_state.get(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, true,
17283                                              "VUID-vkCmdBindVertexBuffers2EXT-pBuffers-03359", "vkCmdBindVertexBuffers2EXT()",
17284                                              "VK_BUFFER_USAGE_VERTEX_BUFFER_BIT");
17285             skip |= ValidateMemoryIsBoundToBuffer(buffer_state.get(), "vkCmdBindVertexBuffers2EXT()",
17286                                                   "VUID-vkCmdBindVertexBuffers2EXT-pBuffers-03360");
17287             if (pOffsets[i] >= buffer_state->createInfo.size) {
17288                 skip |= LogError(buffer_state->buffer(), "VUID-vkCmdBindVertexBuffers2EXT-pOffsets-03357",
17289                                  "vkCmdBindVertexBuffers2EXT() offset (0x%" PRIxLEAST64 ") is beyond the end of the buffer.",
17290                                  pOffsets[i]);
17291             }
17292             if (pSizes && pOffsets[i] + pSizes[i] > buffer_state->createInfo.size) {
17293                 skip |=
17294                     LogError(buffer_state->buffer(), "VUID-vkCmdBindVertexBuffers2EXT-pSizes-03358",
17295                              "vkCmdBindVertexBuffers2EXT() size (0x%" PRIxLEAST64 ") is beyond the end of the buffer.", pSizes[i]);
17296             }
17297         }
17298     }
17299 
17300     return skip;
17301 }
17302 
PreCallValidateCmdSetDepthTestEnableEXT(VkCommandBuffer commandBuffer,VkBool32 depthTestEnable) const17303 bool CoreChecks::PreCallValidateCmdSetDepthTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable) const {
17304     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17305     bool skip = false;
17306     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHTESTENABLEEXT);
17307 
17308     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17309         skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthTestEnableEXT-None-03352",
17310                          "vkCmdSetDepthTestEnableEXT: extendedDynamicState feature is not enabled.");
17311     }
17312 
17313     return skip;
17314 }
17315 
PreCallValidateCmdSetDepthWriteEnableEXT(VkCommandBuffer commandBuffer,VkBool32 depthWriteEnable) const17316 bool CoreChecks::PreCallValidateCmdSetDepthWriteEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable) const {
17317     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17318     bool skip = false;
17319     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHWRITEENABLEEXT);
17320 
17321     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17322         skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthWriteEnableEXT-None-03354",
17323                          "vkCmdSetDepthWriteEnableEXT: extendedDynamicState feature is not enabled.");
17324     }
17325 
17326     return skip;
17327 }
17328 
PreCallValidateCmdSetDepthCompareOpEXT(VkCommandBuffer commandBuffer,VkCompareOp depthCompareOp) const17329 bool CoreChecks::PreCallValidateCmdSetDepthCompareOpEXT(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp) const {
17330     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17331     bool skip = false;
17332     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHCOMPAREOPEXT);
17333 
17334     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17335         skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthCompareOpEXT-None-03353",
17336                          "vkCmdSetDepthCompareOpEXT: extendedDynamicState feature is not enabled.");
17337     }
17338 
17339     return skip;
17340 }
17341 
PreCallValidateCmdSetDepthBoundsTestEnableEXT(VkCommandBuffer commandBuffer,VkBool32 depthBoundsTestEnable) const17342 bool CoreChecks::PreCallValidateCmdSetDepthBoundsTestEnableEXT(VkCommandBuffer commandBuffer,
17343                                                                VkBool32 depthBoundsTestEnable) const {
17344     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17345     bool skip = false;
17346     skip |= ValidateCmd(cb_state.get(), CMD_SETDEPTHBOUNDSTESTENABLEEXT);
17347 
17348     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17349         skip |= LogError(commandBuffer, "VUID-vkCmdSetDepthBoundsTestEnableEXT-None-03349",
17350                          "vkCmdSetDepthBoundsTestEnableEXT: extendedDynamicState feature is not enabled.");
17351     }
17352 
17353     return skip;
17354 }
17355 
PreCallValidateCmdSetStencilTestEnableEXT(VkCommandBuffer commandBuffer,VkBool32 stencilTestEnable) const17356 bool CoreChecks::PreCallValidateCmdSetStencilTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable) const {
17357     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17358     bool skip = false;
17359     skip |= ValidateCmd(cb_state.get(), CMD_SETSTENCILTESTENABLEEXT);
17360 
17361     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17362         skip |= LogError(commandBuffer, "VUID-vkCmdSetStencilTestEnableEXT-None-03350",
17363                          "vkCmdSetStencilTestEnableEXT: extendedDynamicState feature is not enabled.");
17364     }
17365 
17366     return skip;
17367 }
17368 
PreCallValidateCmdSetStencilOpEXT(VkCommandBuffer commandBuffer,VkStencilFaceFlags faceMask,VkStencilOp failOp,VkStencilOp passOp,VkStencilOp depthFailOp,VkCompareOp compareOp) const17369 bool CoreChecks::PreCallValidateCmdSetStencilOpEXT(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp,
17370                                                    VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp) const {
17371     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17372     bool skip = false;
17373     skip |= ValidateCmd(cb_state.get(), CMD_SETSTENCILOPEXT);
17374 
17375     if (!enabled_features.extended_dynamic_state_features.extendedDynamicState) {
17376         skip |= LogError(commandBuffer, "VUID-vkCmdSetStencilOpEXT-None-03351",
17377                          "vkCmdSetStencilOpEXT: extendedDynamicState feature is not enabled.");
17378     }
17379 
17380     return skip;
17381 }
17382 
PreCallValidateCreateEvent(VkDevice device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent) const17383 bool CoreChecks::PreCallValidateCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
17384                                             const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) const {
17385     bool skip = false;
17386     if (IsExtEnabled(device_extensions.vk_khr_portability_subset)) {
17387         if (VK_FALSE == enabled_features.portability_subset_features.events) {
17388             skip |= LogError(device, "VUID-vkCreateEvent-events-04468",
17389                              "vkCreateEvent: events are not supported via VK_KHR_portability_subset");
17390         }
17391     }
17392     return skip;
17393 }
17394 
PreCallValidateCmdSetRayTracingPipelineStackSizeKHR(VkCommandBuffer commandBuffer,uint32_t pipelineStackSize) const17395 bool CoreChecks::PreCallValidateCmdSetRayTracingPipelineStackSizeKHR(VkCommandBuffer commandBuffer,
17396                                                                      uint32_t pipelineStackSize) const {
17397     bool skip = false;
17398     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17399     assert(cb_state);
17400     skip |= ValidateCmd(cb_state.get(), CMD_SETRAYTRACINGPIPELINESTACKSIZEKHR);
17401     return skip;
17402 }
17403 
PreCallValidateGetRayTracingShaderGroupStackSizeKHR(VkDevice device,VkPipeline pipeline,uint32_t group,VkShaderGroupShaderKHR groupShader) const17404 bool CoreChecks::PreCallValidateGetRayTracingShaderGroupStackSizeKHR(VkDevice device, VkPipeline pipeline, uint32_t group,
17405                                                                      VkShaderGroupShaderKHR groupShader) const {
17406     bool skip = false;
17407     const auto pipeline_state = Get<PIPELINE_STATE>(pipeline);
17408     if (pipeline_state) {
17409         if (pipeline_state->GetPipelineType() != VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) {
17410             skip |= LogError(device, "VUID-vkGetRayTracingShaderGroupStackSizeKHR-pipeline-04622",
17411                              "vkGetRayTracingShaderGroupStackSizeKHR: Pipeline must be a ray-tracing pipeline, but is a %s pipeline.",
17412                              GetPipelineTypeName(pipeline_state->GetPipelineType()));
17413         } else if (group >= pipeline_state->create_info.raytracing.groupCount) {
17414             skip |=
17415                 LogError(device, "VUID-vkGetRayTracingShaderGroupStackSizeKHR-group-03608",
17416                          "vkGetRayTracingShaderGroupStackSizeKHR: The value of group must be less than the number of shader groups "
17417                          "in pipeline.");
17418         }
17419     }
17420     return skip;
17421 }
17422 
PreCallValidateCmdSetFragmentShadingRateKHR(VkCommandBuffer commandBuffer,const VkExtent2D * pFragmentSize,const VkFragmentShadingRateCombinerOpKHR combinerOps[2]) const17423 bool CoreChecks::PreCallValidateCmdSetFragmentShadingRateKHR(VkCommandBuffer commandBuffer, const VkExtent2D *pFragmentSize,
17424                                                              const VkFragmentShadingRateCombinerOpKHR combinerOps[2]) const {
17425     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17426     assert(cb_state);
17427     const char *cmd_name = "vkCmdSetFragmentShadingRateKHR()";
17428     bool skip = false;
17429     skip |= ValidateCmd(cb_state.get(), CMD_SETFRAGMENTSHADINGRATEKHR);
17430 
17431     if (!enabled_features.fragment_shading_rate_features.pipelineFragmentShadingRate &&
17432         !enabled_features.fragment_shading_rate_features.primitiveFragmentShadingRate &&
17433         !enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate) {
17434         skip |= LogError(
17435             cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pipelineFragmentShadingRate-04509",
17436             "vkCmdSetFragmentShadingRateKHR: Application called %s, but no fragment shading rate features have been enabled.",
17437             cmd_name);
17438     }
17439 
17440     if (!enabled_features.fragment_shading_rate_features.pipelineFragmentShadingRate && pFragmentSize->width != 1) {
17441         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pipelineFragmentShadingRate-04507",
17442                          "vkCmdSetFragmentShadingRateKHR: Pipeline fragment width of %u has been specified in %s, but "
17443                          "pipelineFragmentShadingRate is not enabled",
17444                          pFragmentSize->width, cmd_name);
17445     }
17446 
17447     if (!enabled_features.fragment_shading_rate_features.pipelineFragmentShadingRate && pFragmentSize->height != 1) {
17448         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pipelineFragmentShadingRate-04508",
17449                          "vkCmdSetFragmentShadingRateKHR: Pipeline fragment height of %u has been specified in %s, but "
17450                          "pipelineFragmentShadingRate is not enabled",
17451                          pFragmentSize->height, cmd_name);
17452     }
17453 
17454     if (!enabled_features.fragment_shading_rate_features.primitiveFragmentShadingRate &&
17455         combinerOps[0] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR) {
17456         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-primitiveFragmentShadingRate-04510",
17457                          "vkCmdSetFragmentShadingRateKHR: First combiner operation of %s has been specified in %s, but "
17458                          "primitiveFragmentShadingRate is not enabled",
17459                          string_VkFragmentShadingRateCombinerOpKHR(combinerOps[0]), cmd_name);
17460     }
17461 
17462     if (!enabled_features.fragment_shading_rate_features.attachmentFragmentShadingRate &&
17463         combinerOps[1] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR) {
17464         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-attachmentFragmentShadingRate-04511",
17465                          "vkCmdSetFragmentShadingRateKHR: Second combiner operation of %s has been specified in %s, but "
17466                          "attachmentFragmentShadingRate is not enabled",
17467                          string_VkFragmentShadingRateCombinerOpKHR(combinerOps[1]), cmd_name);
17468     }
17469 
17470     if (!phys_dev_ext_props.fragment_shading_rate_props.fragmentShadingRateNonTrivialCombinerOps &&
17471         (combinerOps[0] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR &&
17472          combinerOps[0] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR)) {
17473         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-fragmentSizeNonTrivialCombinerOps-04512",
17474                          "vkCmdSetFragmentShadingRateKHR: First combiner operation of %s has been specified in %s, but "
17475                          "fragmentShadingRateNonTrivialCombinerOps is "
17476                          "not supported",
17477                          string_VkFragmentShadingRateCombinerOpKHR(combinerOps[0]), cmd_name);
17478     }
17479 
17480     if (!phys_dev_ext_props.fragment_shading_rate_props.fragmentShadingRateNonTrivialCombinerOps &&
17481         (combinerOps[1] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR &&
17482          combinerOps[1] != VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR)) {
17483         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-fragmentSizeNonTrivialCombinerOps-04512",
17484                          "vkCmdSetFragmentShadingRateKHR: Second combiner operation of %s has been specified in %s, but "
17485                          "fragmentShadingRateNonTrivialCombinerOps "
17486                          "is not supported",
17487                          string_VkFragmentShadingRateCombinerOpKHR(combinerOps[1]), cmd_name);
17488     }
17489 
17490     if (pFragmentSize->width == 0) {
17491         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pFragmentSize-04513",
17492                          "vkCmdSetFragmentShadingRateKHR: Fragment width of %u has been specified in %s.", pFragmentSize->width,
17493                          cmd_name);
17494     }
17495 
17496     if (pFragmentSize->height == 0) {
17497         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pFragmentSize-04514",
17498                          "vkCmdSetFragmentShadingRateKHR: Fragment height of %u has been specified in %s.", pFragmentSize->height,
17499                          cmd_name);
17500     }
17501 
17502     if (pFragmentSize->width != 0 && !IsPowerOfTwo(pFragmentSize->width)) {
17503         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pFragmentSize-04515",
17504                          "vkCmdSetFragmentShadingRateKHR: Non-power-of-two fragment width of %u has been specified in %s.",
17505                          pFragmentSize->width, cmd_name);
17506     }
17507 
17508     if (pFragmentSize->height != 0 && !IsPowerOfTwo(pFragmentSize->height)) {
17509         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pFragmentSize-04516",
17510                          "vkCmdSetFragmentShadingRateKHR: Non-power-of-two fragment height of %u has been specified in %s.",
17511                          pFragmentSize->height, cmd_name);
17512     }
17513 
17514     if (pFragmentSize->width > 4) {
17515         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pFragmentSize-04517",
17516                          "vkCmdSetFragmentShadingRateKHR: Fragment width of %u specified in %s is too large.", pFragmentSize->width,
17517                          cmd_name);
17518     }
17519 
17520     if (pFragmentSize->height > 4) {
17521         skip |= LogError(cb_state->commandBuffer(), "VUID-vkCmdSetFragmentShadingRateKHR-pFragmentSize-04518",
17522                          "vkCmdSetFragmentShadingRateKHR: Fragment height of %u specified in %s is too large",
17523                          pFragmentSize->height, cmd_name);
17524     }
17525     return skip;
17526 }
17527 
PreCallValidateCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer,uint32_t attachmentCount,const VkBool32 * pColorWriteEnables) const17528 bool CoreChecks::PreCallValidateCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
17529                                                           const VkBool32 *pColorWriteEnables) const {
17530     bool skip = false;
17531 
17532     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17533 
17534     if (!enabled_features.color_write_features.colorWriteEnable) {
17535         skip |= LogError(commandBuffer, "VUID-vkCmdSetColorWriteEnableEXT-None-04803",
17536                          "vkCmdSetColorWriteEnableEXT: color write is not enabled.");
17537     }
17538     auto graphics_pipeline = cb_state->GetCurrentPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS);
17539     if (graphics_pipeline) {
17540         uint32_t pipeline_attachment_count = graphics_pipeline->create_info.graphics.pColorBlendState->attachmentCount;
17541         if (attachmentCount != pipeline_attachment_count) {
17542             skip |= LogError(
17543                 commandBuffer, "VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-04804",
17544                 "vkCmdSetColorWriteEnableEXT: attachment count (%" PRIu32
17545                 ") is not equal to currenly bound pipelines VkPipelineColorBlendStateCreateInfo::attachmentCount (%" PRIu32 ").",
17546                 attachmentCount, pipeline_attachment_count);
17547         }
17548     }
17549 
17550     return skip;
17551 }
17552 
PreCallValidateCmdBeginConditionalRenderingEXT(VkCommandBuffer commandBuffer,const VkConditionalRenderingBeginInfoEXT * pConditionalRenderingBegin) const17553 bool CoreChecks::PreCallValidateCmdBeginConditionalRenderingEXT(
17554     VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT *pConditionalRenderingBegin) const {
17555     bool skip = false;
17556 
17557     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17558     if (cb_state && cb_state->conditional_rendering_active) {
17559         skip |= LogError(commandBuffer, "VUID-vkCmdBeginConditionalRenderingEXT-None-01980",
17560                          "vkCmdBeginConditionalRenderingEXT(): Conditional rendering is already active.");
17561     }
17562 
17563     if (pConditionalRenderingBegin) {
17564         const auto buffer_state = Get<BUFFER_STATE>(pConditionalRenderingBegin->buffer);
17565         if (buffer_state) {
17566             if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT) == 0) {
17567                 skip |= LogError(commandBuffer, "VUID-VkConditionalRenderingBeginInfoEXT-buffer-01982",
17568                                  "vkCmdBeginConditionalRenderingEXT(): pConditionalRenderingBegin->buffer (%s) was not create with "
17569                                  "VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT bit.",
17570                                  report_data->FormatHandle(pConditionalRenderingBegin->buffer).c_str());
17571             }
17572             if (pConditionalRenderingBegin->offset + 4 > buffer_state->createInfo.size) {
17573                 skip |= LogError(commandBuffer, "VUID-VkConditionalRenderingBeginInfoEXT-offset-01983",
17574                                  "vkCmdBeginConditionalRenderingEXT(): pConditionalRenderingBegin->offset (%" PRIu64
17575                                  ") + 4 bytes is not less than the size of pConditionalRenderingBegin->buffer (%" PRIu64 ").",
17576                                  pConditionalRenderingBegin->offset, buffer_state->createInfo.size);
17577             }
17578         }
17579     }
17580 
17581     return skip;
17582 }
17583 
PreCallValidateCmdEndConditionalRenderingEXT(VkCommandBuffer commandBuffer) const17584 bool CoreChecks::PreCallValidateCmdEndConditionalRenderingEXT(VkCommandBuffer commandBuffer) const {
17585     bool skip = false;
17586 
17587     const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
17588     if (cb_state) {
17589         if (!cb_state->conditional_rendering_active) {
17590             skip |= LogError(commandBuffer, "VUID-vkCmdEndConditionalRenderingEXT-None-01985",
17591                              "vkCmdBeginConditionalRenderingEXT(): Conditional rendering is not active.");
17592         }
17593         if (!cb_state->conditional_rendering_inside_render_pass && cb_state->activeRenderPass != nullptr) {
17594             skip |= LogError(commandBuffer, "VUID-vkCmdEndConditionalRenderingEXT-None-01986",
17595                              "vkCmdBeginConditionalRenderingEXT(): Conditional rendering was begun outside outside of a render "
17596                              "pass instance, but a render pass instance is currently active in the command buffer.");
17597         }
17598         if (cb_state->conditional_rendering_inside_render_pass && cb_state->activeRenderPass != nullptr &&
17599             cb_state->conditional_rendering_subpass != cb_state->activeSubpass) {
17600             skip |= LogError(commandBuffer, "VUID-vkCmdEndConditionalRenderingEXT-None-01987",
17601                              "vkCmdBeginConditionalRenderingEXT(): Conditional rendering was begun in subpass %" PRIu32
17602                              ", but the current subpass is %" PRIu32 ".",
17603                              cb_state->conditional_rendering_subpass, cb_state->activeSubpass);
17604         }
17605     }
17606 
17607     return skip;
17608 }
17609 
17610 #ifdef VK_USE_PLATFORM_WIN32_KHR
PreCallValidateAcquireFullScreenExclusiveModeEXT(VkDevice device,VkSwapchainKHR swapchain) const17611 bool CoreChecks::PreCallValidateAcquireFullScreenExclusiveModeEXT(VkDevice device, VkSwapchainKHR swapchain) const {
17612     bool skip = false;
17613 
17614     const auto swapchain_state = Get<SWAPCHAIN_NODE>(swapchain);
17615     if (swapchain_state) {
17616         if (swapchain_state->retired) {
17617             skip |= LogError(device, "VUID-vkAcquireFullScreenExclusiveModeEXT-swapchain-02674",
17618                              "vkAcquireFullScreenExclusiveModeEXT(): swapchain %s is retired.",
17619                              report_data->FormatHandle(swapchain).c_str());
17620         }
17621         const auto *surface_full_screen_exclusive_info = LvlFindInChain<VkSurfaceFullScreenExclusiveInfoEXT>(swapchain_state->createInfo.pNext);
17622         if (!surface_full_screen_exclusive_info ||
17623             surface_full_screen_exclusive_info->fullScreenExclusive != VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT) {
17624             skip |= LogError(device, "VUID-vkAcquireFullScreenExclusiveModeEXT-swapchain-02675",
17625                 "vkAcquireFullScreenExclusiveModeEXT(): swapchain %s was not created with VkSurfaceFullScreenExclusiveInfoEXT in "
17626                 "the pNext chain with fullScreenExclusive equal to VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT.",
17627                 report_data->FormatHandle(swapchain).c_str());
17628         }
17629     }
17630 
17631     return skip;
17632 }
17633 #endif
17634 
ValidatePhysicalDeviceSurfaceSupport(VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,const char * vuid,const char * func_name) const17635 bool CoreChecks::ValidatePhysicalDeviceSurfaceSupport(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, const char *vuid,
17636                                                       const char *func_name) const {
17637     bool skip = false;
17638 
17639     const auto pd_state = Get<PHYSICAL_DEVICE_STATE>(physicalDevice);
17640     const auto surface_state = Get<SURFACE_STATE>(surface);
17641     if (pd_state && surface_state) {
17642         bool is_supported = false;
17643         for (uint32_t i = 0; i < pd_state->queue_family_properties.size(); i++) {
17644             if (surface_state->GetQueueSupport(physicalDevice, i)) {
17645                 is_supported = true;
17646                 break;
17647             }
17648         }
17649         if (!is_supported) {
17650             skip |= LogError(physicalDevice, vuid, "%s(): surface is not supported by the physicalDevice.", func_name);
17651         }
17652     }
17653 
17654     return skip;
17655 }
17656 
17657 #ifdef VK_USE_PLATFORM_WIN32_KHR
17658 
PreCallValidateGetDeviceGroupSurfacePresentModes2EXT(VkDevice device,const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo,VkDeviceGroupPresentModeFlagsKHR * pModes) const17659 bool CoreChecks::PreCallValidateGetDeviceGroupSurfacePresentModes2EXT(VkDevice device,
17660                                                                       const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
17661                                                                       VkDeviceGroupPresentModeFlagsKHR *pModes) const {
17662     bool skip = false;
17663 
17664     if (physical_device_count == 1) {
17665         ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
17666         skip |= ValidatePhysicalDeviceSurfaceSupport(device_object->physical_device, pSurfaceInfo->surface,
17667                                                      "VUID-vkGetDeviceGroupSurfacePresentModes2EXT-pSurfaceInfo-06213",
17668                                                      "vkGetDeviceGroupSurfacePresentModes2EXT");
17669     } else {
17670         for (uint32_t i = 0; i < physical_device_count; ++i) {
17671             skip |= ValidatePhysicalDeviceSurfaceSupport(device_group_create_info.pPhysicalDevices[i], pSurfaceInfo->surface,
17672                                                          "VUID-vkGetDeviceGroupSurfacePresentModes2EXT-pSurfaceInfo-06213",
17673                                                          "vkGetDeviceGroupSurfacePresentModes2EXT");
17674         }
17675     }
17676 
17677     return skip;
17678 }
17679 
PreCallValidateGetPhysicalDeviceSurfacePresentModes2EXT(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo,uint32_t * pPresentModeCount,VkPresentModeKHR * pPresentModes) const17680 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfacePresentModes2EXT(VkPhysicalDevice physicalDevice,
17681                                                                          const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
17682                                                                          uint32_t *pPresentModeCount,
17683                                                                          VkPresentModeKHR *pPresentModes) const {
17684     bool skip = false;
17685 
17686     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, pSurfaceInfo->surface,
17687                                                  "VUID-vkGetPhysicalDeviceSurfacePresentModes2EXT-pSurfaceInfo-06210",
17688                                                  "vkGetPhysicalDeviceSurfacePresentModes2EXT");
17689 
17690     return skip;
17691 }
17692 
17693 #endif
17694 
PreCallValidateGetDeviceGroupSurfacePresentModesKHR(VkDevice device,VkSurfaceKHR surface,VkDeviceGroupPresentModeFlagsKHR * pModes) const17695 bool CoreChecks::PreCallValidateGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface,
17696                                                                      VkDeviceGroupPresentModeFlagsKHR *pModes) const {
17697     bool skip = false;
17698 
17699     if (physical_device_count == 1) {
17700         ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
17701         skip |= ValidatePhysicalDeviceSurfaceSupport(device_object->physical_device, surface,
17702                                                      "VUID-vkGetDeviceGroupSurfacePresentModesKHR-surface-06212",
17703                                                      "vkGetDeviceGroupSurfacePresentModesKHR");
17704     } else {
17705         for (uint32_t i = 0; i < physical_device_count; ++i) {
17706             skip |= ValidatePhysicalDeviceSurfaceSupport(device_group_create_info.pPhysicalDevices[i], surface,
17707                                                          "VUID-vkGetDeviceGroupSurfacePresentModesKHR-surface-06212",
17708                                                          "vkGetDeviceGroupSurfacePresentModesKHR");
17709         }
17710     }
17711 
17712     return skip;
17713 }
17714 
PreCallValidateGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,uint32_t * pRectCount,VkRect2D * pRects) const17715 bool CoreChecks::PreCallValidateGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
17716                                                                       uint32_t *pRectCount, VkRect2D *pRects) const {
17717     bool skip = false;
17718 
17719     skip |=
17720         ValidatePhysicalDeviceSurfaceSupport(physicalDevice, surface, "VUID-vkGetPhysicalDevicePresentRectanglesKHR-surface-06211",
17721                                              "vkGetPhysicalDevicePresentRectanglesKHR");
17722 
17723     return skip;
17724 }
17725 
PreCallValidateGetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkSurfaceCapabilities2EXT * pSurfaceCapabilities) const17726 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
17727                                                                          VkSurfaceCapabilities2EXT *pSurfaceCapabilities) const {
17728     bool skip = false;
17729 
17730     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, surface,
17731                                                  "VUID-vkGetPhysicalDeviceSurfaceCapabilities2EXT-surface-06211",
17732                                                  "vkGetPhysicalDeviceSurfaceCapabilities2EXT");
17733 
17734     return skip;
17735 }
17736 
PreCallValidateGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo,VkSurfaceCapabilities2KHR * pSurfaceCapabilities) const17737 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
17738                                                                          const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
17739                                                                          VkSurfaceCapabilities2KHR *pSurfaceCapabilities) const {
17740     bool skip = false;
17741 
17742     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, pSurfaceInfo->surface,
17743                                                  "VUID-vkGetPhysicalDeviceSurfaceCapabilities2KHR-pSurfaceInfo-06210",
17744                                                  "vkGetPhysicalDeviceSurfaceCapabilities2KHR");
17745 
17746     return skip;
17747 }
17748 
PreCallValidateGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkSurfaceCapabilitiesKHR * pSurfaceCapabilities) const17749 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
17750                                                                         VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const {
17751     bool skip = false;
17752 
17753     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, surface,
17754                                                  "VUID-vkGetPhysicalDeviceSurfaceCapabilitiesKHR-surface-06211",
17755                                                  "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
17756 
17757     return skip;
17758 }
17759 
PreCallValidateGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo,uint32_t * pSurfaceFormatCount,VkSurfaceFormat2KHR * pSurfaceFormats) const17760 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
17761                                                                     const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
17762                                                                     uint32_t *pSurfaceFormatCount,
17763                                                                     VkSurfaceFormat2KHR *pSurfaceFormats) const {
17764     bool skip = false;
17765 
17766     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, pSurfaceInfo->surface,
17767                                                  "VUID-vkGetPhysicalDeviceSurfaceFormats2KHR-pSurfaceInfo-06210",
17768                                                  "vkGetPhysicalDeviceSurfaceFormats2KHR");
17769 
17770     return skip;
17771 }
17772 
PreCallValidateGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,uint32_t * pSurfaceFormatCount,VkSurfaceFormatKHR * pSurfaceFormats) const17773 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
17774                                                                    uint32_t *pSurfaceFormatCount,
17775                                                                    VkSurfaceFormatKHR *pSurfaceFormats) const {
17776     bool skip = false;
17777 
17778     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, surface, "VUID-vkGetPhysicalDeviceSurfaceFormatsKHR-surface-06211",
17779                                                  "vkGetPhysicalDeviceSurfaceFormatsKHR");
17780 
17781     return skip;
17782 }
17783 
PreCallValidateGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,uint32_t * pPresentModeCount,VkPresentModeKHR * pPresentModes) const17784 bool CoreChecks::PreCallValidateGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
17785                                                                         uint32_t *pPresentModeCount,
17786                                                                         VkPresentModeKHR *pPresentModes) const {
17787     bool skip = false;
17788 
17789     skip |= ValidatePhysicalDeviceSurfaceSupport(physicalDevice, surface,
17790                                                  "VUID-vkGetPhysicalDeviceSurfacePresentModesKHR-surface-06211",
17791                                                  "vkGetPhysicalDeviceSurfacePresentModesKHR");
17792 
17793     return skip;
17794 }
17795 
PostCallRecordGetQueryPoolResults(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,size_t dataSize,void * pData,VkDeviceSize stride,VkQueryResultFlags flags,VkResult result)17796 void CoreChecks::PostCallRecordGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
17797                                                    size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags,
17798                                                    VkResult result) {
17799     if (result != VK_SUCCESS) {
17800         return;
17801     }
17802     const auto query_pool_state = Get<QUERY_POOL_STATE>(queryPool);
17803     if ((flags & VK_QUERY_RESULT_PARTIAL_BIT) == 0) {
17804         for (uint32_t i = firstQuery; i < queryCount; ++i) {
17805             query_pool_state->SetQueryState(i, 0, QUERYSTATE_AVAILABLE);
17806         }
17807     }
17808 }
17809