blob: 2cadc6286a864a64e5f4a0b3fc149514876eace3 [file] [log] [blame]
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001/* Copyright (c) 2015-2016 The Khronos Group Inc.
2 * Copyright (c) 2015-2016 Valve Corporation
3 * Copyright (c) 2015-2016 LunarG, Inc.
4 * Copyright (C) 2015-2016 Google Inc.
5 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06006 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060010 * http://www.apache.org/licenses/LICENSE-2.0
Tobin Ehlisc96f8062016-03-09 16:12:48 -070011 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060012 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
Tobin Ehlisc96f8062016-03-09 16:12:48 -070017 *
18 * Author: Cody Northrop <cnorthrop@google.com>
19 * Author: Michael Lentine <mlentine@google.com>
20 * Author: Tobin Ehlis <tobine@google.com>
21 * Author: Chia-I Wu <olv@google.com>
22 * Author: Chris Forbes <chrisf@ijw.co.nz>
23 * Author: Mark Lobodzinski <mark@lunarg.com>
24 * Author: Ian Elliott <ianelliott@google.com>
25 */
26
27// Allow use of STL min and max functions in Windows
28#define NOMINMAX
29
30// Turn on mem_tracker merged code
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -060031#define MTMERGESOURCE 1
Tobin Ehlisc96f8062016-03-09 16:12:48 -070032
Tobin Ehlisf263ba42016-04-05 13:33:00 -060033#include <SPIRV/spirv.hpp>
34#include <algorithm>
35#include <assert.h>
36#include <iostream>
37#include <list>
38#include <map>
Jeremy Hayesda8797f2016-04-13 16:20:24 -060039#include <mutex>
Tobin Ehlisf263ba42016-04-05 13:33:00 -060040#include <set>
Tobin Ehlisc96f8062016-03-09 16:12:48 -070041#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
Tobin Ehlisf263ba42016-04-05 13:33:00 -060044#include <string>
Tobin Ehlisc96f8062016-03-09 16:12:48 -070045#include <unordered_map>
46#include <unordered_set>
Tobin Ehlisc96f8062016-03-09 16:12:48 -070047
48#include "vk_loader_platform.h"
49#include "vk_dispatch_table_helper.h"
50#include "vk_struct_string_helper_cpp.h"
51#if defined(__GNUC__)
52#pragma GCC diagnostic ignored "-Wwrite-strings"
53#endif
54#if defined(__GNUC__)
55#pragma GCC diagnostic warning "-Wwrite-strings"
56#endif
57#include "vk_struct_size_helper.h"
Tobin Ehlisc96f8062016-03-09 16:12:48 -070058#include "core_validation.h"
Tobin Ehlisc96f8062016-03-09 16:12:48 -070059#include "vk_layer_table.h"
60#include "vk_layer_data.h"
Tobin Ehlisc96f8062016-03-09 16:12:48 -070061#include "vk_layer_extension_utils.h"
62#include "vk_layer_utils.h"
Chris Forbesb4afd0f2016-04-04 10:48:35 +120063#include "spirv-tools/libspirv.h"
Tobin Ehlisc96f8062016-03-09 16:12:48 -070064
65#if defined __ANDROID__
66#include <android/log.h>
67#define LOGCONSOLE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "DS", __VA_ARGS__))
68#else
69#define LOGCONSOLE(...) printf(__VA_ARGS__)
70#endif
71
72using std::unordered_map;
73using std::unordered_set;
74
Tobin Ehlisc96f8062016-03-09 16:12:48 -070075// WSI Image Objects bypass usual Image Object creation methods. A special Memory
76// Object value will be used to identify them internally.
77static const VkDeviceMemory MEMTRACKER_SWAP_CHAIN_IMAGE_KEY = (VkDeviceMemory)(-1);
Tobin Ehlise54be7b2016-04-11 14:49:55 -060078
Tobin Ehlisc96f8062016-03-09 16:12:48 -070079// Track command pools and their command buffers
80struct CMD_POOL_INFO {
81 VkCommandPoolCreateFlags createFlags;
82 uint32_t queueFamilyIndex;
83 list<VkCommandBuffer> commandBuffers; // list container of cmd buffers allocated from this pool
84};
85
86struct devExts {
Dustin Graves8f1eab92016-04-05 09:41:17 -060087 bool wsi_enabled;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070088 unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> swapchainMap;
89 unordered_map<VkImage, VkSwapchainKHR> imageToSwapchainMap;
90};
91
92// fwd decls
93struct shader_module;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070094
Tobin Ehlise54be7b2016-04-11 14:49:55 -060095// TODO : Split this into separate structs for instance and device level data?
Tobin Ehlisc96f8062016-03-09 16:12:48 -070096struct layer_data {
97 debug_report_data *report_data;
98 std::vector<VkDebugReportCallbackEXT> logging_callback;
99 VkLayerDispatchTable *device_dispatch_table;
100 VkLayerInstanceDispatchTable *instance_dispatch_table;
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600101
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700102 devExts device_extensions;
Mark Lobodzinski600e93d2016-03-29 09:49:15 -0600103 unordered_set<VkQueue> queues; // all queues under given device
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700104 // Global set of all cmdBuffers that are inFlight on this device
105 unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
106 // Layer specific data
107 unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap;
108 unordered_map<VkImageView, VkImageViewCreateInfo> imageViewMap;
109 unordered_map<VkImage, IMAGE_NODE> imageMap;
110 unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap;
111 unordered_map<VkBuffer, BUFFER_NODE> bufferMap;
112 unordered_map<VkPipeline, PIPELINE_NODE *> pipelineMap;
113 unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap;
114 unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap;
115 unordered_map<VkDescriptorSet, SET_NODE *> setMap;
Tobin Ehlis546326f2016-04-26 11:06:05 -0600116 unordered_map<VkDescriptorSetLayout, DescriptorSetLayout *> descriptorSetLayoutMap;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700117 unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600118 unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700119 unordered_map<VkFence, FENCE_NODE> fenceMap;
120 unordered_map<VkQueue, QUEUE_NODE> queueMap;
121 unordered_map<VkEvent, EVENT_NODE> eventMap;
122 unordered_map<QueryObject, bool> queryToStateMap;
123 unordered_map<VkQueryPool, QUERY_POOL_NODE> queryPoolMap;
124 unordered_map<VkSemaphore, SEMAPHORE_NODE> semaphoreMap;
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600125 unordered_map<VkCommandBuffer, GLOBAL_CB_NODE *> commandBufferMap;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700126 unordered_map<VkFramebuffer, FRAMEBUFFER_NODE> frameBufferMap;
127 unordered_map<VkImage, vector<ImageSubresourcePair>> imageSubresourceMap;
128 unordered_map<ImageSubresourcePair, IMAGE_LAYOUT_NODE> imageLayoutMap;
129 unordered_map<VkRenderPass, RENDER_PASS_NODE *> renderPassMap;
Chris Forbes90da2e92016-03-18 16:30:03 +1300130 unordered_map<VkShaderModule, unique_ptr<shader_module>> shaderModuleMap;
Chris Forbes15864502016-03-30 11:35:21 +1300131 VkDevice device;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700132
133 // Device specific data
Tobin Ehlise54be7b2016-04-11 14:49:55 -0600134 PHYS_DEV_PROPERTIES_NODE phys_dev_properties;
135 VkPhysicalDeviceMemoryProperties phys_dev_mem_props;
136
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700137 layer_data()
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600138 : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), device_extensions(),
Tobin Ehlisaff7ae92016-04-18 15:45:20 -0600139 device(VK_NULL_HANDLE), phys_dev_properties{}, phys_dev_mem_props{} {};
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700140};
141
Tobin Ehlise54be7b2016-04-11 14:49:55 -0600142// TODO : Do we need to guard access to layer_data_map w/ lock?
143static unordered_map<void *, layer_data *> layer_data_map;
144
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700145static const VkLayerProperties cv_global_layers[] = {{
Jon Ashburndc9111c2016-03-22 12:57:13 -0600146 "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700147}};
148
149template <class TCreateInfo> void ValidateLayerOrdering(const TCreateInfo &createInfo) {
150 bool foundLayer = false;
151 for (uint32_t i = 0; i < createInfo.enabledLayerCount; ++i) {
152 if (!strcmp(createInfo.ppEnabledLayerNames[i], cv_global_layers[0].layerName)) {
153 foundLayer = true;
154 }
155 // This has to be logged to console as we don't have a callback at this point.
156 if (!foundLayer && !strcmp(createInfo.ppEnabledLayerNames[0], "VK_LAYER_GOOGLE_unique_objects")) {
157 LOGCONSOLE("Cannot activate layer VK_LAYER_GOOGLE_unique_objects prior to activating %s.",
158 cv_global_layers[0].layerName);
159 }
160 }
161}
162
163// Code imported from shader_checker
164static void build_def_index(shader_module *);
165
166// A forward iterator over spirv instructions. Provides easy access to len, opcode, and content words
167// without the caller needing to care too much about the physical SPIRV module layout.
168struct spirv_inst_iter {
169 std::vector<uint32_t>::const_iterator zero;
170 std::vector<uint32_t>::const_iterator it;
171
172 uint32_t len() { return *it >> 16; }
173 uint32_t opcode() { return *it & 0x0ffffu; }
174 uint32_t const &word(unsigned n) { return it[n]; }
175 uint32_t offset() { return (uint32_t)(it - zero); }
176
177 spirv_inst_iter() {}
178
179 spirv_inst_iter(std::vector<uint32_t>::const_iterator zero, std::vector<uint32_t>::const_iterator it) : zero(zero), it(it) {}
180
181 bool operator==(spirv_inst_iter const &other) { return it == other.it; }
182
183 bool operator!=(spirv_inst_iter const &other) { return it != other.it; }
184
185 spirv_inst_iter operator++(int) { /* x++ */
186 spirv_inst_iter ii = *this;
187 it += len();
188 return ii;
189 }
190
191 spirv_inst_iter operator++() { /* ++x; */
192 it += len();
193 return *this;
194 }
195
196 /* The iterator and the value are the same thing. */
197 spirv_inst_iter &operator*() { return *this; }
198 spirv_inst_iter const &operator*() const { return *this; }
199};
200
201struct shader_module {
202 /* the spirv image itself */
203 vector<uint32_t> words;
204 /* a mapping of <id> to the first word of its def. this is useful because walking type
205 * trees, constant expressions, etc requires jumping all over the instruction stream.
206 */
207 unordered_map<unsigned, unsigned> def_index;
208
209 shader_module(VkShaderModuleCreateInfo const *pCreateInfo)
210 : words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)),
211 def_index() {
212
213 build_def_index(this);
214 }
215
216 /* expose begin() / end() to enable range-based for */
217 spirv_inst_iter begin() const { return spirv_inst_iter(words.begin(), words.begin() + 5); } /* first insn */
218 spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); } /* just past last insn */
219 /* given an offset into the module, produce an iterator there. */
220 spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
221
222 /* gets an iterator to the definition of an id */
223 spirv_inst_iter get_def(unsigned id) const {
224 auto it = def_index.find(id);
225 if (it == def_index.end()) {
226 return end();
227 }
228 return at(it->second);
229 }
230};
231
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700232// TODO : This can be much smarter, using separate locks for separate global data
Jeremy Hayesda8797f2016-04-13 16:20:24 -0600233static std::mutex global_lock;
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -0600234#if MTMERGESOURCE
235// MTMERGESOURCE - start of direct pull
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600236static VkDeviceMemory *get_object_mem_binding(layer_data *my_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700237 switch (type) {
238 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600239 auto it = my_data->imageMap.find(VkImage(handle));
240 if (it != my_data->imageMap.end())
241 return &(*it).second.mem;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700242 break;
243 }
244 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600245 auto it = my_data->bufferMap.find(VkBuffer(handle));
246 if (it != my_data->bufferMap.end())
247 return &(*it).second.mem;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700248 break;
249 }
250 default:
251 break;
252 }
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600253 return nullptr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700254}
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -0600255// MTMERGESOURCE - end section
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700256#endif
257template layer_data *get_my_data_ptr<layer_data>(void *data_key, std::unordered_map<void *, layer_data *> &data_map);
258
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600259// prototype
260static GLOBAL_CB_NODE *getCBNode(layer_data *, const VkCommandBuffer);
261
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -0600262#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700263// Helper function to validate correct usage bits set for buffers or images
264// Verify that (actual & desired) flags != 0 or,
265// if strict is true, verify that (actual & desired) flags == desired
266// In case of error, report it via dbg callbacks
Chris Forbes73b82b12016-04-06 15:16:26 +1200267static bool validate_usage_flags(layer_data *my_data, VkFlags actual, VkFlags desired, VkBool32 strict,
268 uint64_t obj_handle, VkDebugReportObjectTypeEXT obj_type, char const *ty_str,
269 char const *func_name, char const *usage_str) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600270 bool correct_usage = false;
271 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700272 if (strict)
273 correct_usage = ((actual & desired) == desired);
274 else
275 correct_usage = ((actual & desired) != 0);
276 if (!correct_usage) {
277 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, obj_type, obj_handle, __LINE__,
278 MEMTRACK_INVALID_USAGE_FLAG, "MEM", "Invalid usage flag for %s %#" PRIxLEAST64
279 " used by %s. In this case, %s should have %s set during creation.",
280 ty_str, obj_handle, func_name, ty_str, usage_str);
281 }
282 return skipCall;
283}
284
285// Helper function to validate usage flags for images
286// Pulls image info and then sends actual vs. desired usage off to helper above where
287// an error will be flagged if usage is not correct
Chris Forbes73b82b12016-04-06 15:16:26 +1200288static bool validate_image_usage_flags(layer_data *dev_data, VkImage image, VkFlags desired, VkBool32 strict,
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600289 char const *func_name, char const *usage_string) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600290 bool skipCall = false;
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600291 auto const image_node = dev_data->imageMap.find(image);
292 if (image_node != dev_data->imageMap.end()) {
Chris Forbes73b82b12016-04-06 15:16:26 +1200293 skipCall = validate_usage_flags(dev_data, image_node->second.createInfo.usage, desired, strict, (uint64_t)image,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700294 VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "image", func_name, usage_string);
295 }
296 return skipCall;
297}
298
299// Helper function to validate usage flags for buffers
300// Pulls buffer info and then sends actual vs. desired usage off to helper above where
301// an error will be flagged if usage is not correct
Chris Forbes73b82b12016-04-06 15:16:26 +1200302static bool validate_buffer_usage_flags(layer_data *dev_data, VkBuffer buffer, VkFlags desired, VkBool32 strict,
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600303 char const *func_name, char const *usage_string) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600304 bool skipCall = false;
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600305 auto const buffer_node = dev_data->bufferMap.find(buffer);
306 if (buffer_node != dev_data->bufferMap.end()) {
Chris Forbes73b82b12016-04-06 15:16:26 +1200307 skipCall = validate_usage_flags(dev_data, buffer_node->second.createInfo.usage, desired, strict, (uint64_t)buffer,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700308 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "buffer", func_name, usage_string);
309 }
310 return skipCall;
311}
312
313// Return ptr to info in map container containing mem, or NULL if not found
314// Calls to this function should be wrapped in mutex
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600315static DEVICE_MEM_INFO *get_mem_obj_info(layer_data *dev_data, const VkDeviceMemory mem) {
316 auto item = dev_data->memObjMap.find(mem);
317 if (item != dev_data->memObjMap.end()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700318 return &(*item).second;
319 } else {
320 return NULL;
321 }
322}
323
324static void add_mem_obj_info(layer_data *my_data, void *object, const VkDeviceMemory mem,
325 const VkMemoryAllocateInfo *pAllocateInfo) {
326 assert(object != NULL);
327
328 memcpy(&my_data->memObjMap[mem].allocInfo, pAllocateInfo, sizeof(VkMemoryAllocateInfo));
329 // TODO: Update for real hardware, actually process allocation info structures
330 my_data->memObjMap[mem].allocInfo.pNext = NULL;
331 my_data->memObjMap[mem].object = object;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700332 my_data->memObjMap[mem].mem = mem;
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600333 my_data->memObjMap[mem].image = VK_NULL_HANDLE;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700334 my_data->memObjMap[mem].memRange.offset = 0;
335 my_data->memObjMap[mem].memRange.size = 0;
336 my_data->memObjMap[mem].pData = 0;
337 my_data->memObjMap[mem].pDriverData = 0;
338 my_data->memObjMap[mem].valid = false;
339}
340
Dustin Graves8f1eab92016-04-05 09:41:17 -0600341static bool validate_memory_is_valid(layer_data *dev_data, VkDeviceMemory mem, const char *functionName,
342 VkImage image = VK_NULL_HANDLE) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700343 if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600344 auto const image_node = dev_data->imageMap.find(image);
345 if (image_node != dev_data->imageMap.end() && !image_node->second.valid) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600346 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700347 (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
348 "%s: Cannot read invalid swapchain image %" PRIx64 ", please fill the memory before using.",
349 functionName, (uint64_t)(image));
350 }
351 } else {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600352 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700353 if (pMemObj && !pMemObj->valid) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600354 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700355 (uint64_t)(mem), __LINE__, MEMTRACK_INVALID_USAGE_FLAG, "MEM",
356 "%s: Cannot read invalid memory %" PRIx64 ", please fill the memory before using.", functionName,
357 (uint64_t)(mem));
358 }
359 }
360 return false;
361}
362
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600363static void set_memory_valid(layer_data *dev_data, VkDeviceMemory mem, bool valid, VkImage image = VK_NULL_HANDLE) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700364 if (mem == MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600365 auto image_node = dev_data->imageMap.find(image);
366 if (image_node != dev_data->imageMap.end()) {
367 image_node->second.valid = valid;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700368 }
369 } else {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600370 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700371 if (pMemObj) {
372 pMemObj->valid = valid;
373 }
374 }
375}
376
377// Find CB Info and add mem reference to list container
378// Find Mem Obj Info and add CB reference to list container
Dustin Graves8f1eab92016-04-05 09:41:17 -0600379static bool update_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb, const VkDeviceMemory mem,
380 const char *apiName) {
381 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700382
383 // Skip validation if this image was created through WSI
384 if (mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
385
386 // First update CB binding in MemObj mini CB list
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600387 DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700388 if (pMemInfo) {
Chris Forbesa11561f2016-03-31 17:58:13 +1300389 pMemInfo->commandBufferBindings.insert(cb);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700390 // Now update CBInfo's Mem reference list
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600391 GLOBAL_CB_NODE *pCBNode = getCBNode(dev_data, cb);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700392 // TODO: keep track of all destroyed CBs so we know if this is a stale or simply invalid object
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600393 if (pCBNode) {
Chris Forbese6625b12016-03-31 18:11:28 +1300394 pCBNode->memObjs.insert(mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700395 }
396 }
397 }
398 return skipCall;
399}
Tobin Ehlis4c522322016-04-11 16:39:29 -0600400// For every mem obj bound to particular CB, free bindings related to that CB
401static void clear_cmd_buf_and_mem_references(layer_data *dev_data, GLOBAL_CB_NODE *pCBNode) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600402 if (pCBNode) {
Chris Forbese6625b12016-03-31 18:11:28 +1300403 if (pCBNode->memObjs.size() > 0) {
404 for (auto mem : pCBNode->memObjs) {
Chris Forbes557de482016-03-31 18:03:56 +1300405 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700406 if (pInfo) {
Tobin Ehlis4c522322016-04-11 16:39:29 -0600407 pInfo->commandBufferBindings.erase(pCBNode->commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700408 }
409 }
Chris Forbese6625b12016-03-31 18:11:28 +1300410 pCBNode->memObjs.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700411 }
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600412 pCBNode->validate_functions.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700413 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700414}
Tobin Ehlis4c522322016-04-11 16:39:29 -0600415// Overloaded call to above function when GLOBAL_CB_NODE has not already been looked-up
416static void clear_cmd_buf_and_mem_references(layer_data *dev_data, const VkCommandBuffer cb) {
417 clear_cmd_buf_and_mem_references(dev_data, getCBNode(dev_data, cb));
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700418}
419
420// For given MemObjInfo, report Obj & CB bindings
Dustin Graves8f1eab92016-04-05 09:41:17 -0600421static bool reportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) {
422 bool skipCall = false;
Chris Forbesa11561f2016-03-31 17:58:13 +1300423 size_t cmdBufRefCount = pMemObjInfo->commandBufferBindings.size();
Chris Forbes2dbf8072016-03-31 17:37:36 +1300424 size_t objRefCount = pMemObjInfo->objBindings.size();
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700425
Chris Forbesa11561f2016-03-31 17:58:13 +1300426 if ((pMemObjInfo->commandBufferBindings.size()) != 0) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600427 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700428 (uint64_t)pMemObjInfo->mem, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM",
429 "Attempting to free memory object %#" PRIxLEAST64 " which still contains " PRINTF_SIZE_T_SPECIFIER
430 " references",
431 (uint64_t)pMemObjInfo->mem, (cmdBufRefCount + objRefCount));
432 }
433
Chris Forbesa11561f2016-03-31 17:58:13 +1300434 if (cmdBufRefCount > 0 && pMemObjInfo->commandBufferBindings.size() > 0) {
435 for (auto cb : pMemObjInfo->commandBufferBindings) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600436 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
Chris Forbesa11561f2016-03-31 17:58:13 +1300437 (uint64_t)cb, __LINE__, MEMTRACK_FREED_MEM_REF, "MEM",
438 "Command Buffer %p still has a reference to mem obj %#" PRIxLEAST64, cb, (uint64_t)pMemObjInfo->mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700439 }
440 // Clear the list of hanging references
Chris Forbesa11561f2016-03-31 17:58:13 +1300441 pMemObjInfo->commandBufferBindings.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700442 }
443
Chris Forbes2dbf8072016-03-31 17:37:36 +1300444 if (objRefCount > 0 && pMemObjInfo->objBindings.size() > 0) {
445 for (auto obj : pMemObjInfo->objBindings) {
446 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700447 MEMTRACK_FREED_MEM_REF, "MEM", "VK Object %#" PRIxLEAST64 " still has a reference to mem obj %#" PRIxLEAST64,
Chris Forbes2dbf8072016-03-31 17:37:36 +1300448 obj.handle, (uint64_t)pMemObjInfo->mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700449 }
450 // Clear the list of hanging references
Chris Forbes2dbf8072016-03-31 17:37:36 +1300451 pMemObjInfo->objBindings.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700452 }
453 return skipCall;
454}
455
Dustin Graves8f1eab92016-04-05 09:41:17 -0600456static bool deleteMemObjInfo(layer_data *my_data, void *object, VkDeviceMemory mem) {
457 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700458 auto item = my_data->memObjMap.find(mem);
459 if (item != my_data->memObjMap.end()) {
460 my_data->memObjMap.erase(item);
461 } else {
462 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
463 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM",
464 "Request to delete memory object %#" PRIxLEAST64 " not present in memory Object Map", (uint64_t)mem);
465 }
466 return skipCall;
467}
468
Dustin Graves8f1eab92016-04-05 09:41:17 -0600469static bool freeMemObjInfo(layer_data *dev_data, void *object, VkDeviceMemory mem, bool internal) {
470 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700471 // Parse global list to find info w/ mem
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600472 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700473 if (pInfo) {
474 if (pInfo->allocInfo.allocationSize == 0 && !internal) {
475 // TODO: Verify against Valid Use section
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600476 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700477 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MEM_OBJ, "MEM",
478 "Attempting to free memory associated with a Persistent Image, %#" PRIxLEAST64 ", "
479 "this should not be explicitly freed\n",
480 (uint64_t)mem);
481 } else {
482 // Clear any CB bindings for completed CBs
483 // TODO : Is there a better place to do this?
484
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700485 assert(pInfo->object != VK_NULL_HANDLE);
Chris Forbesa11561f2016-03-31 17:58:13 +1300486 // clear_cmd_buf_and_mem_references removes elements from
487 // pInfo->commandBufferBindings -- this copy not needed in c++14,
488 // and probably not needed in practice in c++11
489 auto bindings = pInfo->commandBufferBindings;
490 for (auto cb : bindings) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -0600491 if (!dev_data->globalInFlightCmdBuffers.count(cb)) {
Chris Forbesa11561f2016-03-31 17:58:13 +1300492 clear_cmd_buf_and_mem_references(dev_data, cb);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700493 }
494 }
495
496 // Now verify that no references to this mem obj remain and remove bindings
Chris Forbesa11561f2016-03-31 17:58:13 +1300497 if (pInfo->commandBufferBindings.size() || pInfo->objBindings.size()) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600498 skipCall |= reportMemReferencesAndCleanUp(dev_data, pInfo);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700499 }
500 // Delete mem obj info
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600501 skipCall |= deleteMemObjInfo(dev_data, object, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700502 }
503 }
504 return skipCall;
505}
506
507static const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
508 switch (type) {
509 case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
510 return "image";
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700511 case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
512 return "buffer";
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700513 case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
514 return "swapchain";
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700515 default:
516 return "unknown";
517 }
518}
519
520// Remove object binding performs 3 tasks:
521// 1. Remove ObjectInfo from MemObjInfo list container of obj bindings & free it
Chris Forbesd7ebc772016-03-31 17:06:52 +1300522// 2. Clear mem binding for image/buffer by setting its handle to 0
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700523// TODO : This only applied to Buffer, Image, and Swapchain objects now, how should it be updated/customized?
Chris Forbes73b82b12016-04-06 15:16:26 +1200524static bool clear_object_binding(layer_data *dev_data, uint64_t handle, VkDebugReportObjectTypeEXT type) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700525 // TODO : Need to customize images/buffers/swapchains to track mem binding and clear it here appropriately
Dustin Graves8f1eab92016-04-05 09:41:17 -0600526 bool skipCall = false;
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600527 VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
528 if (pMemBinding) {
529 DEVICE_MEM_INFO *pMemObjInfo = get_mem_obj_info(dev_data, *pMemBinding);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700530 // TODO : Make sure this is a reasonable way to reset mem binding
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600531 *pMemBinding = VK_NULL_HANDLE;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700532 if (pMemObjInfo) {
Chris Forbesd7ebc772016-03-31 17:06:52 +1300533 // This obj is bound to a memory object. Remove the reference to this object in that memory object's list,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700534 // and set the objects memory binding pointer to NULL.
Chris Forbes2dbf8072016-03-31 17:37:36 +1300535 if (!pMemObjInfo->objBindings.erase({handle, type})) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700536 skipCall |=
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600537 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700538 "MEM", "While trying to clear mem binding for %s obj %#" PRIxLEAST64
539 ", unable to find that object referenced by mem obj %#" PRIxLEAST64,
540 object_type_to_string(type), handle, (uint64_t)pMemObjInfo->mem);
541 }
542 }
543 }
544 return skipCall;
545}
546
547// For NULL mem case, output warning
548// Make sure given object is in global object map
549// IF a previous binding existed, output validation error
550// Otherwise, add reference from objectInfo to memoryInfo
551// Add reference off of objInfo
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600552static bool set_mem_binding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle,
553 VkDebugReportObjectTypeEXT type, const char *apiName) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600554 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700555 // Handle NULL case separately, just clear previous binding & decrement reference
556 if (mem == VK_NULL_HANDLE) {
557 // TODO: Verify against Valid Use section of spec.
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600558 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_MEM_OBJ,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700559 "MEM", "In %s, attempting to Bind Obj(%#" PRIxLEAST64 ") to NULL", apiName, handle);
560 } else {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600561 VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
562 if (!pMemBinding) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700563 skipCall |=
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600564 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS,
Chris Forbesd63effa2016-03-31 18:02:29 +1300565 "MEM", "In %s, attempting to update Binding of %s Obj(%#" PRIxLEAST64 ") that's not in global list",
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700566 object_type_to_string(type), apiName, handle);
567 } else {
568 // non-null case so should have real mem obj
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600569 DEVICE_MEM_INFO *pMemInfo = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700570 if (pMemInfo) {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600571 DEVICE_MEM_INFO *pPrevBinding = get_mem_obj_info(dev_data, *pMemBinding);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700572 if (pPrevBinding != NULL) {
573 skipCall |=
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600574 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700575 (uint64_t)mem, __LINE__, MEMTRACK_REBIND_OBJECT, "MEM",
576 "In %s, attempting to bind memory (%#" PRIxLEAST64 ") to object (%#" PRIxLEAST64
577 ") which has already been bound to mem object %#" PRIxLEAST64,
578 apiName, (uint64_t)mem, handle, (uint64_t)pPrevBinding->mem);
579 } else {
Chris Forbes2dbf8072016-03-31 17:37:36 +1300580 pMemInfo->objBindings.insert({handle, type});
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700581 // For image objects, make sure default memory state is correctly set
582 // TODO : What's the best/correct way to handle this?
583 if (VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT == type) {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600584 auto const image_node = dev_data->imageMap.find(VkImage(handle));
585 if (image_node != dev_data->imageMap.end()) {
586 VkImageCreateInfo ici = image_node->second.createInfo;
587 if (ici.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
588 // TODO:: More memory state transition stuff.
589 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700590 }
591 }
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600592 *pMemBinding = mem;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700593 }
594 }
595 }
596 }
597 return skipCall;
598}
599
600// For NULL mem case, clear any previous binding Else...
601// Make sure given object is in its object map
602// IF a previous binding existed, update binding
603// Add reference from objectInfo to memoryInfo
604// Add reference off of object's binding info
Chris Forbes73b82b12016-04-06 15:16:26 +1200605// Return VK_TRUE if addition is successful, VK_FALSE otherwise
606static bool set_sparse_mem_binding(layer_data *dev_data, VkDeviceMemory mem, uint64_t handle,
607 VkDebugReportObjectTypeEXT type, const char *apiName) {
608 bool skipCall = VK_FALSE;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700609 // Handle NULL case separately, just clear previous binding & decrement reference
610 if (mem == VK_NULL_HANDLE) {
Chris Forbes73b82b12016-04-06 15:16:26 +1200611 skipCall = clear_object_binding(dev_data, handle, type);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700612 } else {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600613 VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
614 if (!pMemBinding) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700615 skipCall |= log_msg(
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600616 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_MISSING_MEM_BINDINGS, "MEM",
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700617 "In %s, attempting to update Binding of Obj(%#" PRIxLEAST64 ") that's not in global list()", apiName, handle);
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600618 } else {
619 // non-null case so should have real mem obj
620 DEVICE_MEM_INFO *pInfo = get_mem_obj_info(dev_data, mem);
621 if (pInfo) {
622 pInfo->objBindings.insert({handle, type});
623 // Need to set mem binding for this object
624 *pMemBinding = mem;
625 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700626 }
627 }
628 return skipCall;
629}
630
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700631// For given Object, get 'mem' obj that it's bound to or NULL if no binding
Chris Forbes73b82b12016-04-06 15:16:26 +1200632static bool get_mem_binding_from_object(layer_data *dev_data, const uint64_t handle,
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600633 const VkDebugReportObjectTypeEXT type, VkDeviceMemory *mem) {
Dustin Graves8f1eab92016-04-05 09:41:17 -0600634 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700635 *mem = VK_NULL_HANDLE;
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600636 VkDeviceMemory *pMemBinding = get_object_mem_binding(dev_data, handle, type);
637 if (pMemBinding) {
638 *mem = *pMemBinding;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700639 } else {
Tobin Ehlisf263ba42016-04-05 13:33:00 -0600640 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, type, handle, __LINE__, MEMTRACK_INVALID_OBJECT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700641 "MEM", "Trying to get mem binding for object %#" PRIxLEAST64 " but no such object in %s list", handle,
642 object_type_to_string(type));
643 }
644 return skipCall;
645}
646
647// Print details of MemObjInfo list
Chris Forbes73b82b12016-04-06 15:16:26 +1200648static void print_mem_list(layer_data *dev_data) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600649 DEVICE_MEM_INFO *pInfo = NULL;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700650
651 // Early out if info is not requested
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600652 if (!(dev_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700653 return;
654 }
655
656 // Just printing each msg individually for now, may want to package these into single large print
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600657 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700658 MEMTRACK_NONE, "MEM", "Details of Memory Object list (of size " PRINTF_SIZE_T_SPECIFIER " elements)",
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600659 dev_data->memObjMap.size());
660 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700661 MEMTRACK_NONE, "MEM", "=============================");
662
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600663 if (dev_data->memObjMap.size() <= 0)
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700664 return;
665
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600666 for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700667 pInfo = &(*ii).second;
668
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600669 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700670 __LINE__, MEMTRACK_NONE, "MEM", " ===MemObjInfo at %p===", (void *)pInfo);
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600671 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700672 __LINE__, MEMTRACK_NONE, "MEM", " Mem object: %#" PRIxLEAST64, (uint64_t)(pInfo->mem));
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600673 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Chris Forbesd7ebc772016-03-31 17:06:52 +1300674 __LINE__, MEMTRACK_NONE, "MEM", " Ref Count: " PRINTF_SIZE_T_SPECIFIER,
Chris Forbesa11561f2016-03-31 17:58:13 +1300675 pInfo->commandBufferBindings.size() + pInfo->objBindings.size());
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700676 if (0 != pInfo->allocInfo.allocationSize) {
677 string pAllocInfoMsg = vk_print_vkmemoryallocateinfo(&pInfo->allocInfo, "MEM(INFO): ");
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600678 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700679 __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info:\n%s", pAllocInfoMsg.c_str());
680 } else {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600681 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700682 __LINE__, MEMTRACK_NONE, "MEM", " Mem Alloc info is NULL (alloc done by vkCreateSwapchainKHR())");
683 }
684
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600685 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700686 __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT Binding list of size " PRINTF_SIZE_T_SPECIFIER " elements:",
Chris Forbes2dbf8072016-03-31 17:37:36 +1300687 pInfo->objBindings.size());
688 if (pInfo->objBindings.size() > 0) {
689 for (auto obj : pInfo->objBindings) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600690 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Chris Forbes2dbf8072016-03-31 17:37:36 +1300691 0, __LINE__, MEMTRACK_NONE, "MEM", " VK OBJECT %" PRIu64, obj.handle);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700692 }
693 }
694
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600695 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700696 __LINE__, MEMTRACK_NONE, "MEM",
697 " VK Command Buffer (CB) binding list of size " PRINTF_SIZE_T_SPECIFIER " elements",
Chris Forbesa11561f2016-03-31 17:58:13 +1300698 pInfo->commandBufferBindings.size());
699 if (pInfo->commandBufferBindings.size() > 0) {
700 for (auto cb : pInfo->commandBufferBindings) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -0600701 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
Chris Forbesa11561f2016-03-31 17:58:13 +1300702 0, __LINE__, MEMTRACK_NONE, "MEM", " VK CB %p", cb);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700703 }
704 }
705 }
706}
707
Chris Forbes73b82b12016-04-06 15:16:26 +1200708static void printCBList(layer_data *my_data) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600709 GLOBAL_CB_NODE *pCBInfo = NULL;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700710
711 // Early out if info is not requested
712 if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
713 return;
714 }
715
716 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600717 MEMTRACK_NONE, "MEM", "Details of CB list (of size " PRINTF_SIZE_T_SPECIFIER " elements)",
718 my_data->commandBufferMap.size());
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700719 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0, __LINE__,
720 MEMTRACK_NONE, "MEM", "==================");
721
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600722 if (my_data->commandBufferMap.size() <= 0)
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700723 return;
724
Tobin Ehlis223b01e2016-03-21 14:14:44 -0600725 for (auto &cb_node : my_data->commandBufferMap) {
726 pCBInfo = cb_node.second;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700727
728 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Tobin Ehlisaff7ae92016-04-18 15:45:20 -0600729 __LINE__, MEMTRACK_NONE, "MEM", " CB Info (%p) has CB %p", (void *)pCBInfo, (void *)pCBInfo->commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700730
Chris Forbese6625b12016-03-31 18:11:28 +1300731 if (pCBInfo->memObjs.size() <= 0)
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700732 continue;
Chris Forbese6625b12016-03-31 18:11:28 +1300733 for (auto obj : pCBInfo->memObjs) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700734 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, 0,
Chris Forbese6625b12016-03-31 18:11:28 +1300735 __LINE__, MEMTRACK_NONE, "MEM", " Mem obj %" PRIu64, (uint64_t)obj);
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700736 }
737 }
738}
739
740#endif
741
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700742// Return a string representation of CMD_TYPE enum
743static string cmdTypeToString(CMD_TYPE cmd) {
744 switch (cmd) {
745 case CMD_BINDPIPELINE:
746 return "CMD_BINDPIPELINE";
747 case CMD_BINDPIPELINEDELTA:
748 return "CMD_BINDPIPELINEDELTA";
749 case CMD_SETVIEWPORTSTATE:
750 return "CMD_SETVIEWPORTSTATE";
751 case CMD_SETLINEWIDTHSTATE:
752 return "CMD_SETLINEWIDTHSTATE";
753 case CMD_SETDEPTHBIASSTATE:
754 return "CMD_SETDEPTHBIASSTATE";
755 case CMD_SETBLENDSTATE:
756 return "CMD_SETBLENDSTATE";
757 case CMD_SETDEPTHBOUNDSSTATE:
758 return "CMD_SETDEPTHBOUNDSSTATE";
759 case CMD_SETSTENCILREADMASKSTATE:
760 return "CMD_SETSTENCILREADMASKSTATE";
761 case CMD_SETSTENCILWRITEMASKSTATE:
762 return "CMD_SETSTENCILWRITEMASKSTATE";
763 case CMD_SETSTENCILREFERENCESTATE:
764 return "CMD_SETSTENCILREFERENCESTATE";
765 case CMD_BINDDESCRIPTORSETS:
766 return "CMD_BINDDESCRIPTORSETS";
767 case CMD_BINDINDEXBUFFER:
768 return "CMD_BINDINDEXBUFFER";
769 case CMD_BINDVERTEXBUFFER:
770 return "CMD_BINDVERTEXBUFFER";
771 case CMD_DRAW:
772 return "CMD_DRAW";
773 case CMD_DRAWINDEXED:
774 return "CMD_DRAWINDEXED";
775 case CMD_DRAWINDIRECT:
776 return "CMD_DRAWINDIRECT";
777 case CMD_DRAWINDEXEDINDIRECT:
778 return "CMD_DRAWINDEXEDINDIRECT";
779 case CMD_DISPATCH:
780 return "CMD_DISPATCH";
781 case CMD_DISPATCHINDIRECT:
782 return "CMD_DISPATCHINDIRECT";
783 case CMD_COPYBUFFER:
784 return "CMD_COPYBUFFER";
785 case CMD_COPYIMAGE:
786 return "CMD_COPYIMAGE";
787 case CMD_BLITIMAGE:
788 return "CMD_BLITIMAGE";
789 case CMD_COPYBUFFERTOIMAGE:
790 return "CMD_COPYBUFFERTOIMAGE";
791 case CMD_COPYIMAGETOBUFFER:
792 return "CMD_COPYIMAGETOBUFFER";
793 case CMD_CLONEIMAGEDATA:
794 return "CMD_CLONEIMAGEDATA";
795 case CMD_UPDATEBUFFER:
796 return "CMD_UPDATEBUFFER";
797 case CMD_FILLBUFFER:
798 return "CMD_FILLBUFFER";
799 case CMD_CLEARCOLORIMAGE:
800 return "CMD_CLEARCOLORIMAGE";
801 case CMD_CLEARATTACHMENTS:
802 return "CMD_CLEARCOLORATTACHMENT";
803 case CMD_CLEARDEPTHSTENCILIMAGE:
804 return "CMD_CLEARDEPTHSTENCILIMAGE";
805 case CMD_RESOLVEIMAGE:
806 return "CMD_RESOLVEIMAGE";
807 case CMD_SETEVENT:
808 return "CMD_SETEVENT";
809 case CMD_RESETEVENT:
810 return "CMD_RESETEVENT";
811 case CMD_WAITEVENTS:
812 return "CMD_WAITEVENTS";
813 case CMD_PIPELINEBARRIER:
814 return "CMD_PIPELINEBARRIER";
815 case CMD_BEGINQUERY:
816 return "CMD_BEGINQUERY";
817 case CMD_ENDQUERY:
818 return "CMD_ENDQUERY";
819 case CMD_RESETQUERYPOOL:
820 return "CMD_RESETQUERYPOOL";
821 case CMD_COPYQUERYPOOLRESULTS:
822 return "CMD_COPYQUERYPOOLRESULTS";
823 case CMD_WRITETIMESTAMP:
824 return "CMD_WRITETIMESTAMP";
825 case CMD_INITATOMICCOUNTERS:
826 return "CMD_INITATOMICCOUNTERS";
827 case CMD_LOADATOMICCOUNTERS:
828 return "CMD_LOADATOMICCOUNTERS";
829 case CMD_SAVEATOMICCOUNTERS:
830 return "CMD_SAVEATOMICCOUNTERS";
831 case CMD_BEGINRENDERPASS:
832 return "CMD_BEGINRENDERPASS";
833 case CMD_ENDRENDERPASS:
834 return "CMD_ENDRENDERPASS";
835 default:
836 return "UNKNOWN";
837 }
838}
839
840// SPIRV utility functions
841static void build_def_index(shader_module *module) {
842 for (auto insn : *module) {
843 switch (insn.opcode()) {
844 /* Types */
845 case spv::OpTypeVoid:
846 case spv::OpTypeBool:
847 case spv::OpTypeInt:
848 case spv::OpTypeFloat:
849 case spv::OpTypeVector:
850 case spv::OpTypeMatrix:
851 case spv::OpTypeImage:
852 case spv::OpTypeSampler:
853 case spv::OpTypeSampledImage:
854 case spv::OpTypeArray:
855 case spv::OpTypeRuntimeArray:
856 case spv::OpTypeStruct:
857 case spv::OpTypeOpaque:
858 case spv::OpTypePointer:
859 case spv::OpTypeFunction:
860 case spv::OpTypeEvent:
861 case spv::OpTypeDeviceEvent:
862 case spv::OpTypeReserveId:
863 case spv::OpTypeQueue:
864 case spv::OpTypePipe:
865 module->def_index[insn.word(1)] = insn.offset();
866 break;
867
868 /* Fixed constants */
869 case spv::OpConstantTrue:
870 case spv::OpConstantFalse:
871 case spv::OpConstant:
872 case spv::OpConstantComposite:
873 case spv::OpConstantSampler:
874 case spv::OpConstantNull:
875 module->def_index[insn.word(2)] = insn.offset();
876 break;
877
878 /* Specialization constants */
879 case spv::OpSpecConstantTrue:
880 case spv::OpSpecConstantFalse:
881 case spv::OpSpecConstant:
882 case spv::OpSpecConstantComposite:
883 case spv::OpSpecConstantOp:
884 module->def_index[insn.word(2)] = insn.offset();
885 break;
886
887 /* Variables */
888 case spv::OpVariable:
889 module->def_index[insn.word(2)] = insn.offset();
890 break;
891
892 /* Functions */
893 case spv::OpFunction:
894 module->def_index[insn.word(2)] = insn.offset();
895 break;
896
897 default:
898 /* We don't care about any other defs for now. */
899 break;
900 }
901 }
902}
903
904static spirv_inst_iter find_entrypoint(shader_module *src, char const *name, VkShaderStageFlagBits stageBits) {
905 for (auto insn : *src) {
906 if (insn.opcode() == spv::OpEntryPoint) {
907 auto entrypointName = (char const *)&insn.word(3);
908 auto entrypointStageBits = 1u << insn.word(1);
909
910 if (!strcmp(entrypointName, name) && (entrypointStageBits & stageBits)) {
911 return insn;
912 }
913 }
914 }
915
916 return src->end();
917}
918
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700919static char const *storage_class_name(unsigned sc) {
920 switch (sc) {
921 case spv::StorageClassInput:
922 return "input";
923 case spv::StorageClassOutput:
924 return "output";
925 case spv::StorageClassUniformConstant:
926 return "const uniform";
927 case spv::StorageClassUniform:
928 return "uniform";
929 case spv::StorageClassWorkgroup:
930 return "workgroup local";
931 case spv::StorageClassCrossWorkgroup:
932 return "workgroup global";
933 case spv::StorageClassPrivate:
934 return "private global";
935 case spv::StorageClassFunction:
936 return "function";
937 case spv::StorageClassGeneric:
938 return "generic";
939 case spv::StorageClassAtomicCounter:
940 return "atomic counter";
941 case spv::StorageClassImage:
942 return "image";
943 case spv::StorageClassPushConstant:
944 return "push constant";
945 default:
946 return "unknown";
947 }
948}
949
950/* get the value of an integral constant */
951unsigned get_constant_value(shader_module const *src, unsigned id) {
952 auto value = src->get_def(id);
953 assert(value != src->end());
954
955 if (value.opcode() != spv::OpConstant) {
956 /* TODO: Either ensure that the specialization transform is already performed on a module we're
957 considering here, OR -- specialize on the fly now.
958 */
959 return 1;
960 }
961
962 return value.word(3);
963}
964
Chris Forbesfa86ce32016-03-18 14:59:39 +1300965
966static void describe_type_inner(std::ostringstream &ss, shader_module const *src, unsigned type) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700967 auto insn = src->get_def(type);
968 assert(insn != src->end());
969
970 switch (insn.opcode()) {
971 case spv::OpTypeBool:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300972 ss << "bool";
973 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700974 case spv::OpTypeInt:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300975 ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
976 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700977 case spv::OpTypeFloat:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300978 ss << "float" << insn.word(2);
979 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700980 case spv::OpTypeVector:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300981 ss << "vec" << insn.word(3) << " of ";
982 describe_type_inner(ss, src, insn.word(2));
983 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700984 case spv::OpTypeMatrix:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300985 ss << "mat" << insn.word(3) << " of ";
986 describe_type_inner(ss, src, insn.word(2));
987 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700988 case spv::OpTypeArray:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300989 ss << "arr[" << get_constant_value(src, insn.word(3)) << "] of ";
990 describe_type_inner(ss, src, insn.word(2));
991 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700992 case spv::OpTypePointer:
Chris Forbesfa86ce32016-03-18 14:59:39 +1300993 ss << "ptr to " << storage_class_name(insn.word(2)) << " ";
994 describe_type_inner(ss, src, insn.word(3));
995 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700996 case spv::OpTypeStruct: {
Chris Forbesfa86ce32016-03-18 14:59:39 +1300997 ss << "struct of (";
Tobin Ehlisc96f8062016-03-09 16:12:48 -0700998 for (unsigned i = 2; i < insn.len(); i++) {
Chris Forbesfa86ce32016-03-18 14:59:39 +1300999 describe_type_inner(ss, src, insn.word(i));
1000 if (i == insn.len() - 1) {
1001 ss << ")";
1002 } else {
1003 ss << ", ";
1004 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001005 }
Chris Forbesfa86ce32016-03-18 14:59:39 +13001006 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001007 }
1008 case spv::OpTypeSampler:
Chris Forbesfa86ce32016-03-18 14:59:39 +13001009 ss << "sampler";
1010 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001011 case spv::OpTypeSampledImage:
Chris Forbesfa86ce32016-03-18 14:59:39 +13001012 ss << "sampler+";
1013 describe_type_inner(ss, src, insn.word(2));
1014 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001015 case spv::OpTypeImage:
Chris Forbesfa86ce32016-03-18 14:59:39 +13001016 ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
1017 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001018 default:
Chris Forbesfa86ce32016-03-18 14:59:39 +13001019 ss << "oddtype";
1020 break;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001021 }
1022}
1023
Chris Forbesfa86ce32016-03-18 14:59:39 +13001024
1025static std::string describe_type(shader_module const *src, unsigned type) {
1026 std::ostringstream ss;
1027 describe_type_inner(ss, src, type);
1028 return ss.str();
1029}
1030
1031
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001032static bool is_narrow_numeric_type(spirv_inst_iter type)
1033{
1034 if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat)
1035 return false;
1036 return type.word(2) < 64;
1037}
1038
1039
1040static bool types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool a_arrayed, bool b_arrayed, bool relaxed) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001041 /* walk two type trees together, and complain about differences */
1042 auto a_insn = a->get_def(a_type);
1043 auto b_insn = b->get_def(b_type);
1044 assert(a_insn != a->end());
1045 assert(b_insn != b->end());
1046
Chris Forbes43f01d02016-03-29 16:38:44 +13001047 if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001048 return types_match(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
Chris Forbes43f01d02016-03-29 16:38:44 +13001049 }
1050
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001051 if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
1052 /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001053 return types_match(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
1054 }
1055
1056 if (a_insn.opcode() == spv::OpTypeVector && relaxed && is_narrow_numeric_type(b_insn)) {
1057 return types_match(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001058 }
1059
1060 if (a_insn.opcode() != b_insn.opcode()) {
1061 return false;
1062 }
1063
Chris Forbes43f01d02016-03-29 16:38:44 +13001064 if (a_insn.opcode() == spv::OpTypePointer) {
1065 /* match on pointee type. storage class is expected to differ */
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001066 return types_match(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
Chris Forbes43f01d02016-03-29 16:38:44 +13001067 }
1068
1069 if (a_arrayed || b_arrayed) {
1070 /* if we havent resolved array-of-verts by here, we're not going to. */
1071 return false;
1072 }
1073
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001074 switch (a_insn.opcode()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001075 case spv::OpTypeBool:
Chris Forbes43f01d02016-03-29 16:38:44 +13001076 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001077 case spv::OpTypeInt:
1078 /* match on width, signedness */
Chris Forbes43f01d02016-03-29 16:38:44 +13001079 return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001080 case spv::OpTypeFloat:
1081 /* match on width */
Chris Forbes43f01d02016-03-29 16:38:44 +13001082 return a_insn.word(2) == b_insn.word(2);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001083 case spv::OpTypeVector:
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001084 /* match on element type, count. */
1085 if (!types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false))
1086 return false;
1087 if (relaxed && is_narrow_numeric_type(a->get_def(a_insn.word(2)))) {
1088 return a_insn.word(3) >= b_insn.word(3);
1089 }
1090 else {
1091 return a_insn.word(3) == b_insn.word(3);
1092 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001093 case spv::OpTypeMatrix:
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001094 /* match on element type, count. */
1095 return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) && a_insn.word(3) == b_insn.word(3);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001096 case spv::OpTypeArray:
1097 /* match on element type, count. these all have the same layout. we don't get here if
1098 * b_arrayed. This differs from vector & matrix types in that the array size is the id of a constant instruction,
1099 * not a literal within OpTypeArray */
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001100 return types_match(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001101 get_constant_value(a, a_insn.word(3)) == get_constant_value(b, b_insn.word(3));
1102 case spv::OpTypeStruct:
1103 /* match on all element types */
1104 {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001105 if (a_insn.len() != b_insn.len()) {
1106 return false; /* structs cannot match if member counts differ */
1107 }
1108
1109 for (unsigned i = 2; i < a_insn.len(); i++) {
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001110 if (!types_match(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001111 return false;
1112 }
1113 }
1114
1115 return true;
1116 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001117 default:
1118 /* remaining types are CLisms, or may not appear in the interfaces we
1119 * are interested in. Just claim no match.
1120 */
1121 return false;
1122 }
1123}
1124
1125static int value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def) {
1126 auto it = map.find(id);
1127 if (it == map.end())
1128 return def;
1129 else
1130 return it->second;
1131}
1132
1133static unsigned get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level) {
1134 auto insn = src->get_def(type);
1135 assert(insn != src->end());
1136
1137 switch (insn.opcode()) {
1138 case spv::OpTypePointer:
1139 /* see through the ptr -- this is only ever at the toplevel for graphics shaders;
1140 * we're never actually passing pointers around. */
1141 return get_locations_consumed_by_type(src, insn.word(3), strip_array_level);
1142 case spv::OpTypeArray:
1143 if (strip_array_level) {
1144 return get_locations_consumed_by_type(src, insn.word(2), false);
1145 } else {
1146 return get_constant_value(src, insn.word(3)) * get_locations_consumed_by_type(src, insn.word(2), false);
1147 }
1148 case spv::OpTypeMatrix:
1149 /* num locations is the dimension * element size */
1150 return insn.word(3) * get_locations_consumed_by_type(src, insn.word(2), false);
Chris Forbesb91daf02016-04-21 14:46:48 +12001151 case spv::OpTypeVector: {
1152 auto scalar_type = src->get_def(insn.word(2));
1153 auto bit_width = (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ?
1154 scalar_type.word(2) : 32;
1155
1156 /* locations are 128-bit wide; 3- and 4-component vectors of 64 bit
1157 * types require two. */
1158 return (bit_width * insn.word(3) + 127) / 128;
1159 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001160 default:
1161 /* everything else is just 1. */
1162 return 1;
1163
1164 /* TODO: extend to handle 64bit scalar types, whose vectors may need
1165 * multiple locations. */
1166 }
1167}
1168
Chris Forbese32b78a2016-04-21 15:00:58 +12001169static unsigned get_locations_consumed_by_format(VkFormat format) {
1170 switch (format) {
1171 case VK_FORMAT_R64G64B64A64_SFLOAT:
1172 case VK_FORMAT_R64G64B64A64_SINT:
1173 case VK_FORMAT_R64G64B64A64_UINT:
1174 case VK_FORMAT_R64G64B64_SFLOAT:
1175 case VK_FORMAT_R64G64B64_SINT:
1176 case VK_FORMAT_R64G64B64_UINT:
1177 return 2;
1178 default:
1179 return 1;
1180 }
1181}
1182
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001183typedef std::pair<unsigned, unsigned> location_t;
1184typedef std::pair<unsigned, unsigned> descriptor_slot_t;
1185
1186struct interface_var {
1187 uint32_t id;
1188 uint32_t type_id;
1189 uint32_t offset;
Chris Forbes804bae32016-03-29 16:14:02 +13001190 bool is_patch;
Chris Forbesa0ab8152016-04-20 13:34:27 +12001191 bool is_block_member;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001192 /* TODO: collect the name, too? Isn't required to be present. */
1193};
1194
Chris Forbes23a575d2016-03-29 16:41:07 +13001195struct shader_stage_attributes {
1196 char const *const name;
1197 bool arrayed_input;
1198 bool arrayed_output;
1199};
1200
1201static shader_stage_attributes shader_stage_attribs[] = {
1202 {"vertex shader", false, false},
1203 {"tessellation control shader", true, true},
1204 {"tessellation evaluation shader", true, false},
1205 {"geometry shader", true, false},
1206 {"fragment shader", false, false},
1207};
1208
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001209static spirv_inst_iter get_struct_type(shader_module const *src, spirv_inst_iter def, bool is_array_of_verts) {
1210 while (true) {
1211
1212 if (def.opcode() == spv::OpTypePointer) {
1213 def = src->get_def(def.word(3));
1214 } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
1215 def = src->get_def(def.word(2));
1216 is_array_of_verts = false;
1217 } else if (def.opcode() == spv::OpTypeStruct) {
1218 return def;
1219 } else {
1220 return src->end();
1221 }
1222 }
1223}
1224
Chris Forbes15864502016-03-30 11:35:21 +13001225static void collect_interface_block_members(layer_data *my_data, shader_module const *src,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001226 std::map<location_t, interface_var> &out,
1227 std::unordered_map<unsigned, unsigned> const &blocks, bool is_array_of_verts,
Chris Forbes804bae32016-03-29 16:14:02 +13001228 uint32_t id, uint32_t type_id, bool is_patch) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001229 /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */
Chris Forbes23a575d2016-03-29 16:41:07 +13001230 auto type = get_struct_type(src, src->get_def(type_id), is_array_of_verts && !is_patch);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001231 if (type == src->end() || blocks.find(type.word(1)) == blocks.end()) {
1232 /* this isn't an interface block. */
1233 return;
1234 }
1235
1236 std::unordered_map<unsigned, unsigned> member_components;
1237
1238 /* Walk all the OpMemberDecorate for type's result id -- first pass, collect components. */
1239 for (auto insn : *src) {
1240 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
1241 unsigned member_index = insn.word(2);
1242
1243 if (insn.word(3) == spv::DecorationComponent) {
1244 unsigned component = insn.word(4);
1245 member_components[member_index] = component;
1246 }
1247 }
1248 }
1249
1250 /* Second pass -- produce the output, from Location decorations */
1251 for (auto insn : *src) {
1252 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
1253 unsigned member_index = insn.word(2);
1254 unsigned member_type_id = type.word(2 + member_index);
1255
1256 if (insn.word(3) == spv::DecorationLocation) {
1257 unsigned location = insn.word(4);
1258 unsigned num_locations = get_locations_consumed_by_type(src, member_type_id, false);
1259 auto component_it = member_components.find(member_index);
1260 unsigned component = component_it == member_components.end() ? 0 : component_it->second;
1261
1262 for (unsigned int offset = 0; offset < num_locations; offset++) {
1263 interface_var v;
1264 v.id = id;
1265 /* TODO: member index in interface_var too? */
1266 v.type_id = member_type_id;
1267 v.offset = offset;
Chris Forbes804bae32016-03-29 16:14:02 +13001268 v.is_patch = is_patch;
Chris Forbesa0ab8152016-04-20 13:34:27 +12001269 v.is_block_member = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001270 out[std::make_pair(location + offset, component)] = v;
1271 }
1272 }
1273 }
1274 }
1275}
1276
Chris Forbes15864502016-03-30 11:35:21 +13001277static void collect_interface_by_location(layer_data *my_data, shader_module const *src, spirv_inst_iter entrypoint,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001278 spv::StorageClass sinterface, std::map<location_t, interface_var> &out,
1279 bool is_array_of_verts) {
1280 std::unordered_map<unsigned, unsigned> var_locations;
1281 std::unordered_map<unsigned, unsigned> var_builtins;
1282 std::unordered_map<unsigned, unsigned> var_components;
1283 std::unordered_map<unsigned, unsigned> blocks;
Chris Forbes804bae32016-03-29 16:14:02 +13001284 std::unordered_map<unsigned, unsigned> var_patch;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001285
1286 for (auto insn : *src) {
1287
1288 /* We consider two interface models: SSO rendezvous-by-location, and
1289 * builtins. Complain about anything that fits neither model.
1290 */
1291 if (insn.opcode() == spv::OpDecorate) {
1292 if (insn.word(2) == spv::DecorationLocation) {
1293 var_locations[insn.word(1)] = insn.word(3);
1294 }
1295
1296 if (insn.word(2) == spv::DecorationBuiltIn) {
1297 var_builtins[insn.word(1)] = insn.word(3);
1298 }
1299
1300 if (insn.word(2) == spv::DecorationComponent) {
1301 var_components[insn.word(1)] = insn.word(3);
1302 }
1303
1304 if (insn.word(2) == spv::DecorationBlock) {
1305 blocks[insn.word(1)] = 1;
1306 }
Chris Forbes804bae32016-03-29 16:14:02 +13001307
1308 if (insn.word(2) == spv::DecorationPatch) {
1309 var_patch[insn.word(1)] = 1;
1310 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001311 }
1312 }
1313
1314 /* TODO: handle grouped decorations */
1315 /* TODO: handle index=1 dual source outputs from FS -- two vars will
Eric Engestrombcbb0fd2016-04-02 22:06:13 +01001316 * have the same location, and we DON'T want to clobber. */
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001317
1318 /* find the end of the entrypoint's name string. additional zero bytes follow the actual null
1319 terminator, to fill out the rest of the word - so we only need to look at the last byte in
1320 the word to determine which word contains the terminator. */
Michael Mc Donnell75ecdb72016-04-03 14:47:51 -07001321 uint32_t word = 3;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001322 while (entrypoint.word(word) & 0xff000000u) {
1323 ++word;
1324 }
1325 ++word;
1326
1327 for (; word < entrypoint.len(); word++) {
1328 auto insn = src->get_def(entrypoint.word(word));
1329 assert(insn != src->end());
1330 assert(insn.opcode() == spv::OpVariable);
1331
Jamie Madill2b6b8d52016-04-04 15:09:51 -04001332 if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001333 unsigned id = insn.word(2);
1334 unsigned type = insn.word(1);
1335
1336 int location = value_or_default(var_locations, id, -1);
1337 int builtin = value_or_default(var_builtins, id, -1);
1338 unsigned component = value_or_default(var_components, id, 0); /* unspecified is OK, is 0 */
Chris Forbes804bae32016-03-29 16:14:02 +13001339 bool is_patch = var_patch.find(id) != var_patch.end();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001340
1341 /* All variables and interface block members in the Input or Output storage classes
1342 * must be decorated with either a builtin or an explicit location.
1343 *
1344 * TODO: integrate the interface block support here. For now, don't complain --
1345 * a valid SPIRV module will only hit this path for the interface block case, as the
1346 * individual members of the type are decorated, rather than variable declarations.
1347 */
1348
1349 if (location != -1) {
1350 /* A user-defined interface variable, with a location. Where a variable
1351 * occupied multiple locations, emit one result for each. */
Chris Forbes43f01d02016-03-29 16:38:44 +13001352 unsigned num_locations = get_locations_consumed_by_type(src, type, is_array_of_verts && !is_patch);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001353 for (unsigned int offset = 0; offset < num_locations; offset++) {
1354 interface_var v;
1355 v.id = id;
1356 v.type_id = type;
1357 v.offset = offset;
Chris Forbes804bae32016-03-29 16:14:02 +13001358 v.is_patch = is_patch;
Chris Forbesa0ab8152016-04-20 13:34:27 +12001359 v.is_block_member = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001360 out[std::make_pair(location + offset, component)] = v;
1361 }
1362 } else if (builtin == -1) {
1363 /* An interface block instance */
Chris Forbes804bae32016-03-29 16:14:02 +13001364 collect_interface_block_members(my_data, src, out, blocks, is_array_of_verts, id, type, is_patch);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001365 }
1366 }
1367 }
1368}
1369
Chris Forbes15864502016-03-30 11:35:21 +13001370static void collect_interface_by_descriptor_slot(layer_data *my_data, shader_module const *src,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001371 std::unordered_set<uint32_t> const &accessible_ids,
1372 std::map<descriptor_slot_t, interface_var> &out) {
1373
1374 std::unordered_map<unsigned, unsigned> var_sets;
1375 std::unordered_map<unsigned, unsigned> var_bindings;
1376
1377 for (auto insn : *src) {
1378 /* All variables in the Uniform or UniformConstant storage classes are required to be decorated with both
1379 * DecorationDescriptorSet and DecorationBinding.
1380 */
1381 if (insn.opcode() == spv::OpDecorate) {
1382 if (insn.word(2) == spv::DecorationDescriptorSet) {
1383 var_sets[insn.word(1)] = insn.word(3);
1384 }
1385
1386 if (insn.word(2) == spv::DecorationBinding) {
1387 var_bindings[insn.word(1)] = insn.word(3);
1388 }
1389 }
1390 }
1391
1392 for (auto id : accessible_ids) {
1393 auto insn = src->get_def(id);
1394 assert(insn != src->end());
1395
1396 if (insn.opcode() == spv::OpVariable &&
1397 (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant)) {
1398 unsigned set = value_or_default(var_sets, insn.word(2), 0);
1399 unsigned binding = value_or_default(var_bindings, insn.word(2), 0);
1400
1401 auto existing_it = out.find(std::make_pair(set, binding));
1402 if (existing_it != out.end()) {
1403 /* conflict within spv image */
Chris Forbesce5be902016-03-30 13:14:22 +13001404 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001405 __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
1406 "var %d (type %d) in %s interface in descriptor slot (%u,%u) conflicts with existing definition",
1407 insn.word(2), insn.word(1), storage_class_name(insn.word(3)), existing_it->first.first,
1408 existing_it->first.second);
1409 }
1410
1411 interface_var v;
1412 v.id = insn.word(2);
1413 v.type_id = insn.word(1);
Chris Forbes804bae32016-03-29 16:14:02 +13001414 v.offset = 0;
1415 v.is_patch = false;
Chris Forbesa0ab8152016-04-20 13:34:27 +12001416 v.is_block_member = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001417 out[std::make_pair(set, binding)] = v;
1418 }
1419 }
1420}
1421
Chris Forbes15864502016-03-30 11:35:21 +13001422static bool validate_interface_between_stages(layer_data *my_data, shader_module const *producer,
Chris Forbes23a575d2016-03-29 16:41:07 +13001423 spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001424 shader_module const *consumer, spirv_inst_iter consumer_entrypoint,
Chris Forbes23a575d2016-03-29 16:41:07 +13001425 shader_stage_attributes const *consumer_stage) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001426 std::map<location_t, interface_var> outputs;
1427 std::map<location_t, interface_var> inputs;
1428
1429 bool pass = true;
1430
Chris Forbes23a575d2016-03-29 16:41:07 +13001431 collect_interface_by_location(my_data, producer, producer_entrypoint, spv::StorageClassOutput, outputs, producer_stage->arrayed_output);
1432 collect_interface_by_location(my_data, consumer, consumer_entrypoint, spv::StorageClassInput, inputs, consumer_stage->arrayed_input);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001433
1434 auto a_it = outputs.begin();
1435 auto b_it = inputs.begin();
1436
1437 /* maps sorted by key (location); walk them together to find mismatches */
1438 while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
1439 bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
1440 bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
1441 auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
1442 auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
1443
1444 if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
Chris Forbesce5be902016-03-30 13:14:22 +13001445 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1446 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
Chris Forbes23a575d2016-03-29 16:41:07 +13001447 "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
1448 a_first.second, consumer_stage->name)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001449 pass = false;
1450 }
1451 a_it++;
1452 } else if (a_at_end || a_first > b_first) {
Chris Forbesce5be902016-03-30 13:14:22 +13001453 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001454 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC",
Chris Forbes23a575d2016-03-29 16:41:07 +13001455 "%s consumes input location %u.%u which is not written by %s", consumer_stage->name, b_first.first, b_first.second,
1456 producer_stage->name)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001457 pass = false;
1458 }
1459 b_it++;
1460 } else {
Chris Forbesa0ab8152016-04-20 13:34:27 +12001461 // subtleties of arrayed interfaces:
1462 // - if is_patch, then the member is not arrayed, even though the interface may be.
1463 // - if is_block_member, then the extra array level of an arrayed interface is not
1464 // expressed in the member type -- it's expressed in the block type.
Chris Forbes218deeb2016-03-29 16:57:02 +13001465 if (!types_match(producer, consumer, a_it->second.type_id, b_it->second.type_id,
Chris Forbesa0ab8152016-04-20 13:34:27 +12001466 producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
1467 consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member,
Chris Forbes4ad9cbd2016-04-05 17:51:35 +12001468 true)) {
Chris Forbesce5be902016-03-30 13:14:22 +13001469 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001470 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC", "Type mismatch on location %u.%u: '%s' vs '%s'",
Chris Forbesfa86ce32016-03-18 14:59:39 +13001471 a_first.first, a_first.second,
1472 describe_type(producer, a_it->second.type_id).c_str(),
1473 describe_type(consumer, b_it->second.type_id).c_str())) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001474 pass = false;
1475 }
1476 }
Chris Forbes218deeb2016-03-29 16:57:02 +13001477 if (a_it->second.is_patch != b_it->second.is_patch) {
1478 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
1479 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
Chris Forbesa0193bc2016-04-04 19:19:47 +12001480 "Decoration mismatch on location %u.%u: is per-%s in %s stage but "
Chris Forbes218deeb2016-03-29 16:57:02 +13001481 "per-%s in %s stage", a_first.first, a_first.second,
1482 a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
1483 b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name)) {
1484 pass = false;
1485 }
1486 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001487 a_it++;
1488 b_it++;
1489 }
1490 }
1491
1492 return pass;
1493}
1494
1495enum FORMAT_TYPE {
1496 FORMAT_TYPE_UNDEFINED,
1497 FORMAT_TYPE_FLOAT, /* UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader */
1498 FORMAT_TYPE_SINT,
1499 FORMAT_TYPE_UINT,
1500};
1501
1502static unsigned get_format_type(VkFormat fmt) {
1503 switch (fmt) {
1504 case VK_FORMAT_UNDEFINED:
1505 return FORMAT_TYPE_UNDEFINED;
1506 case VK_FORMAT_R8_SINT:
1507 case VK_FORMAT_R8G8_SINT:
1508 case VK_FORMAT_R8G8B8_SINT:
1509 case VK_FORMAT_R8G8B8A8_SINT:
1510 case VK_FORMAT_R16_SINT:
1511 case VK_FORMAT_R16G16_SINT:
1512 case VK_FORMAT_R16G16B16_SINT:
1513 case VK_FORMAT_R16G16B16A16_SINT:
1514 case VK_FORMAT_R32_SINT:
1515 case VK_FORMAT_R32G32_SINT:
1516 case VK_FORMAT_R32G32B32_SINT:
1517 case VK_FORMAT_R32G32B32A32_SINT:
Chris Forbesf57a5202016-04-20 14:22:07 +12001518 case VK_FORMAT_R64_SINT:
1519 case VK_FORMAT_R64G64_SINT:
1520 case VK_FORMAT_R64G64B64_SINT:
1521 case VK_FORMAT_R64G64B64A64_SINT:
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001522 case VK_FORMAT_B8G8R8_SINT:
1523 case VK_FORMAT_B8G8R8A8_SINT:
Chris Forbese9a21d42016-04-20 14:16:10 +12001524 case VK_FORMAT_A8B8G8R8_SINT_PACK32:
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001525 case VK_FORMAT_A2B10G10R10_SINT_PACK32:
1526 case VK_FORMAT_A2R10G10B10_SINT_PACK32:
1527 return FORMAT_TYPE_SINT;
1528 case VK_FORMAT_R8_UINT:
1529 case VK_FORMAT_R8G8_UINT:
1530 case VK_FORMAT_R8G8B8_UINT:
1531 case VK_FORMAT_R8G8B8A8_UINT:
1532 case VK_FORMAT_R16_UINT:
1533 case VK_FORMAT_R16G16_UINT:
1534 case VK_FORMAT_R16G16B16_UINT:
1535 case VK_FORMAT_R16G16B16A16_UINT:
1536 case VK_FORMAT_R32_UINT:
1537 case VK_FORMAT_R32G32_UINT:
1538 case VK_FORMAT_R32G32B32_UINT:
1539 case VK_FORMAT_R32G32B32A32_UINT:
Chris Forbesf57a5202016-04-20 14:22:07 +12001540 case VK_FORMAT_R64_UINT:
1541 case VK_FORMAT_R64G64_UINT:
1542 case VK_FORMAT_R64G64B64_UINT:
1543 case VK_FORMAT_R64G64B64A64_UINT:
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001544 case VK_FORMAT_B8G8R8_UINT:
1545 case VK_FORMAT_B8G8R8A8_UINT:
Chris Forbese9a21d42016-04-20 14:16:10 +12001546 case VK_FORMAT_A8B8G8R8_UINT_PACK32:
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001547 case VK_FORMAT_A2B10G10R10_UINT_PACK32:
1548 case VK_FORMAT_A2R10G10B10_UINT_PACK32:
1549 return FORMAT_TYPE_UINT;
1550 default:
1551 return FORMAT_TYPE_FLOAT;
1552 }
1553}
1554
1555/* characterizes a SPIR-V type appearing in an interface to a FF stage,
1556 * for comparison to a VkFormat's characterization above. */
1557static unsigned get_fundamental_type(shader_module const *src, unsigned type) {
1558 auto insn = src->get_def(type);
1559 assert(insn != src->end());
1560
1561 switch (insn.opcode()) {
1562 case spv::OpTypeInt:
1563 return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
1564 case spv::OpTypeFloat:
1565 return FORMAT_TYPE_FLOAT;
1566 case spv::OpTypeVector:
1567 return get_fundamental_type(src, insn.word(2));
1568 case spv::OpTypeMatrix:
1569 return get_fundamental_type(src, insn.word(2));
1570 case spv::OpTypeArray:
1571 return get_fundamental_type(src, insn.word(2));
1572 case spv::OpTypePointer:
1573 return get_fundamental_type(src, insn.word(3));
1574 default:
1575 return FORMAT_TYPE_UNDEFINED;
1576 }
1577}
1578
1579static uint32_t get_shader_stage_id(VkShaderStageFlagBits stage) {
1580 uint32_t bit_pos = u_ffs(stage);
1581 return bit_pos - 1;
1582}
1583
Chris Forbes15864502016-03-30 11:35:21 +13001584static bool validate_vi_consistency(layer_data *my_data, VkPipelineVertexInputStateCreateInfo const *vi) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001585 /* walk the binding descriptions, which describe the step rate and stride of each vertex buffer.
1586 * each binding should be specified only once.
1587 */
1588 std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
1589 bool pass = true;
1590
1591 for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
1592 auto desc = &vi->pVertexBindingDescriptions[i];
1593 auto &binding = bindings[desc->binding];
1594 if (binding) {
Chris Forbesce5be902016-03-30 13:14:22 +13001595 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001596 __LINE__, SHADER_CHECKER_INCONSISTENT_VI, "SC",
1597 "Duplicate vertex input binding descriptions for binding %d", desc->binding)) {
1598 pass = false;
1599 }
1600 } else {
1601 binding = desc;
1602 }
1603 }
1604
1605 return pass;
1606}
1607
Chris Forbes15864502016-03-30 11:35:21 +13001608static bool validate_vi_against_vs_inputs(layer_data *my_data, VkPipelineVertexInputStateCreateInfo const *vi,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001609 shader_module const *vs, spirv_inst_iter entrypoint) {
1610 std::map<location_t, interface_var> inputs;
1611 bool pass = true;
1612
Chris Forbes15864502016-03-30 11:35:21 +13001613 collect_interface_by_location(my_data, vs, entrypoint, spv::StorageClassInput, inputs, false);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001614
1615 /* Build index by location */
1616 std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
1617 if (vi) {
Chris Forbese32b78a2016-04-21 15:00:58 +12001618 for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
1619 auto num_locations = get_locations_consumed_by_format(vi->pVertexAttributeDescriptions[i].format);
1620 for (auto j = 0u; j < num_locations; j++) {
1621 attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1622 }
1623 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001624 }
1625
1626 auto it_a = attribs.begin();
1627 auto it_b = inputs.begin();
1628
1629 while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
1630 bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
1631 bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
1632 auto a_first = a_at_end ? 0 : it_a->first;
1633 auto b_first = b_at_end ? 0 : it_b->first.first;
1634 if (!a_at_end && (b_at_end || a_first < b_first)) {
Chris Forbesce5be902016-03-30 13:14:22 +13001635 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1636 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001637 "Vertex attribute at location %d not consumed by VS", a_first)) {
1638 pass = false;
1639 }
1640 it_a++;
1641 } else if (!b_at_end && (a_at_end || b_first < a_first)) {
1642 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/ 0,
1643 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "VS consumes input at location %d but not provided",
1644 b_first)) {
1645 pass = false;
1646 }
1647 it_b++;
1648 } else {
1649 unsigned attrib_type = get_format_type(it_a->second->format);
1650 unsigned input_type = get_fundamental_type(vs, it_b->second.type_id);
1651
1652 /* type checking */
1653 if (attrib_type != FORMAT_TYPE_UNDEFINED && input_type != FORMAT_TYPE_UNDEFINED && attrib_type != input_type) {
Chris Forbesce5be902016-03-30 13:14:22 +13001654 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001655 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1656 "Attribute type of `%s` at location %d does not match VS input type of `%s`",
Chris Forbesfa86ce32016-03-18 14:59:39 +13001657 string_VkFormat(it_a->second->format), a_first,
1658 describe_type(vs, it_b->second.type_id).c_str())) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001659 pass = false;
1660 }
1661 }
1662
1663 /* OK! */
1664 it_a++;
1665 it_b++;
1666 }
1667 }
1668
1669 return pass;
1670}
1671
Chris Forbes15864502016-03-30 11:35:21 +13001672static bool validate_fs_outputs_against_render_pass(layer_data *my_data, shader_module const *fs,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001673 spirv_inst_iter entrypoint, RENDER_PASS_NODE const *rp, uint32_t subpass) {
1674 const std::vector<VkFormat> &color_formats = rp->subpassColorFormats[subpass];
1675 std::map<location_t, interface_var> outputs;
1676 bool pass = true;
1677
1678 /* TODO: dual source blend index (spv::DecIndex, zero if not provided) */
1679
Chris Forbes15864502016-03-30 11:35:21 +13001680 collect_interface_by_location(my_data, fs, entrypoint, spv::StorageClassOutput, outputs, false);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001681
1682 auto it = outputs.begin();
1683 uint32_t attachment = 0;
1684
1685 /* Walk attachment list and outputs together -- this is a little overpowered since attachments
1686 * are currently dense, but the parallel with matching between shader stages is nice.
1687 */
1688
1689 while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) {
1690 if (attachment == color_formats.size() || (it != outputs.end() && it->first.first < attachment)) {
Chris Forbesce5be902016-03-30 13:14:22 +13001691 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001692 __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",
1693 "FS writes to output location %d with no matching attachment", it->first.first)) {
1694 pass = false;
1695 }
1696 it++;
1697 } else if (it == outputs.end() || it->first.first > attachment) {
Chris Forbesce5be902016-03-30 13:14:22 +13001698 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001699 __LINE__, SHADER_CHECKER_INPUT_NOT_PRODUCED, "SC", "Attachment %d not written by FS", attachment)) {
1700 pass = false;
1701 }
1702 attachment++;
1703 } else {
1704 unsigned output_type = get_fundamental_type(fs, it->second.type_id);
1705 unsigned att_type = get_format_type(color_formats[attachment]);
1706
1707 /* type checking */
1708 if (att_type != FORMAT_TYPE_UNDEFINED && output_type != FORMAT_TYPE_UNDEFINED && att_type != output_type) {
Chris Forbesce5be902016-03-30 13:14:22 +13001709 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001710 __LINE__, SHADER_CHECKER_INTERFACE_TYPE_MISMATCH, "SC",
1711 "Attachment %d of type `%s` does not match FS output type of `%s`", attachment,
Chris Forbesfa86ce32016-03-18 14:59:39 +13001712 string_VkFormat(color_formats[attachment]),
1713 describe_type(fs, it->second.type_id).c_str())) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001714 pass = false;
1715 }
1716 }
1717
1718 /* OK! */
1719 it++;
1720 attachment++;
1721 }
1722 }
1723
1724 return pass;
1725}
1726
1727/* For some analyses, we need to know about all ids referenced by the static call tree of a particular
1728 * entrypoint. This is important for identifying the set of shader resources actually used by an entrypoint,
1729 * for example.
1730 * Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
1731 * - NOT the shader input/output interfaces.
1732 *
1733 * TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
1734 * converting parts of this to be generated from the machine-readable spec instead.
1735 */
1736static void mark_accessible_ids(shader_module const *src, spirv_inst_iter entrypoint, std::unordered_set<uint32_t> &ids) {
1737 std::unordered_set<uint32_t> worklist;
1738 worklist.insert(entrypoint.word(2));
1739
1740 while (!worklist.empty()) {
1741 auto id_iter = worklist.begin();
1742 auto id = *id_iter;
1743 worklist.erase(id_iter);
1744
1745 auto insn = src->get_def(id);
1746 if (insn == src->end()) {
Eric Engestrombcbb0fd2016-04-02 22:06:13 +01001747 /* id is something we didn't collect in build_def_index. that's OK -- we'll stumble
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001748 * across all kinds of things here that we may not care about. */
1749 continue;
1750 }
1751
1752 /* try to add to the output set */
1753 if (!ids.insert(id).second) {
1754 continue; /* if we already saw this id, we don't want to walk it again. */
1755 }
1756
1757 switch (insn.opcode()) {
1758 case spv::OpFunction:
1759 /* scan whole body of the function, enlisting anything interesting */
1760 while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1761 switch (insn.opcode()) {
1762 case spv::OpLoad:
1763 case spv::OpAtomicLoad:
1764 case spv::OpAtomicExchange:
1765 case spv::OpAtomicCompareExchange:
1766 case spv::OpAtomicCompareExchangeWeak:
1767 case spv::OpAtomicIIncrement:
1768 case spv::OpAtomicIDecrement:
1769 case spv::OpAtomicIAdd:
1770 case spv::OpAtomicISub:
1771 case spv::OpAtomicSMin:
1772 case spv::OpAtomicUMin:
1773 case spv::OpAtomicSMax:
1774 case spv::OpAtomicUMax:
1775 case spv::OpAtomicAnd:
1776 case spv::OpAtomicOr:
1777 case spv::OpAtomicXor:
1778 worklist.insert(insn.word(3)); /* ptr */
1779 break;
1780 case spv::OpStore:
1781 case spv::OpAtomicStore:
1782 worklist.insert(insn.word(1)); /* ptr */
1783 break;
1784 case spv::OpAccessChain:
1785 case spv::OpInBoundsAccessChain:
1786 worklist.insert(insn.word(3)); /* base ptr */
1787 break;
1788 case spv::OpSampledImage:
1789 case spv::OpImageSampleImplicitLod:
1790 case spv::OpImageSampleExplicitLod:
1791 case spv::OpImageSampleDrefImplicitLod:
1792 case spv::OpImageSampleDrefExplicitLod:
1793 case spv::OpImageSampleProjImplicitLod:
1794 case spv::OpImageSampleProjExplicitLod:
1795 case spv::OpImageSampleProjDrefImplicitLod:
1796 case spv::OpImageSampleProjDrefExplicitLod:
1797 case spv::OpImageFetch:
1798 case spv::OpImageGather:
1799 case spv::OpImageDrefGather:
1800 case spv::OpImageRead:
1801 case spv::OpImage:
1802 case spv::OpImageQueryFormat:
1803 case spv::OpImageQueryOrder:
1804 case spv::OpImageQuerySizeLod:
1805 case spv::OpImageQuerySize:
1806 case spv::OpImageQueryLod:
1807 case spv::OpImageQueryLevels:
1808 case spv::OpImageQuerySamples:
1809 case spv::OpImageSparseSampleImplicitLod:
1810 case spv::OpImageSparseSampleExplicitLod:
1811 case spv::OpImageSparseSampleDrefImplicitLod:
1812 case spv::OpImageSparseSampleDrefExplicitLod:
1813 case spv::OpImageSparseSampleProjImplicitLod:
1814 case spv::OpImageSparseSampleProjExplicitLod:
1815 case spv::OpImageSparseSampleProjDrefImplicitLod:
1816 case spv::OpImageSparseSampleProjDrefExplicitLod:
1817 case spv::OpImageSparseFetch:
1818 case spv::OpImageSparseGather:
1819 case spv::OpImageSparseDrefGather:
1820 case spv::OpImageTexelPointer:
1821 worklist.insert(insn.word(3)); /* image or sampled image */
1822 break;
1823 case spv::OpImageWrite:
1824 worklist.insert(insn.word(1)); /* image -- different operand order to above */
1825 break;
1826 case spv::OpFunctionCall:
Michael Mc Donnell75ecdb72016-04-03 14:47:51 -07001827 for (uint32_t i = 3; i < insn.len(); i++) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001828 worklist.insert(insn.word(i)); /* fn itself, and all args */
1829 }
1830 break;
1831
1832 case spv::OpExtInst:
Michael Mc Donnell75ecdb72016-04-03 14:47:51 -07001833 for (uint32_t i = 5; i < insn.len(); i++) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001834 worklist.insert(insn.word(i)); /* operands to ext inst */
1835 }
1836 break;
1837 }
1838 }
1839 break;
1840 }
1841 }
1842}
1843
Chris Forbes15864502016-03-30 11:35:21 +13001844static bool validate_push_constant_block_against_pipeline(layer_data *my_data,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001845 std::vector<VkPushConstantRange> const *pushConstantRanges,
1846 shader_module const *src, spirv_inst_iter type,
1847 VkShaderStageFlagBits stage) {
1848 bool pass = true;
1849
1850 /* strip off ptrs etc */
1851 type = get_struct_type(src, type, false);
1852 assert(type != src->end());
1853
1854 /* validate directly off the offsets. this isn't quite correct for arrays
1855 * and matrices, but is a good first step. TODO: arrays, matrices, weird
1856 * sizes */
1857 for (auto insn : *src) {
1858 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
1859
1860 if (insn.word(3) == spv::DecorationOffset) {
1861 unsigned offset = insn.word(4);
1862 auto size = 4; /* bytes; TODO: calculate this based on the type */
1863
1864 bool found_range = false;
1865 for (auto const &range : *pushConstantRanges) {
1866 if (range.offset <= offset && range.offset + range.size >= offset + size) {
1867 found_range = true;
1868
1869 if ((range.stageFlags & stage) == 0) {
Chris Forbesce5be902016-03-30 13:14:22 +13001870 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1871 __LINE__, SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, "SC",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001872 "Push constant range covering variable starting at "
1873 "offset %u not accessible from stage %s",
1874 offset, string_VkShaderStageFlagBits(stage))) {
1875 pass = false;
1876 }
1877 }
1878
1879 break;
1880 }
1881 }
1882
1883 if (!found_range) {
Chris Forbesce5be902016-03-30 13:14:22 +13001884 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
1885 __LINE__, SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, "SC",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001886 "Push constant range covering variable starting at "
1887 "offset %u not declared in layout",
1888 offset)) {
1889 pass = false;
1890 }
1891 }
1892 }
1893 }
1894 }
1895
1896 return pass;
1897}
1898
Chris Forbes15864502016-03-30 11:35:21 +13001899static bool validate_push_constant_usage(layer_data *my_data,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001900 std::vector<VkPushConstantRange> const *pushConstantRanges, shader_module const *src,
1901 std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
1902 bool pass = true;
1903
1904 for (auto id : accessible_ids) {
1905 auto def_insn = src->get_def(id);
1906 if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
Chris Forbesce5be902016-03-30 13:14:22 +13001907 pass &= validate_push_constant_block_against_pipeline(my_data, pushConstantRanges, src,
1908 src->get_def(def_insn.word(1)), stage);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001909 }
1910 }
1911
1912 return pass;
1913}
1914
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06001915// For given pipelineLayout verify that the set_layout_node at slot.first
1916// has the requested binding at slot.second and return ptr to that binding
Chris Forbes961cee72016-03-30 12:12:01 +13001917static VkDescriptorSetLayoutBinding const * get_descriptor_binding(layer_data *my_data, PIPELINE_LAYOUT_NODE *pipelineLayout, descriptor_slot_t slot) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001918
1919 if (!pipelineLayout)
Chris Forbes4e4191b2016-03-18 11:14:27 +13001920 return nullptr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001921
Chris Forbes961cee72016-03-30 12:12:01 +13001922 if (slot.first >= pipelineLayout->descriptorSetLayouts.size())
Chris Forbes4e4191b2016-03-18 11:14:27 +13001923 return nullptr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001924
Tobin Ehlis546326f2016-04-26 11:06:05 -06001925 const auto & layout_node = my_data->descriptorSetLayoutMap[pipelineLayout->descriptorSetLayouts[slot.first]];
1926 return layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001927}
1928
1929// Block of code at start here for managing/tracking Pipeline state that this layer cares about
1930
1931static uint64_t g_drawCount[NUM_DRAW_TYPES] = {0, 0, 0, 0};
1932
1933// TODO : Should be tracking lastBound per commandBuffer and when draws occur, report based on that cmd buffer lastBound
1934// Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates
1935// to that same cmd buffer by separate thread are not changing state from underneath us
1936// Track the last cmd buffer touched by this thread
1937
Dustin Graves8f1eab92016-04-05 09:41:17 -06001938static bool hasDrawCmd(GLOBAL_CB_NODE *pCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001939 for (uint32_t i = 0; i < NUM_DRAW_TYPES; i++) {
1940 if (pCB->drawCount[i])
Dustin Graves8f1eab92016-04-05 09:41:17 -06001941 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001942 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06001943 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001944}
1945
1946// Check object status for selected flag state
Dustin Graves8f1eab92016-04-05 09:41:17 -06001947static bool validate_status(layer_data *my_data, GLOBAL_CB_NODE *pNode, CBStatusFlags status_mask, VkFlags msg_flags,
1948 DRAW_STATE_ERROR error_code, const char *fail_msg) {
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06001949 if (!(pNode->status & status_mask)) {
1950 return log_msg(my_data->report_data, msg_flags, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
1951 reinterpret_cast<const uint64_t &>(pNode->commandBuffer), __LINE__, error_code, "DS",
1952 "CB object %#" PRIxLEAST64 ": %s", reinterpret_cast<const uint64_t &>(pNode->commandBuffer), fail_msg);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001953 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06001954 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001955}
1956
1957// Retrieve pipeline node ptr for given pipeline object
1958static PIPELINE_NODE *getPipeline(layer_data *my_data, const VkPipeline pipeline) {
1959 if (my_data->pipelineMap.find(pipeline) == my_data->pipelineMap.end()) {
1960 return NULL;
1961 }
1962 return my_data->pipelineMap[pipeline];
1963}
1964
Dustin Graves8f1eab92016-04-05 09:41:17 -06001965// Return true if for a given PSO, the given state enum is dynamic, else return false
1966static bool isDynamic(const PIPELINE_NODE *pPipeline, const VkDynamicState state) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001967 if (pPipeline && pPipeline->graphicsPipelineCI.pDynamicState) {
1968 for (uint32_t i = 0; i < pPipeline->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
1969 if (state == pPipeline->graphicsPipelineCI.pDynamicState->pDynamicStates[i])
Dustin Graves8f1eab92016-04-05 09:41:17 -06001970 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001971 }
1972 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06001973 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07001974}
1975
1976// Validate state stored as flags at time of draw call
Dustin Graves8f1eab92016-04-05 09:41:17 -06001977static bool validate_draw_state_flags(layer_data *dev_data, GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe, bool indexedDraw) {
1978 bool result;
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06001979 result = validate_status(dev_data, pCB, CBSTATUS_VIEWPORT_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_VIEWPORT_NOT_BOUND,
1980 "Dynamic viewport state not set for this command buffer");
1981 result |= validate_status(dev_data, pCB, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_SCISSOR_NOT_BOUND,
1982 "Dynamic scissor state not set for this command buffer");
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06001983 if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
1984 ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
1985 (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06001986 result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
1987 DRAWSTATE_LINE_WIDTH_NOT_BOUND, "Dynamic line width state not set for this command buffer");
1988 }
Dustin Gravesbd9c1a92016-04-05 15:15:40 -06001989 if (pPipe->graphicsPipelineCI.pRasterizationState &&
1990 (pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable == VK_TRUE)) {
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06001991 result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
1992 DRAWSTATE_DEPTH_BIAS_NOT_BOUND, "Dynamic depth bias state not set for this command buffer");
1993 }
1994 if (pPipe->blendConstantsEnabled) {
1995 result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
1996 DRAWSTATE_BLEND_NOT_BOUND, "Dynamic blend constants state not set for this command buffer");
1997 }
Dustin Gravesbd9c1a92016-04-05 15:15:40 -06001998 if (pPipe->graphicsPipelineCI.pDepthStencilState &&
1999 (pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable == VK_TRUE)) {
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06002000 result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2001 DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, "Dynamic depth bounds state not set for this command buffer");
2002 }
Dustin Gravesbd9c1a92016-04-05 15:15:40 -06002003 if (pPipe->graphicsPipelineCI.pDepthStencilState &&
2004 (pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable == VK_TRUE)) {
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06002005 result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2006 DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil read mask state not set for this command buffer");
2007 result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2008 DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil write mask state not set for this command buffer");
2009 result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_REFERENCE_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2010 DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil reference state not set for this command buffer");
2011 }
2012 if (indexedDraw) {
2013 result |= validate_status(dev_data, pCB, CBSTATUS_INDEX_BUFFER_BOUND, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2014 DRAWSTATE_INDEX_BUFFER_NOT_BOUND,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002015 "Index buffer object not bound to this command buffer when Indexed Draw attempted");
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06002016 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002017 return result;
2018}
2019
2020// Verify attachment reference compatibility according to spec
2021// If one array is larger, treat missing elements of shorter array as VK_ATTACHMENT_UNUSED & other array much match this
2022// If both AttachmentReference arrays have requested index, check their corresponding AttachementDescriptions
2023// to make sure that format and samples counts match.
2024// If not, they are not compatible.
2025static bool attachment_references_compatible(const uint32_t index, const VkAttachmentReference *pPrimary,
2026 const uint32_t primaryCount, const VkAttachmentDescription *pPrimaryAttachments,
2027 const VkAttachmentReference *pSecondary, const uint32_t secondaryCount,
2028 const VkAttachmentDescription *pSecondaryAttachments) {
2029 if (index >= primaryCount) { // Check secondary as if primary is VK_ATTACHMENT_UNUSED
Mark Youngeeafb152016-03-24 10:14:35 -06002030 if (VK_ATTACHMENT_UNUSED == pSecondary[index].attachment)
2031 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002032 } else if (index >= secondaryCount) { // Check primary as if secondary is VK_ATTACHMENT_UNUSED
Mark Youngeeafb152016-03-24 10:14:35 -06002033 if (VK_ATTACHMENT_UNUSED == pPrimary[index].attachment)
2034 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002035 } else { // format and sample count must match
2036 if ((pPrimaryAttachments[pPrimary[index].attachment].format ==
2037 pSecondaryAttachments[pSecondary[index].attachment].format) &&
2038 (pPrimaryAttachments[pPrimary[index].attachment].samples ==
2039 pSecondaryAttachments[pSecondary[index].attachment].samples))
2040 return true;
2041 }
2042 // Format and sample counts didn't match
2043 return false;
2044}
2045
2046// For give primary and secondary RenderPass objects, verify that they're compatible
2047static bool verify_renderpass_compatibility(layer_data *my_data, const VkRenderPass primaryRP, const VkRenderPass secondaryRP,
2048 string &errorMsg) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002049 if (my_data->renderPassMap.find(primaryRP) == my_data->renderPassMap.end()) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002050 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002051 errorStr << "invalid VkRenderPass (" << primaryRP << ")";
2052 errorMsg = errorStr.str();
2053 return false;
2054 } else if (my_data->renderPassMap.find(secondaryRP) == my_data->renderPassMap.end()) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002055 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002056 errorStr << "invalid VkRenderPass (" << secondaryRP << ")";
2057 errorMsg = errorStr.str();
2058 return false;
2059 }
2060 // Trivial pass case is exact same RP
2061 if (primaryRP == secondaryRP) {
2062 return true;
2063 }
2064 const VkRenderPassCreateInfo *primaryRPCI = my_data->renderPassMap[primaryRP]->pCreateInfo;
2065 const VkRenderPassCreateInfo *secondaryRPCI = my_data->renderPassMap[secondaryRP]->pCreateInfo;
2066 if (primaryRPCI->subpassCount != secondaryRPCI->subpassCount) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002067 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002068 errorStr << "RenderPass for primary cmdBuffer has " << primaryRPCI->subpassCount
2069 << " subpasses but renderPass for secondary cmdBuffer has " << secondaryRPCI->subpassCount << " subpasses.";
2070 errorMsg = errorStr.str();
2071 return false;
2072 }
2073 uint32_t spIndex = 0;
2074 for (spIndex = 0; spIndex < primaryRPCI->subpassCount; ++spIndex) {
2075 // For each subpass, verify that corresponding color, input, resolve & depth/stencil attachment references are compatible
2076 uint32_t primaryColorCount = primaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
2077 uint32_t secondaryColorCount = secondaryRPCI->pSubpasses[spIndex].colorAttachmentCount;
2078 uint32_t colorMax = std::max(primaryColorCount, secondaryColorCount);
2079 for (uint32_t cIdx = 0; cIdx < colorMax; ++cIdx) {
2080 if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pColorAttachments, primaryColorCount,
2081 primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pColorAttachments,
2082 secondaryColorCount, secondaryRPCI->pAttachments)) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002083 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002084 errorStr << "color attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
2085 errorMsg = errorStr.str();
2086 return false;
2087 } else if (!attachment_references_compatible(cIdx, primaryRPCI->pSubpasses[spIndex].pResolveAttachments,
2088 primaryColorCount, primaryRPCI->pAttachments,
2089 secondaryRPCI->pSubpasses[spIndex].pResolveAttachments,
2090 secondaryColorCount, secondaryRPCI->pAttachments)) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002091 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002092 errorStr << "resolve attachments at index " << cIdx << " of subpass index " << spIndex << " are not compatible.";
2093 errorMsg = errorStr.str();
2094 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002095 }
2096 }
Chris Forbesb442e562016-04-11 18:32:23 +12002097
2098 if (!attachment_references_compatible(0, primaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
2099 1, primaryRPCI->pAttachments,
2100 secondaryRPCI->pSubpasses[spIndex].pDepthStencilAttachment,
2101 1, secondaryRPCI->pAttachments)) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002102 stringstream errorStr;
Chris Forbesb442e562016-04-11 18:32:23 +12002103 errorStr << "depth/stencil attachments of subpass index " << spIndex << " are not compatible.";
2104 errorMsg = errorStr.str();
2105 return false;
2106 }
2107
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002108 uint32_t primaryInputCount = primaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
2109 uint32_t secondaryInputCount = secondaryRPCI->pSubpasses[spIndex].inputAttachmentCount;
2110 uint32_t inputMax = std::max(primaryInputCount, secondaryInputCount);
2111 for (uint32_t i = 0; i < inputMax; ++i) {
2112 if (!attachment_references_compatible(i, primaryRPCI->pSubpasses[spIndex].pInputAttachments, primaryColorCount,
2113 primaryRPCI->pAttachments, secondaryRPCI->pSubpasses[spIndex].pInputAttachments,
2114 secondaryColorCount, secondaryRPCI->pAttachments)) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002115 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002116 errorStr << "input attachments at index " << i << " of subpass index " << spIndex << " are not compatible.";
2117 errorMsg = errorStr.str();
2118 return false;
2119 }
2120 }
2121 }
2122 return true;
2123}
2124
2125// For give SET_NODE, verify that its Set is compatible w/ the setLayout corresponding to pipelineLayout[layoutIndex]
2126static bool verify_set_layout_compatibility(layer_data *my_data, const SET_NODE *pSet, const VkPipelineLayout layout,
2127 const uint32_t layoutIndex, string &errorMsg) {
Chris Forbesedd25d32016-03-18 15:49:58 +13002128 auto pipeline_layout_it = my_data->pipelineLayoutMap.find(layout);
2129 if (pipeline_layout_it == my_data->pipelineLayoutMap.end()) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002130 stringstream errorStr;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002131 errorStr << "invalid VkPipelineLayout (" << layout << ")";
2132 errorMsg = errorStr.str();
2133 return false;
2134 }
Chris Forbesedd25d32016-03-18 15:49:58 +13002135 if (layoutIndex >= pipeline_layout_it->second.descriptorSetLayouts.size()) {
Chris Forbesba2c4662016-04-14 10:30:01 +12002136 stringstream errorStr;
Chris Forbesedd25d32016-03-18 15:49:58 +13002137 errorStr << "VkPipelineLayout (" << layout << ") only contains " << pipeline_layout_it->second.descriptorSetLayouts.size()
2138 << " setLayouts corresponding to sets 0-" << pipeline_layout_it->second.descriptorSetLayouts.size() - 1
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002139 << ", but you're attempting to bind set to index " << layoutIndex;
2140 errorMsg = errorStr.str();
2141 return false;
2142 }
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002143 auto layout_node = my_data->descriptorSetLayoutMap[pipeline_layout_it->second.descriptorSetLayouts[layoutIndex]];
Tobin Ehlis546326f2016-04-26 11:06:05 -06002144 return layout_node->IsCompatible(pSet->p_layout, &errorMsg);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002145}
2146
2147// Validate that data for each specialization entry is fully contained within the buffer.
Dustin Graves8f1eab92016-04-05 09:41:17 -06002148static bool validate_specialization_offsets(layer_data *my_data, VkPipelineShaderStageCreateInfo const *info) {
2149 bool pass = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002150
2151 VkSpecializationInfo const *spec = info->pSpecializationInfo;
2152
2153 if (spec) {
2154 for (auto i = 0u; i < spec->mapEntryCount; i++) {
2155 if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
2156 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
2157 /*dev*/ 0, __LINE__, SHADER_CHECKER_BAD_SPECIALIZATION, "SC",
2158 "Specialization entry %u (for constant id %u) references memory outside provided "
2159 "specialization data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER
2160 " bytes provided)",
2161 i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
2162 spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize)) {
2163
Dustin Graves8f1eab92016-04-05 09:41:17 -06002164 pass = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002165 }
2166 }
2167 }
2168 }
2169
2170 return pass;
2171}
2172
2173static bool descriptor_type_match(layer_data *my_data, shader_module const *module, uint32_t type_id,
Chris Forbesb9fb5fc2016-03-18 11:21:35 +13002174 VkDescriptorType descriptor_type, unsigned &descriptor_count) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002175 auto type = module->get_def(type_id);
2176
Chris Forbesb9fb5fc2016-03-18 11:21:35 +13002177 descriptor_count = 1;
2178
Chris Forbesa1361092016-03-18 11:26:06 +13002179 /* Strip off any array or ptrs. Where we remove array levels, adjust the
2180 * descriptor count for each dimension. */
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002181 while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer) {
Chris Forbesa1361092016-03-18 11:26:06 +13002182 if (type.opcode() == spv::OpTypeArray) {
2183 descriptor_count *= get_constant_value(module, type.word(3));
2184 type = module->get_def(type.word(2));
2185 }
2186 else {
2187 type = module->get_def(type.word(3));
2188 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002189 }
2190
2191 switch (type.opcode()) {
2192 case spv::OpTypeStruct: {
2193 for (auto insn : *module) {
2194 if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2195 if (insn.word(2) == spv::DecorationBlock) {
2196 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
2197 descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
2198 } else if (insn.word(2) == spv::DecorationBufferBlock) {
2199 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2200 descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2201 }
2202 }
2203 }
2204
2205 /* Invalid */
2206 return false;
2207 }
2208
2209 case spv::OpTypeSampler:
2210 return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER;
2211
2212 case spv::OpTypeSampledImage:
Chris Forbesccf300b2016-03-24 14:14:45 +13002213 if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
2214 /* Slight relaxation for some GLSL historical madness: samplerBuffer
2215 * doesn't really have a sampler, and a texel buffer descriptor
2216 * doesn't really provide one. Allow this slight mismatch.
2217 */
2218 auto image_type = module->get_def(type.word(2));
2219 auto dim = image_type.word(3);
2220 auto sampled = image_type.word(7);
2221 return dim == spv::DimBuffer && sampled == 1;
2222 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002223 return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
2224
2225 case spv::OpTypeImage: {
2226 /* Many descriptor types backing image types-- depends on dimension
2227 * and whether the image will be used with a sampler. SPIRV for
2228 * Vulkan requires that sampled be 1 or 2 -- leaving the decision to
2229 * runtime is unacceptable.
2230 */
2231 auto dim = type.word(3);
2232 auto sampled = type.word(7);
2233
2234 if (dim == spv::DimSubpassData) {
2235 return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
2236 } else if (dim == spv::DimBuffer) {
2237 if (sampled == 1) {
2238 return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
2239 } else {
2240 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
2241 }
2242 } else if (sampled == 1) {
2243 return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
2244 } else {
2245 return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
2246 }
2247 }
2248
2249 /* We shouldn't really see any other junk types -- but if we do, they're
2250 * a mismatch.
2251 */
2252 default:
2253 return false; /* Mismatch */
2254 }
2255}
2256
Dustin Graves8f1eab92016-04-05 09:41:17 -06002257static bool require_feature(layer_data *my_data, VkBool32 feature, char const *feature_name) {
Chris Forbesc3a1dbc2016-03-15 10:12:48 +13002258 if (!feature) {
Chris Forbesce5be902016-03-30 13:14:22 +13002259 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2260 __LINE__, SHADER_CHECKER_FEATURE_NOT_ENABLED, "SC",
Chris Forbesc3a1dbc2016-03-15 10:12:48 +13002261 "Shader requires VkPhysicalDeviceFeatures::%s but is not "
2262 "enabled on the device",
2263 feature_name)) {
2264 return false;
2265 }
2266 }
2267
2268 return true;
2269}
2270
Dustin Graves8f1eab92016-04-05 09:41:17 -06002271static bool validate_shader_capabilities(layer_data *my_data, shader_module const *src) {
2272 bool pass = true;
Chris Forbesc3a1dbc2016-03-15 10:12:48 +13002273
Tobin Ehlise54be7b2016-04-11 14:49:55 -06002274 auto enabledFeatures = &my_data->phys_dev_properties.features;
Chris Forbesc3a1dbc2016-03-15 10:12:48 +13002275
2276 for (auto insn : *src) {
2277 if (insn.opcode() == spv::OpCapability) {
2278 switch (insn.word(1)) {
2279 case spv::CapabilityMatrix:
2280 case spv::CapabilityShader:
2281 case spv::CapabilityInputAttachment:
2282 case spv::CapabilitySampled1D:
2283 case spv::CapabilityImage1D:
2284 case spv::CapabilitySampledBuffer:
2285 case spv::CapabilityImageBuffer:
2286 case spv::CapabilityImageQuery:
2287 case spv::CapabilityDerivativeControl:
2288 // Always supported by a Vulkan 1.0 implementation -- no feature bits.
2289 break;
2290
2291 case spv::CapabilityGeometry:
2292 pass &= require_feature(my_data, enabledFeatures->geometryShader, "geometryShader");
2293 break;
2294
2295 case spv::CapabilityTessellation:
2296 pass &= require_feature(my_data, enabledFeatures->tessellationShader, "tessellationShader");
2297 break;
2298
2299 case spv::CapabilityFloat64:
2300 pass &= require_feature(my_data, enabledFeatures->shaderFloat64, "shaderFloat64");
2301 break;
2302
2303 case spv::CapabilityInt64:
2304 pass &= require_feature(my_data, enabledFeatures->shaderInt64, "shaderInt64");
2305 break;
2306
2307 case spv::CapabilityTessellationPointSize:
2308 case spv::CapabilityGeometryPointSize:
2309 pass &= require_feature(my_data, enabledFeatures->shaderTessellationAndGeometryPointSize,
2310 "shaderTessellationAndGeometryPointSize");
2311 break;
2312
2313 case spv::CapabilityImageGatherExtended:
2314 pass &= require_feature(my_data, enabledFeatures->shaderImageGatherExtended, "shaderImageGatherExtended");
2315 break;
2316
2317 case spv::CapabilityStorageImageMultisample:
2318 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample");
2319 break;
2320
2321 case spv::CapabilityUniformBufferArrayDynamicIndexing:
2322 pass &= require_feature(my_data, enabledFeatures->shaderUniformBufferArrayDynamicIndexing,
2323 "shaderUniformBufferArrayDynamicIndexing");
2324 break;
2325
2326 case spv::CapabilitySampledImageArrayDynamicIndexing:
2327 pass &= require_feature(my_data, enabledFeatures->shaderSampledImageArrayDynamicIndexing,
2328 "shaderSampledImageArrayDynamicIndexing");
2329 break;
2330
2331 case spv::CapabilityStorageBufferArrayDynamicIndexing:
2332 pass &= require_feature(my_data, enabledFeatures->shaderStorageBufferArrayDynamicIndexing,
2333 "shaderStorageBufferArrayDynamicIndexing");
2334 break;
2335
2336 case spv::CapabilityStorageImageArrayDynamicIndexing:
2337 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageArrayDynamicIndexing,
2338 "shaderStorageImageArrayDynamicIndexing");
2339 break;
2340
2341 case spv::CapabilityClipDistance:
2342 pass &= require_feature(my_data, enabledFeatures->shaderClipDistance, "shaderClipDistance");
2343 break;
2344
2345 case spv::CapabilityCullDistance:
2346 pass &= require_feature(my_data, enabledFeatures->shaderCullDistance, "shaderCullDistance");
2347 break;
2348
2349 case spv::CapabilityImageCubeArray:
2350 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2351 break;
2352
2353 case spv::CapabilitySampleRateShading:
2354 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2355 break;
2356
2357 case spv::CapabilitySparseResidency:
2358 pass &= require_feature(my_data, enabledFeatures->shaderResourceResidency, "shaderResourceResidency");
2359 break;
2360
2361 case spv::CapabilityMinLod:
2362 pass &= require_feature(my_data, enabledFeatures->shaderResourceMinLod, "shaderResourceMinLod");
2363 break;
2364
2365 case spv::CapabilitySampledCubeArray:
2366 pass &= require_feature(my_data, enabledFeatures->imageCubeArray, "imageCubeArray");
2367 break;
2368
2369 case spv::CapabilityImageMSArray:
2370 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageMultisample, "shaderStorageImageMultisample");
2371 break;
2372
2373 case spv::CapabilityStorageImageExtendedFormats:
2374 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageExtendedFormats,
2375 "shaderStorageImageExtendedFormats");
2376 break;
2377
2378 case spv::CapabilityInterpolationFunction:
2379 pass &= require_feature(my_data, enabledFeatures->sampleRateShading, "sampleRateShading");
2380 break;
2381
2382 case spv::CapabilityStorageImageReadWithoutFormat:
2383 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageReadWithoutFormat,
2384 "shaderStorageImageReadWithoutFormat");
2385 break;
2386
2387 case spv::CapabilityStorageImageWriteWithoutFormat:
2388 pass &= require_feature(my_data, enabledFeatures->shaderStorageImageWriteWithoutFormat,
2389 "shaderStorageImageWriteWithoutFormat");
2390 break;
2391
2392 case spv::CapabilityMultiViewport:
2393 pass &= require_feature(my_data, enabledFeatures->multiViewport, "multiViewport");
2394 break;
2395
2396 default:
Chris Forbesce5be902016-03-30 13:14:22 +13002397 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
Chris Forbesc3a1dbc2016-03-15 10:12:48 +13002398 __LINE__, SHADER_CHECKER_BAD_CAPABILITY, "SC",
2399 "Shader declares capability %u, not supported in Vulkan.",
2400 insn.word(1)))
Dustin Graves8f1eab92016-04-05 09:41:17 -06002401 pass = false;
Chris Forbesc3a1dbc2016-03-15 10:12:48 +13002402 break;
2403 }
2404 }
2405 }
2406
2407 return pass;
2408}
2409
Dustin Graves8f1eab92016-04-05 09:41:17 -06002410static bool validate_pipeline_shader_stage(layer_data *dev_data, VkPipelineShaderStageCreateInfo const *pStage,
2411 PIPELINE_NODE *pipeline, PIPELINE_LAYOUT_NODE *pipelineLayout,
2412 shader_module **out_module, spirv_inst_iter *out_entrypoint) {
2413 bool pass = true;
Chris Forbes961cee72016-03-30 12:12:01 +13002414 auto module = *out_module = dev_data->shaderModuleMap[pStage->module].get();
2415 pass &= validate_specialization_offsets(dev_data, pStage);
2416
2417 /* find the entrypoint */
2418 auto entrypoint = *out_entrypoint = find_entrypoint(module, pStage->pName, pStage->stage);
2419 if (entrypoint == module->end()) {
Chris Forbesce5be902016-03-30 13:14:22 +13002420 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2421 __LINE__, SHADER_CHECKER_MISSING_ENTRYPOINT, "SC",
Chris Forbes961cee72016-03-30 12:12:01 +13002422 "No entrypoint found named `%s` for stage %s", pStage->pName,
2423 string_VkShaderStageFlagBits(pStage->stage))) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002424 pass = false;
Chris Forbes961cee72016-03-30 12:12:01 +13002425 }
2426 }
2427
2428 /* validate shader capabilities against enabled device features */
2429 pass &= validate_shader_capabilities(dev_data, module);
2430
2431 /* mark accessible ids */
2432 std::unordered_set<uint32_t> accessible_ids;
2433 mark_accessible_ids(module, entrypoint, accessible_ids);
2434
2435 /* validate descriptor set layout against what the entrypoint actually uses */
2436 std::map<descriptor_slot_t, interface_var> descriptor_uses;
2437 collect_interface_by_descriptor_slot(dev_data, module, accessible_ids, descriptor_uses);
2438
2439 /* validate push constant usage */
2440 pass &= validate_push_constant_usage(dev_data, &pipelineLayout->pushConstantRanges,
2441 module, accessible_ids, pStage->stage);
2442
2443 /* validate descriptor use */
2444 for (auto use : descriptor_uses) {
2445 // While validating shaders capture which slots are used by the pipeline
2446 pipeline->active_slots[use.first.first].insert(use.first.second);
2447
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002448 /* verify given pipelineLayout has requested setLayout with requested binding */
Tobin Ehlis546326f2016-04-26 11:06:05 -06002449 const auto & binding = get_descriptor_binding(dev_data, pipelineLayout, use.first);
Chris Forbes961cee72016-03-30 12:12:01 +13002450 unsigned required_descriptor_count;
2451
2452 if (!binding) {
Chris Forbesce5be902016-03-30 13:14:22 +13002453 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2454 __LINE__, SHADER_CHECKER_MISSING_DESCRIPTOR, "SC",
Chris Forbes961cee72016-03-30 12:12:01 +13002455 "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
2456 use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str())) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002457 pass = false;
Chris Forbes961cee72016-03-30 12:12:01 +13002458 }
2459 } else if (~binding->stageFlags & pStage->stage) {
2460 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
2461 /*dev*/ 0, __LINE__, SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE, "SC",
2462 "Shader uses descriptor slot %u.%u (used "
2463 "as type `%s`) but descriptor not "
2464 "accessible from stage %s",
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002465 use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
Chris Forbes961cee72016-03-30 12:12:01 +13002466 string_VkShaderStageFlagBits(pStage->stage))) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002467 pass = false;
Chris Forbes961cee72016-03-30 12:12:01 +13002468 }
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002469 } else if (!descriptor_type_match(dev_data, module, use.second.type_id, binding->descriptorType,
2470 /*out*/ required_descriptor_count)) {
2471 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2472 SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", "Type mismatch on descriptor slot "
2473 "%u.%u (used as type `%s`) but "
2474 "descriptor of type %s",
2475 use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
Chris Forbes961cee72016-03-30 12:12:01 +13002476 string_VkDescriptorType(binding->descriptorType))) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002477 pass = false;
Chris Forbes961cee72016-03-30 12:12:01 +13002478 }
2479 } else if (binding->descriptorCount < required_descriptor_count) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002480 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
2481 SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
Chris Forbes961cee72016-03-30 12:12:01 +13002482 "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
2483 required_descriptor_count, use.first.first, use.first.second,
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002484 describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002485 pass = false;
Chris Forbes961cee72016-03-30 12:12:01 +13002486 }
2487 }
2488 }
2489
2490 return pass;
2491}
2492
2493
Tobin Ehlis81e8ca42016-03-24 09:17:25 -06002494// Validate that the shaders used by the given pipeline and store the active_slots
2495// that are actually used by the pipeline into pPipeline->active_slots
Dustin Graves8f1eab92016-04-05 09:41:17 -06002496static bool validate_and_capture_pipeline_shader_state(layer_data *my_data, PIPELINE_NODE *pPipeline) {
Chris Forbes6f6844a2016-04-27 14:00:44 +12002497 auto pCreateInfo = pPipeline->graphicsPipelineCI.ptr();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002498 int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
2499 int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
2500
2501 shader_module *shaders[5];
2502 memset(shaders, 0, sizeof(shaders));
2503 spirv_inst_iter entrypoints[5];
2504 memset(entrypoints, 0, sizeof(entrypoints));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002505 VkPipelineVertexInputStateCreateInfo const *vi = 0;
Dustin Graves8f1eab92016-04-05 09:41:17 -06002506 bool pass = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002507
Chris Forbes961cee72016-03-30 12:12:01 +13002508 auto pipelineLayout = pCreateInfo->layout != VK_NULL_HANDLE ? &my_data->pipelineLayoutMap[pCreateInfo->layout] : nullptr;
2509
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002510 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
Chris Forbes6f6844a2016-04-27 14:00:44 +12002511 auto pStage = &pCreateInfo->pStages[i];
Chris Forbes961cee72016-03-30 12:12:01 +13002512 auto stage_id = get_shader_stage_id(pStage->stage);
2513 pass &= validate_pipeline_shader_stage(my_data, pStage, pPipeline, pipelineLayout,
2514 &shaders[stage_id], &entrypoints[stage_id]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002515 }
2516
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002517 vi = pCreateInfo->pVertexInputState;
2518
2519 if (vi) {
Chris Forbes1bd5db92016-03-30 13:21:20 +13002520 pass &= validate_vi_consistency(my_data, vi);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002521 }
2522
2523 if (shaders[vertex_stage]) {
Chris Forbes1bd5db92016-03-30 13:21:20 +13002524 pass &= validate_vi_against_vs_inputs(my_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002525 }
2526
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002527 int producer = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
2528 int consumer = get_shader_stage_id(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
2529
2530 while (!shaders[producer] && producer != fragment_stage) {
2531 producer++;
2532 consumer++;
2533 }
2534
2535 for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
2536 assert(shaders[producer]);
2537 if (shaders[consumer]) {
Chris Forbes23a575d2016-03-29 16:41:07 +13002538 pass &= validate_interface_between_stages(my_data,
2539 shaders[producer], entrypoints[producer], &shader_stage_attribs[producer],
2540 shaders[consumer], entrypoints[consumer], &shader_stage_attribs[consumer]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002541
2542 producer = consumer;
2543 }
2544 }
2545
Chris Forbes961cee72016-03-30 12:12:01 +13002546 auto rp = pCreateInfo->renderPass != VK_NULL_HANDLE ? my_data->renderPassMap[pCreateInfo->renderPass] : nullptr;
2547
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002548 if (shaders[fragment_stage] && rp) {
Chris Forbes1bd5db92016-03-30 13:21:20 +13002549 pass &= validate_fs_outputs_against_render_pass(my_data, shaders[fragment_stage], entrypoints[fragment_stage], rp,
2550 pCreateInfo->subpass);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002551 }
2552
2553 return pass;
2554}
2555
Dustin Graves8f1eab92016-04-05 09:41:17 -06002556static bool validate_compute_pipeline(layer_data *my_data, PIPELINE_NODE *pPipeline) {
Chris Forbes6f6844a2016-04-27 14:00:44 +12002557 auto pCreateInfo = pPipeline->computePipelineCI.ptr();
Chris Forbesb029e6f2016-03-30 14:04:36 +13002558
2559 auto pipelineLayout = pCreateInfo->layout != VK_NULL_HANDLE ? &my_data->pipelineLayoutMap[pCreateInfo->layout] : nullptr;
2560
2561 shader_module *module;
2562 spirv_inst_iter entrypoint;
2563
2564 return validate_pipeline_shader_stage(my_data, &pCreateInfo->stage, pPipeline, pipelineLayout,
2565 &module, &entrypoint);
2566}
2567
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002568// Return Set node ptr for specified set or else NULL
2569static SET_NODE *getSetNode(layer_data *my_data, const VkDescriptorSet set) {
2570 if (my_data->setMap.find(set) == my_data->setMap.end()) {
2571 return NULL;
2572 }
2573 return my_data->setMap[set];
2574}
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002575// For the given command buffer, verify and update the state for activeSetBindingsPairs
2576// This includes:
2577// 1. Verifying that any dynamic descriptor in that set has a valid dynamic offset bound.
2578// To be valid, the dynamic offset combined with the offset and range from its
2579// descriptor update must not overflow the size of its buffer being updated
2580// 2. Grow updateImages for given pCB to include any bound STORAGE_IMAGE descriptor images
2581// 3. Grow updateBuffers for pCB to include buffers from STORAGE*_BUFFER descriptor buffers
Dustin Graves8f1eab92016-04-05 09:41:17 -06002582static bool validate_and_update_drawtime_descriptor_state(
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002583 layer_data *dev_data, GLOBAL_CB_NODE *pCB,
2584 const vector<std::pair<SET_NODE *, unordered_set<uint32_t>>> &activeSetBindingsPairs) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002585 bool result = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002586
2587 VkWriteDescriptorSet *pWDS = NULL;
2588 uint32_t dynOffsetIndex = 0;
2589 VkDeviceSize bufferSize = 0;
Tobin Ehlis81e8ca42016-03-24 09:17:25 -06002590 for (auto set_bindings_pair : activeSetBindingsPairs) {
2591 SET_NODE *set_node = set_bindings_pair.first;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002592 auto layout_node = set_node->p_layout;
Tobin Ehlis81e8ca42016-03-24 09:17:25 -06002593 for (auto binding : set_bindings_pair.second) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002594 if ((set_node->p_layout->GetTypeFromBinding(binding) == VK_DESCRIPTOR_TYPE_SAMPLER) &&
2595 (set_node->p_layout->GetDescriptorCountFromBinding(binding) != 0) &&
2596 (set_node->p_layout->GetImmutableSamplerPtrFromBinding(binding))) {
Tobin Ehlis5b307012016-04-22 09:16:20 -06002597 // No work for immutable sampler binding
2598 } else {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002599 uint32_t startIdx = layout_node->GetGlobalStartIndexFromBinding(binding);
2600 uint32_t endIdx = layout_node->GetGlobalEndIndexFromBinding(binding);
Tobin Ehlis5b307012016-04-22 09:16:20 -06002601 for (uint32_t i = startIdx; i <= endIdx; ++i) {
2602 // We did check earlier to verify that set was updated, but now make sure given slot was updated
2603 // TODO : Would be better to store set# that set is bound to so we can report set.binding[index] not updated
2604 // For immutable sampler w/o combined image, don't need to update
2605 if (!set_node->pDescriptorUpdates[i]) {
2606 result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2607 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
2608 DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
2609 "DS %#" PRIxLEAST64 " bound and active but it never had binding %u updated. It is now being used to draw so "
2610 "this will result in undefined behavior.",
2611 reinterpret_cast<const uint64_t &>(set_node->set), binding);
2612 } else {
2613 switch (set_node->pDescriptorUpdates[i]->sType) {
2614 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
2615 pWDS = (VkWriteDescriptorSet *)set_node->pDescriptorUpdates[i];
Mark Young735cd7c2016-04-11 17:45:37 -06002616
Tobin Ehlis5b307012016-04-22 09:16:20 -06002617 // Verify uniform and storage buffers actually are bound to valid memory at draw time.
2618 if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
2619 (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
2620 (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
2621 (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
2622 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2623 auto buffer_node = dev_data->bufferMap.find(pWDS->pBufferInfo[j].buffer);
2624 if (buffer_node == dev_data->bufferMap.end()) {
Mark Young735cd7c2016-04-11 17:45:37 -06002625 result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2626 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
2627 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
2628 DRAWSTATE_INVALID_BUFFER, "DS",
Tobin Ehlis5b307012016-04-22 09:16:20 -06002629 "VkDescriptorSet (%#" PRIxLEAST64 ") %s (%#" PRIxLEAST64 ") at index #%u"
2630 " is not defined! Has vkCreateBuffer been called?",
Mark Young735cd7c2016-04-11 17:45:37 -06002631 reinterpret_cast<const uint64_t &>(set_node->set),
2632 string_VkDescriptorType(pWDS->descriptorType),
2633 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), i);
Tobin Ehlis5b307012016-04-22 09:16:20 -06002634 } else {
2635 auto mem_entry = dev_data->memObjMap.find(buffer_node->second.mem);
2636 if (mem_entry == dev_data->memObjMap.end()) {
2637 result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2638 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
2639 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
2640 DRAWSTATE_INVALID_BUFFER, "DS",
2641 "VkDescriptorSet (%#" PRIxLEAST64 ") %s (%#" PRIxLEAST64 ") at index"
2642 " #%u, has no memory bound to it!",
2643 reinterpret_cast<const uint64_t &>(set_node->set),
2644 string_VkDescriptorType(pWDS->descriptorType),
2645 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), i);
Mark Young735cd7c2016-04-11 17:45:37 -06002646 }
Tobin Ehlis5b307012016-04-22 09:16:20 -06002647 }
2648 // If it's a dynamic buffer, make sure the offsets are within the buffer.
2649 if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
2650 (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
2651 bufferSize = dev_data->bufferMap[pWDS->pBufferInfo[j].buffer].createInfo.size;
2652 uint32_t dynOffset =
2653 pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets[dynOffsetIndex];
2654 if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) {
2655 if ((dynOffset + pWDS->pBufferInfo[j].offset) > bufferSize) {
2656 result |= log_msg(
2657 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
Mark Young735cd7c2016-04-11 17:45:37 -06002658 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
2659 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
2660 DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
Tobin Ehlis5b307012016-04-22 09:16:20 -06002661 "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of "
2662 "VK_WHOLE_SIZE but dynamic offset %#" PRIxLEAST32 ". "
2663 "combined with offset %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64
2664 ") which has a size of %#" PRIxLEAST64 ".",
Mark Young735cd7c2016-04-11 17:45:37 -06002665 reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
Tobin Ehlis5b307012016-04-22 09:16:20 -06002666 pWDS->pBufferInfo[j].offset,
Mark Young735cd7c2016-04-11 17:45:37 -06002667 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
Tobin Ehlis5b307012016-04-22 09:16:20 -06002668 }
2669 } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) >
2670 bufferSize) {
2671 result |=
2672 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2673 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
2674 reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
2675 DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
2676 "VkDescriptorSet (%#" PRIxLEAST64
2677 ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". "
2678 "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64
2679 " from its update, this oversteps its buffer "
2680 "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".",
2681 reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
2682 pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range,
2683 reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
2684 }
2685 dynOffsetIndex++;
Mark Young735cd7c2016-04-11 17:45:37 -06002686 }
Mark Young735cd7c2016-04-11 17:45:37 -06002687 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002688 }
Tobin Ehlis5b307012016-04-22 09:16:20 -06002689 if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
2690 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2691 pCB->updateImages.insert(pWDS->pImageInfo[j].imageView);
2692 }
2693 } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
2694 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2695 assert(dev_data->bufferViewMap.find(pWDS->pTexelBufferView[j]) != dev_data->bufferViewMap.end());
2696 pCB->updateBuffers.insert(dev_data->bufferViewMap[pWDS->pTexelBufferView[j]].buffer);
2697 }
2698 } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2699 pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
2700 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2701 pCB->updateBuffers.insert(pWDS->pBufferInfo[j].buffer);
2702 }
2703 }
2704 i += pWDS->descriptorCount; // Advance i to end of this set of descriptors (++i at end of for loop will move 1
2705 // index past last of these descriptors)
2706 break;
2707 default: // Currently only shadowing Write update nodes so shouldn't get here
2708 assert(0);
2709 continue;
Mark Young735cd7c2016-04-11 17:45:37 -06002710 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002711 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002712 }
2713 }
2714 }
2715 }
2716 return result;
2717}
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002718// TODO : This is a temp function that naively updates bound storage images and buffers based on which descriptor sets are bound.
2719// When validate_and_update_draw_state() handles computer shaders so that active_slots is correct for compute pipelines, this
2720// function can be killed and validate_and_update_draw_state() used instead
2721static void update_shader_storage_images_and_buffers(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
2722 VkWriteDescriptorSet *pWDS = nullptr;
2723 SET_NODE *pSet = nullptr;
2724 // For the bound descriptor sets, pull off any storage images and buffers
2725 // This may be more than are actually updated depending on which are active, but for now this is a stop-gap for compute
2726 // pipelines
2727 for (auto set : pCB->lastBound[VK_PIPELINE_BIND_POINT_COMPUTE].uniqueBoundSets) {
2728 // Get the set node
2729 pSet = getSetNode(dev_data, set);
2730 // For each update in the set
2731 for (auto pUpdate : pSet->pDescriptorUpdates) {
2732 // If it's a write update to STORAGE type capture image/buffer being updated
2733 if (pUpdate && (pUpdate->sType == VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET)) {
2734 pWDS = reinterpret_cast<VkWriteDescriptorSet *>(pUpdate);
2735 if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
2736 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2737 pCB->updateImages.insert(pWDS->pImageInfo[j].imageView);
2738 }
2739 } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
2740 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2741 pCB->updateBuffers.insert(dev_data->bufferViewMap[pWDS->pTexelBufferView[j]].buffer);
2742 }
2743 } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
2744 pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
2745 for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
2746 pCB->updateBuffers.insert(pWDS->pBufferInfo[j].buffer);
2747 }
2748 }
2749 }
2750 }
2751 }
2752}
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002753
2754// Validate overall state at the time of a draw call
Dustin Graves8f1eab92016-04-05 09:41:17 -06002755static bool validate_and_update_draw_state(layer_data *my_data, GLOBAL_CB_NODE *pCB, const bool indexedDraw,
2756 const VkPipelineBindPoint bindPoint) {
2757 bool result = false;
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002758 auto const &state = pCB->lastBound[bindPoint];
2759 PIPELINE_NODE *pPipe = getPipeline(my_data, state.pipeline);
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06002760 // First check flag states
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002761 if (VK_PIPELINE_BIND_POINT_GRAPHICS == bindPoint)
2762 result = validate_draw_state_flags(my_data, pCB, pPipe, indexedDraw);
2763
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002764 // Now complete other state checks
2765 // TODO : Currently only performing next check if *something* was bound (non-zero last bound)
2766 // There is probably a better way to gate when this check happens, and to know if something *should* have been bound
2767 // We should have that check separately and then gate this check based on that check
2768 if (pPipe) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06002769 if (state.pipelineLayout) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002770 string errorString;
2771 // Need a vector (vs. std::set) of active Sets for dynamicOffset validation in case same set bound w/ different offsets
Tobin Ehlis81e8ca42016-03-24 09:17:25 -06002772 vector<std::pair<SET_NODE *, unordered_set<uint32_t>>> activeSetBindingsPairs;
2773 for (auto setBindingPair : pPipe->active_slots) {
2774 uint32_t setIndex = setBindingPair.first;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002775 // If valid set is not bound throw an error
Tobin Ehlis223b01e2016-03-21 14:14:44 -06002776 if ((state.boundDescriptorSets.size() <= setIndex) || (!state.boundDescriptorSets[setIndex])) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002777 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
2778 __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND, "DS",
2779 "VkPipeline %#" PRIxLEAST64 " uses set #%u but that set is not bound.",
2780 (uint64_t)pPipe->pipeline, setIndex);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06002781 } else if (!verify_set_layout_compatibility(my_data, my_data->setMap[state.boundDescriptorSets[setIndex]],
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002782 pPipe->graphicsPipelineCI.layout, setIndex, errorString)) {
2783 // Set is bound but not compatible w/ overlapping pipelineLayout from PSO
Tobin Ehlis223b01e2016-03-21 14:14:44 -06002784 VkDescriptorSet setHandle = my_data->setMap[state.boundDescriptorSets[setIndex]]->set;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002785 result |= log_msg(
2786 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
2787 (uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
2788 "VkDescriptorSet (%#" PRIxLEAST64
2789 ") bound as set #%u is not compatible with overlapping VkPipelineLayout %#" PRIxLEAST64 " due to: %s",
2790 (uint64_t)setHandle, setIndex, (uint64_t)pPipe->graphicsPipelineCI.layout, errorString.c_str());
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002791 } else { // Valid set is bound and layout compatible, validate that it's updated
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002792 // Pull the set node
Tobin Ehlis223b01e2016-03-21 14:14:44 -06002793 SET_NODE *pSet = my_data->setMap[state.boundDescriptorSets[setIndex]];
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002794 // Save vector of all active sets to verify dynamicOffsets below
Tobin Ehlis81e8ca42016-03-24 09:17:25 -06002795 activeSetBindingsPairs.push_back(std::make_pair(pSet, setBindingPair.second));
Tobin Ehlis0124ce02016-04-19 08:15:03 -06002796 // Make sure set has been updated if it has no immutable samplers
2797 // If it has immutable samplers, we'll flag error later as needed depending on binding
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06002798 if (!pSet->pUpdateStructs) {
2799 for (auto binding : setBindingPair.second) {
2800 if (!pSet->p_layout->GetImmutableSamplerPtrFromBinding(binding)) {
2801 result |=
2802 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2803 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pSet->set, __LINE__,
2804 DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
2805 "DS %#" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so "
2806 "this will result in undefined behavior.",
2807 (uint64_t)pSet->set);
2808 }
2809 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002810 }
2811 }
2812 }
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002813 // For given active slots, verify any dynamic descriptors and record updated images & buffers
2814 result |= validate_and_update_drawtime_descriptor_state(my_data, pCB, activeSetBindingsPairs);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002815 }
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002816 if (VK_PIPELINE_BIND_POINT_GRAPHICS == bindPoint) {
2817 // Verify Vtx binding
2818 if (pPipe->vertexBindingDescriptions.size() > 0) {
2819 for (size_t i = 0; i < pPipe->vertexBindingDescriptions.size(); i++) {
2820 if ((pCB->currentDrawData.buffers.size() < (i + 1)) || (pCB->currentDrawData.buffers[i] == VK_NULL_HANDLE)) {
2821 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
2822 __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2823 "The Pipeline State Object (%#" PRIxLEAST64
2824 ") expects that this Command Buffer's vertex binding Index " PRINTF_SIZE_T_SPECIFIER
2825 " should be set via vkCmdBindVertexBuffers.",
2826 (uint64_t)state.pipeline, i);
2827 }
2828 }
2829 } else {
2830 if (!pCB->currentDrawData.buffers.empty()) {
2831 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
2832 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS, "DS",
2833 "Vertex buffers are bound to command buffer (%#" PRIxLEAST64
2834 ") but no vertex buffers are attached to this Pipeline State Object (%#" PRIxLEAST64 ").",
2835 (uint64_t)pCB->commandBuffer, (uint64_t)state.pipeline);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002836 }
2837 }
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002838 // If Viewport or scissors are dynamic, verify that dynamic count matches PSO count.
2839 // Skip check if rasterization is disabled or there is no viewport.
2840 if ((!pPipe->graphicsPipelineCI.pRasterizationState ||
Dustin Gravesbd9c1a92016-04-05 15:15:40 -06002841 (pPipe->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) &&
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002842 pPipe->graphicsPipelineCI.pViewportState) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002843 bool dynViewport = isDynamic(pPipe, VK_DYNAMIC_STATE_VIEWPORT);
2844 bool dynScissor = isDynamic(pPipe, VK_DYNAMIC_STATE_SCISSOR);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002845 if (dynViewport) {
2846 if (pCB->viewports.size() != pPipe->graphicsPipelineCI.pViewportState->viewportCount) {
2847 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
2848 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
2849 "Dynamic viewportCount from vkCmdSetViewport() is " PRINTF_SIZE_T_SPECIFIER
2850 ", but PSO viewportCount is %u. These counts must match.",
2851 pCB->viewports.size(), pPipe->graphicsPipelineCI.pViewportState->viewportCount);
2852 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002853 }
Tobin Ehlis2e319d42016-03-25 11:49:51 -06002854 if (dynScissor) {
2855 if (pCB->scissors.size() != pPipe->graphicsPipelineCI.pViewportState->scissorCount) {
2856 result |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
2857 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
2858 "Dynamic scissorCount from vkCmdSetScissor() is " PRINTF_SIZE_T_SPECIFIER
2859 ", but PSO scissorCount is %u. These counts must match.",
2860 pCB->scissors.size(), pPipe->graphicsPipelineCI.pViewportState->scissorCount);
2861 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002862 }
2863 }
2864 }
2865 }
2866 return result;
2867}
2868
Mark Young7394fdd2016-03-31 14:56:43 -06002869// Validate HW line width capabilities prior to setting requested line width.
2870static bool verifyLineWidth(layer_data *my_data, DRAW_STATE_ERROR dsError, const uint64_t &target, float lineWidth) {
2871 bool skip_call = false;
2872
2873 // First check to see if the physical device supports wide lines.
2874 if ((VK_FALSE == my_data->phys_dev_properties.features.wideLines) && (1.0f != lineWidth)) {
2875 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target, __LINE__,
2876 dsError, "DS", "Attempt to set lineWidth to %f but physical device wideLines feature "
2877 "not supported/enabled so lineWidth must be 1.0f!",
2878 lineWidth);
2879 } else {
2880 // Otherwise, make sure the width falls in the valid range.
2881 if ((my_data->phys_dev_properties.properties.limits.lineWidthRange[0] > lineWidth) ||
2882 (my_data->phys_dev_properties.properties.limits.lineWidthRange[1] < lineWidth)) {
2883 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, target,
2884 __LINE__, dsError, "DS", "Attempt to set lineWidth to %f but physical device limits line width "
2885 "to between [%f, %f]!",
2886 lineWidth, my_data->phys_dev_properties.properties.limits.lineWidthRange[0],
2887 my_data->phys_dev_properties.properties.limits.lineWidthRange[1]);
2888 }
2889 }
2890
2891 return skip_call;
2892}
2893
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002894// Verify that create state for a pipeline is valid
Dustin Graves8f1eab92016-04-05 09:41:17 -06002895static bool verifyPipelineCreateState(layer_data *my_data, const VkDevice device, std::vector<PIPELINE_NODE *> pPipelines,
2896 int pipelineIndex) {
2897 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002898
2899 PIPELINE_NODE *pPipeline = pPipelines[pipelineIndex];
2900
2901 // If create derivative bit is set, check that we've specified a base
2902 // pipeline correctly, and that the base pipeline was created to allow
2903 // derivatives.
2904 if (pPipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) {
2905 PIPELINE_NODE *pBasePipeline = nullptr;
2906 if (!((pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) ^
2907 (pPipeline->graphicsPipelineCI.basePipelineIndex != -1))) {
2908 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2909 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
2910 "Invalid Pipeline CreateInfo: exactly one of base pipeline index and handle must be specified");
2911 } else if (pPipeline->graphicsPipelineCI.basePipelineIndex != -1) {
2912 if (pPipeline->graphicsPipelineCI.basePipelineIndex >= pipelineIndex) {
2913 skipCall |=
2914 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2915 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
2916 "Invalid Pipeline CreateInfo: base pipeline must occur earlier in array than derivative pipeline.");
2917 } else {
2918 pBasePipeline = pPipelines[pPipeline->graphicsPipelineCI.basePipelineIndex];
2919 }
2920 } else if (pPipeline->graphicsPipelineCI.basePipelineHandle != VK_NULL_HANDLE) {
2921 pBasePipeline = getPipeline(my_data, pPipeline->graphicsPipelineCI.basePipelineHandle);
2922 }
2923
2924 if (pBasePipeline && !(pBasePipeline->graphicsPipelineCI.flags & VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) {
2925 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2926 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
2927 "Invalid Pipeline CreateInfo: base pipeline does not allow derivatives.");
2928 }
2929 }
2930
2931 if (pPipeline->graphicsPipelineCI.pColorBlendState != NULL) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06002932 if (!my_data->phys_dev_properties.features.independentBlend) {
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06002933 if (pPipeline->attachments.size() > 1) {
Chris Forbes1ae3d402016-03-24 11:42:09 +13002934 VkPipelineColorBlendAttachmentState *pAttachments = &pPipeline->attachments[0];
Mark Lobodzinski2f02dc92016-03-23 14:34:52 -06002935 for (size_t i = 1; i < pPipeline->attachments.size(); i++) {
2936 if ((pAttachments[0].blendEnable != pAttachments[i].blendEnable) ||
2937 (pAttachments[0].srcColorBlendFactor != pAttachments[i].srcColorBlendFactor) ||
2938 (pAttachments[0].dstColorBlendFactor != pAttachments[i].dstColorBlendFactor) ||
2939 (pAttachments[0].colorBlendOp != pAttachments[i].colorBlendOp) ||
2940 (pAttachments[0].srcAlphaBlendFactor != pAttachments[i].srcAlphaBlendFactor) ||
2941 (pAttachments[0].dstAlphaBlendFactor != pAttachments[i].dstAlphaBlendFactor) ||
2942 (pAttachments[0].alphaBlendOp != pAttachments[i].alphaBlendOp) ||
2943 (pAttachments[0].colorWriteMask != pAttachments[i].colorWriteMask)) {
2944 skipCall |=
2945 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2946 DRAWSTATE_INDEPENDENT_BLEND, "DS", "Invalid Pipeline CreateInfo: If independent blend feature not "
2947 "enabled, all elements of pAttachments must be identical");
2948 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002949 }
2950 }
2951 }
Tobin Ehlise54be7b2016-04-11 14:49:55 -06002952 if (!my_data->phys_dev_properties.features.logicOp &&
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002953 (pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable != VK_FALSE)) {
2954 skipCall |=
2955 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2956 DRAWSTATE_DISABLED_LOGIC_OP, "DS",
2957 "Invalid Pipeline CreateInfo: If logic operations feature not enabled, logicOpEnable must be VK_FALSE");
2958 }
2959 if ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOpEnable == VK_TRUE) &&
2960 ((pPipeline->graphicsPipelineCI.pColorBlendState->logicOp < VK_LOGIC_OP_CLEAR) ||
2961 (pPipeline->graphicsPipelineCI.pColorBlendState->logicOp > VK_LOGIC_OP_SET))) {
2962 skipCall |=
2963 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2964 DRAWSTATE_INVALID_LOGIC_OP, "DS",
2965 "Invalid Pipeline CreateInfo: If logicOpEnable is VK_TRUE, logicOp must be a valid VkLogicOp value");
2966 }
2967 }
2968
Tobin Ehlis81e8ca42016-03-24 09:17:25 -06002969 // Ensure the subpass index is valid. If not, then validate_and_capture_pipeline_shader_state
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002970 // produces nonsense errors that confuse users. Other layers should already
2971 // emit errors for renderpass being invalid.
2972 auto rp_data = my_data->renderPassMap.find(pPipeline->graphicsPipelineCI.renderPass);
2973 if (rp_data != my_data->renderPassMap.end() &&
2974 pPipeline->graphicsPipelineCI.subpass >= rp_data->second->pCreateInfo->subpassCount) {
2975 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2976 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Subpass index %u "
2977 "is out of range for this renderpass (0..%u)",
2978 pPipeline->graphicsPipelineCI.subpass, rp_data->second->pCreateInfo->subpassCount - 1);
2979 }
2980
Chris Forbes15864502016-03-30 11:35:21 +13002981 if (!validate_and_capture_pipeline_shader_state(my_data, pPipeline)) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06002982 skipCall = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002983 }
Chris Forbes3001c772016-04-06 11:21:28 +12002984 // Each shader's stage must be unique
2985 if (pPipeline->duplicate_shaders) {
2986 for (uint32_t stage = VK_SHADER_STAGE_VERTEX_BIT; stage & VK_SHADER_STAGE_ALL_GRAPHICS; stage <<= 1) {
2987 if (pPipeline->duplicate_shaders & stage) {
2988 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
2989 __LINE__, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
2990 "Invalid Pipeline CreateInfo State: Multiple shaders provided for stage %s",
2991 string_VkShaderStageFlagBits(VkShaderStageFlagBits(stage)));
2992 }
2993 }
2994 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07002995 // VS is required
2996 if (!(pPipeline->active_shaders & VK_SHADER_STAGE_VERTEX_BIT)) {
2997 skipCall |=
2998 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
2999 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: Vtx Shader required");
3000 }
3001 // Either both or neither TC/TE shaders should be defined
3002 if (((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0) !=
3003 ((pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0)) {
3004 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3005 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
3006 "Invalid Pipeline CreateInfo State: TE and TC shaders must be included or excluded as a pair");
3007 }
3008 // Compute shaders should be specified independent of Gfx shaders
3009 if ((pPipeline->active_shaders & VK_SHADER_STAGE_COMPUTE_BIT) &&
3010 (pPipeline->active_shaders &
3011 (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT |
3012 VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT))) {
3013 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3014 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
3015 "Invalid Pipeline CreateInfo State: Do not specify Compute Shader for Gfx Pipeline");
3016 }
3017 // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
3018 // Mismatching primitive topology and tessellation fails graphics pipeline creation.
3019 if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003020 (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
3021 pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003022 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3023 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
3024 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
3025 "topology for tessellation pipelines");
3026 }
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003027 if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
3028 pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003029 if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
3030 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3031 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
3032 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3033 "topology is only valid for tessellation pipelines");
3034 }
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003035 if (!pPipeline->graphicsPipelineCI.pTessellationState) {
3036 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3037 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
3038 "Invalid Pipeline CreateInfo State: "
3039 "pTessellationState is NULL when VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3040 "topology used. pTessellationState must not be NULL in this case.");
3041 } else if (!pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints ||
3042 (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints > 32)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003043 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3044 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
3045 "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
3046 "topology used with patchControlPoints value %u."
3047 " patchControlPoints should be >0 and <=32.",
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003048 pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003049 }
3050 }
Mark Young7394fdd2016-03-31 14:56:43 -06003051 // If a rasterization state is provided, make sure that the line width conforms to the HW.
3052 if (pPipeline->graphicsPipelineCI.pRasterizationState) {
3053 if (!isDynamic(pPipeline, VK_DYNAMIC_STATE_LINE_WIDTH)) {
3054 skipCall |= verifyLineWidth(my_data, DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, reinterpret_cast<uint64_t &>(pPipeline),
3055 pPipeline->graphicsPipelineCI.pRasterizationState->lineWidth);
3056 }
3057 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003058 // Viewport state must be included if rasterization is enabled.
3059 // If the viewport state is included, the viewport and scissor counts should always match.
3060 // NOTE : Even if these are flagged as dynamic, counts need to be set correctly for shader compiler
3061 if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
Dustin Gravesbd9c1a92016-04-05 15:15:40 -06003062 (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003063 if (!pPipeline->graphicsPipelineCI.pViewportState) {
3064 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3065 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS", "Gfx Pipeline pViewportState is null. Even if viewport "
3066 "and scissors are dynamic PSO must include "
3067 "viewportCount and scissorCount in pViewportState.");
3068 } else if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount !=
3069 pPipeline->graphicsPipelineCI.pViewportState->viewportCount) {
3070 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3071 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
3072 "Gfx Pipeline viewport count (%u) must match scissor count (%u).",
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003073 pPipeline->graphicsPipelineCI.pViewportState->viewportCount,
3074 pPipeline->graphicsPipelineCI.pViewportState->scissorCount);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003075 } else {
3076 // If viewport or scissor are not dynamic, then verify that data is appropriate for count
Dustin Graves8f1eab92016-04-05 09:41:17 -06003077 bool dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
3078 bool dynScissor = isDynamic(pPipeline, VK_DYNAMIC_STATE_SCISSOR);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003079 if (!dynViewport) {
3080 if (pPipeline->graphicsPipelineCI.pViewportState->viewportCount &&
3081 !pPipeline->graphicsPipelineCI.pViewportState->pViewports) {
3082 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
3083 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
3084 "Gfx Pipeline viewportCount is %u, but pViewports is NULL. For non-zero viewportCount, you "
3085 "must either include pViewports data, or include viewport in pDynamicState and set it with "
3086 "vkCmdSetViewport().",
3087 pPipeline->graphicsPipelineCI.pViewportState->viewportCount);
3088 }
3089 }
3090 if (!dynScissor) {
3091 if (pPipeline->graphicsPipelineCI.pViewportState->scissorCount &&
3092 !pPipeline->graphicsPipelineCI.pViewportState->pScissors) {
3093 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
3094 __LINE__, DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
3095 "Gfx Pipeline scissorCount is %u, but pScissors is NULL. For non-zero scissorCount, you "
3096 "must either include pScissors data, or include scissor in pDynamicState and set it with "
3097 "vkCmdSetScissor().",
3098 pPipeline->graphicsPipelineCI.pViewportState->scissorCount);
3099 }
3100 }
3101 }
3102 }
3103 return skipCall;
3104}
3105
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003106// Free the Pipeline nodes
3107static void deletePipelines(layer_data *my_data) {
3108 if (my_data->pipelineMap.size() <= 0)
3109 return;
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003110 for (auto &pipe_map_pair : my_data->pipelineMap) {
3111 delete pipe_map_pair.second;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003112 }
3113 my_data->pipelineMap.clear();
3114}
3115
3116// For given pipeline, return number of MSAA samples, or one if MSAA disabled
3117static VkSampleCountFlagBits getNumSamples(layer_data *my_data, const VkPipeline pipeline) {
3118 PIPELINE_NODE *pPipe = my_data->pipelineMap[pipeline];
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06003119 if (pPipe->graphicsPipelineCI.pMultisampleState &&
3120 (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->graphicsPipelineCI.pMultisampleState->sType)) {
3121 return pPipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003122 }
3123 return VK_SAMPLE_COUNT_1_BIT;
3124}
3125
3126// Validate state related to the PSO
Dustin Graves8f1eab92016-04-05 09:41:17 -06003127static bool validatePipelineState(layer_data *my_data, const GLOBAL_CB_NODE *pCB, const VkPipelineBindPoint pipelineBindPoint,
3128 const VkPipeline pipeline) {
3129 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003130 if (VK_PIPELINE_BIND_POINT_GRAPHICS == pipelineBindPoint) {
3131 // Verify that any MSAA request in PSO matches sample# in bound FB
3132 // Skip the check if rasterization is disabled.
3133 PIPELINE_NODE *pPipeline = my_data->pipelineMap[pipeline];
3134 if (!pPipeline->graphicsPipelineCI.pRasterizationState ||
Dustin Gravesbd9c1a92016-04-05 15:15:40 -06003135 (pPipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable == VK_FALSE)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003136 VkSampleCountFlagBits psoNumSamples = getNumSamples(my_data, pipeline);
3137 if (pCB->activeRenderPass) {
3138 const VkRenderPassCreateInfo *pRPCI = my_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo;
3139 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass];
3140 VkSampleCountFlagBits subpassNumSamples = (VkSampleCountFlagBits)0;
3141 uint32_t i;
3142
Mark Young1d2f1c72016-04-11 14:11:46 -06003143 const VkPipelineColorBlendStateCreateInfo *pColorBlendState = pPipeline->graphicsPipelineCI.pColorBlendState;
3144 if ((pColorBlendState != NULL) && (pCB->activeSubpass == pPipeline->graphicsPipelineCI.subpass) &&
3145 (pColorBlendState->attachmentCount != pSD->colorAttachmentCount)) {
3146 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3147 reinterpret_cast<const uint64_t &>(pipeline), __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
3148 "Render pass subpass %u mismatch with blending state defined and blend state attachment "
3149 "count %u but subpass color attachment count %u! These must be the same.",
3150 pCB->activeSubpass, pColorBlendState->attachmentCount, pSD->colorAttachmentCount);
3151 }
3152
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003153 for (i = 0; i < pSD->colorAttachmentCount; i++) {
3154 VkSampleCountFlagBits samples;
3155
3156 if (pSD->pColorAttachments[i].attachment == VK_ATTACHMENT_UNUSED)
3157 continue;
3158
3159 samples = pRPCI->pAttachments[pSD->pColorAttachments[i].attachment].samples;
3160 if (subpassNumSamples == (VkSampleCountFlagBits)0) {
3161 subpassNumSamples = samples;
3162 } else if (subpassNumSamples != samples) {
3163 subpassNumSamples = (VkSampleCountFlagBits)-1;
3164 break;
3165 }
3166 }
3167 if (pSD->pDepthStencilAttachment && pSD->pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
3168 const VkSampleCountFlagBits samples = pRPCI->pAttachments[pSD->pDepthStencilAttachment->attachment].samples;
3169 if (subpassNumSamples == (VkSampleCountFlagBits)0)
3170 subpassNumSamples = samples;
3171 else if (subpassNumSamples != samples)
3172 subpassNumSamples = (VkSampleCountFlagBits)-1;
3173 }
3174
Dominik Witczak2805f1b2016-04-01 13:19:49 +02003175 if ((pSD->colorAttachmentCount > 0 || pSD->pDepthStencilAttachment) &&
3176 psoNumSamples != subpassNumSamples) {
Mark Youngc89c6312016-03-31 16:03:20 -06003177 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
3178 (uint64_t)pipeline, __LINE__, DRAWSTATE_NUM_SAMPLES_MISMATCH, "DS",
3179 "Num samples mismatch! Binding PSO (%#" PRIxLEAST64
3180 ") with %u samples while current RenderPass (%#" PRIxLEAST64 ") w/ %u samples!",
3181 (uint64_t)pipeline, psoNumSamples, (uint64_t)pCB->activeRenderPass, subpassNumSamples);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003182 }
3183 } else {
3184 // TODO : I believe it's an error if we reach this point and don't have an activeRenderPass
3185 // Verify and flag error as appropriate
3186 }
3187 }
3188 // TODO : Add more checks here
3189 } else {
3190 // TODO : Validate non-gfx pipeline updates
3191 }
Mark Youngc89c6312016-03-31 16:03:20 -06003192 return skipCall;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003193}
3194
3195// Block of code at start here specifically for managing/tracking DSs
3196
3197// Return Pool node ptr for specified pool or else NULL
3198static DESCRIPTOR_POOL_NODE *getPoolNode(layer_data *my_data, const VkDescriptorPool pool) {
3199 if (my_data->descriptorPoolMap.find(pool) == my_data->descriptorPoolMap.end()) {
3200 return NULL;
3201 }
3202 return my_data->descriptorPoolMap[pool];
3203}
3204
Dustin Graves8f1eab92016-04-05 09:41:17 -06003205// Return false if update struct is of valid type, otherwise flag error and return code from callback
3206static bool validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003207 switch (pUpdateStruct->sType) {
3208 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3209 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
Dustin Graves8f1eab92016-04-05 09:41:17 -06003210 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003211 default:
3212 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3213 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
3214 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
3215 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
3216 }
3217}
3218
3219// Set count for given update struct in the last parameter
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003220static uint32_t getUpdateCount(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
3221 switch (pUpdateStruct->sType) {
3222 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3223 return ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorCount;
3224 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
3225 // TODO : Need to understand this case better and make sure code is correct
3226 return ((VkCopyDescriptorSet *)pUpdateStruct)->descriptorCount;
3227 default:
3228 return 0;
3229 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003230}
3231
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003232// For given layout and update, return the first overall index of the layout that is updated
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003233static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003234 const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003235 return binding_start_index + arrayIndex;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003236}
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003237// For given layout and update, return the last overall index of the layout that is updated
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003238static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003239 const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
3240 uint32_t count = getUpdateCount(my_data, device, pUpdateStruct);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003241 return binding_start_index + arrayIndex + count - 1;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003242}
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003243// Verify that the descriptor type in the update struct matches what's expected by the layout
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003244static bool validateUpdateConsistency(layer_data *my_data, const VkDevice device, const VkDescriptorType layout_type,
Dustin Graves8f1eab92016-04-05 09:41:17 -06003245 const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003246 // First get actual type of update
Dustin Graves8f1eab92016-04-05 09:41:17 -06003247 bool skipCall = false;
Jamie Madill2b6b8d52016-04-04 15:09:51 -04003248 VkDescriptorType actualType = VK_DESCRIPTOR_TYPE_MAX_ENUM;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003249 switch (pUpdateStruct->sType) {
3250 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3251 actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType;
3252 break;
3253 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
3254 /* no need to validate */
Dustin Graves8f1eab92016-04-05 09:41:17 -06003255 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003256 break;
3257 default:
3258 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3259 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
3260 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
3261 string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
3262 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06003263 if (!skipCall) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003264 if (layout_type != actualType) {
3265 skipCall |= log_msg(
3266 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3267 DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
3268 "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
3269 string_VkDescriptorType(actualType), string_VkDescriptorType(layout_type));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003270 }
3271 }
3272 return skipCall;
3273}
3274
3275// Determine the update type, allocate a new struct of that type, shadow the given pUpdate
Dustin Graves8f1eab92016-04-05 09:41:17 -06003276// struct into the pNewNode param. Return true if error condition encountered and callback signals early exit.
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003277// NOTE : Calls to this function should be wrapped in mutex
Dustin Graves8f1eab92016-04-05 09:41:17 -06003278static bool shadowUpdateNode(layer_data *my_data, const VkDevice device, GENERIC_HEADER *pUpdate, GENERIC_HEADER **pNewNode) {
3279 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003280 VkWriteDescriptorSet *pWDS = NULL;
3281 VkCopyDescriptorSet *pCDS = NULL;
3282 switch (pUpdate->sType) {
3283 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
3284 pWDS = new VkWriteDescriptorSet;
3285 *pNewNode = (GENERIC_HEADER *)pWDS;
3286 memcpy(pWDS, pUpdate, sizeof(VkWriteDescriptorSet));
3287
3288 switch (pWDS->descriptorType) {
3289 case VK_DESCRIPTOR_TYPE_SAMPLER:
3290 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
3291 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3292 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
3293 VkDescriptorImageInfo *info = new VkDescriptorImageInfo[pWDS->descriptorCount];
3294 memcpy(info, pWDS->pImageInfo, pWDS->descriptorCount * sizeof(VkDescriptorImageInfo));
3295 pWDS->pImageInfo = info;
3296 } break;
3297 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
3298 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
3299 VkBufferView *info = new VkBufferView[pWDS->descriptorCount];
3300 memcpy(info, pWDS->pTexelBufferView, pWDS->descriptorCount * sizeof(VkBufferView));
3301 pWDS->pTexelBufferView = info;
3302 } break;
3303 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3304 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3305 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
3306 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
3307 VkDescriptorBufferInfo *info = new VkDescriptorBufferInfo[pWDS->descriptorCount];
3308 memcpy(info, pWDS->pBufferInfo, pWDS->descriptorCount * sizeof(VkDescriptorBufferInfo));
3309 pWDS->pBufferInfo = info;
3310 } break;
3311 default:
Dustin Graves8f1eab92016-04-05 09:41:17 -06003312 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003313 break;
3314 }
3315 break;
3316 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
3317 pCDS = new VkCopyDescriptorSet;
3318 *pNewNode = (GENERIC_HEADER *)pCDS;
3319 memcpy(pCDS, pUpdate, sizeof(VkCopyDescriptorSet));
3320 break;
3321 default:
3322 if (log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
3323 DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
3324 "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree",
3325 string_VkStructureType(pUpdate->sType), pUpdate->sType))
Dustin Graves8f1eab92016-04-05 09:41:17 -06003326 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003327 }
3328 // Make sure that pNext for the end of shadow copy is NULL
3329 (*pNewNode)->pNext = NULL;
3330 return skipCall;
3331}
3332
3333// Verify that given sampler is valid
Dustin Graves8f1eab92016-04-05 09:41:17 -06003334static bool validateSampler(const layer_data *my_data, const VkSampler *pSampler, const bool immutable) {
3335 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003336 auto sampIt = my_data->sampleMap.find(*pSampler);
3337 if (sampIt == my_data->sampleMap.end()) {
3338 if (!immutable) {
3339 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
3340 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS",
3341 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid sampler %#" PRIxLEAST64,
3342 (uint64_t)*pSampler);
3343 } else { // immutable
3344 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
3345 (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS",
3346 "vkUpdateDescriptorSets: Attempt to update descriptor whose binding has an invalid immutable "
3347 "sampler %#" PRIxLEAST64,
3348 (uint64_t)*pSampler);
3349 }
3350 } else {
3351 // TODO : Any further checks we want to do on the sampler?
3352 }
3353 return skipCall;
3354}
3355
Michael Lentinef7bf6842016-03-30 15:57:52 -05003356//TODO: Consolidate functions
3357bool FindLayout(const GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
3358 layer_data *my_data = get_my_data_ptr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
3359 if (!(imgpair.subresource.aspectMask & aspectMask)) {
3360 return false;
3361 }
3362 VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
3363 imgpair.subresource.aspectMask = aspectMask;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003364 auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
3365 if (imgsubIt == pCB->imageLayoutMap.end()) {
Michael Lentinef7bf6842016-03-30 15:57:52 -05003366 return false;
3367 }
3368 if (node.layout != VK_IMAGE_LAYOUT_MAX_ENUM && node.layout != imgsubIt->second.layout) {
3369 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3370 reinterpret_cast<uint64_t&>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
3371 "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
3372 reinterpret_cast<uint64_t&>(imgpair.image), oldAspectMask, string_VkImageLayout(node.layout), string_VkImageLayout(imgsubIt->second.layout));
3373 }
3374 if (node.initialLayout != VK_IMAGE_LAYOUT_MAX_ENUM && node.initialLayout != imgsubIt->second.initialLayout) {
3375 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3376 reinterpret_cast<uint64_t&>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
3377 "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple initial layout types: %s and %s",
3378 reinterpret_cast<uint64_t&>(imgpair.image), oldAspectMask, string_VkImageLayout(node.initialLayout), string_VkImageLayout(imgsubIt->second.initialLayout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003379 }
3380 node = imgsubIt->second;
3381 return true;
3382}
3383
Michael Lentinef7bf6842016-03-30 15:57:52 -05003384bool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
3385 if (!(imgpair.subresource.aspectMask & aspectMask)) {
3386 return false;
3387 }
3388 VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
3389 imgpair.subresource.aspectMask = aspectMask;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003390 auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
3391 if (imgsubIt == my_data->imageLayoutMap.end()) {
Michael Lentinef7bf6842016-03-30 15:57:52 -05003392 return false;
3393 }
3394 if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
3395 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3396 reinterpret_cast<uint64_t&>(imgpair.image), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
3397 "Cannot query for VkImage 0x%" PRIx64 " layout when combined aspect mask %d has multiple layout types: %s and %s",
3398 reinterpret_cast<uint64_t&>(imgpair.image), oldAspectMask, string_VkImageLayout(layout), string_VkImageLayout(imgsubIt->second.layout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003399 }
3400 layout = imgsubIt->second.layout;
3401 return true;
3402}
3403
Michael Lentinef7bf6842016-03-30 15:57:52 -05003404// find layout(s) on the cmd buf level
3405bool FindLayout(const GLOBAL_CB_NODE *pCB, VkImage image, VkImageSubresource range, IMAGE_CMD_BUF_LAYOUT_NODE &node) {
3406 ImageSubresourcePair imgpair = {image, true, range};
3407 node = IMAGE_CMD_BUF_LAYOUT_NODE(VK_IMAGE_LAYOUT_MAX_ENUM, VK_IMAGE_LAYOUT_MAX_ENUM);
3408 FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_COLOR_BIT);
3409 FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_DEPTH_BIT);
3410 FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_STENCIL_BIT);
3411 FindLayout(pCB, imgpair, node, VK_IMAGE_ASPECT_METADATA_BIT);
3412 if (node.layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
3413 imgpair = {image, false, VkImageSubresource()};
3414 auto imgsubIt = pCB->imageLayoutMap.find(imgpair);
3415 if (imgsubIt == pCB->imageLayoutMap.end())
3416 return false;
3417 node = imgsubIt->second;
3418 }
3419 return true;
3420}
3421
3422// find layout(s) on the global level
3423bool FindLayout(const layer_data *my_data, ImageSubresourcePair imgpair, VkImageLayout &layout) {
3424 layout = VK_IMAGE_LAYOUT_MAX_ENUM;
3425 FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
3426 FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
3427 FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
3428 FindLayout(my_data, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
3429 if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
3430 imgpair = {imgpair.image, false, VkImageSubresource()};
3431 auto imgsubIt = my_data->imageLayoutMap.find(imgpair);
3432 if (imgsubIt == my_data->imageLayoutMap.end())
3433 return false;
3434 layout = imgsubIt->second.layout;
3435 }
3436 return true;
3437}
3438
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003439bool FindLayout(const layer_data *my_data, VkImage image, VkImageSubresource range, VkImageLayout &layout) {
3440 ImageSubresourcePair imgpair = {image, true, range};
3441 return FindLayout(my_data, imgpair, layout);
3442}
3443
3444bool FindLayouts(const layer_data *my_data, VkImage image, std::vector<VkImageLayout> &layouts) {
3445 auto sub_data = my_data->imageSubresourceMap.find(image);
3446 if (sub_data == my_data->imageSubresourceMap.end())
3447 return false;
3448 auto imgIt = my_data->imageMap.find(image);
3449 if (imgIt == my_data->imageMap.end())
3450 return false;
3451 bool ignoreGlobal = false;
3452 // TODO: Make this robust for >1 aspect mask. Now it will just say ignore
3453 // potential errors in this case.
3454 if (sub_data->second.size() >= (imgIt->second.createInfo.arrayLayers * imgIt->second.createInfo.mipLevels + 1)) {
3455 ignoreGlobal = true;
3456 }
3457 for (auto imgsubpair : sub_data->second) {
3458 if (ignoreGlobal && !imgsubpair.hasSubresource)
3459 continue;
3460 auto img_data = my_data->imageLayoutMap.find(imgsubpair);
3461 if (img_data != my_data->imageLayoutMap.end()) {
3462 layouts.push_back(img_data->second.layout);
3463 }
3464 }
3465 return true;
3466}
3467
3468// Set the layout on the global level
3469void SetLayout(layer_data *my_data, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
3470 VkImage &image = imgpair.image;
3471 // TODO (mlentine): Maybe set format if new? Not used atm.
3472 my_data->imageLayoutMap[imgpair].layout = layout;
3473 // TODO (mlentine): Maybe make vector a set?
3474 auto subresource = std::find(my_data->imageSubresourceMap[image].begin(), my_data->imageSubresourceMap[image].end(), imgpair);
3475 if (subresource == my_data->imageSubresourceMap[image].end()) {
3476 my_data->imageSubresourceMap[image].push_back(imgpair);
3477 }
3478}
3479
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003480// Set the layout on the cmdbuf level
Michael Lentine60063c22016-03-24 15:36:27 -05003481void SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const IMAGE_CMD_BUF_LAYOUT_NODE &node) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003482 pCB->imageLayoutMap[imgpair] = node;
3483 // TODO (mlentine): Maybe make vector a set?
Michael Lentine60063c22016-03-24 15:36:27 -05003484 auto subresource =
3485 std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair);
3486 if (subresource == pCB->imageSubresourceMap[imgpair.image].end()) {
3487 pCB->imageSubresourceMap[imgpair.image].push_back(imgpair);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003488 }
3489}
3490
Michael Lentine60063c22016-03-24 15:36:27 -05003491void SetLayout(GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, const VkImageLayout &layout) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003492 // TODO (mlentine): Maybe make vector a set?
Michael Lentine60063c22016-03-24 15:36:27 -05003493 if (std::find(pCB->imageSubresourceMap[imgpair.image].begin(), pCB->imageSubresourceMap[imgpair.image].end(), imgpair) !=
3494 pCB->imageSubresourceMap[imgpair.image].end()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003495 pCB->imageLayoutMap[imgpair].layout = layout;
3496 } else {
3497 // TODO (mlentine): Could be expensive and might need to be removed.
3498 assert(imgpair.hasSubresource);
3499 IMAGE_CMD_BUF_LAYOUT_NODE node;
Mark Lobodzinski41bfce02016-03-28 14:34:40 -06003500 if (!FindLayout(pCB, imgpair.image, imgpair.subresource, node)) {
3501 node.initialLayout = layout;
3502 }
Michael Lentine60063c22016-03-24 15:36:27 -05003503 SetLayout(pCB, imgpair, {node.initialLayout, layout});
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003504 }
3505}
3506
Michael Lentine60063c22016-03-24 15:36:27 -05003507template <class OBJECT, class LAYOUT>
3508void SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout, VkImageAspectFlags aspectMask) {
3509 if (imgpair.subresource.aspectMask & aspectMask) {
3510 imgpair.subresource.aspectMask = aspectMask;
3511 SetLayout(pObject, imgpair, layout);
3512 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003513}
3514
Michael Lentine60063c22016-03-24 15:36:27 -05003515template <class OBJECT, class LAYOUT>
3516void SetLayout(OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003517 ImageSubresourcePair imgpair = {image, true, range};
Michael Lentine60063c22016-03-24 15:36:27 -05003518 SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
3519 SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
3520 SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
3521 SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003522}
3523
Michael Lentine60063c22016-03-24 15:36:27 -05003524template <class OBJECT, class LAYOUT> void SetLayout(OBJECT *pObject, VkImage image, const LAYOUT &layout) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003525 ImageSubresourcePair imgpair = {image, false, VkImageSubresource()};
Michael Lentine60063c22016-03-24 15:36:27 -05003526 SetLayout(pObject, image, imgpair, layout);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003527}
3528
3529void SetLayout(const layer_data *dev_data, GLOBAL_CB_NODE *pCB, VkImageView imageView, const VkImageLayout &layout) {
3530 auto image_view_data = dev_data->imageViewMap.find(imageView);
3531 assert(image_view_data != dev_data->imageViewMap.end());
3532 const VkImage &image = image_view_data->second.image;
3533 const VkImageSubresourceRange &subRange = image_view_data->second.subresourceRange;
3534 // TODO: Do not iterate over every possibility - consolidate where possible
3535 for (uint32_t j = 0; j < subRange.levelCount; j++) {
3536 uint32_t level = subRange.baseMipLevel + j;
3537 for (uint32_t k = 0; k < subRange.layerCount; k++) {
3538 uint32_t layer = subRange.baseArrayLayer + k;
3539 VkImageSubresource sub = {subRange.aspectMask, level, layer};
3540 SetLayout(pCB, image, sub, layout);
3541 }
3542 }
3543}
3544
3545// Verify that given imageView is valid
Dustin Graves8f1eab92016-04-05 09:41:17 -06003546static bool validateImageView(const layer_data *my_data, const VkImageView *pImageView, const VkImageLayout imageLayout) {
3547 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003548 auto ivIt = my_data->imageViewMap.find(*pImageView);
3549 if (ivIt == my_data->imageViewMap.end()) {
3550 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
3551 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
3552 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid imageView %#" PRIxLEAST64,
3553 (uint64_t)*pImageView);
3554 } else {
3555 // Validate that imageLayout is compatible with aspectMask and image format
3556 VkImageAspectFlags aspectMask = ivIt->second.subresourceRange.aspectMask;
3557 VkImage image = ivIt->second.image;
3558 // TODO : Check here in case we have a bad image
3559 VkFormat format = VK_FORMAT_MAX_ENUM;
3560 auto imgIt = my_data->imageMap.find(image);
3561 if (imgIt != my_data->imageMap.end()) {
3562 format = (*imgIt).second.createInfo.format;
3563 } else {
3564 // Also need to check the swapchains.
3565 auto swapchainIt = my_data->device_extensions.imageToSwapchainMap.find(image);
3566 if (swapchainIt != my_data->device_extensions.imageToSwapchainMap.end()) {
3567 VkSwapchainKHR swapchain = swapchainIt->second;
3568 auto swapchain_nodeIt = my_data->device_extensions.swapchainMap.find(swapchain);
3569 if (swapchain_nodeIt != my_data->device_extensions.swapchainMap.end()) {
3570 SWAPCHAIN_NODE *pswapchain_node = swapchain_nodeIt->second;
3571 format = pswapchain_node->createInfo.imageFormat;
3572 }
3573 }
3574 }
3575 if (format == VK_FORMAT_MAX_ENUM) {
3576 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3577 (uint64_t)image, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
3578 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid image %#" PRIxLEAST64
3579 " in imageView %#" PRIxLEAST64,
3580 (uint64_t)image, (uint64_t)*pImageView);
3581 } else {
Dustin Graves8f1eab92016-04-05 09:41:17 -06003582 bool ds = vk_format_is_depth_or_stencil(format);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003583 switch (imageLayout) {
3584 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
3585 // Only Color bit must be set
3586 if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
3587 skipCall |=
3588 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
3589 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
3590 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL "
3591 "and imageView %#" PRIxLEAST64 ""
3592 " that does not have VK_IMAGE_ASPECT_COLOR_BIT set.",
3593 (uint64_t)*pImageView);
3594 }
3595 // format must NOT be DS
3596 if (ds) {
3597 skipCall |=
3598 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
3599 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
3600 "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL "
3601 "and imageView %#" PRIxLEAST64 ""
3602 " but the image format is %s which is not a color format.",
3603 (uint64_t)*pImageView, string_VkFormat(format));
3604 }
3605 break;
3606 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
3607 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
3608 // Depth or stencil bit must be set, but both must NOT be set
3609 if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) {
3610 if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
3611 // both must NOT be set
3612 skipCall |=
3613 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
3614 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
3615 "vkUpdateDescriptorSets: Updating descriptor with imageView %#" PRIxLEAST64 ""
3616 " that has both STENCIL and DEPTH aspects set",
3617 (uint64_t)*pImageView);
3618 }
3619 } else if (!(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
3620 // Neither were set
3621 skipCall |=
3622 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
3623 (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
3624 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 ""
3625 " that does not have STENCIL or DEPTH aspect set.",
3626 string_VkImageLayout(imageLayout), (uint64_t)*pImageView);
3627 }
3628 // format must be DS
3629 if (!ds) {
3630 skipCall |=
3631 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
3632 (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
3633 "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 ""
3634 " but the image format is %s which is not a depth/stencil format.",
3635 string_VkImageLayout(imageLayout), (uint64_t)*pImageView, string_VkFormat(format));
3636 }
3637 break;
3638 default:
3639 // anything to check for other layouts?
3640 break;
3641 }
3642 }
3643 }
3644 return skipCall;
3645}
3646
3647// Verify that given bufferView is valid
Dustin Graves8f1eab92016-04-05 09:41:17 -06003648static bool validateBufferView(const layer_data *my_data, const VkBufferView *pBufferView) {
3649 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003650 auto sampIt = my_data->bufferViewMap.find(*pBufferView);
3651 if (sampIt == my_data->bufferViewMap.end()) {
3652 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT,
3653 (uint64_t)*pBufferView, __LINE__, DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, "DS",
3654 "vkUpdateDescriptorSets: Attempt to update descriptor with invalid bufferView %#" PRIxLEAST64,
3655 (uint64_t)*pBufferView);
3656 } else {
3657 // TODO : Any further checks we want to do on the bufferView?
3658 }
3659 return skipCall;
3660}
3661
3662// Verify that given bufferInfo is valid
Dustin Graves8f1eab92016-04-05 09:41:17 -06003663static bool validateBufferInfo(const layer_data *my_data, const VkDescriptorBufferInfo *pBufferInfo) {
3664 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003665 auto sampIt = my_data->bufferMap.find(pBufferInfo->buffer);
3666 if (sampIt == my_data->bufferMap.end()) {
3667 skipCall |=
3668 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3669 (uint64_t)pBufferInfo->buffer, __LINE__, DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, "DS",
3670 "vkUpdateDescriptorSets: Attempt to update descriptor where bufferInfo has invalid buffer %#" PRIxLEAST64,
3671 (uint64_t)pBufferInfo->buffer);
3672 } else {
3673 // TODO : Any further checks we want to do on the bufferView?
3674 }
3675 return skipCall;
3676}
3677
Dustin Graves8f1eab92016-04-05 09:41:17 -06003678static bool validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS,
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003679 const VkSampler *pImmutableSamplers) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06003680 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003681 // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied
3682 const VkSampler *pSampler = NULL;
Dustin Graves8f1eab92016-04-05 09:41:17 -06003683 bool immutable = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003684 uint32_t i = 0;
3685 // For given update type, verify that update contents are correct
3686 switch (pWDS->descriptorType) {
3687 case VK_DESCRIPTOR_TYPE_SAMPLER:
3688 for (i = 0; i < pWDS->descriptorCount; ++i) {
3689 skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable);
3690 }
3691 break;
3692 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
3693 for (i = 0; i < pWDS->descriptorCount; ++i) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003694 if (NULL == pImmutableSamplers) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003695 pSampler = &(pWDS->pImageInfo[i].sampler);
3696 if (immutable) {
3697 skipCall |= log_msg(
3698 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
3699 (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
3700 "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64
3701 ", but previous update(s) from this "
3702 "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either "
3703 "use immutable or non-immutable samplers.",
3704 i, (uint64_t)*pSampler);
3705 }
3706 } else {
3707 if (i > 0 && !immutable) {
3708 skipCall |= log_msg(
3709 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
3710 (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
3711 "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this "
3712 "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either "
3713 "use immutable or non-immutable samplers.",
3714 i);
3715 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06003716 immutable = true;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003717 pSampler = &(pImmutableSamplers[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003718 }
3719 skipCall |= validateSampler(my_data, pSampler, immutable);
3720 }
3721 // Intentionally fall through here to also validate image stuff
3722 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3723 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
3724 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
3725 for (i = 0; i < pWDS->descriptorCount; ++i) {
3726 skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout);
3727 }
3728 break;
3729 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
3730 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
3731 for (i = 0; i < pWDS->descriptorCount; ++i) {
3732 skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i]));
3733 }
3734 break;
3735 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3736 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3737 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
3738 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
3739 for (i = 0; i < pWDS->descriptorCount; ++i) {
3740 skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i]));
3741 }
3742 break;
3743 default:
3744 break;
3745 }
3746 return skipCall;
3747}
3748// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
3749// func_str is the name of the calling function
Dustin Graves8f1eab92016-04-05 09:41:17 -06003750// Return false if no errors occur
3751// Return true if validation error occurs and callback returns true (to skip upcoming API call down the chain)
3752static bool validateIdleDescriptorSet(const layer_data *my_data, VkDescriptorSet set, std::string func_str) {
3753 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003754 auto set_node = my_data->setMap.find(set);
3755 if (set_node == my_data->setMap.end()) {
3756 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3757 (uint64_t)(set), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
3758 "Cannot call %s() on descriptor set %" PRIxLEAST64 " that has not been allocated.", func_str.c_str(),
3759 (uint64_t)(set));
3760 } else {
3761 if (set_node->second->in_use.load()) {
3762 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
3763 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)(set), __LINE__, DRAWSTATE_OBJECT_INUSE,
3764 "DS", "Cannot call %s() on descriptor set %" PRIxLEAST64 " that is in use by a command buffer.",
3765 func_str.c_str(), (uint64_t)(set));
3766 }
3767 }
3768 return skip_call;
3769}
3770static void invalidateBoundCmdBuffers(layer_data *dev_data, const SET_NODE *pSet) {
3771 // Flag any CBs this set is bound to as INVALID
3772 for (auto cb : pSet->boundCmdBuffers) {
3773 auto cb_node = dev_data->commandBufferMap.find(cb);
3774 if (cb_node != dev_data->commandBufferMap.end()) {
3775 cb_node->second->state = CB_INVALID;
3776 }
3777 }
3778}
3779// update DS mappings based on write and copy update arrays
Dustin Graves8f1eab92016-04-05 09:41:17 -06003780static bool dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS,
3781 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) {
3782 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003783 // Validate Write updates
3784 uint32_t i = 0;
3785 for (i = 0; i < descriptorWriteCount; i++) {
3786 VkDescriptorSet ds = pWDS[i].dstSet;
3787 SET_NODE *pSet = my_data->setMap[ds];
3788 // Set being updated cannot be in-flight
Dustin Graves8f1eab92016-04-05 09:41:17 -06003789 if ((skipCall = validateIdleDescriptorSet(my_data, ds, "VkUpdateDescriptorSets")) == true)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003790 return skipCall;
3791 // If set is bound to any cmdBuffers, mark them invalid
3792 invalidateBoundCmdBuffers(my_data, pSet);
3793 GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i];
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003794 auto layout_node = pSet->p_layout;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003795 // First verify valid update struct
Dustin Graves8f1eab92016-04-05 09:41:17 -06003796 if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == true) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003797 break;
3798 }
3799 uint32_t binding = 0, endIndex = 0;
3800 binding = pWDS[i].dstBinding;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003801 // Make sure that layout being updated has the binding being updated
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003802 if (!layout_node->HasBinding(binding)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003803 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3804 (uint64_t)(ds), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
3805 "Descriptor Set %" PRIu64 " does not have binding to match "
3806 "update binding %u for update type "
3807 "%s!",
3808 (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType));
3809 } else {
3810 // Next verify that update falls within size of given binding
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003811 endIndex = getUpdateEndIndex(my_data, device, layout_node->GetGlobalStartIndexFromBinding(binding),
3812 pWDS[i].dstArrayElement, pUpdate);
3813 if (layout_node->GetGlobalEndIndexFromBinding(binding) < endIndex) {
3814 auto ds_layout = layout_node->GetDescriptorSetLayout();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003815 skipCall |=
3816 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003817 reinterpret_cast<uint64_t &>(ds), __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
3818 "Descriptor update type of %s is out of bounds for matching binding %u in Layout %" PRIu64 "!",
3819 string_VkStructureType(pUpdate->sType), binding, reinterpret_cast<uint64_t &>(ds_layout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003820 } else { // TODO : should we skip update on a type mismatch or force it?
3821 uint32_t startIndex;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003822 startIndex = getUpdateStartIndex(my_data, device, layout_node->GetGlobalStartIndexFromBinding(binding),
3823 pWDS[i].dstArrayElement, pUpdate);
Tobin Ehlis546326f2016-04-26 11:06:05 -06003824 const auto & layout_binding = layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(binding);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003825 // Layout bindings match w/ update, now verify that update type & stageFlags are the same for entire update
3826 if ((skipCall = validateUpdateConsistency(my_data, device, layout_binding->descriptorType, pUpdate, startIndex,
3827 endIndex)) == false) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003828 // The update is within bounds and consistent, but need to
3829 // make sure contents make sense as well
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003830 if ((skipCall = validateUpdateContents(my_data, &pWDS[i], layout_binding->pImmutableSamplers)) == false) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003831 // Update is good. Save the update info
3832 // Create new update struct for this set's shadow copy
3833 GENERIC_HEADER *pNewNode = NULL;
3834 skipCall |= shadowUpdateNode(my_data, device, pUpdate, &pNewNode);
3835 if (NULL == pNewNode) {
3836 skipCall |= log_msg(
3837 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3838 (uint64_t)(ds), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
3839 "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()");
3840 } else {
3841 // Insert shadow node into LL of updates for this set
3842 pNewNode->pNext = pSet->pUpdateStructs;
3843 pSet->pUpdateStructs = pNewNode;
3844 // Now update appropriate descriptor(s) to point to new Update node
3845 for (uint32_t j = startIndex; j <= endIndex; j++) {
3846 assert(j < pSet->descriptorCount);
Tobin Ehlis38f5bbb2016-03-24 10:16:09 -06003847 pSet->pDescriptorUpdates[j] = pNewNode;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003848 }
3849 }
3850 }
3851 }
3852 }
3853 }
3854 }
3855 // Now validate copy updates
3856 for (i = 0; i < descriptorCopyCount; ++i) {
3857 SET_NODE *pSrcSet = NULL, *pDstSet = NULL;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003858 uint32_t srcStartIndex = 0, srcEndIndex = 0, dstStartIndex = 0, dstEndIndex = 0;
3859 // For each copy make sure that update falls within given layout and that types match
3860 pSrcSet = my_data->setMap[pCDS[i].srcSet];
3861 pDstSet = my_data->setMap[pCDS[i].dstSet];
3862 // Set being updated cannot be in-flight
Dustin Graves8f1eab92016-04-05 09:41:17 -06003863 if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == true)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003864 return skipCall;
3865 invalidateBoundCmdBuffers(my_data, pDstSet);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003866 auto src_layout_node = pSrcSet->p_layout;
3867 auto dst_layout_node = pDstSet->p_layout;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003868 // Validate that src binding is valid for src set layout
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003869 if (!src_layout_node->HasBinding(pCDS[i].srcBinding)) {
3870 auto s_layout = src_layout_node->GetDescriptorSetLayout();
3871 skipCall |=
3872 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3873 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
3874 "Copy descriptor update %u has srcBinding %u "
3875 "which is out of bounds for underlying SetLayout "
3876 "%#" PRIxLEAST64 " which only has bindings 0-%u.",
3877 i, pCDS[i].srcBinding, reinterpret_cast<uint64_t &>(s_layout), src_layout_node->GetBindingCount() - 1);
3878 } else if (!dst_layout_node->HasBinding(pCDS[i].dstBinding)) {
3879 auto d_layout = dst_layout_node->GetDescriptorSetLayout();
3880 skipCall |=
3881 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3882 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
3883 "Copy descriptor update %u has dstBinding %u "
3884 "which is out of bounds for underlying SetLayout "
3885 "%#" PRIxLEAST64 " which only has bindings 0-%u.",
3886 i, pCDS[i].dstBinding, reinterpret_cast<uint64_t &>(d_layout), dst_layout_node->GetBindingCount() - 1);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003887 } else {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003888 // Proceed with validation. Bindings are ok, but make sure update is within bounds of given layout and binding
3889 srcEndIndex = getUpdateEndIndex(my_data, device, src_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].srcBinding),
3890 pCDS[i].srcArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
3891 dstEndIndex = getUpdateEndIndex(my_data, device, dst_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].dstBinding),
3892 pCDS[i].dstArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
3893 if (src_layout_node->GetGlobalEndIndexFromBinding(pCDS[i].srcBinding) < srcEndIndex) {
3894 auto s_layout = src_layout_node->GetDescriptorSetLayout();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003895 skipCall |=
3896 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3897 (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003898 "Copy descriptor src update is out of bounds for matching binding %u in Layout %" PRIu64 "!",
3899 pCDS[i].srcBinding, reinterpret_cast<uint64_t &>(s_layout));
3900 } else if (dst_layout_node->GetGlobalEndIndexFromBinding(pCDS[i].dstBinding) < dstEndIndex) {
3901 auto d_layout = dst_layout_node->GetDescriptorSetLayout();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003902 skipCall |=
3903 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
3904 (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003905 "Copy descriptor dest update is out of bounds for matching binding %u in Layout %" PRIu64 "!",
3906 pCDS[i].dstBinding, reinterpret_cast<uint64_t &>(d_layout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003907 } else {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003908 srcStartIndex =
3909 getUpdateStartIndex(my_data, device, src_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].srcBinding),
3910 pCDS[i].srcArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
3911 dstStartIndex =
3912 getUpdateStartIndex(my_data, device, dst_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].dstBinding),
3913 pCDS[i].dstArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
3914 auto s_binding = src_layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(pCDS[i].srcBinding);
3915 auto d_binding = dst_layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(pCDS[i].dstBinding);
3916 // For copy, just make sure types match and then perform update
3917 if (s_binding->descriptorType != d_binding->descriptorType) {
3918 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
3919 __LINE__, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
3920 "Copy descriptor update index %u, has src update descriptor type %s "
3921 "that does not match overlapping dest descriptor type of %s!",
3922 i, string_VkDescriptorType(s_binding->descriptorType),
3923 string_VkDescriptorType(d_binding->descriptorType));
3924 } else {
3925 for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003926 // point dst descriptor at corresponding src descriptor
3927 // TODO : This may be a hole. I believe copy should be its own copy,
3928 // otherwise a subsequent write update to src will incorrectly affect the copy
Tobin Ehlis38f5bbb2016-03-24 10:16:09 -06003929 pDstSet->pDescriptorUpdates[j + dstStartIndex] = pSrcSet->pDescriptorUpdates[j + srcStartIndex];
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003930 pDstSet->pUpdateStructs = pSrcSet->pUpdateStructs;
3931 }
3932 }
3933 }
3934 }
3935 }
3936 return skipCall;
3937}
3938
Mark Lobodzinskia3efb0c2016-03-21 16:32:53 -06003939// Verify that given pool has descriptors that are being requested for allocation.
3940// NOTE : Calls to this function should be wrapped in mutex
Dustin Graves8f1eab92016-04-05 09:41:17 -06003941static bool validate_descriptor_availability_in_pool(layer_data *dev_data, DESCRIPTOR_POOL_NODE *pPoolNode, uint32_t count,
3942 const VkDescriptorSetLayout *pSetLayouts) {
3943 bool skipCall = false;
Mark Lobodzinskia3efb0c2016-03-21 16:32:53 -06003944 uint32_t i = 0;
3945 uint32_t j = 0;
3946
3947 // Track number of descriptorSets allowable in this pool
3948 if (pPoolNode->availableSets < count) {
3949 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
3950 reinterpret_cast<uint64_t &>(pPoolNode->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
3951 "Unable to allocate %u descriptorSets from pool %#" PRIxLEAST64
3952 ". This pool only has %d descriptorSets remaining.",
3953 count, reinterpret_cast<uint64_t &>(pPoolNode->pool), pPoolNode->availableSets);
3954 } else {
3955 pPoolNode->availableSets -= count;
3956 }
3957
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003958 for (i = 0; i < count; ++i) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003959 auto layout_pair = dev_data->descriptorSetLayoutMap.find(pSetLayouts[i]);
3960 if (layout_pair == dev_data->descriptorSetLayoutMap.end()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003961 skipCall |=
3962 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
3963 (uint64_t)pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
3964 "Unable to find set layout node for layout %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call",
3965 (uint64_t)pSetLayouts[i]);
3966 } else {
3967 uint32_t typeIndex = 0, poolSizeCount = 0;
Tobin Ehlis546326f2016-04-26 11:06:05 -06003968 auto &layout_node = layout_pair->second;
3969 for (j = 0; j < layout_node->GetBindingCount(); ++j) {
3970 const auto &binding_layout = layout_node->GetDescriptorSetLayoutBindingPtrFromIndex(j);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003971 typeIndex = static_cast<uint32_t>(binding_layout->descriptorType);
3972 poolSizeCount = binding_layout->descriptorCount;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003973 if (poolSizeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) {
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06003974 skipCall |= log_msg(
3975 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
3976 reinterpret_cast<const uint64_t &>(pSetLayouts[i]), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
3977 "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64
3978 ". This pool only has %d descriptors of this type remaining.",
3979 poolSizeCount, string_VkDescriptorType(binding_layout->descriptorType), (uint64_t)pPoolNode->pool,
3980 pPoolNode->availableDescriptorTypeCount[typeIndex]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003981 } else { // Decrement available descriptors of this type
3982 pPoolNode->availableDescriptorTypeCount[typeIndex] -= poolSizeCount;
3983 }
3984 }
3985 }
3986 }
3987 return skipCall;
3988}
3989
3990// Free the shadowed update node for this Set
3991// NOTE : Calls to this function should be wrapped in mutex
3992static void freeShadowUpdateTree(SET_NODE *pSet) {
3993 GENERIC_HEADER *pShadowUpdate = pSet->pUpdateStructs;
3994 pSet->pUpdateStructs = NULL;
3995 GENERIC_HEADER *pFreeUpdate = pShadowUpdate;
3996 // Clear the descriptor mappings as they will now be invalid
Tobin Ehlis38f5bbb2016-03-24 10:16:09 -06003997 pSet->pDescriptorUpdates.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07003998 while (pShadowUpdate) {
3999 pFreeUpdate = pShadowUpdate;
4000 pShadowUpdate = (GENERIC_HEADER *)pShadowUpdate->pNext;
4001 VkWriteDescriptorSet *pWDS = NULL;
4002 switch (pFreeUpdate->sType) {
4003 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
4004 pWDS = (VkWriteDescriptorSet *)pFreeUpdate;
4005 switch (pWDS->descriptorType) {
4006 case VK_DESCRIPTOR_TYPE_SAMPLER:
4007 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
4008 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
4009 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
4010 delete[] pWDS->pImageInfo;
4011 } break;
4012 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
4013 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
4014 delete[] pWDS->pTexelBufferView;
4015 } break;
4016 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
4017 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
4018 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
4019 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
4020 delete[] pWDS->pBufferInfo;
4021 } break;
4022 default:
4023 break;
4024 }
4025 break;
4026 case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
4027 break;
4028 default:
4029 assert(0);
4030 break;
4031 }
4032 delete pFreeUpdate;
4033 }
4034}
4035
4036// Free all DS Pools including their Sets & related sub-structs
4037// NOTE : Calls to this function should be wrapped in mutex
4038static void deletePools(layer_data *my_data) {
4039 if (my_data->descriptorPoolMap.size() <= 0)
4040 return;
4041 for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) {
4042 SET_NODE *pSet = (*ii).second->pSets;
4043 SET_NODE *pFreeSet = pSet;
4044 while (pSet) {
4045 pFreeSet = pSet;
4046 pSet = pSet->pNext;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004047 // Free Update shadow struct tree
4048 freeShadowUpdateTree(pFreeSet);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004049 delete pFreeSet;
4050 }
4051 delete (*ii).second;
4052 }
4053 my_data->descriptorPoolMap.clear();
4054}
4055
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004056// Currently clearing a set is removing all previous updates to that set
4057// TODO : Validate if this is correct clearing behavior
4058static void clearDescriptorSet(layer_data *my_data, VkDescriptorSet set) {
4059 SET_NODE *pSet = getSetNode(my_data, set);
4060 if (!pSet) {
4061 // TODO : Return error
4062 } else {
4063 freeShadowUpdateTree(pSet);
4064 }
4065}
4066
4067static void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool,
4068 VkDescriptorPoolResetFlags flags) {
4069 DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool);
4070 if (!pPool) {
4071 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
4072 (uint64_t)pool, __LINE__, DRAWSTATE_INVALID_POOL, "DS",
4073 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkResetDescriptorPool() call", (uint64_t)pool);
4074 } else {
4075 // TODO: validate flags
Tobin Ehlis49f85682016-04-15 11:59:39 -06004076 // For every set off of this pool, clear it, remove from setMap, and free SET_NODE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004077 SET_NODE *pSet = pPool->pSets;
Tobin Ehlis49f85682016-04-15 11:59:39 -06004078 SET_NODE *pFreeSet = pSet;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004079 while (pSet) {
4080 clearDescriptorSet(my_data, pSet->set);
Tobin Ehlis49f85682016-04-15 11:59:39 -06004081 my_data->setMap.erase(pSet->set);
4082 pFreeSet = pSet;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004083 pSet = pSet->pNext;
Tobin Ehlis49f85682016-04-15 11:59:39 -06004084 delete pFreeSet;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004085 }
Tobin Ehlis49f85682016-04-15 11:59:39 -06004086 pPool->pSets = nullptr;
Tobin Ehlis1cee1412016-03-30 12:20:53 -06004087 // Reset available count for each type and available sets for this pool
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004088 for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
4089 pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
4090 }
Tobin Ehlis1cee1412016-03-30 12:20:53 -06004091 pPool->availableSets = pPool->maxSets;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004092 }
4093}
4094
4095// For given CB object, fetch associated CB Node from map
4096static GLOBAL_CB_NODE *getCBNode(layer_data *my_data, const VkCommandBuffer cb) {
4097 if (my_data->commandBufferMap.count(cb) == 0) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004098 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4099 reinterpret_cast<const uint64_t &>(cb), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4100 "Attempt to use CommandBuffer %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(cb));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004101 return NULL;
4102 }
4103 return my_data->commandBufferMap[cb];
4104}
4105
4106// Free all CB Nodes
4107// NOTE : Calls to this function should be wrapped in mutex
4108static void deleteCommandBuffers(layer_data *my_data) {
Tobin Ehlis4c522322016-04-11 16:39:29 -06004109 if (my_data->commandBufferMap.empty()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004110 return;
4111 }
4112 for (auto ii = my_data->commandBufferMap.begin(); ii != my_data->commandBufferMap.end(); ++ii) {
4113 delete (*ii).second;
4114 }
4115 my_data->commandBufferMap.clear();
4116}
4117
Dustin Graves8f1eab92016-04-05 09:41:17 -06004118static bool report_error_no_cb_begin(const layer_data *dev_data, const VkCommandBuffer cb, const char *caller_name) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004119 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4120 (uint64_t)cb, __LINE__, DRAWSTATE_NO_BEGIN_COMMAND_BUFFER, "DS",
4121 "You must call vkBeginCommandBuffer() before this call to %s", caller_name);
4122}
4123
Dustin Graves8f1eab92016-04-05 09:41:17 -06004124bool validateCmdsInCmdBuffer(const layer_data *dev_data, const GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd_type) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004125 if (!pCB->activeRenderPass)
Dustin Graves8f1eab92016-04-05 09:41:17 -06004126 return false;
4127 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004128 if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS && cmd_type != CMD_EXECUTECOMMANDS) {
4129 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
4130 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4131 "Commands cannot be called in a subpass using secondary command buffers.");
4132 } else if (pCB->activeSubpassContents == VK_SUBPASS_CONTENTS_INLINE && cmd_type == CMD_EXECUTECOMMANDS) {
4133 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
4134 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4135 "vkCmdExecuteCommands() cannot be called in a subpass using inline commands.");
4136 }
4137 return skip_call;
4138}
4139
4140static bool checkGraphicsBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
4141 if (!(flags & VK_QUEUE_GRAPHICS_BIT))
4142 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
4143 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4144 "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
4145 return false;
4146}
4147
4148static bool checkComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
4149 if (!(flags & VK_QUEUE_COMPUTE_BIT))
4150 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
4151 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4152 "Cannot call %s on a command buffer allocated from a pool without compute capabilities.", name);
4153 return false;
4154}
4155
4156static bool checkGraphicsOrComputeBit(const layer_data *my_data, VkQueueFlags flags, const char *name) {
4157 if (!((flags & VK_QUEUE_GRAPHICS_BIT) || (flags & VK_QUEUE_COMPUTE_BIT)))
4158 return log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
4159 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
4160 "Cannot call %s on a command buffer allocated from a pool without graphics capabilities.", name);
4161 return false;
4162}
4163
4164// Add specified CMD to the CmdBuffer in given pCB, flagging errors if CB is not
4165// in the recording state or if there's an issue with the Cmd ordering
Dustin Graves8f1eab92016-04-05 09:41:17 -06004166static bool addCmd(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const CMD_TYPE cmd, const char *caller_name) {
4167 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004168 auto pool_data = my_data->commandPoolMap.find(pCB->createInfo.commandPool);
4169 if (pool_data != my_data->commandPoolMap.end()) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004170 VkQueueFlags flags = my_data->phys_dev_properties.queue_family_properties[pool_data->second.queueFamilyIndex].queueFlags;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004171 switch (cmd) {
4172 case CMD_BINDPIPELINE:
4173 case CMD_BINDPIPELINEDELTA:
4174 case CMD_BINDDESCRIPTORSETS:
4175 case CMD_FILLBUFFER:
4176 case CMD_CLEARCOLORIMAGE:
4177 case CMD_SETEVENT:
4178 case CMD_RESETEVENT:
4179 case CMD_WAITEVENTS:
4180 case CMD_BEGINQUERY:
4181 case CMD_ENDQUERY:
4182 case CMD_RESETQUERYPOOL:
4183 case CMD_COPYQUERYPOOLRESULTS:
4184 case CMD_WRITETIMESTAMP:
4185 skipCall |= checkGraphicsOrComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
4186 break;
4187 case CMD_SETVIEWPORTSTATE:
4188 case CMD_SETSCISSORSTATE:
4189 case CMD_SETLINEWIDTHSTATE:
4190 case CMD_SETDEPTHBIASSTATE:
4191 case CMD_SETBLENDSTATE:
4192 case CMD_SETDEPTHBOUNDSSTATE:
4193 case CMD_SETSTENCILREADMASKSTATE:
4194 case CMD_SETSTENCILWRITEMASKSTATE:
4195 case CMD_SETSTENCILREFERENCESTATE:
4196 case CMD_BINDINDEXBUFFER:
4197 case CMD_BINDVERTEXBUFFER:
4198 case CMD_DRAW:
4199 case CMD_DRAWINDEXED:
4200 case CMD_DRAWINDIRECT:
4201 case CMD_DRAWINDEXEDINDIRECT:
4202 case CMD_BLITIMAGE:
4203 case CMD_CLEARATTACHMENTS:
4204 case CMD_CLEARDEPTHSTENCILIMAGE:
4205 case CMD_RESOLVEIMAGE:
4206 case CMD_BEGINRENDERPASS:
4207 case CMD_NEXTSUBPASS:
4208 case CMD_ENDRENDERPASS:
4209 skipCall |= checkGraphicsBit(my_data, flags, cmdTypeToString(cmd).c_str());
4210 break;
4211 case CMD_DISPATCH:
4212 case CMD_DISPATCHINDIRECT:
4213 skipCall |= checkComputeBit(my_data, flags, cmdTypeToString(cmd).c_str());
4214 break;
4215 case CMD_COPYBUFFER:
4216 case CMD_COPYIMAGE:
4217 case CMD_COPYBUFFERTOIMAGE:
4218 case CMD_COPYIMAGETOBUFFER:
4219 case CMD_CLONEIMAGEDATA:
4220 case CMD_UPDATEBUFFER:
4221 case CMD_PIPELINEBARRIER:
4222 case CMD_EXECUTECOMMANDS:
4223 break;
4224 default:
4225 break;
4226 }
4227 }
4228 if (pCB->state != CB_RECORDING) {
4229 skipCall |= report_error_no_cb_begin(my_data, pCB->commandBuffer, caller_name);
4230 skipCall |= validateCmdsInCmdBuffer(my_data, pCB, cmd);
4231 CMD_NODE cmdNode = {};
4232 // init cmd node and append to end of cmd LL
4233 cmdNode.cmdNumber = ++pCB->numCmds;
4234 cmdNode.type = cmd;
4235 pCB->cmds.push_back(cmdNode);
4236 }
4237 return skipCall;
4238}
4239// Reset the command buffer state
4240// Maintain the createInfo and set state to CB_NEW, but clear all other state
Tobin Ehlis4c522322016-04-11 16:39:29 -06004241static void resetCB(layer_data *dev_data, const VkCommandBuffer cb) {
4242 GLOBAL_CB_NODE *pCB = dev_data->commandBufferMap[cb];
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004243 if (pCB) {
Michael Lentinefebf20b2016-04-20 23:01:26 -05004244 pCB->in_use.store(0);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004245 pCB->cmds.clear();
4246 // Reset CB state (note that createInfo is not cleared)
4247 pCB->commandBuffer = cb;
4248 memset(&pCB->beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
4249 memset(&pCB->inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004250 pCB->numCmds = 0;
4251 memset(pCB->drawCount, 0, NUM_DRAW_TYPES * sizeof(uint64_t));
4252 pCB->state = CB_NEW;
4253 pCB->submitCount = 0;
4254 pCB->status = 0;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004255 pCB->viewports.clear();
4256 pCB->scissors.clear();
Mark Lobodzinski188b2302016-04-12 10:41:59 -06004257
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004258 for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
4259 // Before clearing lastBoundState, remove any CB bindings from all uniqueBoundSets
4260 for (auto set : pCB->lastBound[i].uniqueBoundSets) {
Tobin Ehlis4c522322016-04-11 16:39:29 -06004261 auto set_node = dev_data->setMap.find(set);
4262 if (set_node != dev_data->setMap.end()) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004263 set_node->second->boundCmdBuffers.erase(pCB->commandBuffer);
4264 }
4265 }
4266 pCB->lastBound[i].reset();
4267 }
Mark Lobodzinski188b2302016-04-12 10:41:59 -06004268
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004269 memset(&pCB->activeRenderPassBeginInfo, 0, sizeof(pCB->activeRenderPassBeginInfo));
4270 pCB->activeRenderPass = 0;
4271 pCB->activeSubpassContents = VK_SUBPASS_CONTENTS_INLINE;
4272 pCB->activeSubpass = 0;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004273 pCB->lastSubmittedFence = VK_NULL_HANDLE;
4274 pCB->lastSubmittedQueue = VK_NULL_HANDLE;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004275 pCB->destroyedSets.clear();
4276 pCB->updatedSets.clear();
4277 pCB->destroyedFramebuffers.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004278 pCB->waitedEvents.clear();
4279 pCB->semaphores.clear();
4280 pCB->events.clear();
4281 pCB->waitedEventsBeforeQueryReset.clear();
4282 pCB->queryToStateMap.clear();
4283 pCB->activeQueries.clear();
4284 pCB->startedQueries.clear();
Michael Lentine11fe3772016-04-20 11:39:50 -05004285 pCB->imageSubresourceMap.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004286 pCB->imageLayoutMap.clear();
4287 pCB->eventToStageMap.clear();
4288 pCB->drawData.clear();
4289 pCB->currentDrawData.buffers.clear();
4290 pCB->primaryCommandBuffer = VK_NULL_HANDLE;
Tobin Ehlis739d62a2016-04-14 12:22:03 -06004291 // Make sure any secondaryCommandBuffers are removed from globalInFlight
4292 for (auto secondary_cb : pCB->secondaryCommandBuffers) {
4293 dev_data->globalInFlightCmdBuffers.erase(secondary_cb);
4294 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004295 pCB->secondaryCommandBuffers.clear();
Tobin Ehlis2e319d42016-03-25 11:49:51 -06004296 pCB->updateImages.clear();
4297 pCB->updateBuffers.clear();
Tobin Ehlis4c522322016-04-11 16:39:29 -06004298 clear_cmd_buf_and_mem_references(dev_data, pCB);
Michael Lentineb653eb22016-03-18 14:11:44 -05004299 pCB->eventUpdates.clear();
Mark Lobodzinski188b2302016-04-12 10:41:59 -06004300
4301 // Remove this cmdBuffer's reference from each FrameBuffer's CB ref list
4302 for (auto framebuffer : pCB->framebuffers) {
4303 auto fbNode = dev_data->frameBufferMap.find(framebuffer);
4304 if (fbNode != dev_data->frameBufferMap.end()) {
4305 fbNode->second.referencingCmdBuffers.erase(pCB->commandBuffer);
4306 }
4307 }
4308 pCB->framebuffers.clear();
4309
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004310 }
4311}
4312
4313// Set PSO-related status bits for CB, including dynamic state set via PSO
4314static void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004315 // Account for any dynamic state not set via this PSO
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06004316 if (!pPipe->graphicsPipelineCI.pDynamicState ||
4317 !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) { // All state is static
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004318 pCB->status = CBSTATUS_ALL;
4319 } else {
4320 // First consider all state on
4321 // Then unset any state that's noted as dynamic in PSO
4322 // Finally OR that into CB statemask
4323 CBStatusFlags psoDynStateMask = CBSTATUS_ALL;
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06004324 for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
4325 switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004326 case VK_DYNAMIC_STATE_VIEWPORT:
4327 psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET;
4328 break;
4329 case VK_DYNAMIC_STATE_SCISSOR:
4330 psoDynStateMask &= ~CBSTATUS_SCISSOR_SET;
4331 break;
4332 case VK_DYNAMIC_STATE_LINE_WIDTH:
4333 psoDynStateMask &= ~CBSTATUS_LINE_WIDTH_SET;
4334 break;
4335 case VK_DYNAMIC_STATE_DEPTH_BIAS:
4336 psoDynStateMask &= ~CBSTATUS_DEPTH_BIAS_SET;
4337 break;
4338 case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06004339 psoDynStateMask &= ~CBSTATUS_BLEND_CONSTANTS_SET;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004340 break;
4341 case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
4342 psoDynStateMask &= ~CBSTATUS_DEPTH_BOUNDS_SET;
4343 break;
4344 case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
4345 psoDynStateMask &= ~CBSTATUS_STENCIL_READ_MASK_SET;
4346 break;
4347 case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
4348 psoDynStateMask &= ~CBSTATUS_STENCIL_WRITE_MASK_SET;
4349 break;
4350 case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
4351 psoDynStateMask &= ~CBSTATUS_STENCIL_REFERENCE_SET;
4352 break;
4353 default:
4354 // TODO : Flag error here
4355 break;
4356 }
4357 }
4358 pCB->status |= psoDynStateMask;
4359 }
4360}
4361
4362// Print the last bound Gfx Pipeline
Dustin Graves8f1eab92016-04-05 09:41:17 -06004363static bool printPipeline(layer_data *my_data, const VkCommandBuffer cb) {
4364 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004365 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb);
4366 if (pCB) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004367 PIPELINE_NODE *pPipeTrav = getPipeline(my_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004368 if (!pPipeTrav) {
4369 // nothing to print
4370 } else {
4371 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
4372 __LINE__, DRAWSTATE_NONE, "DS", "%s",
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06004373 vk_print_vkgraphicspipelinecreateinfo(
4374 reinterpret_cast<const VkGraphicsPipelineCreateInfo *>(&pPipeTrav->graphicsPipelineCI), "{DS}")
4375 .c_str());
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004376 }
4377 }
4378 return skipCall;
4379}
4380
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004381static void printCB(layer_data *my_data, const VkCommandBuffer cb) {
4382 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cb);
4383 if (pCB && pCB->cmds.size() > 0) {
4384 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
4385 DRAWSTATE_NONE, "DS", "Cmds in CB %p", (void *)cb);
4386 vector<CMD_NODE> cmds = pCB->cmds;
4387 for (auto ii = cmds.begin(); ii != cmds.end(); ++ii) {
4388 // TODO : Need to pass cb as srcObj here
4389 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4390 __LINE__, DRAWSTATE_NONE, "DS", " CMD#%" PRIu64 ": %s", (*ii).cmdNumber, cmdTypeToString((*ii).type).c_str());
4391 }
4392 } else {
4393 // Nothing to print
4394 }
4395}
4396
Dustin Graves8f1eab92016-04-05 09:41:17 -06004397static bool synchAndPrintDSConfig(layer_data *my_data, const VkCommandBuffer cb) {
4398 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004399 if (!(my_data->report_data->active_flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) {
4400 return skipCall;
4401 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004402 skipCall |= printPipeline(my_data, cb);
4403 return skipCall;
4404}
4405
4406// Flags validation error if the associated call is made inside a render pass. The apiName
4407// routine should ONLY be called outside a render pass.
Dustin Graves8f1eab92016-04-05 09:41:17 -06004408static bool insideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) {
4409 bool inside = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004410 if (pCB->activeRenderPass) {
4411 inside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4412 (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
4413 "%s: It is invalid to issue this call inside an active render pass (%#" PRIxLEAST64 ")", apiName,
4414 (uint64_t)pCB->activeRenderPass);
4415 }
4416 return inside;
4417}
4418
4419// Flags validation error if the associated call is made outside a render pass. The apiName
4420// routine should ONLY be called inside a render pass.
Dustin Graves8f1eab92016-04-05 09:41:17 -06004421static bool outsideRenderPass(const layer_data *my_data, GLOBAL_CB_NODE *pCB, const char *apiName) {
4422 bool outside = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004423 if (((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) && (!pCB->activeRenderPass)) ||
4424 ((pCB->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) && (!pCB->activeRenderPass) &&
4425 !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT))) {
4426 outside = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4427 (uint64_t)pCB->commandBuffer, __LINE__, DRAWSTATE_NO_ACTIVE_RENDERPASS, "DS",
4428 "%s: This call must be issued inside an active render pass.", apiName);
4429 }
4430 return outside;
4431}
4432
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004433static void init_core_validation(layer_data *instance_data, const VkAllocationCallbacks *pAllocator) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004434
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004435 layer_debug_actions(instance_data->report_data, instance_data->logging_callback, pAllocator, "lunarg_core_validation");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004436
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004437}
4438
4439VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4440vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
4441 VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
4442
4443 assert(chain_info->u.pLayerInfo);
4444 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
4445 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
4446 if (fpCreateInstance == NULL)
4447 return VK_ERROR_INITIALIZATION_FAILED;
4448
4449 // Advance the link info for the next element on the chain
4450 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
4451
4452 VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
4453 if (result != VK_SUCCESS)
4454 return result;
4455
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004456 layer_data *instance_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
4457 instance_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
4458 layer_init_instance_dispatch_table(*pInstance, instance_data->instance_dispatch_table, fpGetInstanceProcAddr);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004459
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004460 instance_data->report_data =
4461 debug_report_create_instance(instance_data->instance_dispatch_table, *pInstance, pCreateInfo->enabledExtensionCount,
4462 pCreateInfo->ppEnabledExtensionNames);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004463
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004464 init_core_validation(instance_data, pAllocator);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004465
4466 ValidateLayerOrdering(*pCreateInfo);
4467
4468 return result;
4469}
4470
4471/* hook DestroyInstance to remove tableInstanceMap entry */
4472VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
4473 // TODOSC : Shouldn't need any customization here
4474 dispatch_key key = get_dispatch_key(instance);
4475 // TBD: Need any locking this early, in case this function is called at the
4476 // same time by more than one thread?
4477 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
4478 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
4479 pTable->DestroyInstance(instance, pAllocator);
4480
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004481 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004482 // Clean up logging callback, if any
4483 while (my_data->logging_callback.size() > 0) {
4484 VkDebugReportCallbackEXT callback = my_data->logging_callback.back();
4485 layer_destroy_msg_callback(my_data->report_data, callback, pAllocator);
4486 my_data->logging_callback.pop_back();
4487 }
4488
4489 layer_debug_report_destroy_instance(my_data->report_data);
4490 delete my_data->instance_dispatch_table;
4491 layer_data_map.erase(key);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004492}
4493
4494static void createDeviceRegisterExtensions(const VkDeviceCreateInfo *pCreateInfo, VkDevice device) {
4495 uint32_t i;
4496 // TBD: Need any locking, in case this function is called at the same time
4497 // by more than one thread?
4498 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
4499 dev_data->device_extensions.wsi_enabled = false;
4500
4501 VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table;
4502 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
4503 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)gpa(device, "vkCreateSwapchainKHR");
4504 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)gpa(device, "vkDestroySwapchainKHR");
4505 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)gpa(device, "vkGetSwapchainImagesKHR");
4506 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)gpa(device, "vkAcquireNextImageKHR");
4507 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR)gpa(device, "vkQueuePresentKHR");
4508
4509 for (i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4510 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
4511 dev_data->device_extensions.wsi_enabled = true;
4512 }
4513}
4514
4515VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
4516 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
4517 VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
4518
4519 assert(chain_info->u.pLayerInfo);
4520 PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
4521 PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
4522 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
4523 if (fpCreateDevice == NULL) {
4524 return VK_ERROR_INITIALIZATION_FAILED;
4525 }
4526
4527 // Advance the link info for the next element on the chain
4528 chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
4529
4530 VkResult result = fpCreateDevice(gpu, pCreateInfo, pAllocator, pDevice);
4531 if (result != VK_SUCCESS) {
4532 return result;
4533 }
4534
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004535 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004536 layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map);
4537 layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map);
4538
4539 // Setup device dispatch table
4540 my_device_data->device_dispatch_table = new VkLayerDispatchTable;
4541 layer_init_device_dispatch_table(*pDevice, my_device_data->device_dispatch_table, fpGetDeviceProcAddr);
Chris Forbes15864502016-03-30 11:35:21 +13004542 my_device_data->device = *pDevice;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004543
4544 my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice);
4545 createDeviceRegisterExtensions(pCreateInfo, *pDevice);
4546 // Get physical device limits for this device
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004547 my_instance_data->instance_dispatch_table->GetPhysicalDeviceProperties(gpu, &(my_device_data->phys_dev_properties.properties));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004548 uint32_t count;
4549 my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004550 my_device_data->phys_dev_properties.queue_family_properties.resize(count);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004551 my_instance_data->instance_dispatch_table->GetPhysicalDeviceQueueFamilyProperties(
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004552 gpu, &count, &my_device_data->phys_dev_properties.queue_family_properties[0]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004553 // TODO: device limits should make sure these are compatible
4554 if (pCreateInfo->pEnabledFeatures) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004555 my_device_data->phys_dev_properties.features = *pCreateInfo->pEnabledFeatures;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004556 } else {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004557 memset(&my_device_data->phys_dev_properties.features, 0, sizeof(VkPhysicalDeviceFeatures));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004558 }
Tobin Ehlise54be7b2016-04-11 14:49:55 -06004559 // Store physical device mem limits into device layer_data struct
4560 my_instance_data->instance_dispatch_table->GetPhysicalDeviceMemoryProperties(gpu, &my_device_data->phys_dev_mem_props);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004561 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004562
4563 ValidateLayerOrdering(*pCreateInfo);
4564
4565 return result;
4566}
4567
4568// prototype
4569static void deleteRenderPasses(layer_data *);
4570VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
4571 // TODOSC : Shouldn't need any customization here
4572 dispatch_key key = get_dispatch_key(device);
4573 layer_data *dev_data = get_my_data_ptr(key, layer_data_map);
4574 // Free all the memory
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004575 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004576 deletePipelines(dev_data);
4577 deleteRenderPasses(dev_data);
4578 deleteCommandBuffers(dev_data);
4579 deletePools(dev_data);
Tobin Ehlis546326f2016-04-26 11:06:05 -06004580 for (auto del_layout : dev_data->descriptorSetLayoutMap) {
4581 delete del_layout.second;
4582 }
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06004583 dev_data->descriptorSetLayoutMap.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004584 dev_data->imageViewMap.clear();
4585 dev_data->imageMap.clear();
4586 dev_data->imageSubresourceMap.clear();
4587 dev_data->imageLayoutMap.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004588 dev_data->bufferViewMap.clear();
4589 dev_data->bufferMap.clear();
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06004590 // Queues persist until device is destroyed
4591 dev_data->queueMap.clear();
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004592 lock.unlock();
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06004593#if MTMERGESOURCE
Dustin Graves8f1eab92016-04-05 09:41:17 -06004594 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004595 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004596 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4597 (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "Printing List details prior to vkDestroyDevice()");
4598 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
4599 (uint64_t)device, __LINE__, MEMTRACK_NONE, "MEM", "================================================");
Chris Forbes73b82b12016-04-06 15:16:26 +12004600 print_mem_list(dev_data);
4601 printCBList(dev_data);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004602 // Report any memory leaks
Tobin Ehlisb3593a42016-03-16 16:00:36 -06004603 DEVICE_MEM_INFO *pInfo = NULL;
Tobin Ehlis4c522322016-04-11 16:39:29 -06004604 if (!dev_data->memObjMap.empty()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004605 for (auto ii = dev_data->memObjMap.begin(); ii != dev_data->memObjMap.end(); ++ii) {
4606 pInfo = &(*ii).second;
4607 if (pInfo->allocInfo.allocationSize != 0) {
4608 // Valid Usage: All child objects created on device must have been destroyed prior to destroying device
4609 skipCall |=
4610 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4611 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pInfo->mem, __LINE__, MEMTRACK_MEMORY_LEAK,
4612 "MEM", "Mem Object %" PRIu64 " has not been freed. You should clean up this memory by calling "
4613 "vkFreeMemory(%" PRIu64 ") prior to vkDestroyDevice().",
4614 (uint64_t)(pInfo->mem), (uint64_t)(pInfo->mem));
4615 }
4616 }
4617 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004618 layer_debug_report_destroy_device(device);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06004619 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004620
4621#if DISPATCH_MAP_DEBUG
4622 fprintf(stderr, "Device: %p, key: %p\n", device, key);
4623#endif
4624 VkLayerDispatchTable *pDisp = dev_data->device_dispatch_table;
Dustin Graves8f1eab92016-04-05 09:41:17 -06004625 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004626 pDisp->DestroyDevice(device, pAllocator);
4627 }
4628#else
4629 dev_data->device_dispatch_table->DestroyDevice(device, pAllocator);
4630#endif
4631 delete dev_data->device_dispatch_table;
4632 layer_data_map.erase(key);
4633}
4634
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004635static const VkExtensionProperties instance_extensions[] = {{VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION}};
4636
4637VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4638vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties) {
4639 return util_GetExtensionProperties(1, instance_extensions, pCount, pProperties);
4640}
4641
4642VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4643vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties) {
4644 return util_GetLayerProperties(ARRAY_SIZE(cv_global_layers), cv_global_layers, pCount, pProperties);
4645}
4646
4647// TODO: Why does this exist - can we just use global?
4648static const VkLayerProperties cv_device_layers[] = {{
Jon Ashburndc9111c2016-03-22 12:57:13 -06004649 "VK_LAYER_LUNARG_core_validation", VK_LAYER_API_VERSION, 1, "LunarG Validation Layer",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004650}};
4651
4652VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
4653 const char *pLayerName, uint32_t *pCount,
4654 VkExtensionProperties *pProperties) {
4655 if (pLayerName == NULL) {
4656 dispatch_key key = get_dispatch_key(physicalDevice);
4657 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
4658 return my_data->instance_dispatch_table->EnumerateDeviceExtensionProperties(physicalDevice, NULL, pCount, pProperties);
4659 } else {
4660 return util_GetExtensionProperties(0, NULL, pCount, pProperties);
4661 }
4662}
4663
4664VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
4665vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties) {
4666 /* draw_state physical device layers are the same as global */
4667 return util_GetLayerProperties(ARRAY_SIZE(cv_device_layers), cv_device_layers, pCount, pProperties);
4668}
4669
4670// This validates that the initial layout specified in the command buffer for
4671// the IMAGE is the same
4672// as the global IMAGE layout
Dustin Graves8f1eab92016-04-05 09:41:17 -06004673static bool ValidateCmdBufImageLayouts(VkCommandBuffer cmdBuffer) {
4674 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004675 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
4676 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
4677 for (auto cb_image_data : pCB->imageLayoutMap) {
4678 VkImageLayout imageLayout;
4679 if (!FindLayout(dev_data, cb_image_data.first, imageLayout)) {
4680 skip_call |=
4681 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
4682 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot submit cmd buffer using deleted image %" PRIu64 ".",
4683 reinterpret_cast<const uint64_t &>(cb_image_data.first));
4684 } else {
4685 if (cb_image_data.second.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
4686 // TODO: Set memory invalid which is in mem_tracker currently
4687 } else if (imageLayout != cb_image_data.second.initialLayout) {
Mark Young000d14d2016-04-11 16:53:53 -06004688 if (cb_image_data.first.hasSubresource) {
4689 skip_call |= log_msg(
4690 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4691 reinterpret_cast<uint64_t &>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
4692 "Cannot submit cmd buffer using image (%" PRIx64 ") [sub-resource: array layer %u, mip level %u], "
4693 "with layout %s when first use is %s.",
4694 reinterpret_cast<const uint64_t &>(cb_image_data.first.image), cb_image_data.first.subresource.arrayLayer,
4695 cb_image_data.first.subresource.mipLevel, string_VkImageLayout(imageLayout),
4696 string_VkImageLayout(cb_image_data.second.initialLayout));
4697 } else {
4698 skip_call |= log_msg(
4699 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4700 reinterpret_cast<uint64_t &>(cmdBuffer), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
4701 "Cannot submit cmd buffer using image (%" PRIx64 ") with layout %s when "
4702 "first use is %s.",
4703 reinterpret_cast<const uint64_t &>(cb_image_data.first.image), string_VkImageLayout(imageLayout),
4704 string_VkImageLayout(cb_image_data.second.initialLayout));
4705 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004706 }
4707 SetLayout(dev_data, cb_image_data.first, cb_image_data.second.layout);
4708 }
4709 }
4710 return skip_call;
4711}
Mark Lobodzinskif7422d92016-03-25 15:22:33 -06004712
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004713// Track which resources are in-flight by atomically incrementing their "in_use" count
Dustin Graves8f1eab92016-04-05 09:41:17 -06004714static bool validateAndIncrementResources(layer_data *my_data, GLOBAL_CB_NODE *pCB) {
4715 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004716 for (auto drawDataElement : pCB->drawData) {
4717 for (auto buffer : drawDataElement.buffers) {
4718 auto buffer_data = my_data->bufferMap.find(buffer);
4719 if (buffer_data == my_data->bufferMap.end()) {
4720 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4721 (uint64_t)(buffer), __LINE__, DRAWSTATE_INVALID_BUFFER, "DS",
4722 "Cannot submit cmd buffer using deleted buffer %" PRIu64 ".", (uint64_t)(buffer));
4723 } else {
4724 buffer_data->second.in_use.fetch_add(1);
4725 }
4726 }
4727 }
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004728 for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
4729 for (auto set : pCB->lastBound[i].uniqueBoundSets) {
4730 auto setNode = my_data->setMap.find(set);
4731 if (setNode == my_data->setMap.end()) {
4732 skip_call |=
4733 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
4734 (uint64_t)(set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
4735 "Cannot submit cmd buffer using deleted descriptor set %" PRIu64 ".", (uint64_t)(set));
4736 } else {
4737 setNode->second->in_use.fetch_add(1);
4738 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004739 }
4740 }
4741 for (auto semaphore : pCB->semaphores) {
4742 auto semaphoreNode = my_data->semaphoreMap.find(semaphore);
4743 if (semaphoreNode == my_data->semaphoreMap.end()) {
4744 skip_call |=
4745 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
4746 reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS",
4747 "Cannot submit cmd buffer using deleted semaphore %" PRIu64 ".", reinterpret_cast<uint64_t &>(semaphore));
4748 } else {
4749 semaphoreNode->second.in_use.fetch_add(1);
4750 }
4751 }
4752 for (auto event : pCB->events) {
4753 auto eventNode = my_data->eventMap.find(event);
4754 if (eventNode == my_data->eventMap.end()) {
4755 skip_call |=
4756 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
4757 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
4758 "Cannot submit cmd buffer using deleted event %" PRIu64 ".", reinterpret_cast<uint64_t &>(event));
4759 } else {
4760 eventNode->second.in_use.fetch_add(1);
4761 }
4762 }
4763 return skip_call;
4764}
4765
Michael Lentinefebf20b2016-04-20 23:01:26 -05004766// Note: This function assumes that the global lock is held by the calling
4767// thread.
4768static bool cleanInFlightCmdBuffer(layer_data *my_data, VkCommandBuffer cmdBuffer) {
4769 bool skip_call = false;
4770 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer);
4771 if (pCB) {
4772 for (auto queryEventsPair : pCB->waitedEventsBeforeQueryReset) {
4773 for (auto event : queryEventsPair.second) {
4774 if (my_data->eventMap[event].needsSignaled) {
4775 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4776 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS",
4777 "Cannot get query results on queryPool %" PRIu64
4778 " with index %d which was guarded by unsignaled event %" PRIu64 ".",
4779 (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event));
4780 }
4781 }
4782 }
4783 }
4784 return skip_call;
4785}
4786// Decrement cmd_buffer in_use and if it goes to 0 remove cmd_buffer from globalInFlightCmdBuffers
4787static inline void removeInFlightCmdBuffer(layer_data *dev_data, VkCommandBuffer cmd_buffer) {
4788 // Pull it off of global list initially, but if we find it in any other queue list, add it back in
4789 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmd_buffer);
4790 pCB->in_use.fetch_sub(1);
4791 if (!pCB->in_use.load()) {
4792 dev_data->globalInFlightCmdBuffers.erase(cmd_buffer);
4793 }
4794}
4795
Dustin Graves8f1eab92016-04-05 09:41:17 -06004796static void decrementResources(layer_data *my_data, VkCommandBuffer cmdBuffer) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004797 GLOBAL_CB_NODE *pCB = getCBNode(my_data, cmdBuffer);
4798 for (auto drawDataElement : pCB->drawData) {
4799 for (auto buffer : drawDataElement.buffers) {
4800 auto buffer_data = my_data->bufferMap.find(buffer);
4801 if (buffer_data != my_data->bufferMap.end()) {
4802 buffer_data->second.in_use.fetch_sub(1);
4803 }
4804 }
4805 }
Tobin Ehlis223b01e2016-03-21 14:14:44 -06004806 for (uint32_t i = 0; i < VK_PIPELINE_BIND_POINT_RANGE_SIZE; ++i) {
4807 for (auto set : pCB->lastBound[i].uniqueBoundSets) {
4808 auto setNode = my_data->setMap.find(set);
4809 if (setNode != my_data->setMap.end()) {
4810 setNode->second->in_use.fetch_sub(1);
4811 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004812 }
4813 }
4814 for (auto semaphore : pCB->semaphores) {
4815 auto semaphoreNode = my_data->semaphoreMap.find(semaphore);
4816 if (semaphoreNode != my_data->semaphoreMap.end()) {
4817 semaphoreNode->second.in_use.fetch_sub(1);
4818 }
4819 }
4820 for (auto event : pCB->events) {
4821 auto eventNode = my_data->eventMap.find(event);
4822 if (eventNode != my_data->eventMap.end()) {
4823 eventNode->second.in_use.fetch_sub(1);
4824 }
4825 }
4826 for (auto queryStatePair : pCB->queryToStateMap) {
4827 my_data->queryToStateMap[queryStatePair.first] = queryStatePair.second;
4828 }
4829 for (auto eventStagePair : pCB->eventToStageMap) {
4830 my_data->eventMap[eventStagePair.first].stageMask = eventStagePair.second;
4831 }
4832}
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06004833// For fenceCount fences in pFences, mark fence signaled, decrement in_use, and call
4834// decrementResources for all priorFences and cmdBuffers associated with fence.
Michael Lentinefebf20b2016-04-20 23:01:26 -05004835static bool decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence *pFences) {
4836 bool skip_call = false;
Michael Lentineb48e1412016-04-29 18:37:32 -05004837 std::vector<VkFence> fences;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004838 for (uint32_t i = 0; i < fenceCount; ++i) {
4839 auto fence_data = my_data->fenceMap.find(pFences[i]);
4840 if (fence_data == my_data->fenceMap.end() || !fence_data->second.needsSignaled)
Michael Lentinefebf20b2016-04-20 23:01:26 -05004841 return skip_call;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004842 fence_data->second.needsSignaled = false;
Michael Lentineb48e1412016-04-29 18:37:32 -05004843 if (fence_data->second.in_use.load()) {
4844 fences.push_back(pFences[i]);
4845 fence_data->second.in_use.fetch_sub(1);
4846 }
Jamie Madill2b6b8d52016-04-04 15:09:51 -04004847 decrementResources(my_data, static_cast<uint32_t>(fence_data->second.priorFences.size()),
4848 fence_data->second.priorFences.data());
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004849 for (auto cmdBuffer : fence_data->second.cmdBuffers) {
4850 decrementResources(my_data, cmdBuffer);
Michael Lentinefebf20b2016-04-20 23:01:26 -05004851 skip_call |= cleanInFlightCmdBuffer(my_data, cmdBuffer);
4852 removeInFlightCmdBuffer(my_data, cmdBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004853 }
4854 }
Michael Lentineb48e1412016-04-29 18:37:32 -05004855 for (auto fence : fences) {
4856 for (auto queue_data : my_data->queueMap) {
4857 auto last_fence_data = std::find(queue_data.second.lastFences.begin(), queue_data.second.lastFences.end(), fence);
4858 if (last_fence_data != queue_data.second.lastFences.end()) {
4859 queue_data.second.lastFences.erase(last_fence_data);
4860 break;
4861 }
4862 }
4863 }
Michael Lentinefebf20b2016-04-20 23:01:26 -05004864 return skip_call;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004865}
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06004866// Decrement in_use for all outstanding cmd buffers that were submitted on this queue
Michael Lentinefebf20b2016-04-20 23:01:26 -05004867static bool decrementResources(layer_data *my_data, VkQueue queue) {
4868 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004869 auto queue_data = my_data->queueMap.find(queue);
4870 if (queue_data != my_data->queueMap.end()) {
4871 for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) {
4872 decrementResources(my_data, cmdBuffer);
Michael Lentinefebf20b2016-04-20 23:01:26 -05004873 skip_call |= cleanInFlightCmdBuffer(my_data, cmdBuffer);
4874 removeInFlightCmdBuffer(my_data, cmdBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004875 }
4876 queue_data->second.untrackedCmdBuffers.clear();
Michael Lentinefebf20b2016-04-20 23:01:26 -05004877 skip_call |= decrementResources(my_data, static_cast<uint32_t>(queue_data->second.lastFences.size()),
4878 queue_data->second.lastFences.data());
Michael Lentined4f382b2016-03-17 16:34:32 -05004879 }
Michael Lentinefebf20b2016-04-20 23:01:26 -05004880 return skip_call;
Michael Lentined4f382b2016-03-17 16:34:32 -05004881}
4882
Michael Lentinefebf20b2016-04-20 23:01:26 -05004883// This function merges command buffer tracking between queues when there is a semaphore dependency
4884// between them (see below for details as to how tracking works). When this happens, the prior
4885// fences from the signaling queue are merged into the wait queue as well as any untracked command
4886// buffers.
Dustin Graves8f1eab92016-04-05 09:41:17 -06004887static void updateTrackedCommandBuffers(layer_data *dev_data, VkQueue queue, VkQueue other_queue, VkFence fence) {
Michael Lentined4f382b2016-03-17 16:34:32 -05004888 if (queue == other_queue) {
4889 return;
4890 }
4891 auto queue_data = dev_data->queueMap.find(queue);
4892 auto other_queue_data = dev_data->queueMap.find(other_queue);
4893 if (queue_data == dev_data->queueMap.end() || other_queue_data == dev_data->queueMap.end()) {
4894 return;
4895 }
Jamie Madill9be81ff2016-04-04 14:39:53 -04004896 for (auto fenceInner : other_queue_data->second.lastFences) {
4897 queue_data->second.lastFences.push_back(fenceInner);
Michael Lentined4f382b2016-03-17 16:34:32 -05004898 }
4899 if (fence != VK_NULL_HANDLE) {
4900 auto fence_data = dev_data->fenceMap.find(fence);
4901 if (fence_data == dev_data->fenceMap.end()) {
4902 return;
4903 }
4904 for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) {
4905 fence_data->second.cmdBuffers.push_back(cmdbuffer);
4906 }
4907 other_queue_data->second.untrackedCmdBuffers.clear();
4908 } else {
4909 for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) {
4910 queue_data->second.untrackedCmdBuffers.push_back(cmdbuffer);
4911 }
4912 other_queue_data->second.untrackedCmdBuffers.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004913 }
Michael Lentineb653eb22016-03-18 14:11:44 -05004914 for (auto eventStagePair : other_queue_data->second.eventToStageMap) {
4915 queue_data->second.eventToStageMap[eventStagePair.first] = eventStagePair.second;
4916 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004917}
4918
Michael Lentinefebf20b2016-04-20 23:01:26 -05004919// This is the core function for tracking command buffers. There are two primary ways command
4920// buffers are tracked. When submitted they are stored in the command buffer list associated
4921// with a fence or the untracked command buffer list associated with a queue if no fence is used.
4922// Each queue also stores the last fence that was submitted onto the queue. This allows us to
4923// create a linked list of fences and their associated command buffers so if one fence is
4924// waited on, prior fences on that queue are also considered to have been waited on. When a fence is
4925// waited on (either via a queue, device or fence), we free the cmd buffers for that fence and
4926// recursively call with the prior fences.
Dustin Graves8f1eab92016-04-05 09:41:17 -06004927static void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
4928 VkFence fence) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004929 auto queue_data = my_data->queueMap.find(queue);
4930 if (fence != VK_NULL_HANDLE) {
Michael Lentined4f382b2016-03-17 16:34:32 -05004931 vector<VkFence> prior_fences;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004932 auto fence_data = my_data->fenceMap.find(fence);
4933 if (fence_data == my_data->fenceMap.end()) {
4934 return;
4935 }
Michael Lentine11fe3772016-04-20 11:39:50 -05004936 fence_data->second.cmdBuffers.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004937 if (queue_data != my_data->queueMap.end()) {
Michael Lentined4f382b2016-03-17 16:34:32 -05004938 prior_fences = queue_data->second.lastFences;
4939 queue_data->second.lastFences.clear();
4940 queue_data->second.lastFences.push_back(fence);
4941 for (auto cmdbuffer : queue_data->second.untrackedCmdBuffers) {
4942 fence_data->second.cmdBuffers.push_back(cmdbuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004943 }
4944 queue_data->second.untrackedCmdBuffers.clear();
4945 }
Michael Lentined4f382b2016-03-17 16:34:32 -05004946 fence_data->second.priorFences = prior_fences;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004947 fence_data->second.needsSignaled = true;
4948 fence_data->second.queue = queue;
4949 fence_data->second.in_use.fetch_add(1);
4950 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
4951 const VkSubmitInfo *submit = &pSubmits[submit_idx];
4952 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
4953 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
4954 fence_data->second.cmdBuffers.push_back(secondaryCmdBuffer);
4955 }
4956 fence_data->second.cmdBuffers.push_back(submit->pCommandBuffers[i]);
4957 }
4958 }
4959 } else {
4960 if (queue_data != my_data->queueMap.end()) {
4961 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
4962 const VkSubmitInfo *submit = &pSubmits[submit_idx];
4963 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
4964 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
4965 queue_data->second.untrackedCmdBuffers.push_back(secondaryCmdBuffer);
4966 }
4967 queue_data->second.untrackedCmdBuffers.push_back(submit->pCommandBuffers[i]);
4968 }
4969 }
4970 }
4971 }
Michael Lentinefebf20b2016-04-20 23:01:26 -05004972}
4973
4974static void markCommandBuffersInFlight(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits,
4975 VkFence fence) {
4976 auto queue_data = my_data->queueMap.find(queue);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004977 if (queue_data != my_data->queueMap.end()) {
4978 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
4979 const VkSubmitInfo *submit = &pSubmits[submit_idx];
4980 for (uint32_t i = 0; i < submit->commandBufferCount; ++i) {
Michael Lentinefebf20b2016-04-20 23:01:26 -05004981 // Add cmdBuffers to the global set and increment count
4982 GLOBAL_CB_NODE *pCB = getCBNode(my_data, submit->pCommandBuffers[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004983 for (auto secondaryCmdBuffer : my_data->commandBufferMap[submit->pCommandBuffers[i]]->secondaryCommandBuffers) {
4984 my_data->globalInFlightCmdBuffers.insert(secondaryCmdBuffer);
Michael Lentinefebf20b2016-04-20 23:01:26 -05004985 GLOBAL_CB_NODE *pSubCB = getCBNode(my_data, secondaryCmdBuffer);
4986 pSubCB->in_use.fetch_add(1);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004987 }
4988 my_data->globalInFlightCmdBuffers.insert(submit->pCommandBuffers[i]);
Michael Lentinefebf20b2016-04-20 23:01:26 -05004989 pCB->in_use.fetch_add(1);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004990 }
4991 }
4992 }
4993}
4994
Dustin Graves8f1eab92016-04-05 09:41:17 -06004995static bool validateCommandBufferSimultaneousUse(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07004996 bool skip_call = false;
4997 if (dev_data->globalInFlightCmdBuffers.count(pCB->commandBuffer) &&
4998 !(pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
4999 skip_call |=
5000 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
Chris Forbes0fa92212016-03-31 11:47:29 +13005001 __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
5002 "Command Buffer %#" PRIx64 " is already in use and is not marked for simultaneous use.",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005003 reinterpret_cast<uint64_t>(pCB->commandBuffer));
5004 }
5005 return skip_call;
5006}
5007
5008static bool validateCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
5009 bool skipCall = false;
Tobin Ehlise5184af2016-04-14 15:44:20 -06005010 // Validate ONE_TIME_SUBMIT_BIT CB is not being submitted more than once
5011 if ((pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) && (pCB->submitCount > 1)) {
5012 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
5013 __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
5014 "CB %#" PRIxLEAST64 " was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT "
5015 "set, but has been submitted %#" PRIxLEAST64 " times.",
5016 (uint64_t)(pCB->commandBuffer), pCB->submitCount);
5017 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005018 // Validate that cmd buffers have been updated
5019 if (CB_RECORDED != pCB->state) {
5020 if (CB_INVALID == pCB->state) {
5021 // Inform app of reason CB invalid
5022 bool causeReported = false;
5023 if (!pCB->destroyedSets.empty()) {
5024 std::stringstream set_string;
5025 for (auto set : pCB->destroyedSets)
5026 set_string << " " << set;
5027
5028 skipCall |=
5029 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5030 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5031 "You are submitting command buffer %#" PRIxLEAST64
5032 " that is invalid because it had the following bound descriptor set(s) destroyed: %s",
5033 (uint64_t)(pCB->commandBuffer), set_string.str().c_str());
5034 causeReported = true;
5035 }
5036 if (!pCB->updatedSets.empty()) {
5037 std::stringstream set_string;
5038 for (auto set : pCB->updatedSets)
5039 set_string << " " << set;
5040
5041 skipCall |=
5042 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5043 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5044 "You are submitting command buffer %#" PRIxLEAST64
5045 " that is invalid because it had the following bound descriptor set(s) updated: %s",
5046 (uint64_t)(pCB->commandBuffer), set_string.str().c_str());
5047 causeReported = true;
5048 }
5049 if (!pCB->destroyedFramebuffers.empty()) {
5050 std::stringstream fb_string;
5051 for (auto fb : pCB->destroyedFramebuffers)
5052 fb_string << " " << fb;
5053
5054 skipCall |=
5055 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5056 reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5057 "You are submitting command buffer %#" PRIxLEAST64 " that is invalid because it had the following "
5058 "referenced framebuffers destroyed: %s",
5059 reinterpret_cast<uint64_t &>(pCB->commandBuffer), fb_string.str().c_str());
5060 causeReported = true;
5061 }
5062 // TODO : This is defensive programming to make sure an error is
5063 // flagged if we hit this INVALID cmd buffer case and none of the
5064 // above cases are hit. As the number of INVALID cases grows, this
5065 // code should be updated to seemlessly handle all the cases.
5066 if (!causeReported) {
5067 skipCall |= log_msg(
5068 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5069 reinterpret_cast<uint64_t &>(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
5070 "You are submitting command buffer %#" PRIxLEAST64 " that is invalid due to an unknown cause. Validation "
5071 "should "
5072 "be improved to report the exact cause.",
5073 reinterpret_cast<uint64_t &>(pCB->commandBuffer));
5074 }
5075 } else { // Flag error for using CB w/o vkEndCommandBuffer() called
5076 skipCall |=
5077 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5078 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_NO_END_COMMAND_BUFFER, "DS",
5079 "You must call vkEndCommandBuffer() on CB %#" PRIxLEAST64 " before this call to vkQueueSubmit()!",
5080 (uint64_t)(pCB->commandBuffer));
5081 }
5082 }
5083 return skipCall;
5084}
5085
Dustin Graves8f1eab92016-04-05 09:41:17 -06005086static bool validatePrimaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005087 // Track in-use for resources off of primary and any secondary CBs
Dustin Graves8f1eab92016-04-05 09:41:17 -06005088 bool skipCall = validateAndIncrementResources(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005089 if (!pCB->secondaryCommandBuffers.empty()) {
5090 for (auto secondaryCmdBuffer : pCB->secondaryCommandBuffers) {
5091 skipCall |= validateAndIncrementResources(dev_data, dev_data->commandBufferMap[secondaryCmdBuffer]);
5092 GLOBAL_CB_NODE *pSubCB = getCBNode(dev_data, secondaryCmdBuffer);
5093 if (pSubCB->primaryCommandBuffer != pCB->commandBuffer) {
5094 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
5095 __LINE__, DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, "DS",
5096 "CB %#" PRIxLEAST64 " was submitted with secondary buffer %#" PRIxLEAST64
5097 " but that buffer has subsequently been bound to "
5098 "primary cmd buffer %#" PRIxLEAST64 ".",
5099 reinterpret_cast<uint64_t>(pCB->commandBuffer), reinterpret_cast<uint64_t>(secondaryCmdBuffer),
5100 reinterpret_cast<uint64_t>(pSubCB->primaryCommandBuffer));
5101 }
5102 }
5103 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005104 skipCall |= validateCommandBufferState(dev_data, pCB);
5105 // If USAGE_SIMULTANEOUS_USE_BIT not set then CB cannot already be executing
5106 // on device
5107 skipCall |= validateCommandBufferSimultaneousUse(dev_data, pCB);
5108 return skipCall;
5109}
5110
5111VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
5112vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06005113 bool skipCall = false;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06005114 GLOBAL_CB_NODE *pCBNode = NULL;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005115 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
5116 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005117 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005118 // First verify that fence is not in use
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005119 if (fence != VK_NULL_HANDLE) {
5120 dev_data->fenceMap[fence].queue = queue;
5121 if ((submitCount != 0) && dev_data->fenceMap[fence].in_use.load()) {
5122 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5123 (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
5124 "Fence %#" PRIx64 " is already in use by another submission.", (uint64_t)(fence));
5125 }
5126 if (!dev_data->fenceMap[fence].needsSignaled) {
5127 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5128 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
5129 "Fence %#" PRIxLEAST64 " submitted in SIGNALED state. Fences must be reset before being submitted",
5130 reinterpret_cast<uint64_t &>(fence));
5131 }
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005132 }
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005133 // TODO : Review these old print functions and clean up as appropriate
Chris Forbes73b82b12016-04-06 15:16:26 +12005134 print_mem_list(dev_data);
5135 printCBList(dev_data);
Michael Lentinefebf20b2016-04-20 23:01:26 -05005136 // Update cmdBuffer-related data structs and mark fence in-use
5137 trackCommandBuffers(dev_data, queue, submitCount, pSubmits, fence);
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005138 // Now verify each individual submit
5139 std::unordered_set<VkQueue> processed_other_queues;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005140 for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) {
5141 const VkSubmitInfo *submit = &pSubmits[submit_idx];
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005142 vector<VkSemaphore> semaphoreList;
5143 for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) {
5144 const VkSemaphore &semaphore = submit->pWaitSemaphores[i];
Tobin Ehlis75e72b62016-04-13 14:36:16 -06005145 semaphoreList.push_back(semaphore);
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005146 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
5147 if (dev_data->semaphoreMap[semaphore].signaled) {
5148 dev_data->semaphoreMap[semaphore].signaled = false;
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005149 } else {
5150 skipCall |=
5151 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
5152 reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
5153 "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.",
5154 reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
5155 }
5156 const VkQueue &other_queue = dev_data->semaphoreMap[semaphore].queue;
5157 if (other_queue != VK_NULL_HANDLE && !processed_other_queues.count(other_queue)) {
5158 updateTrackedCommandBuffers(dev_data, queue, other_queue, fence);
5159 processed_other_queues.insert(other_queue);
5160 }
5161 }
5162 }
5163 for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) {
5164 const VkSemaphore &semaphore = submit->pSignalSemaphores[i];
5165 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
5166 semaphoreList.push_back(semaphore);
5167 if (dev_data->semaphoreMap[semaphore].signaled) {
5168 skipCall |=
5169 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
5170 reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
5171 "Queue %#" PRIx64 " is signaling semaphore %#" PRIx64
5172 " that has already been signaled but not waited on by queue %#" PRIx64 ".",
5173 reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore),
5174 reinterpret_cast<uint64_t &>(dev_data->semaphoreMap[semaphore].queue));
5175 } else {
5176 dev_data->semaphoreMap[semaphore].signaled = true;
5177 dev_data->semaphoreMap[semaphore].queue = queue;
5178 }
5179 }
5180 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005181 for (uint32_t i = 0; i < submit->commandBufferCount; i++) {
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005182 skipCall |= ValidateCmdBufImageLayouts(submit->pCommandBuffers[i]);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06005183 pCBNode = getCBNode(dev_data, submit->pCommandBuffers[i]);
5184 if (pCBNode) {
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005185 pCBNode->semaphores = semaphoreList;
5186 pCBNode->submitCount++; // increment submit count
Tobin Ehlis223b01e2016-03-21 14:14:44 -06005187 pCBNode->lastSubmittedFence = fence;
5188 pCBNode->lastSubmittedQueue = queue;
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005189 skipCall |= validatePrimaryCommandBufferState(dev_data, pCBNode);
5190 // Call submit-time functions to validate/update state
Tobin Ehlis223b01e2016-03-21 14:14:44 -06005191 for (auto &function : pCBNode->validate_functions) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005192 skipCall |= function();
5193 }
Michael Lentineb653eb22016-03-18 14:11:44 -05005194 for (auto &function : pCBNode->eventUpdates) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06005195 skipCall |= function(queue);
Michael Lentineb653eb22016-03-18 14:11:44 -05005196 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005197 }
5198 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005199 }
Michael Lentinefebf20b2016-04-20 23:01:26 -05005200 markCommandBuffersInFlight(dev_data, queue, submitCount, pSubmits, fence);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005201 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06005202 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005203 result = dev_data->device_dispatch_table->QueueSubmit(queue, submitCount, pSubmits, fence);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005204
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005205 return result;
5206}
5207
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06005208#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005209VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
5210 const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) {
5211 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5212 VkResult result = my_data->device_dispatch_table->AllocateMemory(device, pAllocateInfo, pAllocator, pMemory);
5213 // TODO : Track allocations and overall size here
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005214 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005215 add_mem_obj_info(my_data, device, *pMemory, pAllocateInfo);
Chris Forbes73b82b12016-04-06 15:16:26 +12005216 print_mem_list(my_data);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005217 return result;
5218}
5219
5220VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5221vkFreeMemory(VkDevice device, VkDeviceMemory mem, const VkAllocationCallbacks *pAllocator) {
5222 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005223
5224 // From spec : A memory object is freed by calling vkFreeMemory() when it is no longer needed.
5225 // Before freeing a memory object, an application must ensure the memory object is no longer
5226 // in use by the device—for example by command buffers queued for execution. The memory need
5227 // not yet be unbound from all images and buffers, but any further use of those images or
5228 // buffers (on host or device) for anything other than destroying those objects will result in
5229 // undefined behavior.
5230
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005231 std::unique_lock<std::mutex> lock(global_lock);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005232 freeMemObjInfo(my_data, device, mem, false);
Chris Forbes73b82b12016-04-06 15:16:26 +12005233 print_mem_list(my_data);
5234 printCBList(my_data);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005235 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005236 my_data->device_dispatch_table->FreeMemory(device, mem, pAllocator);
5237}
5238
Dustin Graves8f1eab92016-04-05 09:41:17 -06005239static bool validateMemRange(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
5240 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005241
5242 if (size == 0) {
5243 // TODO: a size of 0 is not listed as an invalid use in the spec, should it be?
5244 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5245 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
5246 "VkMapMemory: Attempting to map memory range of size zero");
5247 }
5248
5249 auto mem_element = my_data->memObjMap.find(mem);
5250 if (mem_element != my_data->memObjMap.end()) {
5251 // It is an application error to call VkMapMemory on an object that is already mapped
5252 if (mem_element->second.memRange.size != 0) {
5253 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5254 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
5255 "VkMapMemory: Attempting to map memory on an already-mapped object %#" PRIxLEAST64, (uint64_t)mem);
5256 }
5257
5258 // Validate that offset + size is within object's allocationSize
5259 if (size == VK_WHOLE_SIZE) {
5260 if (offset >= mem_element->second.allocInfo.allocationSize) {
5261 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5262 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
5263 "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset,
5264 mem_element->second.allocInfo.allocationSize, mem_element->second.allocInfo.allocationSize);
5265 }
5266 } else {
5267 if ((offset + size) > mem_element->second.allocInfo.allocationSize) {
5268 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5269 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP,
5270 "MEM", "Mapping Memory from %" PRIu64 " to %" PRIu64 " with total array size %" PRIu64, offset,
5271 size + offset, mem_element->second.allocInfo.allocationSize);
5272 }
5273 }
5274 }
5275 return skipCall;
5276}
5277
Dustin Graves8f1eab92016-04-05 09:41:17 -06005278static void storeMemRanges(layer_data *my_data, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005279 auto mem_element = my_data->memObjMap.find(mem);
5280 if (mem_element != my_data->memObjMap.end()) {
5281 MemRange new_range;
5282 new_range.offset = offset;
5283 new_range.size = size;
5284 mem_element->second.memRange = new_range;
5285 }
5286}
5287
Dustin Graves8f1eab92016-04-05 09:41:17 -06005288static bool deleteMemRanges(layer_data *my_data, VkDeviceMemory mem) {
5289 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005290 auto mem_element = my_data->memObjMap.find(mem);
5291 if (mem_element != my_data->memObjMap.end()) {
5292 if (!mem_element->second.memRange.size) {
5293 // Valid Usage: memory must currently be mapped
5294 skipCall = log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
5295 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
5296 "Unmapping Memory without memory being mapped: mem obj %#" PRIxLEAST64, (uint64_t)mem);
5297 }
5298 mem_element->second.memRange.size = 0;
5299 if (mem_element->second.pData) {
5300 free(mem_element->second.pData);
5301 mem_element->second.pData = 0;
5302 }
5303 }
5304 return skipCall;
5305}
5306
5307static char NoncoherentMemoryFillValue = 0xb;
5308
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005309static void initializeAndTrackMemory(layer_data *dev_data, VkDeviceMemory mem, VkDeviceSize size, void **ppData) {
5310 auto mem_element = dev_data->memObjMap.find(mem);
5311 if (mem_element != dev_data->memObjMap.end()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005312 mem_element->second.pDriverData = *ppData;
5313 uint32_t index = mem_element->second.allocInfo.memoryTypeIndex;
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005314 if (dev_data->phys_dev_mem_props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005315 mem_element->second.pData = 0;
5316 } else {
5317 if (size == VK_WHOLE_SIZE) {
5318 size = mem_element->second.allocInfo.allocationSize;
5319 }
5320 size_t convSize = (size_t)(size);
5321 mem_element->second.pData = malloc(2 * convSize);
5322 memset(mem_element->second.pData, NoncoherentMemoryFillValue, 2 * convSize);
5323 *ppData = static_cast<char *>(mem_element->second.pData) + (convSize / 2);
5324 }
5325 }
5326}
5327#endif
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005328// Verify that state for fence being waited on is appropriate. That is,
5329// a fence being waited on should not already be signalled and
5330// it should have been submitted on a queue or during acquire next image
5331static inline bool verifyWaitFenceState(VkDevice device, VkFence fence, const char *apiCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005332 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005333 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005334 auto pFenceInfo = my_data->fenceMap.find(fence);
5335 if (pFenceInfo != my_data->fenceMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06005336 if (!pFenceInfo->second.firstTimeFlag) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005337 if (!pFenceInfo->second.needsSignaled) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005338 skipCall |=
5339 log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5340 (uint64_t)fence, __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
5341 "%s specified fence %#" PRIxLEAST64 " already in SIGNALED state.", apiCall, (uint64_t)fence);
5342 }
5343 if (!pFenceInfo->second.queue && !pFenceInfo->second.swapchain) { // Checking status of unsubmitted fence
5344 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5345 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
5346 "%s called for fence %#" PRIxLEAST64 " which has not been submitted on a Queue or during "
5347 "acquire next image.",
5348 apiCall, reinterpret_cast<uint64_t &>(fence));
5349 }
5350 } else {
Dustin Graves8f1eab92016-04-05 09:41:17 -06005351 pFenceInfo->second.firstTimeFlag = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005352 }
5353 }
5354 return skipCall;
5355}
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005356
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005357VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
5358vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) {
5359 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005360 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005361 // Verify fence status of submitted fences
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005362 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005363 for (uint32_t i = 0; i < fenceCount; i++) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005364 skip_call |= verifyWaitFenceState(device, pFences[i], "vkWaitForFences");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005365 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005366 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005367 if (skip_call)
5368 return VK_ERROR_VALIDATION_FAILED_EXT;
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005369
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005370 VkResult result = dev_data->device_dispatch_table->WaitForFences(device, fenceCount, pFences, waitAll, timeout);
5371
5372 if (result == VK_SUCCESS) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005373 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005374 // When we know that all fences are complete we can clean/remove their CBs
5375 if (waitAll || fenceCount == 1) {
Michael Lentinefebf20b2016-04-20 23:01:26 -05005376 skip_call |= decrementResources(dev_data, fenceCount, pFences);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005377 }
5378 // NOTE : Alternate case not handled here is when some fences have completed. In
5379 // this case for app to guarantee which fences completed it will have to call
5380 // vkGetFenceStatus() at which point we'll clean/remove their CBs if complete.
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005381 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005382 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06005383 if (skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005384 return VK_ERROR_VALIDATION_FAILED_EXT;
5385 return result;
5386}
5387
5388VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) {
5389 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5390 bool skipCall = false;
5391 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005392 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005393 skipCall = verifyWaitFenceState(device, fence, "vkGetFenceStatus");
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005394 lock.unlock();
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005395
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005396 if (skipCall)
5397 return result;
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005398
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005399 result = dev_data->device_dispatch_table->GetFenceStatus(device, fence);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005400 bool skip_call = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005401 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005402 if (result == VK_SUCCESS) {
Michael Lentinefebf20b2016-04-20 23:01:26 -05005403 skipCall |= decrementResources(dev_data, 1, &fence);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005404 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005405 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06005406 if (skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005407 return VK_ERROR_VALIDATION_FAILED_EXT;
5408 return result;
5409}
5410
Mark Lobodzinski600e93d2016-03-29 09:49:15 -06005411VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex,
5412 VkQueue *pQueue) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005413 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5414 dev_data->device_dispatch_table->GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005415 std::lock_guard<std::mutex> lock(global_lock);
Mark Lobodzinski600e93d2016-03-29 09:49:15 -06005416
5417 // Add queue to tracking set only if it is new
5418 auto result = dev_data->queues.emplace(*pQueue);
5419 if (result.second == true) {
5420 QUEUE_NODE *pQNode = &dev_data->queueMap[*pQueue];
5421 pQNode->device = device;
Mark Lobodzinski600e93d2016-03-29 09:49:15 -06005422 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005423}
5424
5425VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue) {
5426 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005427 bool skip_call = false;
Michael Lentinefebf20b2016-04-20 23:01:26 -05005428 skip_call |= decrementResources(dev_data, queue);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005429 if (skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005430 return VK_ERROR_VALIDATION_FAILED_EXT;
5431 VkResult result = dev_data->device_dispatch_table->QueueWaitIdle(queue);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005432 return result;
5433}
5434
5435VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06005436 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005437 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005438 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005439 for (auto queue : dev_data->queues) {
Michael Lentinefebf20b2016-04-20 23:01:26 -05005440 skip_call |= decrementResources(dev_data, queue);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005441 }
5442 dev_data->globalInFlightCmdBuffers.clear();
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005443 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06005444 if (skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005445 return VK_ERROR_VALIDATION_FAILED_EXT;
5446 VkResult result = dev_data->device_dispatch_table->DeviceWaitIdle(device);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005447 return result;
5448}
5449
5450VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) {
5451 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5452 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005453 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005454 auto fence_pair = dev_data->fenceMap.find(fence);
5455 if (fence_pair != dev_data->fenceMap.end()) {
5456 if (fence_pair->second.in_use.load()) {
5457 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5458 (uint64_t)(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
5459 "Fence %#" PRIx64 " is in use by a command buffer.", (uint64_t)(fence));
5460 }
5461 dev_data->fenceMap.erase(fence_pair);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005462 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005463 lock.unlock();
Tobin Ehlis9984f1e2016-04-12 10:49:41 -06005464
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005465 if (!skipCall)
5466 dev_data->device_dispatch_table->DestroyFence(device, fence, pAllocator);
5467}
5468
5469VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5470vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) {
5471 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5472 dev_data->device_dispatch_table->DestroySemaphore(device, semaphore, pAllocator);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005473 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005474 auto item = dev_data->semaphoreMap.find(semaphore);
5475 if (item != dev_data->semaphoreMap.end()) {
5476 if (item->second.in_use.load()) {
5477 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
5478 reinterpret_cast<uint64_t &>(semaphore), __LINE__, DRAWSTATE_INVALID_SEMAPHORE, "DS",
5479 "Cannot delete semaphore %" PRIx64 " which is in use.", reinterpret_cast<uint64_t &>(semaphore));
5480 }
5481 dev_data->semaphoreMap.erase(semaphore);
5482 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005483 // TODO : Clean up any internal data structures using this obj.
5484}
5485
5486VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) {
5487 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5488 bool skip_call = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005489 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005490 auto event_data = dev_data->eventMap.find(event);
5491 if (event_data != dev_data->eventMap.end()) {
5492 if (event_data->second.in_use.load()) {
5493 skip_call |= log_msg(
5494 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
5495 reinterpret_cast<uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
5496 "Cannot delete event %" PRIx64 " which is in use by a command buffer.", reinterpret_cast<uint64_t &>(event));
5497 }
5498 dev_data->eventMap.erase(event_data);
5499 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005500 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005501 if (!skip_call)
5502 dev_data->device_dispatch_table->DestroyEvent(device, event, pAllocator);
5503 // TODO : Clean up any internal data structures using this obj.
5504}
5505
5506VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5507vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) {
5508 get_my_data_ptr(get_dispatch_key(device), layer_data_map)
5509 ->device_dispatch_table->DestroyQueryPool(device, queryPool, pAllocator);
5510 // TODO : Clean up any internal data structures using this obj.
5511}
5512
5513VKAPI_ATTR VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery,
5514 uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride,
5515 VkQueryResultFlags flags) {
5516 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5517 unordered_map<QueryObject, vector<VkCommandBuffer>> queriesInFlight;
5518 GLOBAL_CB_NODE *pCB = nullptr;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005519 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005520 for (auto cmdBuffer : dev_data->globalInFlightCmdBuffers) {
5521 pCB = getCBNode(dev_data, cmdBuffer);
5522 for (auto queryStatePair : pCB->queryToStateMap) {
5523 queriesInFlight[queryStatePair.first].push_back(cmdBuffer);
5524 }
5525 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06005526 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005527 for (uint32_t i = 0; i < queryCount; ++i) {
5528 QueryObject query = {queryPool, firstQuery + i};
5529 auto queryElement = queriesInFlight.find(query);
5530 auto queryToStateElement = dev_data->queryToStateMap.find(query);
5531 if (queryToStateElement != dev_data->queryToStateMap.end()) {
Mark Lobodzinski6a312182016-04-01 15:58:32 -06005532 // Available and in flight
5533 if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() &&
5534 queryToStateElement->second) {
5535 for (auto cmdBuffer : queryElement->second) {
5536 pCB = getCBNode(dev_data, cmdBuffer);
5537 auto queryEventElement = pCB->waitedEventsBeforeQueryReset.find(query);
5538 if (queryEventElement == pCB->waitedEventsBeforeQueryReset.end()) {
5539 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5540 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
5541 "Cannot get query results on queryPool %" PRIu64 " with index %d which is in flight.",
5542 (uint64_t)(queryPool), firstQuery + i);
5543 } else {
5544 for (auto event : queryEventElement->second) {
5545 dev_data->eventMap[event].needsSignaled = true;
5546 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005547 }
5548 }
Mark Lobodzinski6a312182016-04-01 15:58:32 -06005549 // Unavailable and in flight
5550 } else if (queryElement != queriesInFlight.end() && queryToStateElement != dev_data->queryToStateMap.end() &&
5551 !queryToStateElement->second) {
5552 // TODO : Can there be the same query in use by multiple command buffers in flight?
5553 bool make_available = false;
5554 for (auto cmdBuffer : queryElement->second) {
5555 pCB = getCBNode(dev_data, cmdBuffer);
5556 make_available |= pCB->queryToStateMap[query];
5557 }
5558 if (!(((flags & VK_QUERY_RESULT_PARTIAL_BIT) || (flags & VK_QUERY_RESULT_WAIT_BIT)) && make_available)) {
5559 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5560 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
5561 "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.",
5562 (uint64_t)(queryPool), firstQuery + i);
5563 }
5564 // Unavailable
5565 } else if (queryToStateElement != dev_data->queryToStateMap.end() && !queryToStateElement->second) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005566 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5567 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
5568 "Cannot get query results on queryPool %" PRIu64 " with index %d which is unavailable.",
5569 (uint64_t)(queryPool), firstQuery + i);
Mark Lobodzinski6a312182016-04-01 15:58:32 -06005570 // Unitialized
5571 } else if (queryToStateElement == dev_data->queryToStateMap.end()) {
5572 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
5573 VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
5574 "Cannot get query results on queryPool %" PRIu64
5575 " with index %d as data has not been collected for this index.",
5576 (uint64_t)(queryPool), firstQuery + i);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005577 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005578 }
5579 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005580 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005581 if (skip_call)
5582 return VK_ERROR_VALIDATION_FAILED_EXT;
5583 return dev_data->device_dispatch_table->GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride,
5584 flags);
5585}
5586
Dustin Graves8f1eab92016-04-05 09:41:17 -06005587static bool validateIdleBuffer(const layer_data *my_data, VkBuffer buffer) {
5588 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005589 auto buffer_data = my_data->bufferMap.find(buffer);
5590 if (buffer_data == my_data->bufferMap.end()) {
5591 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5592 (uint64_t)(buffer), __LINE__, DRAWSTATE_DOUBLE_DESTROY, "DS",
5593 "Cannot free buffer %" PRIxLEAST64 " that has not been allocated.", (uint64_t)(buffer));
5594 } else {
5595 if (buffer_data->second.in_use.load()) {
5596 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
5597 (uint64_t)(buffer), __LINE__, DRAWSTATE_OBJECT_INUSE, "DS",
5598 "Cannot free buffer %" PRIxLEAST64 " that is in use by a command buffer.", (uint64_t)(buffer));
5599 }
5600 }
5601 return skip_call;
5602}
5603
5604VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5605vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
5606 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005607 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005608 std::unique_lock<std::mutex> lock(global_lock);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005609 if (!validateIdleBuffer(dev_data, buffer) && !skipCall) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005610 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005611 dev_data->device_dispatch_table->DestroyBuffer(device, buffer, pAllocator);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005612 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005613 }
5614 dev_data->bufferMap.erase(buffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005615}
5616
5617VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5618vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) {
5619 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5620 dev_data->device_dispatch_table->DestroyBufferView(device, bufferView, pAllocator);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005621 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005622 auto item = dev_data->bufferViewMap.find(bufferView);
5623 if (item != dev_data->bufferViewMap.end()) {
5624 dev_data->bufferViewMap.erase(item);
5625 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005626}
5627
5628VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
5629 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005630 bool skipCall = false;
Dustin Graves8f1eab92016-04-05 09:41:17 -06005631 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005632 dev_data->device_dispatch_table->DestroyImage(device, image, pAllocator);
5633
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005634 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005635 const auto& entry = dev_data->imageMap.find(image);
5636 if (entry != dev_data->imageMap.end()) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005637 // Clear any memory mapping for this image
Tobin Ehlisf263ba42016-04-05 13:33:00 -06005638 auto mem_entry = dev_data->memObjMap.find(entry->second.mem);
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005639 if (mem_entry != dev_data->memObjMap.end())
5640 mem_entry->second.image = VK_NULL_HANDLE;
5641
5642 // Remove image from imageMap
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005643 dev_data->imageMap.erase(entry);
5644 }
5645 const auto& subEntry = dev_data->imageSubresourceMap.find(image);
5646 if (subEntry != dev_data->imageSubresourceMap.end()) {
5647 for (const auto& pair : subEntry->second) {
5648 dev_data->imageLayoutMap.erase(pair);
5649 }
5650 dev_data->imageSubresourceMap.erase(subEntry);
5651 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005652}
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06005653#if MTMERGESOURCE
Dustin Graves8f1eab92016-04-05 09:41:17 -06005654static bool print_memory_range_error(layer_data *dev_data, const uint64_t object_handle, const uint64_t other_handle,
5655 VkDebugReportObjectTypeEXT object_type) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005656 if (object_type == VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005657 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005658 MEMTRACK_INVALID_ALIASING, "MEM", "Buffer %" PRIx64 " is alised with image %" PRIx64, object_handle,
5659 other_handle);
5660 } else {
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005661 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, object_type, object_handle, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005662 MEMTRACK_INVALID_ALIASING, "MEM", "Image %" PRIx64 " is alised with buffer %" PRIx64, object_handle,
5663 other_handle);
5664 }
5665}
5666
Dustin Graves8f1eab92016-04-05 09:41:17 -06005667static bool validate_memory_range(layer_data *dev_data, const vector<MEMORY_RANGE> &ranges, const MEMORY_RANGE &new_range,
5668 VkDebugReportObjectTypeEXT object_type) {
5669 bool skip_call = false;
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005670
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005671 for (auto range : ranges) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005672 if ((range.end & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)) <
5673 (new_range.start & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)))
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005674 continue;
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005675 if ((range.start & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)) >
5676 (new_range.end & ~(dev_data->phys_dev_properties.properties.limits.bufferImageGranularity - 1)))
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005677 continue;
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005678 skip_call |= print_memory_range_error(dev_data, new_range.handle, range.handle, object_type);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005679 }
5680 return skip_call;
5681}
5682
Dustin Graves8f1eab92016-04-05 09:41:17 -06005683static bool validate_buffer_image_aliasing(layer_data *dev_data, uint64_t handle, VkDeviceMemory mem, VkDeviceSize memoryOffset,
5684 VkMemoryRequirements memRequirements, vector<MEMORY_RANGE> &ranges,
5685 const vector<MEMORY_RANGE> &other_ranges, VkDebugReportObjectTypeEXT object_type) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005686 MEMORY_RANGE range;
5687 range.handle = handle;
5688 range.memory = mem;
5689 range.start = memoryOffset;
5690 range.end = memoryOffset + memRequirements.size - 1;
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005691 ranges.push_back(range);
5692 return validate_memory_range(dev_data, other_ranges, range, object_type);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005693}
5694
5695VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
5696vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005697 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005698 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005699 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005700 // Track objects tied to memory
5701 uint64_t buffer_handle = (uint64_t)(buffer);
Dustin Graves8f1eab92016-04-05 09:41:17 -06005702 bool skipCall =
Tobin Ehlisf263ba42016-04-05 13:33:00 -06005703 set_mem_binding(dev_data, mem, buffer_handle, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, "vkBindBufferMemory");
5704 auto buffer_node = dev_data->bufferMap.find(buffer);
5705 if (buffer_node != dev_data->bufferMap.end()) {
5706 buffer_node->second.mem = mem;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005707 VkMemoryRequirements memRequirements;
Tobin Ehlisf263ba42016-04-05 13:33:00 -06005708 dev_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, &memRequirements);
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005709 skipCall |= validate_buffer_image_aliasing(dev_data, buffer_handle, mem, memoryOffset, memRequirements,
5710 dev_data->memObjMap[mem].bufferRanges, dev_data->memObjMap[mem].imageRanges,
5711 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
Dustin Gravesa97c3942016-03-31 18:01:37 -06005712 // Validate memory requirements alignment
5713 if (vk_safe_modulo(memoryOffset, memRequirements.alignment) != 0) {
5714 skipCall |=
5715 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0,
5716 __LINE__, DRAWSTATE_INVALID_BUFFER_MEMORY_OFFSET, "DS",
5717 "vkBindBufferMemory(): memoryOffset is %#" PRIxLEAST64 " but must be an integer multiple of the "
5718 "VkMemoryRequirements::alignment value %#" PRIxLEAST64
5719 ", returned from a call to vkGetBufferMemoryRequirements with buffer",
5720 memoryOffset, memRequirements.alignment);
5721 }
5722 // Validate device limits alignments
Tobin Ehlisf263ba42016-04-05 13:33:00 -06005723 VkBufferUsageFlags usage = dev_data->bufferMap[buffer].createInfo.usage;
Dustin Gravesa97c3942016-03-31 18:01:37 -06005724 if (usage & (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005725 if (vk_safe_modulo(memoryOffset, dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment) != 0) {
Dustin Gravesa97c3942016-03-31 18:01:37 -06005726 skipCall |=
5727 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
5728 0, __LINE__, DRAWSTATE_INVALID_TEXEL_BUFFER_OFFSET, "DS",
5729 "vkBindBufferMemory(): memoryOffset is %#" PRIxLEAST64 " but must be a multiple of "
5730 "device limit minTexelBufferOffsetAlignment %#" PRIxLEAST64,
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005731 memoryOffset, dev_data->phys_dev_properties.properties.limits.minTexelBufferOffsetAlignment);
Dustin Gravesa97c3942016-03-31 18:01:37 -06005732 }
5733 }
5734 if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005735 if (vk_safe_modulo(memoryOffset, dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) !=
5736 0) {
Dustin Gravesa97c3942016-03-31 18:01:37 -06005737 skipCall |=
5738 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
5739 0, __LINE__, DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS",
5740 "vkBindBufferMemory(): memoryOffset is %#" PRIxLEAST64 " but must be a multiple of "
5741 "device limit minUniformBufferOffsetAlignment %#" PRIxLEAST64,
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005742 memoryOffset, dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
Dustin Gravesa97c3942016-03-31 18:01:37 -06005743 }
5744 }
5745 if (usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005746 if (vk_safe_modulo(memoryOffset, dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) !=
5747 0) {
Dustin Gravesa97c3942016-03-31 18:01:37 -06005748 skipCall |=
5749 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
5750 0, __LINE__, DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS",
5751 "vkBindBufferMemory(): memoryOffset is %#" PRIxLEAST64 " but must be a multiple of "
5752 "device limit minStorageBufferOffsetAlignment %#" PRIxLEAST64,
Tobin Ehlise54be7b2016-04-11 14:49:55 -06005753 memoryOffset, dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment);
Dustin Gravesa97c3942016-03-31 18:01:37 -06005754 }
5755 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005756 }
Chris Forbes73b82b12016-04-06 15:16:26 +12005757 print_mem_list(dev_data);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005758 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06005759 if (!skipCall) {
Tobin Ehlisb3593a42016-03-16 16:00:36 -06005760 result = dev_data->device_dispatch_table->BindBufferMemory(device, buffer, mem, memoryOffset);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005761 }
5762 return result;
5763}
5764
5765VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5766vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) {
5767 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5768 // TODO : What to track here?
5769 // Could potentially save returned mem requirements and validate values passed into BindBufferMemory
5770 my_data->device_dispatch_table->GetBufferMemoryRequirements(device, buffer, pMemoryRequirements);
5771}
5772
5773VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5774vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) {
5775 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5776 // TODO : What to track here?
5777 // Could potentially save returned mem requirements and validate values passed into BindImageMemory
5778 my_data->device_dispatch_table->GetImageMemoryRequirements(device, image, pMemoryRequirements);
5779}
5780#endif
5781VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5782vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
5783 get_my_data_ptr(get_dispatch_key(device), layer_data_map)
5784 ->device_dispatch_table->DestroyImageView(device, imageView, pAllocator);
5785 // TODO : Clean up any internal data structures using this obj.
5786}
5787
5788VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5789vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) {
Chris Forbes90da2e92016-03-18 16:30:03 +13005790 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5791
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005792 std::unique_lock<std::mutex> lock(global_lock);
Chris Forbes90da2e92016-03-18 16:30:03 +13005793 my_data->shaderModuleMap.erase(shaderModule);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005794 lock.unlock();
Chris Forbes90da2e92016-03-18 16:30:03 +13005795
5796 my_data->device_dispatch_table->DestroyShaderModule(device, shaderModule, pAllocator);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005797}
5798
5799VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5800vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) {
5801 get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroyPipeline(device, pipeline, pAllocator);
5802 // TODO : Clean up any internal data structures using this obj.
5803}
5804
5805VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5806vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) {
5807 get_my_data_ptr(get_dispatch_key(device), layer_data_map)
5808 ->device_dispatch_table->DestroyPipelineLayout(device, pipelineLayout, pAllocator);
5809 // TODO : Clean up any internal data structures using this obj.
5810}
5811
5812VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5813vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
5814 get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator);
5815 // TODO : Clean up any internal data structures using this obj.
5816}
5817
5818VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5819vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) {
5820 get_my_data_ptr(get_dispatch_key(device), layer_data_map)
5821 ->device_dispatch_table->DestroyDescriptorSetLayout(device, descriptorSetLayout, pAllocator);
5822 // TODO : Clean up any internal data structures using this obj.
5823}
5824
5825VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5826vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) {
5827 get_my_data_ptr(get_dispatch_key(device), layer_data_map)
5828 ->device_dispatch_table->DestroyDescriptorPool(device, descriptorPool, pAllocator);
5829 // TODO : Clean up any internal data structures using this obj.
5830}
Tobin Ehlis739d62a2016-04-14 12:22:03 -06005831// Verify cmdBuffer in given cb_node is not in global in-flight set, and return skip_call result
5832// If this is a secondary command buffer, then make sure its primary is also in-flight
5833// If primary is not in-flight, then remove secondary from global in-flight set
5834// This function is only valid at a point when cmdBuffer is being reset or freed
5835static bool checkAndClearCommandBufferInFlight(layer_data *dev_data, const GLOBAL_CB_NODE *cb_node, const char *action) {
5836 bool skip_call = false;
5837 if (dev_data->globalInFlightCmdBuffers.count(cb_node->commandBuffer)) {
5838 // Primary CB or secondary where primary is also in-flight is an error
5839 if ((cb_node->createInfo.level != VK_COMMAND_BUFFER_LEVEL_SECONDARY) ||
5840 (dev_data->globalInFlightCmdBuffers.count(cb_node->primaryCommandBuffer))) {
5841 skip_call |= log_msg(
5842 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5843 reinterpret_cast<const uint64_t &>(cb_node->commandBuffer), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
5844 "Attempt to %s command buffer (%#" PRIxLEAST64 ") which is in use.", action,
5845 reinterpret_cast<const uint64_t &>(cb_node->commandBuffer));
5846 } else { // Secondary CB w/o primary in-flight, remove from in-flight
5847 dev_data->globalInFlightCmdBuffers.erase(cb_node->commandBuffer);
5848 }
5849 }
5850 return skip_call;
5851}
5852// Iterate over all cmdBuffers in given commandPool and verify that each is not in use
5853static bool checkAndClearCommandBuffersInFlight(layer_data *dev_data, const VkCommandPool commandPool, const char *action) {
5854 bool skip_call = false;
5855 auto pool_data = dev_data->commandPoolMap.find(commandPool);
5856 if (pool_data != dev_data->commandPoolMap.end()) {
5857 for (auto cmd_buffer : pool_data->second.commandBuffers) {
5858 if (dev_data->globalInFlightCmdBuffers.count(cmd_buffer)) {
5859 skip_call |= checkAndClearCommandBufferInFlight(dev_data, getCBNode(dev_data, cmd_buffer), action);
5860 }
5861 }
5862 }
5863 return skip_call;
5864}
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005865
5866VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5867vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) {
5868 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5869
5870 bool skip_call = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005871 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005872 for (uint32_t i = 0; i < commandBufferCount; i++) {
Tobin Ehlis739d62a2016-04-14 12:22:03 -06005873 auto cb_pair = dev_data->commandBufferMap.find(pCommandBuffers[i]);
5874 skip_call |= checkAndClearCommandBufferInFlight(dev_data, cb_pair->second, "free");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005875 // Delete CB information structure, and remove from commandBufferMap
Tobin Ehlis739d62a2016-04-14 12:22:03 -06005876 if (cb_pair != dev_data->commandBufferMap.end()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005877 // reset prior to delete for data clean-up
Tobin Ehlis739d62a2016-04-14 12:22:03 -06005878 resetCB(dev_data, (*cb_pair).second->commandBuffer);
5879 delete (*cb_pair).second;
5880 dev_data->commandBufferMap.erase(cb_pair);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005881 }
5882
5883 // Remove commandBuffer reference from commandPoolMap
5884 dev_data->commandPoolMap[commandPool].commandBuffers.remove(pCommandBuffers[i]);
5885 }
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06005886#if MTMERGESOURCE
Chris Forbes73b82b12016-04-06 15:16:26 +12005887 printCBList(dev_data);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005888#endif
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005889 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005890
5891 if (!skip_call)
5892 dev_data->device_dispatch_table->FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers);
5893}
5894
5895VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo,
5896 const VkAllocationCallbacks *pAllocator,
5897 VkCommandPool *pCommandPool) {
5898 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5899
5900 VkResult result = dev_data->device_dispatch_table->CreateCommandPool(device, pCreateInfo, pAllocator, pCommandPool);
5901
5902 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005903 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005904 dev_data->commandPoolMap[*pCommandPool].createFlags = pCreateInfo->flags;
5905 dev_data->commandPoolMap[*pCommandPool].queueFamilyIndex = pCreateInfo->queueFamilyIndex;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005906 }
5907 return result;
5908}
5909
5910VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo,
5911 const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) {
5912
5913 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5914 VkResult result = dev_data->device_dispatch_table->CreateQueryPool(device, pCreateInfo, pAllocator, pQueryPool);
5915 if (result == VK_SUCCESS) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005916 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005917 dev_data->queryPoolMap[*pQueryPool].createInfo = *pCreateInfo;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005918 }
5919 return result;
5920}
5921
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005922// Destroy commandPool along with all of the commandBuffers allocated from that pool
5923VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
5924vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
5925 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005926 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005927 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005928 // Verify that command buffers in pool are complete (not in-flight)
Tobin Ehlis739d62a2016-04-14 12:22:03 -06005929 VkBool32 result = checkAndClearCommandBuffersInFlight(dev_data, commandPool, "destroy command pool with");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005930 // Must remove cmdpool from cmdpoolmap, after removing all cmdbuffers in its list from the commandPoolMap
5931 if (dev_data->commandPoolMap.find(commandPool) != dev_data->commandPoolMap.end()) {
5932 for (auto poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
5933 poolCb != dev_data->commandPoolMap[commandPool].commandBuffers.end();) {
Tobin Ehlis4c522322016-04-11 16:39:29 -06005934 clear_cmd_buf_and_mem_references(dev_data, *poolCb);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005935 auto del_cb = dev_data->commandBufferMap.find(*poolCb);
5936 delete (*del_cb).second; // delete CB info structure
Tobin Ehlis223b01e2016-03-21 14:14:44 -06005937 dev_data->commandBufferMap.erase(del_cb); // Remove this command buffer
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005938 poolCb = dev_data->commandPoolMap[commandPool].commandBuffers.erase(
5939 poolCb); // Remove CB reference from commandPoolMap's list
5940 }
5941 }
5942 dev_data->commandPoolMap.erase(commandPool);
5943
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005944 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005945
Tony Barboured9b4412016-04-06 18:17:57 -06005946 if (result)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005947 return;
5948
5949 if (!skipCall)
5950 dev_data->device_dispatch_table->DestroyCommandPool(device, commandPool, pAllocator);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005951}
5952
5953VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
5954vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
5955 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005956 bool skipCall = false;
5957 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Tobin Ehlis4c522322016-04-11 16:39:29 -06005958
Tobin Ehlis739d62a2016-04-14 12:22:03 -06005959 if (checkAndClearCommandBuffersInFlight(dev_data, commandPool, "reset command pool with"))
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005960 return VK_ERROR_VALIDATION_FAILED_EXT;
5961
5962 if (!skipCall)
5963 result = dev_data->device_dispatch_table->ResetCommandPool(device, commandPool, flags);
5964
5965 // Reset all of the CBs allocated from this pool
5966 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005967 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005968 auto it = dev_data->commandPoolMap[commandPool].commandBuffers.begin();
5969 while (it != dev_data->commandPoolMap[commandPool].commandBuffers.end()) {
5970 resetCB(dev_data, (*it));
5971 ++it;
5972 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005973 }
5974 return result;
5975}
5976
5977VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) {
5978 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
5979 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
5980 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005981 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005982 for (uint32_t i = 0; i < fenceCount; ++i) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005983 auto fence_item = dev_data->fenceMap.find(pFences[i]);
5984 if (fence_item != dev_data->fenceMap.end()) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06005985 fence_item->second.needsSignaled = true;
5986 if (fence_item->second.in_use.load()) {
5987 skipCall |=
5988 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
5989 reinterpret_cast<const uint64_t &>(pFences[i]), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
5990 "Fence %#" PRIx64 " is in use by a command buffer.", reinterpret_cast<const uint64_t &>(pFences[i]));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005991 }
5992 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005993 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06005994 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07005995 if (!skipCall)
5996 result = dev_data->device_dispatch_table->ResetFences(device, fenceCount, pFences);
5997 return result;
5998}
5999
6000VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6001vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) {
6002 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006003 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006004 auto fbNode = dev_data->frameBufferMap.find(framebuffer);
6005 if (fbNode != dev_data->frameBufferMap.end()) {
6006 for (auto cb : fbNode->second.referencingCmdBuffers) {
6007 auto cbNode = dev_data->commandBufferMap.find(cb);
6008 if (cbNode != dev_data->commandBufferMap.end()) {
6009 // Set CB as invalid and record destroyed framebuffer
6010 cbNode->second->state = CB_INVALID;
6011 cbNode->second->destroyedFramebuffers.insert(framebuffer);
6012 }
6013 }
Chris Forbes52bde742016-03-31 16:13:36 +13006014 delete [] fbNode->second.createInfo.pAttachments;
6015 dev_data->frameBufferMap.erase(fbNode);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006016 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006017 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006018 dev_data->device_dispatch_table->DestroyFramebuffer(device, framebuffer, pAllocator);
6019}
6020
6021VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6022vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) {
6023 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6024 dev_data->device_dispatch_table->DestroyRenderPass(device, renderPass, pAllocator);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006025 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006026 dev_data->renderPassMap.erase(renderPass);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006027}
6028
Mark Lobodzinskif20f0942016-03-22 10:07:26 -06006029VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
6030 const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006031 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Mark Lobodzinskif20f0942016-03-22 10:07:26 -06006032
6033 VkResult result = dev_data->device_dispatch_table->CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006034
6035 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006036 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006037 // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
Tobin Ehlisf263ba42016-04-05 13:33:00 -06006038 dev_data->bufferMap[*pBuffer].createInfo = *pCreateInfo;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006039 dev_data->bufferMap[*pBuffer].in_use.store(0);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006040 }
6041 return result;
6042}
6043
6044VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
6045 const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
6046 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6047 VkResult result = dev_data->device_dispatch_table->CreateBufferView(device, pCreateInfo, pAllocator, pView);
6048 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006049 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006050 dev_data->bufferViewMap[*pView] = VkBufferViewCreateInfo(*pCreateInfo);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06006051#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006052 // In order to create a valid buffer view, the buffer must have been created with at least one of the
6053 // following flags: UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
Chris Forbes73b82b12016-04-06 15:16:26 +12006054 validate_buffer_usage_flags(dev_data, pCreateInfo->buffer,
Dustin Graves8f1eab92016-04-05 09:41:17 -06006055 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006056 "vkCreateBufferView()", "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
6057#endif
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006058 }
6059 return result;
6060}
6061
Mark Lobodzinskif20f0942016-03-22 10:07:26 -06006062VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
6063 const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006064 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Mark Lobodzinskif20f0942016-03-22 10:07:26 -06006065
6066 VkResult result = dev_data->device_dispatch_table->CreateImage(device, pCreateInfo, pAllocator, pImage);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006067
6068 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006069 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006070 IMAGE_LAYOUT_NODE image_node;
6071 image_node.layout = pCreateInfo->initialLayout;
6072 image_node.format = pCreateInfo->format;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006073 dev_data->imageMap[*pImage].createInfo = *pCreateInfo;
6074 ImageSubresourcePair subpair = {*pImage, false, VkImageSubresource()};
6075 dev_data->imageSubresourceMap[*pImage].push_back(subpair);
6076 dev_data->imageLayoutMap[subpair] = image_node;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006077 }
6078 return result;
6079}
6080
6081static void ResolveRemainingLevelsLayers(layer_data *dev_data, VkImageSubresourceRange *range, VkImage image) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006082 /* expects global_lock to be held by caller */
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006083
6084 auto image_node_it = dev_data->imageMap.find(image);
6085 if (image_node_it != dev_data->imageMap.end()) {
6086 /* If the caller used the special values VK_REMAINING_MIP_LEVELS and
6087 * VK_REMAINING_ARRAY_LAYERS, resolve them now in our internal state to
6088 * the actual values.
6089 */
6090 if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
6091 range->levelCount = image_node_it->second.createInfo.mipLevels - range->baseMipLevel;
6092 }
6093
6094 if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
6095 range->layerCount = image_node_it->second.createInfo.arrayLayers - range->baseArrayLayer;
6096 }
6097 }
6098}
6099
6100// Return the correct layer/level counts if the caller used the special
6101// values VK_REMAINING_MIP_LEVELS or VK_REMAINING_ARRAY_LAYERS.
6102static void ResolveRemainingLevelsLayers(layer_data *dev_data, uint32_t *levels, uint32_t *layers, VkImageSubresourceRange range,
6103 VkImage image) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006104 /* expects global_lock to be held by caller */
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006105
6106 *levels = range.levelCount;
6107 *layers = range.layerCount;
6108 auto image_node_it = dev_data->imageMap.find(image);
6109 if (image_node_it != dev_data->imageMap.end()) {
6110 if (range.levelCount == VK_REMAINING_MIP_LEVELS) {
6111 *levels = image_node_it->second.createInfo.mipLevels - range.baseMipLevel;
6112 }
6113 if (range.layerCount == VK_REMAINING_ARRAY_LAYERS) {
6114 *layers = image_node_it->second.createInfo.arrayLayers - range.baseArrayLayer;
6115 }
6116 }
6117}
6118
6119VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
6120 const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
6121 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6122 VkResult result = dev_data->device_dispatch_table->CreateImageView(device, pCreateInfo, pAllocator, pView);
6123 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006124 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006125 VkImageViewCreateInfo localCI = VkImageViewCreateInfo(*pCreateInfo);
6126 ResolveRemainingLevelsLayers(dev_data, &localCI.subresourceRange, pCreateInfo->image);
6127 dev_data->imageViewMap[*pView] = localCI;
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06006128#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006129 // Validate that img has correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12006130 validate_image_usage_flags(dev_data, pCreateInfo->image,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006131 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
6132 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
Dustin Graves8f1eab92016-04-05 09:41:17 -06006133 false, "vkCreateImageView()", "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT]_BIT");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006134#endif
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006135 }
6136 return result;
6137}
6138
6139VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6140vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) {
6141 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6142 VkResult result = dev_data->device_dispatch_table->CreateFence(device, pCreateInfo, pAllocator, pFence);
6143 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006144 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06006145 auto &fence_node = dev_data->fenceMap[*pFence];
6146 fence_node.createInfo = *pCreateInfo;
6147 fence_node.needsSignaled = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006148 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06006149 fence_node.firstTimeFlag = true;
6150 fence_node.needsSignaled = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006151 }
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06006152 fence_node.in_use.store(0);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006153 }
6154 return result;
6155}
6156
6157// TODO handle pipeline caches
6158VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo,
6159 const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) {
6160 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6161 VkResult result = dev_data->device_dispatch_table->CreatePipelineCache(device, pCreateInfo, pAllocator, pPipelineCache);
6162 return result;
6163}
6164
6165VKAPI_ATTR void VKAPI_CALL
6166vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) {
6167 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6168 dev_data->device_dispatch_table->DestroyPipelineCache(device, pipelineCache, pAllocator);
6169}
6170
6171VKAPI_ATTR VkResult VKAPI_CALL
6172vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) {
6173 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6174 VkResult result = dev_data->device_dispatch_table->GetPipelineCacheData(device, pipelineCache, pDataSize, pData);
6175 return result;
6176}
6177
6178VKAPI_ATTR VkResult VKAPI_CALL
6179vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) {
6180 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6181 VkResult result = dev_data->device_dispatch_table->MergePipelineCaches(device, dstCache, srcCacheCount, pSrcCaches);
6182 return result;
6183}
6184
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06006185// utility function to set collective state for pipeline
6186void set_pipeline_state(PIPELINE_NODE *pPipe) {
6187 // If any attachment used by this pipeline has blendEnable, set top-level blendEnable
6188 if (pPipe->graphicsPipelineCI.pColorBlendState) {
6189 for (size_t i = 0; i < pPipe->attachments.size(); ++i) {
6190 if (VK_TRUE == pPipe->attachments[i].blendEnable) {
6191 if (((pPipe->attachments[i].dstAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
6192 (pPipe->attachments[i].dstAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
6193 ((pPipe->attachments[i].dstColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
6194 (pPipe->attachments[i].dstColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
6195 ((pPipe->attachments[i].srcAlphaBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
6196 (pPipe->attachments[i].srcAlphaBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)) ||
6197 ((pPipe->attachments[i].srcColorBlendFactor >= VK_BLEND_FACTOR_CONSTANT_COLOR) &&
6198 (pPipe->attachments[i].srcColorBlendFactor <= VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA))) {
6199 pPipe->blendConstantsEnabled = true;
6200 }
6201 }
6202 }
6203 }
6204}
6205
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006206VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6207vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6208 const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
6209 VkPipeline *pPipelines) {
6210 VkResult result = VK_SUCCESS;
6211 // TODO What to do with pipelineCache?
6212 // The order of operations here is a little convoluted but gets the job done
6213 // 1. Pipeline create state is first shadowed into PIPELINE_NODE struct
6214 // 2. Create state is then validated (which uses flags setup during shadowing)
6215 // 3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
Dustin Graves8f1eab92016-04-05 09:41:17 -06006216 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006217 // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
6218 vector<PIPELINE_NODE *> pPipeNode(count);
6219 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6220
6221 uint32_t i = 0;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006222 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006223
6224 for (i = 0; i < count; i++) {
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06006225 pPipeNode[i] = new PIPELINE_NODE;
6226 pPipeNode[i]->initGraphicsPipeline(&pCreateInfos[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006227 skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i);
6228 }
6229
Dustin Graves8f1eab92016-04-05 09:41:17 -06006230 if (!skipCall) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006231 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006232 result = dev_data->device_dispatch_table->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
6233 pPipelines);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006234 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006235 for (i = 0; i < count; i++) {
6236 pPipeNode[i]->pipeline = pPipelines[i];
6237 dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i];
6238 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006239 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006240 } else {
6241 for (i = 0; i < count; i++) {
Chris Forbesec1ed132016-03-18 11:07:59 +13006242 delete pPipeNode[i];
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006243 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006244 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006245 return VK_ERROR_VALIDATION_FAILED_EXT;
6246 }
6247 return result;
6248}
6249
6250VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6251vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
6252 const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
6253 VkPipeline *pPipelines) {
6254 VkResult result = VK_SUCCESS;
Dustin Graves8f1eab92016-04-05 09:41:17 -06006255 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006256
6257 // TODO : Improve this data struct w/ unique_ptrs so cleanup below is automatic
6258 vector<PIPELINE_NODE *> pPipeNode(count);
6259 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6260
6261 uint32_t i = 0;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006262 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006263 for (i = 0; i < count; i++) {
6264 // TODO: Verify compute stage bits
6265
6266 // Create and initialize internal tracking data structure
6267 pPipeNode[i] = new PIPELINE_NODE;
Tobin Ehlis5f4cef12016-04-01 13:51:33 -06006268 pPipeNode[i]->initComputePipeline(&pCreateInfos[i]);
6269 // memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006270
6271 // TODO: Add Compute Pipeline Verification
6272 // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]);
6273 }
6274
Dustin Graves8f1eab92016-04-05 09:41:17 -06006275 if (!skipCall) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006276 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006277 result = dev_data->device_dispatch_table->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pAllocator,
6278 pPipelines);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006279 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006280 for (i = 0; i < count; i++) {
6281 pPipeNode[i]->pipeline = pPipelines[i];
6282 dev_data->pipelineMap[pPipeNode[i]->pipeline] = pPipeNode[i];
6283 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006284 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006285 } else {
6286 for (i = 0; i < count; i++) {
6287 // Clean up any locally allocated data structures
6288 delete pPipeNode[i];
6289 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006290 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006291 return VK_ERROR_VALIDATION_FAILED_EXT;
6292 }
6293 return result;
6294}
6295
6296VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
6297 const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
6298 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6299 VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler);
6300 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006301 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006302 dev_data->sampleMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006303 }
6304 return result;
6305}
6306
6307VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6308vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
6309 const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) {
6310 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6311 VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
6312 if (VK_SUCCESS == result) {
6313 // TODOSC : Capture layout bindings set
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006314 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlis546326f2016-04-26 11:06:05 -06006315 dev_data->descriptorSetLayoutMap[*pSetLayout] = new DescriptorSetLayout(dev_data->report_data, pCreateInfo, *pSetLayout);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006316 }
6317 return result;
6318}
6319
6320static bool validatePushConstantSize(const layer_data *dev_data, const uint32_t offset, const uint32_t size,
6321 const char *caller_name) {
6322 bool skipCall = false;
Tobin Ehlise54be7b2016-04-11 14:49:55 -06006323 if ((offset + size) > dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006324 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6325 DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "%s call has push constants with offset %u and size %u that "
6326 "exceeds this device's maxPushConstantSize of %u.",
Tobin Ehlise54be7b2016-04-11 14:49:55 -06006327 caller_name, offset, size, dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006328 }
6329 return skipCall;
6330}
6331
6332VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo,
6333 const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) {
6334 bool skipCall = false;
6335 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6336 uint32_t i = 0;
6337 for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6338 skipCall |= validatePushConstantSize(dev_data, pCreateInfo->pPushConstantRanges[i].offset,
6339 pCreateInfo->pPushConstantRanges[i].size, "vkCreatePipelineLayout()");
6340 if ((pCreateInfo->pPushConstantRanges[i].size == 0) || ((pCreateInfo->pPushConstantRanges[i].size & 0x3) != 0)) {
6341 skipCall |=
6342 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6343 DRAWSTATE_PUSH_CONSTANTS_ERROR, "DS", "vkCreatePipelineLayout() call has push constant index %u with "
6344 "size %u. Size must be greater than zero and a multiple of 4.",
6345 i, pCreateInfo->pPushConstantRanges[i].size);
6346 }
6347 // TODO : Add warning if ranges overlap
6348 }
6349 VkResult result = dev_data->device_dispatch_table->CreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout);
6350 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006351 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006352 // TODOSC : Merge capture of the setLayouts per pipeline
6353 PIPELINE_LAYOUT_NODE &plNode = dev_data->pipelineLayoutMap[*pPipelineLayout];
6354 plNode.descriptorSetLayouts.resize(pCreateInfo->setLayoutCount);
6355 for (i = 0; i < pCreateInfo->setLayoutCount; ++i) {
6356 plNode.descriptorSetLayouts[i] = pCreateInfo->pSetLayouts[i];
6357 }
6358 plNode.pushConstantRanges.resize(pCreateInfo->pushConstantRangeCount);
6359 for (i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
6360 plNode.pushConstantRanges[i] = pCreateInfo->pPushConstantRanges[i];
6361 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006362 }
6363 return result;
6364}
6365
6366VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6367vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
6368 VkDescriptorPool *pDescriptorPool) {
6369 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6370 VkResult result = dev_data->device_dispatch_table->CreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
6371 if (VK_SUCCESS == result) {
6372 // Insert this pool into Global Pool LL at head
6373 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6374 (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS", "Created Descriptor Pool %#" PRIxLEAST64,
6375 (uint64_t)*pDescriptorPool))
6376 return VK_ERROR_VALIDATION_FAILED_EXT;
6377 DESCRIPTOR_POOL_NODE *pNewNode = new DESCRIPTOR_POOL_NODE(*pDescriptorPool, pCreateInfo);
6378 if (NULL == pNewNode) {
6379 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6380 (uint64_t)*pDescriptorPool, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
6381 "Out of memory while attempting to allocate DESCRIPTOR_POOL_NODE in vkCreateDescriptorPool()"))
6382 return VK_ERROR_VALIDATION_FAILED_EXT;
6383 } else {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006384 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006385 dev_data->descriptorPoolMap[*pDescriptorPool] = pNewNode;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006386 }
6387 } else {
6388 // Need to do anything if pool create fails?
6389 }
6390 return result;
6391}
6392
6393VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6394vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) {
6395 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6396 VkResult result = dev_data->device_dispatch_table->ResetDescriptorPool(device, descriptorPool, flags);
6397 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006398 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006399 clearDescriptorPool(dev_data, device, descriptorPool, flags);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006400 }
6401 return result;
6402}
6403
6404VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6405vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006406 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006407 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6408
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006409 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006410 // Verify that requested descriptorSets are available in pool
6411 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
6412 if (!pPoolNode) {
6413 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
6414 (uint64_t)pAllocateInfo->descriptorPool, __LINE__, DRAWSTATE_INVALID_POOL, "DS",
6415 "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocateDescriptorSets() call",
6416 (uint64_t)pAllocateInfo->descriptorPool);
6417 } else { // Make sure pool has all the available descriptors before calling down chain
6418 skipCall |= validate_descriptor_availability_in_pool(dev_data, pPoolNode, pAllocateInfo->descriptorSetCount,
6419 pAllocateInfo->pSetLayouts);
6420 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006421 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006422 if (skipCall)
6423 return VK_ERROR_VALIDATION_FAILED_EXT;
6424 VkResult result = dev_data->device_dispatch_table->AllocateDescriptorSets(device, pAllocateInfo, pDescriptorSets);
6425 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006426 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006427 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, pAllocateInfo->descriptorPool);
6428 if (pPoolNode) {
6429 if (pAllocateInfo->descriptorSetCount == 0) {
6430 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
6431 pAllocateInfo->descriptorSetCount, __LINE__, DRAWSTATE_NONE, "DS",
6432 "AllocateDescriptorSets called with 0 count");
6433 }
6434 for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
6435 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
6436 (uint64_t)pDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", "Created Descriptor Set %#" PRIxLEAST64,
6437 (uint64_t)pDescriptorSets[i]);
6438 // Create new set node and add to head of pool nodes
6439 SET_NODE *pNewNode = new SET_NODE;
6440 if (NULL == pNewNode) {
6441 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6442 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
6443 DRAWSTATE_OUT_OF_MEMORY, "DS",
Tobin Ehlis9e44eef2016-03-24 12:50:14 -06006444 "Out of memory while attempting to allocate SET_NODE in vkAllocateDescriptorSets()")) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006445 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006446 return VK_ERROR_VALIDATION_FAILED_EXT;
Tobin Ehlis9e44eef2016-03-24 12:50:14 -06006447 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006448 } else {
6449 // TODO : Pool should store a total count of each type of Descriptor available
6450 // When descriptors are allocated, decrement the count and validate here
6451 // that the count doesn't go below 0. One reset/free need to bump count back up.
6452 // Insert set at head of Set LL for this pool
6453 pNewNode->pNext = pPoolNode->pSets;
6454 pNewNode->in_use.store(0);
6455 pPoolNode->pSets = pNewNode;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06006456 auto layout_pair = dev_data->descriptorSetLayoutMap.find(pAllocateInfo->pSetLayouts[i]);
6457 if (layout_pair == dev_data->descriptorSetLayoutMap.end()) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006458 if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6459 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i],
6460 __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
6461 "Unable to find set layout node for layout %#" PRIxLEAST64
6462 " specified in vkAllocateDescriptorSets() call",
Tobin Ehlis9e44eef2016-03-24 12:50:14 -06006463 (uint64_t)pAllocateInfo->pSetLayouts[i])) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006464 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006465 return VK_ERROR_VALIDATION_FAILED_EXT;
Tobin Ehlis9e44eef2016-03-24 12:50:14 -06006466 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006467 }
Tobin Ehlis546326f2016-04-26 11:06:05 -06006468 pNewNode->p_layout = layout_pair->second;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006469 pNewNode->pool = pAllocateInfo->descriptorPool;
6470 pNewNode->set = pDescriptorSets[i];
Tobin Ehlis546326f2016-04-26 11:06:05 -06006471 pNewNode->descriptorCount = layout_pair->second->GetTotalDescriptorCount();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006472 if (pNewNode->descriptorCount) {
Karl Schultz75b58a32016-03-25 13:21:25 -06006473 pNewNode->pDescriptorUpdates.resize(pNewNode->descriptorCount);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006474 }
6475 dev_data->setMap[pDescriptorSets[i]] = pNewNode;
6476 }
6477 }
6478 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006479 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006480 }
6481 return result;
6482}
6483
6484VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6485vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t count, const VkDescriptorSet *pDescriptorSets) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006486 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006487 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6488 // Make sure that no sets being destroyed are in-flight
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006489 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006490 for (uint32_t i = 0; i < count; ++i)
Mark Muellerff4ce752016-04-14 11:01:58 -06006491 skipCall |= validateIdleDescriptorSet(dev_data, pDescriptorSets[i], "vkFreeDescriptorSets");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006492 DESCRIPTOR_POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
6493 if (pPoolNode && !(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT & pPoolNode->createInfo.flags)) {
6494 // Can't Free from a NON_FREE pool
6495 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
6496 (uint64_t)device, __LINE__, DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL, "DS",
6497 "It is invalid to call vkFreeDescriptorSets() with a pool created without setting "
6498 "VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT.");
6499 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006500 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006501 if (skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006502 return VK_ERROR_VALIDATION_FAILED_EXT;
6503 VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
6504 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006505 lock.lock();
Mark Lobodzinskia3efb0c2016-03-21 16:32:53 -06006506
6507 // Update available descriptor sets in pool
6508 pPoolNode->availableSets += count;
6509
6510 // For each freed descriptor add it back into the pool as available
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006511 for (uint32_t i = 0; i < count; ++i) {
6512 SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking
6513 invalidateBoundCmdBuffers(dev_data, pSet);
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06006514 auto p_layout = pSet->p_layout;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006515 uint32_t typeIndex = 0, poolSizeCount = 0;
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06006516 for (uint32_t j = 0; j < p_layout->GetBindingCount(); ++j) {
6517 auto layout_binding = p_layout->GetDescriptorSetLayoutBindingPtrFromIndex(j);
6518 typeIndex = static_cast<uint32_t>(layout_binding->descriptorType);
6519 poolSizeCount = layout_binding->descriptorCount;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006520 pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount;
6521 }
6522 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006523 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006524 }
6525 // TODO : Any other clean-up or book-keeping to do here?
6526 return result;
6527}
6528
6529VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6530vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites,
6531 uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006532 // dsUpdate will return true only if a bailout error occurs, so we want to call down tree when update returns false
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006533 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006534 std::unique_lock<std::mutex> lock(global_lock);
Dustin Graves8f1eab92016-04-05 09:41:17 -06006535 bool rtn = dsUpdate(dev_data, device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006536 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006537 if (!rtn) {
6538 dev_data->device_dispatch_table->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount,
6539 pDescriptorCopies);
6540 }
6541}
6542
6543VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6544vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pCreateInfo, VkCommandBuffer *pCommandBuffer) {
6545 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
6546 VkResult result = dev_data->device_dispatch_table->AllocateCommandBuffers(device, pCreateInfo, pCommandBuffer);
6547 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006548 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06006549 auto const &cp_it = dev_data->commandPoolMap.find(pCreateInfo->commandPool);
6550 if (cp_it != dev_data->commandPoolMap.end()) {
6551 for (uint32_t i = 0; i < pCreateInfo->commandBufferCount; i++) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006552 // Add command buffer to its commandPool map
Tobin Ehlis223b01e2016-03-21 14:14:44 -06006553 cp_it->second.commandBuffers.push_back(pCommandBuffer[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006554 GLOBAL_CB_NODE *pCB = new GLOBAL_CB_NODE;
6555 // Add command buffer to map
6556 dev_data->commandBufferMap[pCommandBuffer[i]] = pCB;
6557 resetCB(dev_data, pCommandBuffer[i]);
6558 pCB->createInfo = *pCreateInfo;
6559 pCB->device = device;
6560 }
6561 }
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06006562#if MTMERGESOURCE
Chris Forbes73b82b12016-04-06 15:16:26 +12006563 printCBList(dev_data);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006564#endif
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006565 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006566 }
6567 return result;
6568}
6569
6570VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6571vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006572 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006573 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006574 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006575 // Validate command buffer level
6576 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6577 if (pCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006578 // This implicitly resets the Cmd Buffer so make sure any fence is done and then clear memory references
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06006579 if (dev_data->globalInFlightCmdBuffers.count(commandBuffer)) {
6580 skipCall |=
6581 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6582 (uint64_t)commandBuffer, __LINE__, MEMTRACK_RESET_CB_WHILE_IN_FLIGHT, "MEM",
6583 "Calling vkBeginCommandBuffer() on active CB %p before it has completed. "
6584 "You must check CB fence before this call.",
6585 commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006586 }
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06006587 clear_cmd_buf_and_mem_references(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006588 if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
6589 // Secondary Command Buffer
6590 const VkCommandBufferInheritanceInfo *pInfo = pBeginInfo->pInheritanceInfo;
6591 if (!pInfo) {
6592 skipCall |=
6593 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6594 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
6595 "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must have inheritance info.",
6596 reinterpret_cast<void *>(commandBuffer));
6597 } else {
6598 if (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) {
Tobin Ehlis4c522322016-04-11 16:39:29 -06006599 if (!pInfo->renderPass) { // renderpass should NOT be null for a Secondary CB
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006600 skipCall |= log_msg(
6601 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6602 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
6603 "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must specify a valid renderpass parameter.",
6604 reinterpret_cast<void *>(commandBuffer));
6605 }
Tobin Ehlis4c522322016-04-11 16:39:29 -06006606 if (!pInfo->framebuffer) { // framebuffer may be null for a Secondary CB, but this affects perf
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006607 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
6608 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6609 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE,
6610 "DS", "vkBeginCommandBuffer(): Secondary Command Buffers (%p) may perform better if a "
6611 "valid framebuffer parameter is specified.",
6612 reinterpret_cast<void *>(commandBuffer));
6613 } else {
6614 string errorString = "";
6615 auto fbNode = dev_data->frameBufferMap.find(pInfo->framebuffer);
6616 if (fbNode != dev_data->frameBufferMap.end()) {
6617 VkRenderPass fbRP = fbNode->second.createInfo.renderPass;
6618 if (!verify_renderpass_compatibility(dev_data, fbRP, pInfo->renderPass, errorString)) {
Tobin Ehlis4c522322016-04-11 16:39:29 -06006619 // renderPass that framebuffer was created with must be compatible with local renderPass
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006620 skipCall |=
6621 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6622 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6623 reinterpret_cast<uint64_t>(commandBuffer), __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE,
6624 "DS", "vkBeginCommandBuffer(): Secondary Command "
6625 "Buffer (%p) renderPass (%#" PRIxLEAST64 ") is incompatible w/ framebuffer "
6626 "(%#" PRIxLEAST64 ") w/ render pass (%#" PRIxLEAST64 ") due to: %s",
6627 reinterpret_cast<void *>(commandBuffer), (uint64_t)(pInfo->renderPass),
6628 (uint64_t)(pInfo->framebuffer), (uint64_t)(fbRP), errorString.c_str());
6629 }
6630 // Connect this framebuffer to this cmdBuffer
6631 fbNode->second.referencingCmdBuffers.insert(pCB->commandBuffer);
6632 }
6633 }
6634 }
6635 if ((pInfo->occlusionQueryEnable == VK_FALSE ||
Tobin Ehlise54be7b2016-04-11 14:49:55 -06006636 dev_data->phys_dev_properties.features.occlusionQueryPrecise == VK_FALSE) &&
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006637 (pInfo->queryFlags & VK_QUERY_CONTROL_PRECISE_BIT)) {
6638 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6639 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, reinterpret_cast<uint64_t>(commandBuffer),
6640 __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
6641 "vkBeginCommandBuffer(): Secondary Command Buffer (%p) must not have "
6642 "VK_QUERY_CONTROL_PRECISE_BIT if occulusionQuery is disabled or the device does not "
6643 "support precise occlusion queries.",
6644 reinterpret_cast<void *>(commandBuffer));
6645 }
6646 }
6647 if (pInfo && pInfo->renderPass != VK_NULL_HANDLE) {
6648 auto rp_data = dev_data->renderPassMap.find(pInfo->renderPass);
6649 if (rp_data != dev_data->renderPassMap.end() && rp_data->second && rp_data->second->pCreateInfo) {
6650 if (pInfo->subpass >= rp_data->second->pCreateInfo->subpassCount) {
6651 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6652 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
6653 DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
6654 "vkBeginCommandBuffer(): Secondary Command Buffers (%p) must has a subpass index (%d) "
6655 "that is less than the number of subpasses (%d).",
6656 (void *)commandBuffer, pInfo->subpass, rp_data->second->pCreateInfo->subpassCount);
6657 }
6658 }
6659 }
6660 }
6661 if (CB_RECORDING == pCB->state) {
6662 skipCall |=
6663 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6664 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
6665 "vkBeginCommandBuffer(): Cannot call Begin on CB (%#" PRIxLEAST64
6666 ") in the RECORDING state. Must first call vkEndCommandBuffer().",
6667 (uint64_t)commandBuffer);
6668 } else if (CB_RECORDED == pCB->state) {
6669 VkCommandPool cmdPool = pCB->createInfo.commandPool;
6670 if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) {
6671 skipCall |=
6672 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6673 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
6674 "Call to vkBeginCommandBuffer() on command buffer (%#" PRIxLEAST64
6675 ") attempts to implicitly reset cmdBuffer created from command pool (%#" PRIxLEAST64
6676 ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
6677 (uint64_t)commandBuffer, (uint64_t)cmdPool);
6678 }
6679 resetCB(dev_data, commandBuffer);
6680 }
6681 // Set updated state here in case implicit reset occurs above
6682 pCB->state = CB_RECORDING;
6683 pCB->beginInfo = *pBeginInfo;
6684 if (pCB->beginInfo.pInheritanceInfo) {
6685 pCB->inheritanceInfo = *(pCB->beginInfo.pInheritanceInfo);
6686 pCB->beginInfo.pInheritanceInfo = &pCB->inheritanceInfo;
6687 }
6688 } else {
6689 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6690 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
6691 "In vkBeginCommandBuffer() and unable to find CommandBuffer Node for CB %p!", (void *)commandBuffer);
6692 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006693 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006694 if (skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006695 return VK_ERROR_VALIDATION_FAILED_EXT;
6696 }
6697 VkResult result = dev_data->device_dispatch_table->BeginCommandBuffer(commandBuffer, pBeginInfo);
Tobin Ehlis4c522322016-04-11 16:39:29 -06006698
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006699 return result;
6700}
6701
6702VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006703 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006704 VkResult result = VK_SUCCESS;
6705 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006706 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006707 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6708 if (pCB) {
6709 if (pCB->state != CB_RECORDING) {
6710 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkEndCommandBuffer()");
6711 }
6712 for (auto query : pCB->activeQueries) {
6713 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
6714 DRAWSTATE_INVALID_QUERY, "DS",
6715 "Ending command buffer with in progress query: queryPool %" PRIu64 ", index %d",
6716 (uint64_t)(query.pool), query.index);
6717 }
6718 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06006719 if (!skipCall) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006720 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006721 result = dev_data->device_dispatch_table->EndCommandBuffer(commandBuffer);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006722 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006723 if (VK_SUCCESS == result) {
6724 pCB->state = CB_RECORDED;
6725 // Reset CB status flags
6726 pCB->status = 0;
6727 printCB(dev_data, commandBuffer);
6728 }
6729 } else {
6730 result = VK_ERROR_VALIDATION_FAILED_EXT;
6731 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006732 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006733 return result;
6734}
6735
6736VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
6737vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) {
Tobin Ehlis739d62a2016-04-14 12:22:03 -06006738 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006739 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006740 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006741 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6742 VkCommandPool cmdPool = pCB->createInfo.commandPool;
6743 if (!(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT & dev_data->commandPoolMap[cmdPool].createFlags)) {
Tobin Ehlis739d62a2016-04-14 12:22:03 -06006744 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
6745 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, "DS",
6746 "Attempt to reset command buffer (%#" PRIxLEAST64 ") created from command pool (%#" PRIxLEAST64
6747 ") that does NOT have the VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT bit set.",
6748 (uint64_t)commandBuffer, (uint64_t)cmdPool);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006749 }
Tobin Ehlis739d62a2016-04-14 12:22:03 -06006750 skip_call |= checkAndClearCommandBufferInFlight(dev_data, pCB, "reset");
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006751 lock.unlock();
Tobin Ehlis739d62a2016-04-14 12:22:03 -06006752 if (skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006753 return VK_ERROR_VALIDATION_FAILED_EXT;
6754 VkResult result = dev_data->device_dispatch_table->ResetCommandBuffer(commandBuffer, flags);
6755 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006756 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006757 resetCB(dev_data, commandBuffer);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006758 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006759 }
6760 return result;
6761}
Mark Lobodzinski188b2302016-04-12 10:41:59 -06006762
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06006763#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006764// TODO : For any vkCmdBind* calls that include an object which has mem bound to it,
6765// need to account for that mem now having binding to given commandBuffer
6766#endif
6767VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6768vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006769 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006770 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006771 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006772 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6773 if (pCB) {
6774 skipCall |= addCmd(dev_data, pCB, CMD_BINDPIPELINE, "vkCmdBindPipeline()");
6775 if ((VK_PIPELINE_BIND_POINT_COMPUTE == pipelineBindPoint) && (pCB->activeRenderPass)) {
6776 skipCall |=
6777 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
6778 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_RENDERPASS_CMD, "DS",
6779 "Incorrectly binding compute pipeline (%#" PRIxLEAST64 ") during active RenderPass (%#" PRIxLEAST64 ")",
6780 (uint64_t)pipeline, (uint64_t)pCB->activeRenderPass);
6781 }
6782
6783 PIPELINE_NODE *pPN = getPipeline(dev_data, pipeline);
6784 if (pPN) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06006785 pCB->lastBound[pipelineBindPoint].pipeline = pipeline;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006786 set_cb_pso_status(pCB, pPN);
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06006787 set_pipeline_state(pPN);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006788 skipCall |= validatePipelineState(dev_data, pCB, pipelineBindPoint, pipeline);
6789 } else {
6790 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
6791 (uint64_t)pipeline, __LINE__, DRAWSTATE_INVALID_PIPELINE, "DS",
6792 "Attempt to bind Pipeline %#" PRIxLEAST64 " that doesn't exist!", (uint64_t)(pipeline));
6793 }
6794 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006795 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006796 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006797 dev_data->device_dispatch_table->CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
6798}
6799
6800VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6801vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006802 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006803 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006804 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006805 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6806 if (pCB) {
6807 skipCall |= addCmd(dev_data, pCB, CMD_SETVIEWPORTSTATE, "vkCmdSetViewport()");
6808 pCB->status |= CBSTATUS_VIEWPORT_SET;
6809 pCB->viewports.resize(viewportCount);
6810 memcpy(pCB->viewports.data(), pViewports, viewportCount * sizeof(VkViewport));
6811 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006812 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006813 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006814 dev_data->device_dispatch_table->CmdSetViewport(commandBuffer, firstViewport, viewportCount, pViewports);
6815}
6816
6817VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6818vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006819 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006820 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006821 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006822 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6823 if (pCB) {
6824 skipCall |= addCmd(dev_data, pCB, CMD_SETSCISSORSTATE, "vkCmdSetScissor()");
6825 pCB->status |= CBSTATUS_SCISSOR_SET;
6826 pCB->scissors.resize(scissorCount);
6827 memcpy(pCB->scissors.data(), pScissors, scissorCount * sizeof(VkRect2D));
6828 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006829 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006830 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006831 dev_data->device_dispatch_table->CmdSetScissor(commandBuffer, firstScissor, scissorCount, pScissors);
6832}
6833
6834VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) {
Mark Young7394fdd2016-03-31 14:56:43 -06006835 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006836 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006837 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006838 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6839 if (pCB) {
Mark Young7394fdd2016-03-31 14:56:43 -06006840 skip_call |= addCmd(dev_data, pCB, CMD_SETLINEWIDTHSTATE, "vkCmdSetLineWidth()");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006841 pCB->status |= CBSTATUS_LINE_WIDTH_SET;
Mark Young7394fdd2016-03-31 14:56:43 -06006842
6843 PIPELINE_NODE *pPipeTrav = getPipeline(dev_data, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
6844 if (pPipeTrav != NULL && !isDynamic(pPipeTrav, VK_DYNAMIC_STATE_LINE_WIDTH)) {
6845 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
6846 reinterpret_cast<uint64_t &>(commandBuffer), __LINE__, DRAWSTATE_INVALID_SET, "DS",
6847 "vkCmdSetLineWidth called but pipeline was created without VK_DYNAMIC_STATE_LINE_WIDTH"
6848 "flag. This is undefined behavior and could be ignored.");
6849 } else {
6850 skip_call |= verifyLineWidth(dev_data, DRAWSTATE_INVALID_SET, reinterpret_cast<uint64_t &>(commandBuffer), lineWidth);
6851 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006852 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006853 lock.unlock();
Mark Young7394fdd2016-03-31 14:56:43 -06006854 if (!skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006855 dev_data->device_dispatch_table->CmdSetLineWidth(commandBuffer, lineWidth);
6856}
6857
6858VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6859vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006860 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006861 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006862 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006863 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6864 if (pCB) {
6865 skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBIASSTATE, "vkCmdSetDepthBias()");
6866 pCB->status |= CBSTATUS_DEPTH_BIAS_SET;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006867 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006868 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006869 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006870 dev_data->device_dispatch_table->CmdSetDepthBias(commandBuffer, depthBiasConstantFactor, depthBiasClamp,
6871 depthBiasSlopeFactor);
6872}
6873
6874VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006875 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006876 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006877 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006878 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6879 if (pCB) {
6880 skipCall |= addCmd(dev_data, pCB, CMD_SETBLENDSTATE, "vkCmdSetBlendConstants()");
Tobin Ehlis7a1d2352016-03-28 11:18:19 -06006881 pCB->status |= CBSTATUS_BLEND_CONSTANTS_SET;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006882 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006883 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006884 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006885 dev_data->device_dispatch_table->CmdSetBlendConstants(commandBuffer, blendConstants);
6886}
6887
6888VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6889vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006890 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006891 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006892 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006893 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6894 if (pCB) {
6895 skipCall |= addCmd(dev_data, pCB, CMD_SETDEPTHBOUNDSSTATE, "vkCmdSetDepthBounds()");
6896 pCB->status |= CBSTATUS_DEPTH_BOUNDS_SET;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006897 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006898 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006899 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006900 dev_data->device_dispatch_table->CmdSetDepthBounds(commandBuffer, minDepthBounds, maxDepthBounds);
6901}
6902
6903VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6904vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006905 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006906 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006907 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006908 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6909 if (pCB) {
6910 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREADMASKSTATE, "vkCmdSetStencilCompareMask()");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006911 pCB->status |= CBSTATUS_STENCIL_READ_MASK_SET;
6912 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006913 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006914 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006915 dev_data->device_dispatch_table->CmdSetStencilCompareMask(commandBuffer, faceMask, compareMask);
6916}
6917
6918VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6919vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006920 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006921 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006922 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006923 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6924 if (pCB) {
6925 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILWRITEMASKSTATE, "vkCmdSetStencilWriteMask()");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006926 pCB->status |= CBSTATUS_STENCIL_WRITE_MASK_SET;
6927 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006928 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006929 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006930 dev_data->device_dispatch_table->CmdSetStencilWriteMask(commandBuffer, faceMask, writeMask);
6931}
6932
6933VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6934vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006935 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006936 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006937 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006938 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6939 if (pCB) {
6940 skipCall |= addCmd(dev_data, pCB, CMD_SETSTENCILREFERENCESTATE, "vkCmdSetStencilReference()");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006941 pCB->status |= CBSTATUS_STENCIL_REFERENCE_SET;
6942 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006943 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06006944 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006945 dev_data->device_dispatch_table->CmdSetStencilReference(commandBuffer, faceMask, reference);
6946}
6947
6948VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
6949vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout,
6950 uint32_t firstSet, uint32_t setCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount,
6951 const uint32_t *pDynamicOffsets) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06006952 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006953 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06006954 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006955 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
6956 if (pCB) {
6957 if (pCB->state == CB_RECORDING) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06006958 // Track total count of dynamic descriptor types to make sure we have an offset for each one
6959 uint32_t totalDynamicDescriptors = 0;
6960 string errorString = "";
6961 uint32_t lastSetIndex = firstSet + setCount - 1;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06006962 if (lastSetIndex >= pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size())
6963 pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
6964 VkDescriptorSet oldFinalBoundSet = pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex];
Tobin Ehlis285a8282016-03-17 13:37:40 -06006965 for (uint32_t i = 0; i < setCount; i++) {
6966 SET_NODE *pSet = getSetNode(dev_data, pDescriptorSets[i]);
6967 if (pSet) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06006968 pCB->lastBound[pipelineBindPoint].uniqueBoundSets.insert(pDescriptorSets[i]);
Tobin Ehlis285a8282016-03-17 13:37:40 -06006969 pSet->boundCmdBuffers.insert(commandBuffer);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06006970 pCB->lastBound[pipelineBindPoint].pipelineLayout = layout;
6971 pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i + firstSet] = pDescriptorSets[i];
Tobin Ehlis285a8282016-03-17 13:37:40 -06006972 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
6973 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
6974 DRAWSTATE_NONE, "DS", "DS %#" PRIxLEAST64 " bound on pipeline %s",
6975 (uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint));
6976 if (!pSet->pUpdateStructs && (pSet->descriptorCount != 0)) {
6977 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
6978 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i],
6979 __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
6980 "DS %#" PRIxLEAST64
6981 " bound but it was never updated. You may want to either update it or not bind it.",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07006982 (uint64_t)pDescriptorSets[i]);
6983 }
Tobin Ehlis285a8282016-03-17 13:37:40 -06006984 // Verify that set being bound is compatible with overlapping setLayout of pipelineLayout
6985 if (!verify_set_layout_compatibility(dev_data, pSet, layout, i + firstSet, errorString)) {
6986 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
Tobin Ehlis087b77d2016-04-29 07:32:31 -06006987 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
6988 DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
6989 "descriptorSet #%u being bound is not compatible with overlapping descriptorSetLayout "
6990 "at index %u of pipelineLayout %#" PRIxLEAST64 " due to: %s",
6991 i, i + firstSet, reinterpret_cast<uint64_t &>(layout), errorString.c_str());
Tobin Ehlis285a8282016-03-17 13:37:40 -06006992 }
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06006993 if (pSet->p_layout->GetDynamicDescriptorCount()) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06006994 // First make sure we won't overstep bounds of pDynamicOffsets array
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06006995 if ((totalDynamicDescriptors + pSet->p_layout->GetDynamicDescriptorCount()) > dynamicOffsetCount) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06006996 skipCall |=
6997 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
6998 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
6999 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7000 "descriptorSet #%u (%#" PRIxLEAST64
7001 ") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
7002 "array. There must be one dynamic offset for each dynamic descriptor being bound.",
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06007003 i, (uint64_t)pDescriptorSets[i], pSet->p_layout->GetDynamicDescriptorCount(),
Tobin Ehlis285a8282016-03-17 13:37:40 -06007004 (dynamicOffsetCount - totalDynamicDescriptors));
7005 } else { // Validate and store dynamic offsets with the set
7006 // Validate Dynamic Offset Minimums
7007 uint32_t cur_dyn_offset = totalDynamicDescriptors;
7008 for (uint32_t d = 0; d < pSet->descriptorCount; d++) {
Tobin Ehlis660aba42016-04-26 13:09:51 -06007009 if (pSet->p_layout->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06007010 if (vk_safe_modulo(
7011 pDynamicOffsets[cur_dyn_offset],
Tobin Ehlise54be7b2016-04-11 14:49:55 -06007012 dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06007013 skipCall |= log_msg(
7014 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7015 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
7016 DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, "DS",
7017 "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7018 "device limit minUniformBufferOffsetAlignment %#" PRIxLEAST64,
7019 cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
Tobin Ehlise54be7b2016-04-11 14:49:55 -06007020 dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
Tobin Ehlis285a8282016-03-17 13:37:40 -06007021 }
7022 cur_dyn_offset++;
Tobin Ehlis660aba42016-04-26 13:09:51 -06007023 } else if (pSet->p_layout->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06007024 if (vk_safe_modulo(
7025 pDynamicOffsets[cur_dyn_offset],
Tobin Ehlise54be7b2016-04-11 14:49:55 -06007026 dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
Tobin Ehlis285a8282016-03-17 13:37:40 -06007027 skipCall |= log_msg(
7028 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7029 VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT, 0, __LINE__,
7030 DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, "DS",
7031 "vkCmdBindDescriptorSets(): pDynamicOffsets[%d] is %d but must be a multiple of "
7032 "device limit minStorageBufferOffsetAlignment %#" PRIxLEAST64,
7033 cur_dyn_offset, pDynamicOffsets[cur_dyn_offset],
Tobin Ehlise54be7b2016-04-11 14:49:55 -06007034 dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment);
Tobin Ehlis285a8282016-03-17 13:37:40 -06007035 }
7036 cur_dyn_offset++;
7037 }
7038 }
7039 // Keep running total of dynamic descriptor count to verify at the end
Tobin Ehlis2d9deec2016-04-21 14:19:26 -06007040 totalDynamicDescriptors += pSet->p_layout->GetDynamicDescriptorCount();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007041 }
7042 }
Tobin Ehlis285a8282016-03-17 13:37:40 -06007043 } else {
7044 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7045 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
7046 DRAWSTATE_INVALID_SET, "DS", "Attempt to bind DS %#" PRIxLEAST64 " that doesn't exist!",
7047 (uint64_t)pDescriptorSets[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007048 }
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007049 skipCall |= addCmd(dev_data, pCB, CMD_BINDDESCRIPTORSETS, "vkCmdBindDescriptorSets()");
7050 // For any previously bound sets, need to set them to "invalid" if they were disturbed by this update
7051 if (firstSet > 0) { // Check set #s below the first bound set
7052 for (uint32_t i = 0; i < firstSet; ++i) {
7053 if (pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] &&
7054 !verify_set_layout_compatibility(
7055 dev_data, dev_data->setMap[pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i]], layout, i,
7056 errorString)) {
7057 skipCall |= log_msg(
7058 dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7059 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
7060 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS",
7061 "DescriptorSetDS %#" PRIxLEAST64
7062 " previously bound as set #%u was disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")",
7063 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i], i, (uint64_t)layout);
7064 pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i] = VK_NULL_HANDLE;
7065 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007066 }
7067 }
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007068 // Check if newly last bound set invalidates any remaining bound sets
7069 if ((pCB->lastBound[pipelineBindPoint].boundDescriptorSets.size() - 1) > (lastSetIndex)) {
7070 if (oldFinalBoundSet &&
7071 !verify_set_layout_compatibility(dev_data, dev_data->setMap[oldFinalBoundSet], layout, lastSetIndex,
7072 errorString)) {
7073 skipCall |=
7074 log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7075 VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)oldFinalBoundSet, __LINE__,
7076 DRAWSTATE_NONE, "DS", "DescriptorSetDS %#" PRIxLEAST64
7077 " previously bound as set #%u is incompatible with set %#" PRIxLEAST64
7078 " newly bound as set #%u so set #%u and any subsequent sets were "
7079 "disturbed by newly bound pipelineLayout (%#" PRIxLEAST64 ")",
7080 (uint64_t)oldFinalBoundSet, lastSetIndex,
7081 (uint64_t)pCB->lastBound[pipelineBindPoint].boundDescriptorSets[lastSetIndex], lastSetIndex,
7082 lastSetIndex + 1, (uint64_t)layout);
7083 pCB->lastBound[pipelineBindPoint].boundDescriptorSets.resize(lastSetIndex + 1);
7084 }
7085 }
Tobin Ehlis285a8282016-03-17 13:37:40 -06007086 }
7087 // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound
7088 if (totalDynamicDescriptors != dynamicOffsetCount) {
7089 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
7090 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)commandBuffer, __LINE__,
7091 DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT, "DS",
7092 "Attempting to bind %u descriptorSets with %u dynamic descriptors, but dynamicOffsetCount "
7093 "is %u. It should exactly match the number of dynamic descriptors.",
7094 setCount, totalDynamicDescriptors, dynamicOffsetCount);
7095 }
7096 // Save dynamicOffsets bound to this CB
7097 for (uint32_t i = 0; i < dynamicOffsetCount; i++) {
Tobin Ehlisbcd8d022016-03-30 09:32:19 -06007098 pCB->lastBound[pipelineBindPoint].dynamicOffsets.emplace_back(pDynamicOffsets[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007099 }
7100 } else {
7101 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindDescriptorSets()");
7102 }
7103 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007104 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007105 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007106 dev_data->device_dispatch_table->CmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, setCount,
7107 pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
7108}
7109
7110VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7111vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007112 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007113 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007114 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007115#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007116 VkDeviceMemory mem;
7117 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007118 get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007119 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
7120 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007121 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindIndexBuffer()"); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007122 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007123 }
7124 // TODO : Somewhere need to verify that IBs have correct usage state flagged
7125#endif
7126 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7127 if (pCB) {
7128 skipCall |= addCmd(dev_data, pCB, CMD_BINDINDEXBUFFER, "vkCmdBindIndexBuffer()");
7129 VkDeviceSize offset_align = 0;
7130 switch (indexType) {
7131 case VK_INDEX_TYPE_UINT16:
7132 offset_align = 2;
7133 break;
7134 case VK_INDEX_TYPE_UINT32:
7135 offset_align = 4;
7136 break;
7137 default:
7138 // ParamChecker should catch bad enum, we'll also throw alignment error below if offset_align stays 0
7139 break;
7140 }
7141 if (!offset_align || (offset % offset_align)) {
7142 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
7143 DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR, "DS",
7144 "vkCmdBindIndexBuffer() offset (%#" PRIxLEAST64 ") does not fall on alignment (%s) boundary.",
7145 offset, string_VkIndexType(indexType));
7146 }
7147 pCB->status |= CBSTATUS_INDEX_BUFFER_BOUND;
7148 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007149 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007150 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007151 dev_data->device_dispatch_table->CmdBindIndexBuffer(commandBuffer, buffer, offset, indexType);
7152}
7153
7154void updateResourceTracking(GLOBAL_CB_NODE *pCB, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers) {
7155 uint32_t end = firstBinding + bindingCount;
7156 if (pCB->currentDrawData.buffers.size() < end) {
7157 pCB->currentDrawData.buffers.resize(end);
7158 }
7159 for (uint32_t i = 0; i < bindingCount; ++i) {
7160 pCB->currentDrawData.buffers[i + firstBinding] = pBuffers[i];
7161 }
7162}
7163
Dustin Graves8f1eab92016-04-05 09:41:17 -06007164static inline void updateResourceTrackingOnDraw(GLOBAL_CB_NODE *pCB) { pCB->drawData.push_back(pCB->currentDrawData); }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007165
7166VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding,
7167 uint32_t bindingCount, const VkBuffer *pBuffers,
7168 const VkDeviceSize *pOffsets) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007169 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007170 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007171 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007172#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007173 for (uint32_t i = 0; i < bindingCount; ++i) {
7174 VkDeviceMemory mem;
Chris Forbes73b82b12016-04-06 15:16:26 +12007175 skipCall |= get_mem_binding_from_object(dev_data, (uint64_t)pBuffers[i], VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007176 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
7177 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007178 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBindVertexBuffers()"); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007179 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007180 }
7181 }
7182 // TODO : Somewhere need to verify that VBs have correct usage state flagged
7183#endif
7184 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7185 if (pCB) {
7186 addCmd(dev_data, pCB, CMD_BINDVERTEXBUFFER, "vkCmdBindVertexBuffer()");
7187 updateResourceTracking(pCB, firstBinding, bindingCount, pBuffers);
7188 } else {
7189 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdBindVertexBuffer()");
7190 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007191 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007192 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007193 dev_data->device_dispatch_table->CmdBindVertexBuffers(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets);
7194}
7195
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007196/* expects global_lock to be held by caller */
Dustin Graves8f1eab92016-04-05 09:41:17 -06007197static bool markStoreImagesAndBuffersAsWritten(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007198 bool skip_call = false;
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007199
7200 for (auto imageView : pCB->updateImages) {
7201 auto iv_data = dev_data->imageViewMap.find(imageView);
7202 if (iv_data == dev_data->imageViewMap.end())
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007203 continue;
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007204 VkImage image = iv_data->second.image;
7205 VkDeviceMemory mem;
7206 skip_call |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007207 get_mem_binding_from_object(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007208 std::function<bool()> function = [=]() {
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007209 set_memory_valid(dev_data, mem, true, image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007210 return false;
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007211 };
7212 pCB->validate_functions.push_back(function);
7213 }
7214 for (auto buffer : pCB->updateBuffers) {
7215 VkDeviceMemory mem;
Chris Forbes73b82b12016-04-06 15:16:26 +12007216 skip_call |= get_mem_binding_from_object(dev_data, (uint64_t)buffer,
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007217 VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007218 std::function<bool()> function = [=]() {
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007219 set_memory_valid(dev_data, mem, true);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007220 return false;
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007221 };
7222 pCB->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007223 }
7224 return skip_call;
7225}
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007226
7227VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount,
7228 uint32_t firstVertex, uint32_t firstInstance) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007229 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007230 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007231 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007232 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7233 if (pCB) {
7234 skipCall |= addCmd(dev_data, pCB, CMD_DRAW, "vkCmdDraw()");
7235 pCB->drawCount[DRAW]++;
Dustin Graves8f1eab92016-04-05 09:41:17 -06007236 skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007237 skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007238 // TODO : Need to pass commandBuffer as srcObj here
7239 skipCall |=
7240 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
7241 __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDraw() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW]++);
7242 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007243 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007244 updateResourceTrackingOnDraw(pCB);
7245 }
7246 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDraw");
7247 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007248 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007249 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007250 dev_data->device_dispatch_table->CmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance);
7251}
7252
7253VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount,
7254 uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset,
7255 uint32_t firstInstance) {
7256 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007257 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007258 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007259 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7260 if (pCB) {
7261 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXED, "vkCmdDrawIndexed()");
7262 pCB->drawCount[DRAW_INDEXED]++;
Dustin Graves8f1eab92016-04-05 09:41:17 -06007263 skipCall |= validate_and_update_draw_state(dev_data, pCB, true, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007264 skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007265 // TODO : Need to pass commandBuffer as srcObj here
7266 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
7267 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS",
7268 "vkCmdDrawIndexed() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDEXED]++);
7269 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007270 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007271 updateResourceTrackingOnDraw(pCB);
7272 }
7273 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexed");
7274 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007275 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007276 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007277 dev_data->device_dispatch_table->CmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset,
7278 firstInstance);
7279}
7280
7281VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7282vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
7283 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007284 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007285 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007286#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007287 VkDeviceMemory mem;
7288 // MTMTODO : merge with code below
7289 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007290 get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007291 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndirect");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007292#endif
7293 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7294 if (pCB) {
7295 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDIRECT, "vkCmdDrawIndirect()");
7296 pCB->drawCount[DRAW_INDIRECT]++;
Dustin Graves8f1eab92016-04-05 09:41:17 -06007297 skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007298 skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007299 // TODO : Need to pass commandBuffer as srcObj here
7300 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
7301 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_NONE, "DS",
7302 "vkCmdDrawIndirect() call #%" PRIu64 ", reporting DS state:", g_drawCount[DRAW_INDIRECT]++);
7303 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007304 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007305 updateResourceTrackingOnDraw(pCB);
7306 }
7307 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndirect");
7308 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007309 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007310 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007311 dev_data->device_dispatch_table->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride);
7312}
7313
7314VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7315vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007316 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007317 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007318 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007319#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007320 VkDeviceMemory mem;
7321 // MTMTODO : merge with code below
7322 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007323 get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007324 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDrawIndexedIndirect");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007325#endif
7326 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7327 if (pCB) {
7328 skipCall |= addCmd(dev_data, pCB, CMD_DRAWINDEXEDINDIRECT, "vkCmdDrawIndexedIndirect()");
7329 pCB->drawCount[DRAW_INDEXED_INDIRECT]++;
Dustin Graves8f1eab92016-04-05 09:41:17 -06007330 skipCall |= validate_and_update_draw_state(dev_data, pCB, true, VK_PIPELINE_BIND_POINT_GRAPHICS);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007331 skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007332 // TODO : Need to pass commandBuffer as srcObj here
7333 skipCall |=
7334 log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
7335 __LINE__, DRAWSTATE_NONE, "DS", "vkCmdDrawIndexedIndirect() call #%" PRIu64 ", reporting DS state:",
7336 g_drawCount[DRAW_INDEXED_INDIRECT]++);
7337 skipCall |= synchAndPrintDSConfig(dev_data, commandBuffer);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007338 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007339 updateResourceTrackingOnDraw(pCB);
7340 }
7341 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdDrawIndexedIndirect");
7342 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007343 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007344 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007345 dev_data->device_dispatch_table->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride);
7346}
7347
7348VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007349 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007350 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007351 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007352 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7353 if (pCB) {
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007354 // TODO : Re-enable validate_and_update_draw_state() when it supports compute shaders
Dustin Graves8f1eab92016-04-05 09:41:17 -06007355 // skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_COMPUTE);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007356 // TODO : Call below is temporary until call above can be re-enabled
7357 update_shader_storage_images_and_buffers(dev_data, pCB);
7358 skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007359 skipCall |= addCmd(dev_data, pCB, CMD_DISPATCH, "vkCmdDispatch()");
7360 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatch");
7361 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007362 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007363 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007364 dev_data->device_dispatch_table->CmdDispatch(commandBuffer, x, y, z);
7365}
7366
7367VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7368vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007369 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007370 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007371 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007372#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007373 VkDeviceMemory mem;
7374 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007375 get_mem_binding_from_object(dev_data, (uint64_t)buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007376 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdDispatchIndirect");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007377#endif
7378 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7379 if (pCB) {
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007380 // TODO : Re-enable validate_and_update_draw_state() when it supports compute shaders
Dustin Graves8f1eab92016-04-05 09:41:17 -06007381 // skipCall |= validate_and_update_draw_state(dev_data, pCB, false, VK_PIPELINE_BIND_POINT_COMPUTE);
Tobin Ehlis2e319d42016-03-25 11:49:51 -06007382 // TODO : Call below is temporary until call above can be re-enabled
7383 update_shader_storage_images_and_buffers(dev_data, pCB);
7384 skipCall |= markStoreImagesAndBuffersAsWritten(dev_data, pCB);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007385 skipCall |= addCmd(dev_data, pCB, CMD_DISPATCHINDIRECT, "vkCmdDispatchIndirect()");
7386 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdDispatchIndirect");
7387 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007388 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007389 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007390 dev_data->device_dispatch_table->CmdDispatchIndirect(commandBuffer, buffer, offset);
7391}
7392
7393VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
7394 uint32_t regionCount, const VkBufferCopy *pRegions) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007395 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007396 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007397 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007398#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007399 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007400 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007401 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007402 get_mem_binding_from_object(dev_data, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007403 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007404 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBuffer()"); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007405 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007406 }
7407 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer");
7408 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007409 get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007410 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007411 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007412 set_memory_valid(dev_data, mem, true);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007413 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007414 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007415 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007416 }
7417 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBuffer");
7418 // Validate that SRC & DST buffers have correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007419 skipCall |= validate_buffer_usage_flags(dev_data, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007420 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
Chris Forbes73b82b12016-04-06 15:16:26 +12007421 skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007422 "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7423#endif
7424 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7425 if (pCB) {
7426 skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
7427 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBuffer");
7428 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007429 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007430 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007431 dev_data->device_dispatch_table->CmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
7432}
7433
Dustin Graves8f1eab92016-04-05 09:41:17 -06007434static bool VerifySourceImageLayout(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageSubresourceLayers subLayers,
7435 VkImageLayout srcImageLayout) {
7436 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007437
7438 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
7439 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
7440 for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
7441 uint32_t layer = i + subLayers.baseArrayLayer;
7442 VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
7443 IMAGE_CMD_BUF_LAYOUT_NODE node;
7444 if (!FindLayout(pCB, srcImage, sub, node)) {
Michael Lentine60063c22016-03-24 15:36:27 -05007445 SetLayout(pCB, srcImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(srcImageLayout, srcImageLayout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007446 continue;
7447 }
7448 if (node.layout != srcImageLayout) {
7449 // TODO: Improve log message in the next pass
7450 skip_call |=
7451 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
7452 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose source layout is %s "
7453 "and doesn't match the current layout %s.",
7454 string_VkImageLayout(srcImageLayout), string_VkImageLayout(node.layout));
7455 }
7456 }
7457 if (srcImageLayout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
7458 if (srcImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
7459 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
7460 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
7461 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
7462 "Layout for input image should be TRANSFER_SRC_OPTIMAL instead of GENERAL.");
7463 } else {
7464 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
7465 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for input image is %s but can only be "
7466 "TRANSFER_SRC_OPTIMAL or GENERAL.",
7467 string_VkImageLayout(srcImageLayout));
7468 }
7469 }
7470 return skip_call;
7471}
7472
Dustin Graves8f1eab92016-04-05 09:41:17 -06007473static bool VerifyDestImageLayout(VkCommandBuffer cmdBuffer, VkImage destImage, VkImageSubresourceLayers subLayers,
7474 VkImageLayout destImageLayout) {
7475 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007476
7477 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
7478 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
7479 for (uint32_t i = 0; i < subLayers.layerCount; ++i) {
7480 uint32_t layer = i + subLayers.baseArrayLayer;
7481 VkImageSubresource sub = {subLayers.aspectMask, subLayers.mipLevel, layer};
7482 IMAGE_CMD_BUF_LAYOUT_NODE node;
7483 if (!FindLayout(pCB, destImage, sub, node)) {
Michael Lentine60063c22016-03-24 15:36:27 -05007484 SetLayout(pCB, destImage, sub, IMAGE_CMD_BUF_LAYOUT_NODE(destImageLayout, destImageLayout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007485 continue;
7486 }
7487 if (node.layout != destImageLayout) {
7488 skip_call |=
7489 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0,
7490 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot copy from an image whose dest layout is %s and "
7491 "doesn't match the current layout %s.",
7492 string_VkImageLayout(destImageLayout), string_VkImageLayout(node.layout));
7493 }
7494 }
7495 if (destImageLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
7496 if (destImageLayout == VK_IMAGE_LAYOUT_GENERAL) {
7497 // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
7498 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
7499 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
7500 "Layout for output image should be TRANSFER_DST_OPTIMAL instead of GENERAL.");
7501 } else {
7502 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
7503 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Layout for output image is %s but can only be "
7504 "TRANSFER_DST_OPTIMAL or GENERAL.",
7505 string_VkImageLayout(destImageLayout));
7506 }
7507 }
7508 return skip_call;
7509}
7510
7511VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7512vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
7513 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007514 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007515 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007516 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007517#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007518 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007519 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007520 // Validate that src & dst images have correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007521 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007522 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007523 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImage()", srcImage); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007524 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007525 }
7526 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage");
7527 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007528 get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007529 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007530 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007531 set_memory_valid(dev_data, mem, true, dstImage);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007532 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007533 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007534 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007535 }
7536 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImage");
Chris Forbes73b82b12016-04-06 15:16:26 +12007537 skipCall |= validate_image_usage_flags(dev_data, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007538 "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
Chris Forbes73b82b12016-04-06 15:16:26 +12007539 skipCall |= validate_image_usage_flags(dev_data, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007540 "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
7541#endif
7542 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7543 if (pCB) {
7544 skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGE, "vkCmdCopyImage()");
7545 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImage");
7546 for (uint32_t i = 0; i < regionCount; ++i) {
7547 skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].srcSubresource, srcImageLayout);
7548 skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].dstSubresource, dstImageLayout);
7549 }
7550 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007551 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007552 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007553 dev_data->device_dispatch_table->CmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
7554 regionCount, pRegions);
7555}
7556
7557VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7558vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
7559 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007560 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007561 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007562 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007563#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007564 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007565 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007566 // Validate that src & dst images have correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007567 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007568 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007569 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdBlitImage()", srcImage); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007570 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007571 }
7572 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage");
7573 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007574 get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007575 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007576 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007577 set_memory_valid(dev_data, mem, true, dstImage);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007578 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007579 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007580 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007581 }
7582 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdBlitImage");
Chris Forbes73b82b12016-04-06 15:16:26 +12007583 skipCall |= validate_image_usage_flags(dev_data, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007584 "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
Chris Forbes73b82b12016-04-06 15:16:26 +12007585 skipCall |= validate_image_usage_flags(dev_data, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007586 "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
7587#endif
7588 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7589 if (pCB) {
7590 skipCall |= addCmd(dev_data, pCB, CMD_BLITIMAGE, "vkCmdBlitImage()");
7591 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBlitImage");
7592 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007593 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007594 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007595 dev_data->device_dispatch_table->CmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
7596 regionCount, pRegions, filter);
7597}
7598
7599VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer,
7600 VkImage dstImage, VkImageLayout dstImageLayout,
7601 uint32_t regionCount, const VkBufferImageCopy *pRegions) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007602 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007603 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007604 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007605#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007606 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007607 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Chris Forbes73b82b12016-04-06 15:16:26 +12007608 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007609 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007610 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007611 set_memory_valid(dev_data, mem, true, dstImage);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007612 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007613 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007614 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007615 }
7616 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage");
7617 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007618 get_mem_binding_from_object(dev_data, (uint64_t)srcBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007619 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007620 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdCopyBufferToImage()"); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007621 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007622 }
7623 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyBufferToImage");
7624 // Validate that src buff & dst image have correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007625 skipCall |= validate_buffer_usage_flags(dev_data, srcBuffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007626 "vkCmdCopyBufferToImage()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
Chris Forbes73b82b12016-04-06 15:16:26 +12007627 skipCall |= validate_image_usage_flags(dev_data, dstImage, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007628 "vkCmdCopyBufferToImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
7629#endif
7630 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7631 if (pCB) {
7632 skipCall |= addCmd(dev_data, pCB, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
7633 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyBufferToImage");
7634 for (uint32_t i = 0; i < regionCount; ++i) {
7635 skipCall |= VerifyDestImageLayout(commandBuffer, dstImage, pRegions[i].imageSubresource, dstImageLayout);
7636 }
7637 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007638 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007639 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007640 dev_data->device_dispatch_table->CmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount,
7641 pRegions);
7642}
7643
7644VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
7645 VkImageLayout srcImageLayout, VkBuffer dstBuffer,
7646 uint32_t regionCount, const VkBufferImageCopy *pRegions) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007647 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007648 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007649 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007650#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007651 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007652 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Chris Forbes73b82b12016-04-06 15:16:26 +12007653 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007654 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007655 std::function<bool()> function = [=]() {
7656 return validate_memory_is_valid(dev_data, mem, "vkCmdCopyImageToBuffer()", srcImage);
7657 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007658 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007659 }
7660 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer");
7661 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007662 get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007663 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007664 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007665 set_memory_valid(dev_data, mem, true);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007666 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007667 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007668 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007669 }
7670 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyImageToBuffer");
7671 // Validate that dst buff & src image have correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007672 skipCall |= validate_image_usage_flags(dev_data, srcImage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007673 "vkCmdCopyImageToBuffer()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
Chris Forbes73b82b12016-04-06 15:16:26 +12007674 skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007675 "vkCmdCopyImageToBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7676#endif
7677 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7678 if (pCB) {
7679 skipCall |= addCmd(dev_data, pCB, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
7680 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyImageToBuffer");
7681 for (uint32_t i = 0; i < regionCount; ++i) {
7682 skipCall |= VerifySourceImageLayout(commandBuffer, srcImage, pRegions[i].imageSubresource, srcImageLayout);
7683 }
7684 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007685 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007686 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007687 dev_data->device_dispatch_table->CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount,
7688 pRegions);
7689}
7690
7691VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
7692 VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t *pData) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007693 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007694 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007695 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007696#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007697 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007698 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007699 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007700 get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007701 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007702 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007703 set_memory_valid(dev_data, mem, true);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007704 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007705 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007706 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007707 }
7708 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdUpdateBuffer");
7709 // Validate that dst buff has correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007710 skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007711 "vkCmdUpdateBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7712#endif
7713 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7714 if (pCB) {
7715 skipCall |= addCmd(dev_data, pCB, CMD_UPDATEBUFFER, "vkCmdUpdateBuffer()");
7716 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyUpdateBuffer");
7717 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007718 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007719 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007720 dev_data->device_dispatch_table->CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
7721}
7722
7723VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7724vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007725 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007726 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007727 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007728#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007729 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007730 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007731 skipCall =
Chris Forbes73b82b12016-04-06 15:16:26 +12007732 get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007733 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007734 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007735 set_memory_valid(dev_data, mem, true);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007736 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007737 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007738 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007739 }
7740 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdFillBuffer");
7741 // Validate that dst buff has correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12007742 skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007743 "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
7744#endif
7745 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7746 if (pCB) {
7747 skipCall |= addCmd(dev_data, pCB, CMD_FILLBUFFER, "vkCmdFillBuffer()");
7748 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyFillBuffer");
7749 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007750 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007751 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007752 dev_data->device_dispatch_table->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data);
7753}
7754
7755VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
7756 const VkClearAttachment *pAttachments, uint32_t rectCount,
7757 const VkClearRect *pRects) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007758 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007759 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007760 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007761 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7762 if (pCB) {
7763 skipCall |= addCmd(dev_data, pCB, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
7764 // Warn if this is issued prior to Draw Cmd and clearing the entire attachment
7765 if (!hasDrawCmd(pCB) && (pCB->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) &&
7766 (pCB->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) {
7767 // TODO : commandBuffer should be srcObj
7768 // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
7769 // Can we make this warning more specific? I'd like to avoid triggering this test if we can tell it's a use that must
7770 // call CmdClearAttachments
7771 // Otherwise this seems more like a performance warning.
7772 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
7773 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, 0, DRAWSTATE_CLEAR_CMD_BEFORE_DRAW, "DS",
7774 "vkCmdClearAttachments() issued on CB object 0x%" PRIxLEAST64 " prior to any Draw Cmds."
7775 " It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
7776 (uint64_t)(commandBuffer));
7777 }
7778 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdClearAttachments");
7779 }
7780
7781 // Validate that attachment is in reference list of active subpass
7782 if (pCB->activeRenderPass) {
7783 const VkRenderPassCreateInfo *pRPCI = dev_data->renderPassMap[pCB->activeRenderPass]->pCreateInfo;
7784 const VkSubpassDescription *pSD = &pRPCI->pSubpasses[pCB->activeSubpass];
7785
7786 for (uint32_t attachment_idx = 0; attachment_idx < attachmentCount; attachment_idx++) {
7787 const VkClearAttachment *attachment = &pAttachments[attachment_idx];
7788 if (attachment->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007789 bool found = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007790 for (uint32_t i = 0; i < pSD->colorAttachmentCount; i++) {
7791 if (attachment->colorAttachment == pSD->pColorAttachments[i].attachment) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007792 found = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007793 break;
7794 }
7795 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06007796 if (!found) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007797 skipCall |= log_msg(
7798 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7799 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
7800 "vkCmdClearAttachments() attachment index %d not found in attachment reference array of active subpass %d",
7801 attachment->colorAttachment, pCB->activeSubpass);
7802 }
7803 } else if (attachment->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
7804 if (!pSD->pDepthStencilAttachment || // Says no DS will be used in active subpass
7805 (pSD->pDepthStencilAttachment->attachment ==
7806 VK_ATTACHMENT_UNUSED)) { // Says no DS will be used in active subpass
7807
7808 skipCall |= log_msg(
7809 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
7810 (uint64_t)commandBuffer, __LINE__, DRAWSTATE_MISSING_ATTACHMENT_REFERENCE, "DS",
7811 "vkCmdClearAttachments() attachment index %d does not match depthStencilAttachment.attachment (%d) found "
7812 "in active subpass %d",
7813 attachment->colorAttachment,
7814 (pSD->pDepthStencilAttachment) ? pSD->pDepthStencilAttachment->attachment : VK_ATTACHMENT_UNUSED,
7815 pCB->activeSubpass);
7816 }
7817 }
7818 }
7819 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007820 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007821 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007822 dev_data->device_dispatch_table->CmdClearAttachments(commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
7823}
7824
7825VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image,
7826 VkImageLayout imageLayout, const VkClearColorValue *pColor,
7827 uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007828 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007829 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007830 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007831#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007832 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
7833 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007834 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Chris Forbes73b82b12016-04-06 15:16:26 +12007835 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007836 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007837 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007838 set_memory_valid(dev_data, mem, true, image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007839 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007840 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007841 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007842 }
7843 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearColorImage");
7844#endif
7845 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7846 if (pCB) {
7847 skipCall |= addCmd(dev_data, pCB, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
7848 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearColorImage");
7849 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007850 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007851 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007852 dev_data->device_dispatch_table->CmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
7853}
7854
7855VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7856vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
7857 const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
7858 const VkImageSubresourceRange *pRanges) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007859 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007860 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007861 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007862#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007863 // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
7864 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007865 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Chris Forbes73b82b12016-04-06 15:16:26 +12007866 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007867 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007868 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007869 set_memory_valid(dev_data, mem, true, image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007870 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007871 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007872 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007873 }
7874 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdClearDepthStencilImage");
7875#endif
7876 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7877 if (pCB) {
7878 skipCall |= addCmd(dev_data, pCB, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
7879 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdClearDepthStencilImage");
7880 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007881 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007882 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007883 dev_data->device_dispatch_table->CmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount,
7884 pRanges);
7885}
7886
7887VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7888vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage,
7889 VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007890 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007891 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007892 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06007893#if MTMERGESOURCE
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007894 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007895 VkDeviceMemory mem;
Chris Forbes73b82b12016-04-06 15:16:26 +12007896 skipCall = get_mem_binding_from_object(dev_data, (uint64_t)srcImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007897 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007898 std::function<bool()> function = [=]() { return validate_memory_is_valid(dev_data, mem, "vkCmdResolveImage()", srcImage); };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007899 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007900 }
7901 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage");
7902 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12007903 get_mem_binding_from_object(dev_data, (uint64_t)dstImage, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007904 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007905 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007906 set_memory_valid(dev_data, mem, true, dstImage);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007907 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007908 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06007909 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007910 }
7911 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdResolveImage");
7912#endif
7913 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7914 if (pCB) {
7915 skipCall |= addCmd(dev_data, pCB, CMD_RESOLVEIMAGE, "vkCmdResolveImage()");
7916 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResolveImage");
7917 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007918 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007919 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007920 dev_data->device_dispatch_table->CmdResolveImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout,
7921 regionCount, pRegions);
7922}
7923
Michael Lentineb653eb22016-03-18 14:11:44 -05007924bool setEventStageMask(VkQueue queue, VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
7925 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
7926 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7927 if (pCB) {
7928 pCB->eventToStageMap[event] = stageMask;
7929 }
7930 auto queue_data = dev_data->queueMap.find(queue);
7931 if (queue_data != dev_data->queueMap.end()) {
7932 queue_data->second.eventToStageMap[event] = stageMask;
7933 }
7934 return false;
7935}
7936
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007937VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7938vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007939 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007940 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007941 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007942 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7943 if (pCB) {
7944 skipCall |= addCmd(dev_data, pCB, CMD_SETEVENT, "vkCmdSetEvent()");
7945 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdSetEvent");
7946 pCB->events.push_back(event);
Michael Lentineb653eb22016-03-18 14:11:44 -05007947 std::function<bool(VkQueue)> eventUpdate =
7948 std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, stageMask);
7949 pCB->eventUpdates.push_back(eventUpdate);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007950 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007951 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007952 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007953 dev_data->device_dispatch_table->CmdSetEvent(commandBuffer, event, stageMask);
7954}
7955
7956VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
7957vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06007958 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007959 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007960 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007961 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
7962 if (pCB) {
7963 skipCall |= addCmd(dev_data, pCB, CMD_RESETEVENT, "vkCmdResetEvent()");
7964 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdResetEvent");
7965 pCB->events.push_back(event);
Michael Lentineb653eb22016-03-18 14:11:44 -05007966 std::function<bool(VkQueue)> eventUpdate =
7967 std::bind(setEventStageMask, std::placeholders::_1, commandBuffer, event, VkPipelineStageFlags(0));
7968 pCB->eventUpdates.push_back(eventUpdate);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007969 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06007970 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06007971 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007972 dev_data->device_dispatch_table->CmdResetEvent(commandBuffer, event, stageMask);
7973}
7974
Dustin Graves8f1eab92016-04-05 09:41:17 -06007975static bool TransitionImageLayouts(VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
7976 const VkImageMemoryBarrier *pImgMemBarriers) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007977 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
7978 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
Dustin Graves8f1eab92016-04-05 09:41:17 -06007979 bool skip = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07007980 uint32_t levelCount = 0;
7981 uint32_t layerCount = 0;
7982
7983 for (uint32_t i = 0; i < memBarrierCount; ++i) {
7984 auto mem_barrier = &pImgMemBarriers[i];
7985 if (!mem_barrier)
7986 continue;
7987 // TODO: Do not iterate over every possibility - consolidate where
7988 // possible
7989 ResolveRemainingLevelsLayers(dev_data, &levelCount, &layerCount, mem_barrier->subresourceRange, mem_barrier->image);
7990
7991 for (uint32_t j = 0; j < levelCount; j++) {
7992 uint32_t level = mem_barrier->subresourceRange.baseMipLevel + j;
7993 for (uint32_t k = 0; k < layerCount; k++) {
7994 uint32_t layer = mem_barrier->subresourceRange.baseArrayLayer + k;
7995 VkImageSubresource sub = {mem_barrier->subresourceRange.aspectMask, level, layer};
7996 IMAGE_CMD_BUF_LAYOUT_NODE node;
7997 if (!FindLayout(pCB, mem_barrier->image, sub, node)) {
Michael Lentine60063c22016-03-24 15:36:27 -05007998 SetLayout(pCB, mem_barrier->image, sub,
7999 IMAGE_CMD_BUF_LAYOUT_NODE(mem_barrier->oldLayout, mem_barrier->newLayout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008000 continue;
8001 }
8002 if (mem_barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
8003 // TODO: Set memory invalid which is in mem_tracker currently
8004 } else if (node.layout != mem_barrier->oldLayout) {
8005 skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8006 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "You cannot transition the layout from %s "
8007 "when current layout is %s.",
8008 string_VkImageLayout(mem_barrier->oldLayout), string_VkImageLayout(node.layout));
8009 }
8010 SetLayout(pCB, mem_barrier->image, sub, mem_barrier->newLayout);
8011 }
8012 }
8013 }
8014 return skip;
8015}
8016
8017// Print readable FlagBits in FlagMask
Dustin Graves8f1eab92016-04-05 09:41:17 -06008018static std::string string_VkAccessFlags(VkAccessFlags accessMask) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008019 std::string result;
8020 std::string separator;
8021
8022 if (accessMask == 0) {
8023 result = "[None]";
8024 } else {
8025 result = "[";
8026 for (auto i = 0; i < 32; i++) {
8027 if (accessMask & (1 << i)) {
8028 result = result + separator + string_VkAccessFlagBits((VkAccessFlagBits)(1 << i));
8029 separator = " | ";
8030 }
8031 }
8032 result = result + "]";
8033 }
8034 return result;
8035}
8036
8037// AccessFlags MUST have 'required_bit' set, and may have one or more of 'optional_bits' set.
8038// If required_bit is zero, accessMask must have at least one of 'optional_bits' set
8039// TODO: Add tracking to ensure that at least one barrier has been set for these layout transitions
Dustin Graves8f1eab92016-04-05 09:41:17 -06008040static bool ValidateMaskBits(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
8041 const VkImageLayout &layout, VkAccessFlags required_bit, VkAccessFlags optional_bits,
8042 const char *type) {
8043 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008044
8045 if ((accessMask & required_bit) || (!required_bit && (accessMask & optional_bits))) {
8046 if (accessMask & !(required_bit | optional_bits)) {
8047 // TODO: Verify against Valid Use
8048 skip_call |=
8049 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8050 DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.",
8051 type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
8052 }
8053 } else {
8054 if (!required_bit) {
Michael Lentine02508232016-04-13 17:12:57 -05008055 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008056 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must contain at least one of access bits %d "
8057 "%s when layout is %s, unless the app has previously added a "
8058 "barrier for this transition.",
8059 type, accessMask, string_VkAccessFlags(accessMask).c_str(), optional_bits,
8060 string_VkAccessFlags(optional_bits).c_str(), string_VkImageLayout(layout));
8061 } else {
8062 std::string opt_bits;
8063 if (optional_bits != 0) {
8064 std::stringstream ss;
8065 ss << optional_bits;
8066 opt_bits = "and may have optional bits " + ss.str() + ' ' + string_VkAccessFlags(optional_bits);
8067 }
Michael Lentine02508232016-04-13 17:12:57 -05008068 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008069 DRAWSTATE_INVALID_BARRIER, "DS", "%s AccessMask %d %s must have required access bit %d %s %s when "
8070 "layout is %s, unless the app has previously added a barrier for "
8071 "this transition.",
8072 type, accessMask, string_VkAccessFlags(accessMask).c_str(), required_bit,
8073 string_VkAccessFlags(required_bit).c_str(), opt_bits.c_str(), string_VkImageLayout(layout));
8074 }
8075 }
8076 return skip_call;
8077}
8078
Dustin Graves8f1eab92016-04-05 09:41:17 -06008079static bool ValidateMaskBitsFromLayouts(const layer_data *my_data, VkCommandBuffer cmdBuffer, const VkAccessFlags &accessMask,
8080 const VkImageLayout &layout, const char *type) {
8081 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008082 switch (layout) {
8083 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: {
8084 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
8085 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, type);
8086 break;
8087 }
8088 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: {
8089 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
8090 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, type);
8091 break;
8092 }
8093 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: {
8094 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, type);
8095 break;
8096 }
8097 case VK_IMAGE_LAYOUT_PREINITIALIZED: {
8098 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_HOST_WRITE_BIT, 0, type);
8099 break;
8100 }
8101 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: {
8102 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
8103 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
8104 break;
8105 }
8106 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: {
8107 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, 0,
8108 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT, type);
8109 break;
8110 }
8111 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: {
8112 skip_call |= ValidateMaskBits(my_data, cmdBuffer, accessMask, layout, VK_ACCESS_TRANSFER_READ_BIT, 0, type);
8113 break;
8114 }
8115 case VK_IMAGE_LAYOUT_UNDEFINED: {
8116 if (accessMask != 0) {
8117 // TODO: Verify against Valid Use section spec
8118 skip_call |=
8119 log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8120 DRAWSTATE_INVALID_BARRIER, "DS", "Additional bits in %s accessMask %d %s are specified when layout is %s.",
8121 type, accessMask, string_VkAccessFlags(accessMask).c_str(), string_VkImageLayout(layout));
8122 }
8123 break;
8124 }
8125 case VK_IMAGE_LAYOUT_GENERAL:
8126 default: { break; }
8127 }
8128 return skip_call;
8129}
8130
Dustin Graves8f1eab92016-04-05 09:41:17 -06008131static bool ValidateBarriers(const char *funcName, VkCommandBuffer cmdBuffer, uint32_t memBarrierCount,
8132 const VkMemoryBarrier *pMemBarriers, uint32_t bufferBarrierCount,
8133 const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
8134 const VkImageMemoryBarrier *pImageMemBarriers) {
8135 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008136 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
8137 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
8138 if (pCB->activeRenderPass && memBarrierCount) {
8139 if (!dev_data->renderPassMap[pCB->activeRenderPass]->hasSelfDependency[pCB->activeSubpass]) {
8140 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8141 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Barriers cannot be set during subpass %d "
8142 "with no self dependency specified.",
8143 funcName, pCB->activeSubpass);
8144 }
8145 }
8146 for (uint32_t i = 0; i < imageMemBarrierCount; ++i) {
8147 auto mem_barrier = &pImageMemBarriers[i];
8148 auto image_data = dev_data->imageMap.find(mem_barrier->image);
8149 if (image_data != dev_data->imageMap.end()) {
8150 uint32_t src_q_f_index = mem_barrier->srcQueueFamilyIndex;
8151 uint32_t dst_q_f_index = mem_barrier->dstQueueFamilyIndex;
8152 if (image_data->second.createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) {
8153 // srcQueueFamilyIndex and dstQueueFamilyIndex must both
8154 // be VK_QUEUE_FAMILY_IGNORED
8155 if ((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) {
8156 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8157 __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8158 "%s: Image Barrier for image 0x%" PRIx64 " was created with sharingMode of "
8159 "VK_SHARING_MODE_CONCURRENT. Src and dst "
8160 " queueFamilyIndices must be VK_QUEUE_FAMILY_IGNORED.",
8161 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
8162 }
8163 } else {
8164 // Sharing mode is VK_SHARING_MODE_EXCLUSIVE. srcQueueFamilyIndex and
8165 // dstQueueFamilyIndex must either both be VK_QUEUE_FAMILY_IGNORED,
8166 // or both be a valid queue family
8167 if (((src_q_f_index == VK_QUEUE_FAMILY_IGNORED) || (dst_q_f_index == VK_QUEUE_FAMILY_IGNORED)) &&
8168 (src_q_f_index != dst_q_f_index)) {
8169 skip_call |=
8170 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8171 DRAWSTATE_INVALID_QUEUE_INDEX, "DS", "%s: Image 0x%" PRIx64 " was created with sharingMode "
8172 "of VK_SHARING_MODE_EXCLUSIVE. If one of src- or "
8173 "dstQueueFamilyIndex is VK_QUEUE_FAMILY_IGNORED, both "
8174 "must be.",
8175 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image));
8176 } else if (((src_q_f_index != VK_QUEUE_FAMILY_IGNORED) && (dst_q_f_index != VK_QUEUE_FAMILY_IGNORED)) &&
Tobin Ehlise54be7b2016-04-11 14:49:55 -06008177 ((src_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
8178 (dst_q_f_index >= dev_data->phys_dev_properties.queue_family_properties.size()))) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008179 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8180 __LINE__, DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8181 "%s: Image 0x%" PRIx64 " was created with sharingMode "
8182 "of VK_SHARING_MODE_EXCLUSIVE, but srcQueueFamilyIndex %d"
8183 " or dstQueueFamilyIndex %d is greater than " PRINTF_SIZE_T_SPECIFIER
8184 "queueFamilies crated for this device.",
8185 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->image), src_q_f_index,
Tobin Ehlise54be7b2016-04-11 14:49:55 -06008186 dst_q_f_index, dev_data->phys_dev_properties.queue_family_properties.size());
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008187 }
8188 }
8189 }
8190
8191 if (mem_barrier) {
8192 skip_call |=
8193 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->srcAccessMask, mem_barrier->oldLayout, "Source");
8194 skip_call |=
8195 ValidateMaskBitsFromLayouts(dev_data, cmdBuffer, mem_barrier->dstAccessMask, mem_barrier->newLayout, "Dest");
8196 if (mem_barrier->newLayout == VK_IMAGE_LAYOUT_UNDEFINED || mem_barrier->newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
8197 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8198 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image Layout cannot be transitioned to UNDEFINED or "
8199 "PREINITIALIZED.",
8200 funcName);
8201 }
8202 auto image_data = dev_data->imageMap.find(mem_barrier->image);
Jamie Madill2b6b8d52016-04-04 15:09:51 -04008203 VkFormat format = VK_FORMAT_UNDEFINED;
8204 uint32_t arrayLayers = 0, mipLevels = 0;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008205 bool imageFound = false;
8206 if (image_data != dev_data->imageMap.end()) {
8207 format = image_data->second.createInfo.format;
8208 arrayLayers = image_data->second.createInfo.arrayLayers;
8209 mipLevels = image_data->second.createInfo.mipLevels;
8210 imageFound = true;
8211 } else if (dev_data->device_extensions.wsi_enabled) {
8212 auto imageswap_data = dev_data->device_extensions.imageToSwapchainMap.find(mem_barrier->image);
8213 if (imageswap_data != dev_data->device_extensions.imageToSwapchainMap.end()) {
8214 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(imageswap_data->second);
8215 if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) {
8216 format = swapchain_data->second->createInfo.imageFormat;
8217 arrayLayers = swapchain_data->second->createInfo.imageArrayLayers;
8218 mipLevels = 1;
8219 imageFound = true;
8220 }
8221 }
8222 }
8223 if (imageFound) {
8224 if (vk_format_is_depth_and_stencil(format) &&
8225 (!(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
8226 !(mem_barrier->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT))) {
8227 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8228 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Image is a depth and stencil format and thus must "
8229 "have both VK_IMAGE_ASPECT_DEPTH_BIT and "
8230 "VK_IMAGE_ASPECT_STENCIL_BIT set.",
8231 funcName);
8232 }
Michael Lentine87e44e02016-03-18 14:49:09 -05008233 int layerCount = (mem_barrier->subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS)
8234 ? 1
8235 : mem_barrier->subresourceRange.layerCount;
8236 if ((mem_barrier->subresourceRange.baseArrayLayer + layerCount) > arrayLayers) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008237 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8238 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the "
8239 "baseArrayLayer (%d) and layerCount (%d) be less "
8240 "than or equal to the total number of layers (%d).",
8241 funcName, mem_barrier->subresourceRange.baseArrayLayer, mem_barrier->subresourceRange.layerCount,
8242 arrayLayers);
8243 }
Michael Lentine87e44e02016-03-18 14:49:09 -05008244 int levelCount = (mem_barrier->subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS)
8245 ? 1
8246 : mem_barrier->subresourceRange.levelCount;
8247 if ((mem_barrier->subresourceRange.baseMipLevel + levelCount) > mipLevels) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008248 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8249 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Subresource must have the sum of the baseMipLevel "
8250 "(%d) and levelCount (%d) be less than or equal to "
8251 "the total number of levels (%d).",
8252 funcName, mem_barrier->subresourceRange.baseMipLevel, mem_barrier->subresourceRange.levelCount,
8253 mipLevels);
8254 }
8255 }
8256 }
8257 }
8258 for (uint32_t i = 0; i < bufferBarrierCount; ++i) {
8259 auto mem_barrier = &pBufferMemBarriers[i];
8260 if (pCB->activeRenderPass) {
8261 skip_call |=
8262 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8263 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barriers cannot be used during a render pass.", funcName);
8264 }
8265 if (!mem_barrier)
8266 continue;
8267
8268 // Validate buffer barrier queue family indices
8269 if ((mem_barrier->srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
Tobin Ehlise54be7b2016-04-11 14:49:55 -06008270 mem_barrier->srcQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size()) ||
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008271 (mem_barrier->dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED &&
Tobin Ehlise54be7b2016-04-11 14:49:55 -06008272 mem_barrier->dstQueueFamilyIndex >= dev_data->phys_dev_properties.queue_family_properties.size())) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008273 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8274 DRAWSTATE_INVALID_QUEUE_INDEX, "DS",
8275 "%s: Buffer Barrier 0x%" PRIx64 " has QueueFamilyIndex greater "
8276 "than the number of QueueFamilies (" PRINTF_SIZE_T_SPECIFIER ") for this device.",
8277 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
Tobin Ehlise54be7b2016-04-11 14:49:55 -06008278 dev_data->phys_dev_properties.queue_family_properties.size());
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008279 }
8280
8281 auto buffer_data = dev_data->bufferMap.find(mem_barrier->buffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008282 if (buffer_data != dev_data->bufferMap.end()) {
Karl Schultz9e66a292016-04-21 15:57:51 -06008283 VkDeviceSize buffer_size = (buffer_data->second.createInfo.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO)
8284 ? buffer_data->second.createInfo.size
8285 : 0;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008286 if (mem_barrier->offset >= buffer_size) {
Tobin Ehlisf263ba42016-04-05 13:33:00 -06008287 skip_call |= log_msg(
8288 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8289 DRAWSTATE_INVALID_BARRIER, "DS",
8290 "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 " which is not less than total size %" PRIu64 ".",
8291 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8292 reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(buffer_size));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008293 } else if (mem_barrier->size != VK_WHOLE_SIZE && (mem_barrier->offset + mem_barrier->size > buffer_size)) {
Tobin Ehlisf263ba42016-04-05 13:33:00 -06008294 skip_call |= log_msg(
8295 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8296 DRAWSTATE_INVALID_BARRIER, "DS", "%s: Buffer Barrier 0x%" PRIx64 " has offset %" PRIu64 " and size %" PRIu64
8297 " whose sum is greater than total size %" PRIu64 ".",
8298 funcName, reinterpret_cast<const uint64_t &>(mem_barrier->buffer),
8299 reinterpret_cast<const uint64_t &>(mem_barrier->offset), reinterpret_cast<const uint64_t &>(mem_barrier->size),
8300 reinterpret_cast<const uint64_t &>(buffer_size));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008301 }
8302 }
8303 }
8304 return skip_call;
8305}
8306
Chris Forbesf321eba2016-03-31 11:22:37 +13008307bool validateEventStageMask(VkQueue queue, GLOBAL_CB_NODE *pCB, uint32_t eventCount, size_t firstEventIndex, VkPipelineStageFlags sourceStageMask) {
Michael Lentineb653eb22016-03-18 14:11:44 -05008308 bool skip_call = false;
8309 VkPipelineStageFlags stageMask = 0;
8310 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
8311 for (uint32_t i = 0; i < eventCount; ++i) {
Chris Forbesf321eba2016-03-31 11:22:37 +13008312 auto event = pCB->events[firstEventIndex + i];
Michael Lentineb653eb22016-03-18 14:11:44 -05008313 auto queue_data = dev_data->queueMap.find(queue);
8314 if (queue_data == dev_data->queueMap.end())
8315 return false;
Chris Forbesf321eba2016-03-31 11:22:37 +13008316 auto event_data = queue_data->second.eventToStageMap.find(event);
Michael Lentineb653eb22016-03-18 14:11:44 -05008317 if (event_data != queue_data->second.eventToStageMap.end()) {
8318 stageMask |= event_data->second;
8319 } else {
Chris Forbesf321eba2016-03-31 11:22:37 +13008320 auto global_event_data = dev_data->eventMap.find(event);
Michael Lentineb653eb22016-03-18 14:11:44 -05008321 if (global_event_data == dev_data->eventMap.end()) {
8322 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
Chris Forbes0fa92212016-03-31 11:47:29 +13008323 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_INVALID_EVENT, "DS",
8324 "Event 0x%" PRIx64 " cannot be waited on if it has never been set.",
Chris Forbesf321eba2016-03-31 11:22:37 +13008325 reinterpret_cast<const uint64_t &>(event));
Michael Lentineb653eb22016-03-18 14:11:44 -05008326 } else {
8327 stageMask |= global_event_data->second.stageMask;
8328 }
8329 }
8330 }
8331 if (sourceStageMask != stageMask) {
8332 skip_call |=
8333 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Chris Forbes0fa92212016-03-31 11:47:29 +13008334 DRAWSTATE_INVALID_EVENT, "DS",
Michael Lentineb653eb22016-03-18 14:11:44 -05008335 "Submitting cmdbuffer with call to VkCmdWaitEvents using srcStageMask 0x%x which must be the bitwise OR of the "
8336 "stageMask parameters used in calls to vkCmdSetEvent and VK_PIPELINE_STAGE_HOST_BIT if used with vkSetEvent.",
8337 sourceStageMask);
8338 }
8339 return skip_call;
8340}
8341
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008342VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
8343vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags sourceStageMask,
8344 VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8345 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8346 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008347 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008348 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008349 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008350 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8351 if (pCB) {
Chris Forbesf321eba2016-03-31 11:22:37 +13008352 auto firstEventIndex = pCB->events.size();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008353 for (uint32_t i = 0; i < eventCount; ++i) {
8354 pCB->waitedEvents.push_back(pEvents[i]);
8355 pCB->events.push_back(pEvents[i]);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008356 }
Michael Lentineb653eb22016-03-18 14:11:44 -05008357 std::function<bool(VkQueue)> eventUpdate =
Chris Forbesf321eba2016-03-31 11:22:37 +13008358 std::bind(validateEventStageMask, std::placeholders::_1, pCB, eventCount, firstEventIndex, sourceStageMask);
Michael Lentineb653eb22016-03-18 14:11:44 -05008359 pCB->eventUpdates.push_back(eventUpdate);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008360 if (pCB->state == CB_RECORDING) {
8361 skipCall |= addCmd(dev_data, pCB, CMD_WAITEVENTS, "vkCmdWaitEvents()");
8362 } else {
8363 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWaitEvents()");
8364 }
8365 skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8366 skipCall |=
8367 ValidateBarriers("vkCmdWaitEvents", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8368 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
8369 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008370 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008371 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008372 dev_data->device_dispatch_table->CmdWaitEvents(commandBuffer, eventCount, pEvents, sourceStageMask, dstStageMask,
8373 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8374 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
8375}
8376
8377VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
8378vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
8379 VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
8380 uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
8381 uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008382 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008383 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008384 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008385 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8386 if (pCB) {
8387 skipCall |= addCmd(dev_data, pCB, CMD_PIPELINEBARRIER, "vkCmdPipelineBarrier()");
8388 skipCall |= TransitionImageLayouts(commandBuffer, imageMemoryBarrierCount, pImageMemoryBarriers);
8389 skipCall |=
8390 ValidateBarriers("vkCmdPipelineBarrier", commandBuffer, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8391 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
8392 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008393 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008394 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008395 dev_data->device_dispatch_table->CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
8396 memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
8397 pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
8398}
8399
8400VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
8401vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkFlags flags) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008402 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008403 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008404 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008405 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8406 if (pCB) {
8407 QueryObject query = {queryPool, slot};
8408 pCB->activeQueries.insert(query);
8409 if (!pCB->startedQueries.count(query)) {
8410 pCB->startedQueries.insert(query);
8411 }
8412 skipCall |= addCmd(dev_data, pCB, CMD_BEGINQUERY, "vkCmdBeginQuery()");
8413 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008414 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008415 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008416 dev_data->device_dispatch_table->CmdBeginQuery(commandBuffer, queryPool, slot, flags);
8417}
8418
8419VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008420 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008421 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008422 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008423 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8424 if (pCB) {
8425 QueryObject query = {queryPool, slot};
8426 if (!pCB->activeQueries.count(query)) {
8427 skipCall |=
8428 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8429 DRAWSTATE_INVALID_QUERY, "DS", "Ending a query before it was started: queryPool %" PRIu64 ", index %d",
8430 (uint64_t)(queryPool), slot);
8431 } else {
8432 pCB->activeQueries.erase(query);
8433 }
8434 pCB->queryToStateMap[query] = 1;
8435 if (pCB->state == CB_RECORDING) {
8436 skipCall |= addCmd(dev_data, pCB, CMD_ENDQUERY, "VkCmdEndQuery()");
8437 } else {
8438 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdEndQuery()");
8439 }
8440 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008441 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008442 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008443 dev_data->device_dispatch_table->CmdEndQuery(commandBuffer, queryPool, slot);
8444}
8445
8446VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
8447vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008448 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008449 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008450 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008451 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8452 if (pCB) {
8453 for (uint32_t i = 0; i < queryCount; i++) {
8454 QueryObject query = {queryPool, firstQuery + i};
8455 pCB->waitedEventsBeforeQueryReset[query] = pCB->waitedEvents;
8456 pCB->queryToStateMap[query] = 0;
8457 }
8458 if (pCB->state == CB_RECORDING) {
8459 skipCall |= addCmd(dev_data, pCB, CMD_RESETQUERYPOOL, "VkCmdResetQueryPool()");
8460 } else {
8461 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdResetQueryPool()");
8462 }
8463 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdQueryPool");
8464 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008465 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008466 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008467 dev_data->device_dispatch_table->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount);
8468}
8469
8470VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
8471vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount,
8472 VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008473 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008474 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008475 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008476 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06008477#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008478 VkDeviceMemory mem;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06008479 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008480 skipCall |=
Chris Forbes73b82b12016-04-06 15:16:26 +12008481 get_mem_binding_from_object(dev_data, (uint64_t)dstBuffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, &mem);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06008482 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008483 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008484 set_memory_valid(dev_data, mem, true);
Dustin Graves8f1eab92016-04-05 09:41:17 -06008485 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008486 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06008487 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008488 }
8489 skipCall |= update_cmd_buf_and_mem_references(dev_data, commandBuffer, mem, "vkCmdCopyQueryPoolResults");
8490 // Validate that DST buffer has correct usage flags set
Chris Forbes73b82b12016-04-06 15:16:26 +12008491 skipCall |= validate_buffer_usage_flags(dev_data, dstBuffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008492 "vkCmdCopyQueryPoolResults()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
8493#endif
8494 if (pCB) {
8495 for (uint32_t i = 0; i < queryCount; i++) {
8496 QueryObject query = {queryPool, firstQuery + i};
8497 if (!pCB->queryToStateMap[query]) {
8498 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8499 __LINE__, DRAWSTATE_INVALID_QUERY, "DS",
8500 "Requesting a copy from query to buffer with invalid query: queryPool %" PRIu64 ", index %d",
8501 (uint64_t)(queryPool), firstQuery + i);
8502 }
8503 }
8504 if (pCB->state == CB_RECORDING) {
8505 skipCall |= addCmd(dev_data, pCB, CMD_COPYQUERYPOOLRESULTS, "vkCmdCopyQueryPoolResults()");
8506 } else {
8507 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdCopyQueryPoolResults()");
8508 }
8509 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdCopyQueryPoolResults");
8510 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008511 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008512 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008513 dev_data->device_dispatch_table->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer,
8514 dstOffset, stride, flags);
8515}
8516
8517VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout,
8518 VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size,
8519 const void *pValues) {
8520 bool skipCall = false;
8521 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008522 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008523 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8524 if (pCB) {
8525 if (pCB->state == CB_RECORDING) {
8526 skipCall |= addCmd(dev_data, pCB, CMD_PUSHCONSTANTS, "vkCmdPushConstants()");
8527 } else {
8528 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdPushConstants()");
8529 }
8530 }
Tobin Ehlise54be7b2016-04-11 14:49:55 -06008531 if ((offset + size) > dev_data->phys_dev_properties.properties.limits.maxPushConstantsSize) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008532 skipCall |= validatePushConstantSize(dev_data, offset, size, "vkCmdPushConstants()");
8533 }
8534 // TODO : Add warning if push constant update doesn't align with range
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008535 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008536 if (!skipCall)
8537 dev_data->device_dispatch_table->CmdPushConstants(commandBuffer, layout, stageFlags, offset, size, pValues);
8538}
8539
8540VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
8541vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008542 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008543 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008544 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008545 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
8546 if (pCB) {
8547 QueryObject query = {queryPool, slot};
8548 pCB->queryToStateMap[query] = 1;
8549 if (pCB->state == CB_RECORDING) {
8550 skipCall |= addCmd(dev_data, pCB, CMD_WRITETIMESTAMP, "vkCmdWriteTimestamp()");
8551 } else {
8552 skipCall |= report_error_no_cb_begin(dev_data, commandBuffer, "vkCmdWriteTimestamp()");
8553 }
8554 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008555 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06008556 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008557 dev_data->device_dispatch_table->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot);
8558}
8559
8560VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
8561 const VkAllocationCallbacks *pAllocator,
8562 VkFramebuffer *pFramebuffer) {
8563 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
8564 VkResult result = dev_data->device_dispatch_table->CreateFramebuffer(device, pCreateInfo, pAllocator, pFramebuffer);
8565 if (VK_SUCCESS == result) {
8566 // Shadow create info and store in map
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008567 std::lock_guard<std::mutex> lock(global_lock);
Chris Forbes695c2d42016-03-31 16:05:02 +13008568
8569 auto & fbNode = dev_data->frameBufferMap[*pFramebuffer];
8570 fbNode.createInfo = *pCreateInfo;
8571 if (pCreateInfo->pAttachments) {
8572 auto attachments = new VkImageView[pCreateInfo->attachmentCount];
8573 memcpy(attachments,
8574 pCreateInfo->pAttachments,
8575 pCreateInfo->attachmentCount * sizeof(VkImageView));
8576 fbNode.createInfo.pAttachments = attachments;
8577 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008578 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
8579 VkImageView view = pCreateInfo->pAttachments[i];
8580 auto view_data = dev_data->imageViewMap.find(view);
8581 if (view_data == dev_data->imageViewMap.end()) {
8582 continue;
8583 }
8584 MT_FB_ATTACHMENT_INFO fb_info;
Chris Forbes73b82b12016-04-06 15:16:26 +12008585 get_mem_binding_from_object(dev_data, (uint64_t)(view_data->second.image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008586 &fb_info.mem);
8587 fb_info.image = view_data->second.image;
Chris Forbes695c2d42016-03-31 16:05:02 +13008588 fbNode.attachments.push_back(fb_info);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008589 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008590 }
8591 return result;
8592}
8593
Dustin Graves8f1eab92016-04-05 09:41:17 -06008594static bool FindDependency(const int index, const int dependent, const std::vector<DAGNode> &subpass_to_node,
8595 std::unordered_set<uint32_t> &processed_nodes) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008596 // If we have already checked this node we have not found a dependency path so return false.
8597 if (processed_nodes.count(index))
Dustin Graves8f1eab92016-04-05 09:41:17 -06008598 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008599 processed_nodes.insert(index);
8600 const DAGNode &node = subpass_to_node[index];
8601 // Look for a dependency path. If one exists return true else recurse on the previous nodes.
8602 if (std::find(node.prev.begin(), node.prev.end(), dependent) == node.prev.end()) {
8603 for (auto elem : node.prev) {
8604 if (FindDependency(elem, dependent, subpass_to_node, processed_nodes))
Dustin Graves8f1eab92016-04-05 09:41:17 -06008605 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008606 }
8607 } else {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008608 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008609 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06008610 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008611}
8612
Dustin Graves8f1eab92016-04-05 09:41:17 -06008613static bool CheckDependencyExists(const layer_data *my_data, const int subpass, const std::vector<uint32_t> &dependent_subpasses,
8614 const std::vector<DAGNode> &subpass_to_node, bool &skip_call) {
8615 bool result = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008616 // Loop through all subpasses that share the same attachment and make sure a dependency exists
8617 for (uint32_t k = 0; k < dependent_subpasses.size(); ++k) {
Jamie Madill2b6b8d52016-04-04 15:09:51 -04008618 if (static_cast<uint32_t>(subpass) == dependent_subpasses[k])
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008619 continue;
8620 const DAGNode &node = subpass_to_node[subpass];
8621 // Check for a specified dependency between the two nodes. If one exists we are done.
8622 auto prev_elem = std::find(node.prev.begin(), node.prev.end(), dependent_subpasses[k]);
8623 auto next_elem = std::find(node.next.begin(), node.next.end(), dependent_subpasses[k]);
8624 if (prev_elem == node.prev.end() && next_elem == node.next.end()) {
8625 // If no dependency exits an implicit dependency still might. If so, warn and if not throw an error.
8626 std::unordered_set<uint32_t> processed_nodes;
8627 if (FindDependency(subpass, dependent_subpasses[k], subpass_to_node, processed_nodes) ||
8628 FindDependency(dependent_subpasses[k], subpass, subpass_to_node, processed_nodes)) {
Michael Lentine4a5a9a02016-04-14 14:46:28 -05008629 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008630 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
8631 "A dependency between subpasses %d and %d must exist but only an implicit one is specified.",
8632 subpass, dependent_subpasses[k]);
8633 } else {
8634 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
8635 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
8636 "A dependency between subpasses %d and %d must exist but one is not specified.", subpass,
8637 dependent_subpasses[k]);
Dustin Graves8f1eab92016-04-05 09:41:17 -06008638 result = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008639 }
8640 }
8641 }
8642 return result;
8643}
8644
Dustin Graves8f1eab92016-04-05 09:41:17 -06008645static bool CheckPreserved(const layer_data *my_data, const VkRenderPassCreateInfo *pCreateInfo, const int index,
8646 const uint32_t attachment, const std::vector<DAGNode> &subpass_to_node, int depth, bool &skip_call) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008647 const DAGNode &node = subpass_to_node[index];
8648 // If this node writes to the attachment return true as next nodes need to preserve the attachment.
8649 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
8650 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8651 if (attachment == subpass.pColorAttachments[j].attachment)
Dustin Graves8f1eab92016-04-05 09:41:17 -06008652 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008653 }
8654 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8655 if (attachment == subpass.pDepthStencilAttachment->attachment)
Dustin Graves8f1eab92016-04-05 09:41:17 -06008656 return true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008657 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06008658 bool result = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008659 // Loop through previous nodes and see if any of them write to the attachment.
8660 for (auto elem : node.prev) {
8661 result |= CheckPreserved(my_data, pCreateInfo, elem, attachment, subpass_to_node, depth + 1, skip_call);
8662 }
8663 // If the attachment was written to by a previous node than this node needs to preserve it.
8664 if (result && depth > 0) {
8665 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[index];
Dustin Graves8f1eab92016-04-05 09:41:17 -06008666 bool has_preserved = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008667 for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
8668 if (subpass.pPreserveAttachments[j] == attachment) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008669 has_preserved = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008670 break;
8671 }
8672 }
Dustin Graves8f1eab92016-04-05 09:41:17 -06008673 if (!has_preserved) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008674 skip_call |=
8675 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8676 DRAWSTATE_INVALID_RENDERPASS, "DS",
8677 "Attachment %d is used by a later subpass and must be preserved in subpass %d.", attachment, index);
8678 }
8679 }
8680 return result;
8681}
8682
8683template <class T> bool isRangeOverlapping(T offset1, T size1, T offset2, T size2) {
8684 return (((offset1 + size1) > offset2) && ((offset1 + size1) < (offset2 + size2))) ||
8685 ((offset1 > offset2) && (offset1 < (offset2 + size2)));
8686}
8687
8688bool isRegionOverlapping(VkImageSubresourceRange range1, VkImageSubresourceRange range2) {
8689 return (isRangeOverlapping(range1.baseMipLevel, range1.levelCount, range2.baseMipLevel, range2.levelCount) &&
8690 isRangeOverlapping(range1.baseArrayLayer, range1.layerCount, range2.baseArrayLayer, range2.layerCount));
8691}
8692
Dustin Graves8f1eab92016-04-05 09:41:17 -06008693static bool ValidateDependencies(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin,
8694 const std::vector<DAGNode> &subpass_to_node) {
8695 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008696 const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo;
8697 const VkRenderPassCreateInfo *pCreateInfo = my_data->renderPassMap.at(pRenderPassBegin->renderPass)->pCreateInfo;
8698 std::vector<std::vector<uint32_t>> output_attachment_to_subpass(pCreateInfo->attachmentCount);
8699 std::vector<std::vector<uint32_t>> input_attachment_to_subpass(pCreateInfo->attachmentCount);
8700 std::vector<std::vector<uint32_t>> overlapping_attachments(pCreateInfo->attachmentCount);
8701 // Find overlapping attachments
8702 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
8703 for (uint32_t j = i + 1; j < pCreateInfo->attachmentCount; ++j) {
8704 VkImageView viewi = pFramebufferInfo->pAttachments[i];
8705 VkImageView viewj = pFramebufferInfo->pAttachments[j];
8706 if (viewi == viewj) {
8707 overlapping_attachments[i].push_back(j);
8708 overlapping_attachments[j].push_back(i);
8709 continue;
8710 }
8711 auto view_data_i = my_data->imageViewMap.find(viewi);
8712 auto view_data_j = my_data->imageViewMap.find(viewj);
8713 if (view_data_i == my_data->imageViewMap.end() || view_data_j == my_data->imageViewMap.end()) {
8714 continue;
8715 }
8716 if (view_data_i->second.image == view_data_j->second.image &&
8717 isRegionOverlapping(view_data_i->second.subresourceRange, view_data_j->second.subresourceRange)) {
8718 overlapping_attachments[i].push_back(j);
8719 overlapping_attachments[j].push_back(i);
8720 continue;
8721 }
8722 auto image_data_i = my_data->imageMap.find(view_data_i->second.image);
8723 auto image_data_j = my_data->imageMap.find(view_data_j->second.image);
8724 if (image_data_i == my_data->imageMap.end() || image_data_j == my_data->imageMap.end()) {
8725 continue;
8726 }
8727 if (image_data_i->second.mem == image_data_j->second.mem &&
8728 isRangeOverlapping(image_data_i->second.memOffset, image_data_i->second.memSize, image_data_j->second.memOffset,
8729 image_data_j->second.memSize)) {
8730 overlapping_attachments[i].push_back(j);
8731 overlapping_attachments[j].push_back(i);
8732 }
8733 }
8734 }
8735 for (uint32_t i = 0; i < overlapping_attachments.size(); ++i) {
8736 uint32_t attachment = i;
8737 for (auto other_attachment : overlapping_attachments[i]) {
8738 if (!(pCreateInfo->pAttachments[attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
8739 skip_call |=
8740 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8741 DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't "
8742 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
8743 attachment, other_attachment);
8744 }
8745 if (!(pCreateInfo->pAttachments[other_attachment].flags & VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT)) {
8746 skip_call |=
8747 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8748 DRAWSTATE_INVALID_RENDERPASS, "DS", "Attachment %d aliases attachment %d but doesn't "
8749 "set VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT.",
8750 other_attachment, attachment);
8751 }
8752 }
8753 }
8754 // Find for each attachment the subpasses that use them.
Mark Youngf5bba552016-03-30 02:23:18 -06008755 unordered_set<uint32_t> attachmentIndices;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008756 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
8757 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
Mark Youngf5bba552016-03-30 02:23:18 -06008758 attachmentIndices.clear();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008759 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8760 uint32_t attachment = subpass.pInputAttachments[j].attachment;
8761 input_attachment_to_subpass[attachment].push_back(i);
8762 for (auto overlapping_attachment : overlapping_attachments[attachment]) {
8763 input_attachment_to_subpass[overlapping_attachment].push_back(i);
8764 }
8765 }
8766 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8767 uint32_t attachment = subpass.pColorAttachments[j].attachment;
8768 output_attachment_to_subpass[attachment].push_back(i);
8769 for (auto overlapping_attachment : overlapping_attachments[attachment]) {
8770 output_attachment_to_subpass[overlapping_attachment].push_back(i);
8771 }
Mark Youngf5bba552016-03-30 02:23:18 -06008772 attachmentIndices.insert(attachment);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008773 }
8774 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8775 uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
8776 output_attachment_to_subpass[attachment].push_back(i);
8777 for (auto overlapping_attachment : overlapping_attachments[attachment]) {
8778 output_attachment_to_subpass[overlapping_attachment].push_back(i);
8779 }
Mark Youngf5bba552016-03-30 02:23:18 -06008780
8781 if (attachmentIndices.count(attachment)) {
8782 skip_call |=
8783 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0,
8784 0, __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
8785 "Cannot use same attachment (%u) as both color and depth output in same subpass (%u).",
8786 attachment, i);
8787 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008788 }
8789 }
8790 // If there is a dependency needed make sure one exists
8791 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
8792 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
8793 // If the attachment is an input then all subpasses that output must have a dependency relationship
8794 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8795 const uint32_t &attachment = subpass.pInputAttachments[j].attachment;
8796 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
8797 }
8798 // If the attachment is an output then all subpasses that use the attachment must have a dependency relationship
8799 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8800 const uint32_t &attachment = subpass.pColorAttachments[j].attachment;
8801 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
8802 CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
8803 }
8804 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
8805 const uint32_t &attachment = subpass.pDepthStencilAttachment->attachment;
8806 CheckDependencyExists(my_data, i, output_attachment_to_subpass[attachment], subpass_to_node, skip_call);
8807 CheckDependencyExists(my_data, i, input_attachment_to_subpass[attachment], subpass_to_node, skip_call);
8808 }
8809 }
8810 // Loop through implicit dependencies, if this pass reads make sure the attachment is preserved for all passes after it was
8811 // written.
8812 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
8813 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
8814 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8815 CheckPreserved(my_data, pCreateInfo, i, subpass.pInputAttachments[j].attachment, subpass_to_node, 0, skip_call);
8816 }
8817 }
8818 return skip_call;
8819}
8820
Dustin Graves8f1eab92016-04-05 09:41:17 -06008821static bool ValidateLayouts(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo) {
8822 bool skip = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008823
8824 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
8825 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
8826 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
8827 if (subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL &&
8828 subpass.pInputAttachments[j].layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
8829 if (subpass.pInputAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) {
8830 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
8831 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
8832 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8833 "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL.");
8834 } else {
Michael Lentineacab9c82016-03-25 17:06:04 -05008835 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008836 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8837 "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.",
8838 string_VkImageLayout(subpass.pInputAttachments[j].layout));
8839 }
8840 }
8841 }
8842 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
8843 if (subpass.pColorAttachments[j].layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
8844 if (subpass.pColorAttachments[j].layout == VK_IMAGE_LAYOUT_GENERAL) {
8845 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
8846 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
8847 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8848 "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL.");
8849 } else {
Michael Lentineacab9c82016-03-25 17:06:04 -05008850 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008851 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8852 "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
8853 string_VkImageLayout(subpass.pColorAttachments[j].layout));
8854 }
8855 }
8856 }
8857 if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
8858 if (subpass.pDepthStencilAttachment->layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
8859 if (subpass.pDepthStencilAttachment->layout == VK_IMAGE_LAYOUT_GENERAL) {
8860 // TODO: Verify Valid Use in spec. I believe this is allowed (valid) but may not be optimal performance
8861 skip |= log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
8862 (VkDebugReportObjectTypeEXT)0, 0, __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8863 "Layout for depth attachment is GENERAL but should be DEPTH_STENCIL_ATTACHMENT_OPTIMAL.");
8864 } else {
8865 skip |=
Michael Lentineacab9c82016-03-25 17:06:04 -05008866 log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008867 DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
8868 "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL or GENERAL.",
8869 string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
8870 }
8871 }
8872 }
8873 }
8874 return skip;
8875}
8876
Dustin Graves8f1eab92016-04-05 09:41:17 -06008877static bool CreatePassDAG(const layer_data *my_data, VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
8878 std::vector<DAGNode> &subpass_to_node, std::vector<bool> &has_self_dependency) {
8879 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008880 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
8881 DAGNode &subpass_node = subpass_to_node[i];
8882 subpass_node.pass = i;
8883 }
8884 for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
8885 const VkSubpassDependency &dependency = pCreateInfo->pDependencies[i];
8886 if (dependency.srcSubpass > dependency.dstSubpass && dependency.srcSubpass != VK_SUBPASS_EXTERNAL &&
8887 dependency.dstSubpass != VK_SUBPASS_EXTERNAL) {
8888 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8889 DRAWSTATE_INVALID_RENDERPASS, "DS",
8890 "Depedency graph must be specified such that an earlier pass cannot depend on a later pass.");
8891 } else if (dependency.srcSubpass == VK_SUBPASS_EXTERNAL && dependency.dstSubpass == VK_SUBPASS_EXTERNAL) {
8892 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
8893 DRAWSTATE_INVALID_RENDERPASS, "DS", "The src and dest subpasses cannot both be external.");
8894 } else if (dependency.srcSubpass == dependency.dstSubpass) {
8895 has_self_dependency[dependency.srcSubpass] = true;
8896 }
8897 if (dependency.dstSubpass != VK_SUBPASS_EXTERNAL) {
8898 subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
8899 }
8900 if (dependency.srcSubpass != VK_SUBPASS_EXTERNAL) {
8901 subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
8902 }
8903 }
8904 return skip_call;
8905}
Chris Forbes90da2e92016-03-18 16:30:03 +13008906
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008907
8908VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
8909 const VkAllocationCallbacks *pAllocator,
8910 VkShaderModule *pShaderModule) {
8911 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06008912 bool skip_call = false;
Chris Forbesb4afd0f2016-04-04 10:48:35 +12008913
8914 /* Use SPIRV-Tools validator to try and catch any issues with the module itself */
8915 spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
8916 spv_const_binary_t binary { pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t) };
8917 spv_diagnostic diag = nullptr;
8918
8919 auto result = spvValidate(ctx, &binary, &diag);
8920 if (result != SPV_SUCCESS) {
8921 skip_call |= log_msg(my_data->report_data,
8922 result == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
8923 VkDebugReportObjectTypeEXT(0), 0,
8924 __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC", "SPIR-V module not valid: %s",
8925 diag && diag->error ? diag->error : "(no error text)");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008926 }
8927
Chris Forbesb4afd0f2016-04-04 10:48:35 +12008928 spvDiagnosticDestroy(diag);
8929 spvContextDestroy(ctx);
8930
Dustin Graves8f1eab92016-04-05 09:41:17 -06008931 if (skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008932 return VK_ERROR_VALIDATION_FAILED_EXT;
8933
8934 VkResult res = my_data->device_dispatch_table->CreateShaderModule(device, pCreateInfo, pAllocator, pShaderModule);
8935
8936 if (res == VK_SUCCESS) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008937 std::lock_guard<std::mutex> lock(global_lock);
Chris Forbes90da2e92016-03-18 16:30:03 +13008938 my_data->shaderModuleMap[*pShaderModule] = unique_ptr<shader_module>(new shader_module(pCreateInfo));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008939 }
8940 return res;
8941}
8942
8943VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo,
8944 const VkAllocationCallbacks *pAllocator,
8945 VkRenderPass *pRenderPass) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06008946 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008947 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008948 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008949 // Create DAG
8950 std::vector<bool> has_self_dependency(pCreateInfo->subpassCount);
8951 std::vector<DAGNode> subpass_to_node(pCreateInfo->subpassCount);
8952 skip_call |= CreatePassDAG(dev_data, device, pCreateInfo, subpass_to_node, has_self_dependency);
8953 // Validate
8954 skip_call |= ValidateLayouts(dev_data, device, pCreateInfo);
Dustin Graves8f1eab92016-04-05 09:41:17 -06008955 if (skip_call) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008956 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008957 return VK_ERROR_VALIDATION_FAILED_EXT;
8958 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008959 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008960 VkResult result = dev_data->device_dispatch_table->CreateRenderPass(device, pCreateInfo, pAllocator, pRenderPass);
8961 if (VK_SUCCESS == result) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -06008962 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07008963 // TODOSC : Merge in tracking of renderpass from shader_checker
8964 // Shadow create info and store in map
8965 VkRenderPassCreateInfo *localRPCI = new VkRenderPassCreateInfo(*pCreateInfo);
8966 if (pCreateInfo->pAttachments) {
8967 localRPCI->pAttachments = new VkAttachmentDescription[localRPCI->attachmentCount];
8968 memcpy((void *)localRPCI->pAttachments, pCreateInfo->pAttachments,
8969 localRPCI->attachmentCount * sizeof(VkAttachmentDescription));
8970 }
8971 if (pCreateInfo->pSubpasses) {
8972 localRPCI->pSubpasses = new VkSubpassDescription[localRPCI->subpassCount];
8973 memcpy((void *)localRPCI->pSubpasses, pCreateInfo->pSubpasses, localRPCI->subpassCount * sizeof(VkSubpassDescription));
8974
8975 for (uint32_t i = 0; i < localRPCI->subpassCount; i++) {
8976 VkSubpassDescription *subpass = (VkSubpassDescription *)&localRPCI->pSubpasses[i];
8977 const uint32_t attachmentCount = subpass->inputAttachmentCount +
8978 subpass->colorAttachmentCount * (1 + (subpass->pResolveAttachments ? 1 : 0)) +
8979 ((subpass->pDepthStencilAttachment) ? 1 : 0) + subpass->preserveAttachmentCount;
8980 VkAttachmentReference *attachments = new VkAttachmentReference[attachmentCount];
8981
8982 memcpy(attachments, subpass->pInputAttachments, sizeof(attachments[0]) * subpass->inputAttachmentCount);
8983 subpass->pInputAttachments = attachments;
8984 attachments += subpass->inputAttachmentCount;
8985
8986 memcpy(attachments, subpass->pColorAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount);
8987 subpass->pColorAttachments = attachments;
8988 attachments += subpass->colorAttachmentCount;
8989
8990 if (subpass->pResolveAttachments) {
8991 memcpy(attachments, subpass->pResolveAttachments, sizeof(attachments[0]) * subpass->colorAttachmentCount);
8992 subpass->pResolveAttachments = attachments;
8993 attachments += subpass->colorAttachmentCount;
8994 }
8995
8996 if (subpass->pDepthStencilAttachment) {
8997 memcpy(attachments, subpass->pDepthStencilAttachment, sizeof(attachments[0]) * 1);
8998 subpass->pDepthStencilAttachment = attachments;
8999 attachments += 1;
9000 }
9001
9002 memcpy(attachments, subpass->pPreserveAttachments, sizeof(attachments[0]) * subpass->preserveAttachmentCount);
9003 subpass->pPreserveAttachments = &attachments->attachment;
9004 }
9005 }
9006 if (pCreateInfo->pDependencies) {
9007 localRPCI->pDependencies = new VkSubpassDependency[localRPCI->dependencyCount];
9008 memcpy((void *)localRPCI->pDependencies, pCreateInfo->pDependencies,
9009 localRPCI->dependencyCount * sizeof(VkSubpassDependency));
9010 }
9011 dev_data->renderPassMap[*pRenderPass] = new RENDER_PASS_NODE(localRPCI);
9012 dev_data->renderPassMap[*pRenderPass]->hasSelfDependency = has_self_dependency;
9013 dev_data->renderPassMap[*pRenderPass]->subpassToNode = subpass_to_node;
Tobin Ehlis54948522016-03-22 13:50:21 -06009014#if MTMERGESOURCE
9015 // MTMTODO : Merge with code from above to eliminate duplication
9016 for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
9017 VkAttachmentDescription desc = pCreateInfo->pAttachments[i];
9018 MT_PASS_ATTACHMENT_INFO pass_info;
9019 pass_info.load_op = desc.loadOp;
9020 pass_info.store_op = desc.storeOp;
9021 pass_info.attachment = i;
9022 dev_data->renderPassMap[*pRenderPass]->attachments.push_back(pass_info);
9023 }
9024 // TODO: Maybe fill list and then copy instead of locking
9025 std::unordered_map<uint32_t, bool> &attachment_first_read = dev_data->renderPassMap[*pRenderPass]->attachment_first_read;
9026 std::unordered_map<uint32_t, VkImageLayout> &attachment_first_layout =
9027 dev_data->renderPassMap[*pRenderPass]->attachment_first_layout;
9028 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
9029 const VkSubpassDescription &subpass = pCreateInfo->pSubpasses[i];
Michael Lentinead3fec82016-04-06 13:15:46 -05009030 if (subpass.pipelineBindPoint != VK_PIPELINE_BIND_POINT_GRAPHICS) {
9031 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9032 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
9033 "Pipeline bind point for subpass %d must be VK_PIPELINE_BIND_POINT_GRAPHICS.", i);
9034 }
Michael Lentine5007eb92016-04-05 11:38:12 -05009035 for (uint32_t j = 0; j < subpass.preserveAttachmentCount; ++j) {
9036 uint32_t attachment = subpass.pPreserveAttachments[j];
9037 if (attachment >= pCreateInfo->attachmentCount) {
9038 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9039 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
9040 "Preserve attachment %d cannot be greater than the total number of attachments %d.",
9041 attachment, pCreateInfo->attachmentCount);
9042 }
9043 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009044 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
Michael Lentine5007eb92016-04-05 11:38:12 -05009045 uint32_t attachment;
9046 if (subpass.pResolveAttachments) {
9047 attachment = subpass.pResolveAttachments[j].attachment;
9048 if (attachment >= pCreateInfo->attachmentCount && attachment != VK_ATTACHMENT_UNUSED) {
9049 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9050 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
9051 "Color attachment %d cannot be greater than the total number of attachments %d.",
9052 attachment, pCreateInfo->attachmentCount);
9053 continue;
9054 }
9055 }
9056 attachment = subpass.pColorAttachments[j].attachment;
Michael Lentine9e1290e2016-03-31 14:45:20 -05009057 if (attachment >= pCreateInfo->attachmentCount) {
9058 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9059 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
9060 "Color attachment %d cannot be greater than the total number of attachments %d.",
9061 attachment, pCreateInfo->attachmentCount);
9062 continue;
9063 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009064 if (attachment_first_read.count(attachment))
9065 continue;
9066 attachment_first_read.insert(std::make_pair(attachment, false));
9067 attachment_first_layout.insert(std::make_pair(attachment, subpass.pColorAttachments[j].layout));
9068 }
9069 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
9070 uint32_t attachment = subpass.pDepthStencilAttachment->attachment;
Michael Lentine9e1290e2016-03-31 14:45:20 -05009071 if (attachment >= pCreateInfo->attachmentCount) {
9072 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9073 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
9074 "Depth stencil attachment %d cannot be greater than the total number of attachments %d.",
9075 attachment, pCreateInfo->attachmentCount);
9076 continue;
9077 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009078 if (attachment_first_read.count(attachment))
9079 continue;
9080 attachment_first_read.insert(std::make_pair(attachment, false));
9081 attachment_first_layout.insert(std::make_pair(attachment, subpass.pDepthStencilAttachment->layout));
9082 }
Michael Lentine4e8777c2016-03-31 13:46:44 -05009083 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
9084 uint32_t attachment = subpass.pInputAttachments[j].attachment;
Michael Lentine9e1290e2016-03-31 14:45:20 -05009085 if (attachment >= pCreateInfo->attachmentCount) {
9086 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9087 __LINE__, DRAWSTATE_INVALID_RENDERPASS, "DS",
9088 "Input attachment %d cannot be greater than the total number of attachments %d.",
9089 attachment, pCreateInfo->attachmentCount);
9090 continue;
9091 }
Michael Lentine4e8777c2016-03-31 13:46:44 -05009092 if (attachment_first_read.count(attachment))
9093 continue;
9094 attachment_first_read.insert(std::make_pair(attachment, true));
9095 attachment_first_layout.insert(std::make_pair(attachment, subpass.pInputAttachments[j].layout));
9096 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009097 }
9098#endif
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009099 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009100 }
9101 return result;
9102}
9103// Free the renderpass shadow
9104static void deleteRenderPasses(layer_data *my_data) {
9105 if (my_data->renderPassMap.size() <= 0)
9106 return;
9107 for (auto ii = my_data->renderPassMap.begin(); ii != my_data->renderPassMap.end(); ++ii) {
9108 const VkRenderPassCreateInfo *pRenderPassInfo = (*ii).second->pCreateInfo;
9109 delete[] pRenderPassInfo->pAttachments;
9110 if (pRenderPassInfo->pSubpasses) {
9111 for (uint32_t i = 0; i < pRenderPassInfo->subpassCount; ++i) {
9112 // Attachements are all allocated in a block, so just need to
9113 // find the first non-null one to delete
9114 if (pRenderPassInfo->pSubpasses[i].pInputAttachments) {
9115 delete[] pRenderPassInfo->pSubpasses[i].pInputAttachments;
9116 } else if (pRenderPassInfo->pSubpasses[i].pColorAttachments) {
9117 delete[] pRenderPassInfo->pSubpasses[i].pColorAttachments;
9118 } else if (pRenderPassInfo->pSubpasses[i].pResolveAttachments) {
9119 delete[] pRenderPassInfo->pSubpasses[i].pResolveAttachments;
9120 } else if (pRenderPassInfo->pSubpasses[i].pPreserveAttachments) {
9121 delete[] pRenderPassInfo->pSubpasses[i].pPreserveAttachments;
9122 }
9123 }
9124 delete[] pRenderPassInfo->pSubpasses;
9125 }
9126 delete[] pRenderPassInfo->pDependencies;
9127 delete pRenderPassInfo;
9128 delete (*ii).second;
9129 }
9130 my_data->renderPassMap.clear();
9131}
9132
Dustin Graves8f1eab92016-04-05 09:41:17 -06009133static bool VerifyFramebufferAndRenderPassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) {
9134 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009135 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
9136 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
9137 const VkRenderPassCreateInfo *pRenderPassInfo = dev_data->renderPassMap[pRenderPassBegin->renderPass]->pCreateInfo;
9138 const VkFramebufferCreateInfo framebufferInfo = dev_data->frameBufferMap[pRenderPassBegin->framebuffer].createInfo;
9139 if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
9140 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9141 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using a framebuffer "
9142 "with a different number of attachments.");
9143 }
9144 for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
9145 const VkImageView &image_view = framebufferInfo.pAttachments[i];
9146 auto image_data = dev_data->imageViewMap.find(image_view);
9147 assert(image_data != dev_data->imageViewMap.end());
9148 const VkImage &image = image_data->second.image;
9149 const VkImageSubresourceRange &subRange = image_data->second.subresourceRange;
9150 IMAGE_CMD_BUF_LAYOUT_NODE newNode = {pRenderPassInfo->pAttachments[i].initialLayout,
9151 pRenderPassInfo->pAttachments[i].initialLayout};
9152 // TODO: Do not iterate over every possibility - consolidate where possible
9153 for (uint32_t j = 0; j < subRange.levelCount; j++) {
9154 uint32_t level = subRange.baseMipLevel + j;
9155 for (uint32_t k = 0; k < subRange.layerCount; k++) {
9156 uint32_t layer = subRange.baseArrayLayer + k;
9157 VkImageSubresource sub = {subRange.aspectMask, level, layer};
9158 IMAGE_CMD_BUF_LAYOUT_NODE node;
9159 if (!FindLayout(pCB, image, sub, node)) {
9160 SetLayout(pCB, image, sub, newNode);
9161 continue;
9162 }
9163 if (newNode.layout != node.layout) {
9164 skip_call |=
9165 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9166 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot start a render pass using attachment %i "
9167 "where the "
Karl Schultz24e2dfe2016-03-25 09:10:34 -06009168 "initial layout is %s and the layout of the attachment at the "
Michael Lentine8f6abe72016-03-24 21:36:53 -05009169 "start of the render pass is %s. The layouts must match.",
9170 i, string_VkImageLayout(newNode.layout), string_VkImageLayout(node.layout));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009171 }
9172 }
9173 }
9174 }
9175 return skip_call;
9176}
9177
Dustin Graves8f1eab92016-04-05 09:41:17 -06009178static void TransitionSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
9179 const int subpass_index) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009180 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
9181 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
9182 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
9183 if (render_pass_data == dev_data->renderPassMap.end()) {
9184 return;
9185 }
9186 const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo;
9187 auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer);
9188 if (framebuffer_data == dev_data->frameBufferMap.end()) {
9189 return;
9190 }
9191 const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo;
9192 const VkSubpassDescription &subpass = pRenderPassInfo->pSubpasses[subpass_index];
9193 for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
9194 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pInputAttachments[j].attachment];
9195 SetLayout(dev_data, pCB, image_view, subpass.pInputAttachments[j].layout);
9196 }
9197 for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
9198 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pColorAttachments[j].attachment];
9199 SetLayout(dev_data, pCB, image_view, subpass.pColorAttachments[j].layout);
9200 }
9201 if ((subpass.pDepthStencilAttachment != NULL) && (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)) {
9202 const VkImageView &image_view = framebufferInfo.pAttachments[subpass.pDepthStencilAttachment->attachment];
9203 SetLayout(dev_data, pCB, image_view, subpass.pDepthStencilAttachment->layout);
9204 }
9205}
9206
Dustin Graves8f1eab92016-04-05 09:41:17 -06009207static bool validatePrimaryCommandBuffer(const layer_data *my_data, const GLOBAL_CB_NODE *pCB, const std::string &cmd_name) {
9208 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009209 if (pCB->createInfo.level != VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
9210 skip_call |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9211 DRAWSTATE_INVALID_COMMAND_BUFFER, "DS", "Cannot execute command %s on a secondary command buffer.",
9212 cmd_name.c_str());
9213 }
9214 return skip_call;
9215}
9216
Dustin Graves8f1eab92016-04-05 09:41:17 -06009217static void TransitionFinalSubpassLayouts(VkCommandBuffer cmdBuffer, const VkRenderPassBeginInfo *pRenderPassBegin) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009218 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(cmdBuffer), layer_data_map);
9219 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, cmdBuffer);
9220 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
9221 if (render_pass_data == dev_data->renderPassMap.end()) {
9222 return;
9223 }
9224 const VkRenderPassCreateInfo *pRenderPassInfo = render_pass_data->second->pCreateInfo;
9225 auto framebuffer_data = dev_data->frameBufferMap.find(pRenderPassBegin->framebuffer);
9226 if (framebuffer_data == dev_data->frameBufferMap.end()) {
9227 return;
9228 }
9229 const VkFramebufferCreateInfo framebufferInfo = framebuffer_data->second.createInfo;
9230 for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
9231 const VkImageView &image_view = framebufferInfo.pAttachments[i];
9232 SetLayout(dev_data, pCB, image_view, pRenderPassInfo->pAttachments[i].finalLayout);
9233 }
9234}
9235
Dustin Graves8f1eab92016-04-05 09:41:17 -06009236static bool VerifyRenderAreaBounds(const layer_data *my_data, const VkRenderPassBeginInfo *pRenderPassBegin) {
Michael Lentined4648812016-03-24 20:48:59 -05009237 bool skip_call = false;
9238 const VkFramebufferCreateInfo *pFramebufferInfo = &my_data->frameBufferMap.at(pRenderPassBegin->framebuffer).createInfo;
9239 if (pRenderPassBegin->renderArea.offset.x < 0 ||
9240 (pRenderPassBegin->renderArea.offset.x + pRenderPassBegin->renderArea.extent.width) > pFramebufferInfo->width ||
9241 pRenderPassBegin->renderArea.offset.y < 0 ||
9242 (pRenderPassBegin->renderArea.offset.y + pRenderPassBegin->renderArea.extent.height) > pFramebufferInfo->height) {
9243 skip_call |= static_cast<bool>(log_msg(
9244 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9245 DRAWSTATE_INVALID_RENDER_AREA, "CORE",
9246 "Cannot execute a render pass with renderArea not within the bound of the "
9247 "framebuffer. RenderArea: x %d, y %d, width %d, height %d. Framebuffer: width %d, "
9248 "height %d.",
9249 pRenderPassBegin->renderArea.offset.x, pRenderPassBegin->renderArea.offset.y, pRenderPassBegin->renderArea.extent.width,
9250 pRenderPassBegin->renderArea.extent.height, pFramebufferInfo->width, pFramebufferInfo->height));
9251 }
9252 return skip_call;
9253}
9254
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009255VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
9256vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009257 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009258 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009259 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009260 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
9261 if (pCB) {
9262 if (pRenderPassBegin && pRenderPassBegin->renderPass) {
Tobin Ehlis54948522016-03-22 13:50:21 -06009263#if MTMERGE
9264 auto pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
9265 if (pass_data != dev_data->renderPassMap.end()) {
9266 RENDER_PASS_NODE* pRPNode = pass_data->second;
9267 pRPNode->fb = pRenderPassBegin->framebuffer;
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009268 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
Tobin Ehlis54948522016-03-22 13:50:21 -06009269 for (size_t i = 0; i < pRPNode->attachments.size(); ++i) {
9270 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->frameBufferMap[pRPNode->fb].attachments[i];
9271 if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009272 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009273 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009274 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06009275 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009276 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009277 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009278 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009279 VkImageLayout &attachment_layout = pRPNode->attachment_first_layout[pRPNode->attachments[i].attachment];
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009280 if (attachment_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ||
9281 attachment_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
9282 skipCall |=
9283 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9284 VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT, (uint64_t)(pRenderPassBegin->renderPass), __LINE__,
9285 MEMTRACK_INVALID_LAYOUT, "MEM", "Cannot clear attachment %d with invalid first layout %d.",
Tobin Ehlis54948522016-03-22 13:50:21 -06009286 pRPNode->attachments[i].attachment, attachment_layout);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009287 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009288 } else if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009289 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009290 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009291 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06009292 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009293 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009294 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009295 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009296 } else if (pRPNode->attachments[i].load_op == VK_ATTACHMENT_LOAD_OP_LOAD) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009297 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009298 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009299 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image);
9300 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009301 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009302 }
9303 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009304 if (pRPNode->attachment_first_read[pRPNode->attachments[i].attachment]) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009305 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009306 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009307 return validate_memory_is_valid(dev_data, fb_info.mem, "vkCmdBeginRenderPass()", fb_info.image);
9308 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009309 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009310 }
9311 }
9312 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009313 }
9314#endif
Dustin Graves8f1eab92016-04-05 09:41:17 -06009315 skipCall |= VerifyRenderAreaBounds(dev_data, pRenderPassBegin);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009316 skipCall |= VerifyFramebufferAndRenderPassLayouts(commandBuffer, pRenderPassBegin);
9317 auto render_pass_data = dev_data->renderPassMap.find(pRenderPassBegin->renderPass);
9318 if (render_pass_data != dev_data->renderPassMap.end()) {
9319 skipCall |= ValidateDependencies(dev_data, pRenderPassBegin, render_pass_data->second->subpassToNode);
9320 }
9321 skipCall |= insideRenderPass(dev_data, pCB, "vkCmdBeginRenderPass");
9322 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdBeginRenderPass");
9323 skipCall |= addCmd(dev_data, pCB, CMD_BEGINRENDERPASS, "vkCmdBeginRenderPass()");
9324 pCB->activeRenderPass = pRenderPassBegin->renderPass;
9325 // This is a shallow copy as that is all that is needed for now
9326 pCB->activeRenderPassBeginInfo = *pRenderPassBegin;
9327 pCB->activeSubpass = 0;
9328 pCB->activeSubpassContents = contents;
Mark Lobodzinski188b2302016-04-12 10:41:59 -06009329 pCB->framebuffers.insert(pRenderPassBegin->framebuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009330 // Connect this framebuffer to this cmdBuffer
Mark Lobodzinski188b2302016-04-12 10:41:59 -06009331 dev_data->frameBufferMap[pRenderPassBegin->framebuffer].referencingCmdBuffers.insert(pCB->commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009332 } else {
9333 skipCall |=
9334 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9335 DRAWSTATE_INVALID_RENDERPASS, "DS", "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()");
9336 }
9337 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009338 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009339 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009340 dev_data->device_dispatch_table->CmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009341 }
9342}
9343
9344VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009345 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009346 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009347 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009348 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009349 if (pCB) {
9350 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdNextSubpass");
9351 skipCall |= addCmd(dev_data, pCB, CMD_NEXTSUBPASS, "vkCmdNextSubpass()");
9352 pCB->activeSubpass++;
9353 pCB->activeSubpassContents = contents;
9354 TransitionSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo, pCB->activeSubpass);
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009355 if (pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline) {
9356 skipCall |= validatePipelineState(dev_data, pCB, VK_PIPELINE_BIND_POINT_GRAPHICS,
9357 pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].pipeline);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009358 }
9359 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdNextSubpass");
9360 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009361 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009362 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009363 dev_data->device_dispatch_table->CmdNextSubpass(commandBuffer, contents);
9364}
9365
9366VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009367 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009368 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009369 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06009370#if MTMERGESOURCE
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009371 auto cb_data = dev_data->commandBufferMap.find(commandBuffer);
9372 if (cb_data != dev_data->commandBufferMap.end()) {
Tobin Ehlis54948522016-03-22 13:50:21 -06009373 auto pass_data = dev_data->renderPassMap.find(cb_data->second->activeRenderPass);
9374 if (pass_data != dev_data->renderPassMap.end()) {
9375 RENDER_PASS_NODE* pRPNode = pass_data->second;
9376 for (size_t i = 0; i < pRPNode->attachments.size(); ++i) {
9377 MT_FB_ATTACHMENT_INFO &fb_info = dev_data->frameBufferMap[pRPNode->fb].attachments[i];
9378 if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_STORE) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009379 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009380 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009381 set_memory_valid(dev_data, fb_info.mem, true, fb_info.image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06009382 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009383 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009384 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009385 }
Tobin Ehlis54948522016-03-22 13:50:21 -06009386 } else if (pRPNode->attachments[i].store_op == VK_ATTACHMENT_STORE_OP_DONT_CARE) {
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009387 if (cb_data != dev_data->commandBufferMap.end()) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009388 std::function<bool()> function = [=]() {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009389 set_memory_valid(dev_data, fb_info.mem, false, fb_info.image);
Dustin Graves8f1eab92016-04-05 09:41:17 -06009390 return false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009391 };
Tobin Ehlis223b01e2016-03-21 14:14:44 -06009392 cb_data->second->validate_functions.push_back(function);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009393 }
9394 }
9395 }
9396 }
9397 }
9398#endif
9399 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009400 if (pCB) {
9401 skipCall |= outsideRenderPass(dev_data, pCB, "vkCmdEndRenderpass");
9402 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdEndRenderPass");
9403 skipCall |= addCmd(dev_data, pCB, CMD_ENDRENDERPASS, "vkCmdEndRenderPass()");
9404 TransitionFinalSubpassLayouts(commandBuffer, &pCB->activeRenderPassBeginInfo);
9405 pCB->activeRenderPass = 0;
9406 pCB->activeSubpass = 0;
9407 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009408 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009409 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009410 dev_data->device_dispatch_table->CmdEndRenderPass(commandBuffer);
9411}
9412
Dustin Graves8f1eab92016-04-05 09:41:17 -06009413static bool logInvalidAttachmentMessage(layer_data *dev_data, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass,
9414 VkRenderPass primaryPass, uint32_t primaryAttach, uint32_t secondaryAttach,
9415 const char *msg) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009416 return log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9417 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9418 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64
9419 " that is not compatible with the current render pass %" PRIx64 "."
Eric Engestrombcbb0fd2016-04-02 22:06:13 +01009420 "Attachment %" PRIu32 " is not compatible with %" PRIu32 ". %s",
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009421 (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass), primaryAttach, secondaryAttach,
9422 msg);
9423}
9424
Dustin Graves8f1eab92016-04-05 09:41:17 -06009425static bool validateAttachmentCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
9426 uint32_t primaryAttach, VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass,
9427 uint32_t secondaryAttach, bool is_multi) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009428 bool skip_call = false;
9429 auto primary_data = dev_data->renderPassMap.find(primaryPass);
9430 auto secondary_data = dev_data->renderPassMap.find(secondaryPass);
9431 if (primary_data->second->pCreateInfo->attachmentCount <= primaryAttach) {
9432 primaryAttach = VK_ATTACHMENT_UNUSED;
9433 }
9434 if (secondary_data->second->pCreateInfo->attachmentCount <= secondaryAttach) {
9435 secondaryAttach = VK_ATTACHMENT_UNUSED;
9436 }
9437 if (primaryAttach == VK_ATTACHMENT_UNUSED && secondaryAttach == VK_ATTACHMENT_UNUSED) {
9438 return skip_call;
9439 }
9440 if (primaryAttach == VK_ATTACHMENT_UNUSED) {
9441 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
9442 secondaryAttach, "The first is unused while the second is not.");
9443 return skip_call;
9444 }
9445 if (secondaryAttach == VK_ATTACHMENT_UNUSED) {
9446 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
9447 secondaryAttach, "The second is unused while the first is not.");
9448 return skip_call;
9449 }
9450 if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].format !=
9451 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].format) {
9452 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
9453 secondaryAttach, "They have different formats.");
9454 }
9455 if (primary_data->second->pCreateInfo->pAttachments[primaryAttach].samples !=
9456 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].samples) {
9457 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
9458 secondaryAttach, "They have different samples.");
9459 }
9460 if (is_multi &&
9461 primary_data->second->pCreateInfo->pAttachments[primaryAttach].flags !=
9462 secondary_data->second->pCreateInfo->pAttachments[secondaryAttach].flags) {
9463 skip_call |= logInvalidAttachmentMessage(dev_data, secondaryBuffer, secondaryPass, primaryPass, primaryAttach,
9464 secondaryAttach, "They have different flags.");
9465 }
9466 return skip_call;
9467}
9468
Dustin Graves8f1eab92016-04-05 09:41:17 -06009469static bool validateSubpassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
9470 VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass, const int subpass,
9471 bool is_multi) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009472 bool skip_call = false;
9473 auto primary_data = dev_data->renderPassMap.find(primaryPass);
9474 auto secondary_data = dev_data->renderPassMap.find(secondaryPass);
9475 const VkSubpassDescription &primary_desc = primary_data->second->pCreateInfo->pSubpasses[subpass];
9476 const VkSubpassDescription &secondary_desc = secondary_data->second->pCreateInfo->pSubpasses[subpass];
9477 uint32_t maxInputAttachmentCount = std::max(primary_desc.inputAttachmentCount, secondary_desc.inputAttachmentCount);
9478 for (uint32_t i = 0; i < maxInputAttachmentCount; ++i) {
9479 uint32_t primary_input_attach = VK_ATTACHMENT_UNUSED, secondary_input_attach = VK_ATTACHMENT_UNUSED;
9480 if (i < primary_desc.inputAttachmentCount) {
9481 primary_input_attach = primary_desc.pInputAttachments[i].attachment;
9482 }
9483 if (i < secondary_desc.inputAttachmentCount) {
9484 secondary_input_attach = secondary_desc.pInputAttachments[i].attachment;
9485 }
9486 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_input_attach, secondaryBuffer,
9487 secondaryPass, secondary_input_attach, is_multi);
9488 }
9489 uint32_t maxColorAttachmentCount = std::max(primary_desc.colorAttachmentCount, secondary_desc.colorAttachmentCount);
9490 for (uint32_t i = 0; i < maxColorAttachmentCount; ++i) {
9491 uint32_t primary_color_attach = VK_ATTACHMENT_UNUSED, secondary_color_attach = VK_ATTACHMENT_UNUSED;
9492 if (i < primary_desc.colorAttachmentCount) {
9493 primary_color_attach = primary_desc.pColorAttachments[i].attachment;
9494 }
9495 if (i < secondary_desc.colorAttachmentCount) {
9496 secondary_color_attach = secondary_desc.pColorAttachments[i].attachment;
9497 }
9498 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_color_attach, secondaryBuffer,
9499 secondaryPass, secondary_color_attach, is_multi);
9500 uint32_t primary_resolve_attach = VK_ATTACHMENT_UNUSED, secondary_resolve_attach = VK_ATTACHMENT_UNUSED;
9501 if (i < primary_desc.colorAttachmentCount && primary_desc.pResolveAttachments) {
9502 primary_resolve_attach = primary_desc.pResolveAttachments[i].attachment;
9503 }
9504 if (i < secondary_desc.colorAttachmentCount && secondary_desc.pResolveAttachments) {
9505 secondary_resolve_attach = secondary_desc.pResolveAttachments[i].attachment;
9506 }
9507 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_resolve_attach, secondaryBuffer,
9508 secondaryPass, secondary_resolve_attach, is_multi);
9509 }
9510 uint32_t primary_depthstencil_attach = VK_ATTACHMENT_UNUSED, secondary_depthstencil_attach = VK_ATTACHMENT_UNUSED;
9511 if (primary_desc.pDepthStencilAttachment) {
9512 primary_depthstencil_attach = primary_desc.pDepthStencilAttachment[0].attachment;
9513 }
9514 if (secondary_desc.pDepthStencilAttachment) {
9515 secondary_depthstencil_attach = secondary_desc.pDepthStencilAttachment[0].attachment;
9516 }
9517 skip_call |= validateAttachmentCompatibility(dev_data, primaryBuffer, primaryPass, primary_depthstencil_attach, secondaryBuffer,
9518 secondaryPass, secondary_depthstencil_attach, is_multi);
9519 return skip_call;
9520}
9521
Dustin Graves8f1eab92016-04-05 09:41:17 -06009522static bool validateRenderPassCompatibility(layer_data *dev_data, VkCommandBuffer primaryBuffer, VkRenderPass primaryPass,
9523 VkCommandBuffer secondaryBuffer, VkRenderPass secondaryPass) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009524 bool skip_call = false;
9525 // Early exit if renderPass objects are identical (and therefore compatible)
9526 if (primaryPass == secondaryPass)
9527 return skip_call;
9528 auto primary_data = dev_data->renderPassMap.find(primaryPass);
9529 auto secondary_data = dev_data->renderPassMap.find(secondaryPass);
9530 if (primary_data == dev_data->renderPassMap.end() || primary_data->second == nullptr) {
9531 skip_call |=
9532 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9533 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9534 "vkCmdExecuteCommands() called w/ invalid current Cmd Buffer %p which has invalid render pass %" PRIx64 ".",
9535 (void *)primaryBuffer, (uint64_t)(primaryPass));
9536 return skip_call;
9537 }
9538 if (secondary_data == dev_data->renderPassMap.end() || secondary_data->second == nullptr) {
9539 skip_call |=
9540 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9541 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9542 "vkCmdExecuteCommands() called w/ invalid secondary Cmd Buffer %p which has invalid render pass %" PRIx64 ".",
9543 (void *)secondaryBuffer, (uint64_t)(secondaryPass));
9544 return skip_call;
9545 }
9546 if (primary_data->second->pCreateInfo->subpassCount != secondary_data->second->pCreateInfo->subpassCount) {
9547 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9548 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9549 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a render pass %" PRIx64
9550 " that is not compatible with the current render pass %" PRIx64 "."
9551 "They have a different number of subpasses.",
9552 (void *)secondaryBuffer, (uint64_t)(secondaryPass), (uint64_t)(primaryPass));
9553 return skip_call;
9554 }
9555 bool is_multi = primary_data->second->pCreateInfo->subpassCount > 1;
9556 for (uint32_t i = 0; i < primary_data->second->pCreateInfo->subpassCount; ++i) {
9557 skip_call |=
9558 validateSubpassCompatibility(dev_data, primaryBuffer, primaryPass, secondaryBuffer, secondaryPass, i, is_multi);
9559 }
9560 return skip_call;
9561}
9562
Dustin Graves8f1eab92016-04-05 09:41:17 -06009563static bool validateFramebuffer(layer_data *dev_data, VkCommandBuffer primaryBuffer, const GLOBAL_CB_NODE *pCB,
9564 VkCommandBuffer secondaryBuffer, const GLOBAL_CB_NODE *pSubCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009565 bool skip_call = false;
9566 if (!pSubCB->beginInfo.pInheritanceInfo) {
9567 return skip_call;
9568 }
Mark Lobodzinski188b2302016-04-12 10:41:59 -06009569 VkFramebuffer primary_fb = dev_data->renderPassMap[pCB->activeRenderPass]->fb;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009570 VkFramebuffer secondary_fb = pSubCB->beginInfo.pInheritanceInfo->framebuffer;
9571 if (secondary_fb != VK_NULL_HANDLE) {
9572 if (primary_fb != secondary_fb) {
9573 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9574 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9575 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p which has a framebuffer %" PRIx64
9576 " that is not compatible with the current framebuffer %" PRIx64 ".",
9577 (void *)secondaryBuffer, (uint64_t)(secondary_fb), (uint64_t)(primary_fb));
9578 }
9579 auto fb_data = dev_data->frameBufferMap.find(secondary_fb);
9580 if (fb_data == dev_data->frameBufferMap.end()) {
9581 skip_call |=
9582 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9583 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS", "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p "
9584 "which has invalid framebuffer %" PRIx64 ".",
9585 (void *)secondaryBuffer, (uint64_t)(secondary_fb));
9586 return skip_call;
9587 }
9588 skip_call |= validateRenderPassCompatibility(dev_data, secondaryBuffer, fb_data->second.createInfo.renderPass,
9589 secondaryBuffer, pSubCB->beginInfo.pInheritanceInfo->renderPass);
9590 }
9591 return skip_call;
9592}
9593
Dustin Graves8f1eab92016-04-05 09:41:17 -06009594static bool validateSecondaryCommandBufferState(layer_data *dev_data, GLOBAL_CB_NODE *pCB, GLOBAL_CB_NODE *pSubCB) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009595 bool skipCall = false;
9596 unordered_set<int> activeTypes;
9597 for (auto queryObject : pCB->activeQueries) {
9598 auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
9599 if (queryPoolData != dev_data->queryPoolMap.end()) {
9600 if (queryPoolData->second.createInfo.queryType == VK_QUERY_TYPE_PIPELINE_STATISTICS &&
9601 pSubCB->beginInfo.pInheritanceInfo) {
9602 VkQueryPipelineStatisticFlags cmdBufStatistics = pSubCB->beginInfo.pInheritanceInfo->pipelineStatistics;
9603 if ((cmdBufStatistics & queryPoolData->second.createInfo.pipelineStatistics) != cmdBufStatistics) {
9604 skipCall |= log_msg(
9605 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9606 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9607 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p "
9608 "which has invalid active query pool %" PRIx64 ". Pipeline statistics is being queried so the command "
9609 "buffer must have all bits set on the queryPool.",
9610 reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first));
9611 }
9612 }
9613 activeTypes.insert(queryPoolData->second.createInfo.queryType);
9614 }
9615 }
9616 for (auto queryObject : pSubCB->startedQueries) {
9617 auto queryPoolData = dev_data->queryPoolMap.find(queryObject.pool);
9618 if (queryPoolData != dev_data->queryPoolMap.end() && activeTypes.count(queryPoolData->second.createInfo.queryType)) {
9619 skipCall |=
9620 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9621 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9622 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p "
9623 "which has invalid active query pool %" PRIx64 "of type %d but a query of that type has been started on "
9624 "secondary Cmd Buffer %p.",
9625 reinterpret_cast<void *>(pCB->commandBuffer), reinterpret_cast<const uint64_t &>(queryPoolData->first),
9626 queryPoolData->second.createInfo.queryType, reinterpret_cast<void *>(pSubCB->commandBuffer));
9627 }
9628 }
9629 return skipCall;
9630}
9631
9632VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
9633vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBuffersCount, const VkCommandBuffer *pCommandBuffers) {
Dustin Graves8f1eab92016-04-05 09:41:17 -06009634 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009635 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009636 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009637 GLOBAL_CB_NODE *pCB = getCBNode(dev_data, commandBuffer);
9638 if (pCB) {
9639 GLOBAL_CB_NODE *pSubCB = NULL;
9640 for (uint32_t i = 0; i < commandBuffersCount; i++) {
9641 pSubCB = getCBNode(dev_data, pCommandBuffers[i]);
9642 if (!pSubCB) {
9643 skipCall |=
9644 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
9645 DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9646 "vkCmdExecuteCommands() called w/ invalid Cmd Buffer %p in element %u of pCommandBuffers array.",
9647 (void *)pCommandBuffers[i], i);
9648 } else if (VK_COMMAND_BUFFER_LEVEL_PRIMARY == pSubCB->createInfo.level) {
9649 skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9650 __LINE__, DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, "DS",
9651 "vkCmdExecuteCommands() called w/ Primary Cmd Buffer %p in element %u of pCommandBuffers "
9652 "array. All cmd buffers in pCommandBuffers array must be secondary.",
9653 (void *)pCommandBuffers[i], i);
9654 } else if (pCB->activeRenderPass) { // Secondary CB w/i RenderPass must have *CONTINUE_BIT set
9655 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) {
9656 skipCall |= log_msg(
9657 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9658 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_BEGIN_CB_INVALID_STATE, "DS",
9659 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) executed within render pass (%#" PRIxLEAST64
9660 ") must have had vkBeginCommandBuffer() called w/ VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT set.",
9661 (void *)pCommandBuffers[i], (uint64_t)pCB->activeRenderPass);
9662 } else {
9663 // Make sure render pass is compatible with parent command buffer pass if has continue
9664 skipCall |= validateRenderPassCompatibility(dev_data, commandBuffer, pCB->activeRenderPass, pCommandBuffers[i],
9665 pSubCB->beginInfo.pInheritanceInfo->renderPass);
9666 skipCall |= validateFramebuffer(dev_data, commandBuffer, pCB, pCommandBuffers[i], pSubCB);
9667 }
9668 string errorString = "";
9669 if (!verify_renderpass_compatibility(dev_data, pCB->activeRenderPass,
9670 pSubCB->beginInfo.pInheritanceInfo->renderPass, errorString)) {
9671 skipCall |= log_msg(
9672 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9673 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_RENDERPASS_INCOMPATIBLE, "DS",
9674 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) w/ render pass (%#" PRIxLEAST64
9675 ") is incompatible w/ primary command buffer (%p) w/ render pass (%#" PRIxLEAST64 ") due to: %s",
9676 (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->renderPass, (void *)commandBuffer,
9677 (uint64_t)pCB->activeRenderPass, errorString.c_str());
9678 }
9679 // If framebuffer for secondary CB is not NULL, then it must match FB from vkCmdBeginRenderPass()
9680 // that this CB will be executed in AND framebuffer must have been created w/ RP compatible w/ renderpass
9681 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer) {
9682 if (pSubCB->beginInfo.pInheritanceInfo->framebuffer != pCB->activeRenderPassBeginInfo.framebuffer) {
9683 skipCall |= log_msg(
9684 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9685 (uint64_t)pCommandBuffers[i], __LINE__, DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE, "DS",
9686 "vkCmdExecuteCommands(): Secondary Command Buffer (%p) references framebuffer (%#" PRIxLEAST64
9687 ") that does not match framebuffer (%#" PRIxLEAST64 ") in active renderpass (%#" PRIxLEAST64 ").",
9688 (void *)pCommandBuffers[i], (uint64_t)pSubCB->beginInfo.pInheritanceInfo->framebuffer,
9689 (uint64_t)pCB->activeRenderPassBeginInfo.framebuffer, (uint64_t)pCB->activeRenderPass);
9690 }
9691 }
9692 }
9693 // TODO(mlentine): Move more logic into this method
9694 skipCall |= validateSecondaryCommandBufferState(dev_data, pCB, pSubCB);
9695 skipCall |= validateCommandBufferState(dev_data, pSubCB);
9696 // Secondary cmdBuffers are considered pending execution starting w/
9697 // being recorded
9698 if (!(pSubCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) {
9699 if (dev_data->globalInFlightCmdBuffers.find(pSubCB->commandBuffer) != dev_data->globalInFlightCmdBuffers.end()) {
9700 skipCall |= log_msg(
9701 dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9702 (uint64_t)(pCB->commandBuffer), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9703 "Attempt to simultaneously execute CB %#" PRIxLEAST64 " w/o VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
9704 "set!",
9705 (uint64_t)(pCB->commandBuffer));
9706 }
9707 if (pCB->beginInfo.flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT) {
9708 // Warn that non-simultaneous secondary cmd buffer renders primary non-simultaneous
9709 skipCall |= log_msg(
9710 dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9711 (uint64_t)(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE, "DS",
9712 "vkCmdExecuteCommands(): Secondary Command Buffer (%#" PRIxLEAST64
9713 ") does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT set and will cause primary command buffer "
9714 "(%#" PRIxLEAST64 ") to be treated as if it does not have VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT "
9715 "set, even though it does.",
9716 (uint64_t)(pCommandBuffers[i]), (uint64_t)(pCB->commandBuffer));
9717 pCB->beginInfo.flags &= ~VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
9718 }
9719 }
Tobin Ehlise54be7b2016-04-11 14:49:55 -06009720 if (!pCB->activeQueries.empty() && !dev_data->phys_dev_properties.features.inheritedQueries) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009721 skipCall |=
9722 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
9723 reinterpret_cast<uint64_t>(pCommandBuffers[i]), __LINE__, DRAWSTATE_INVALID_COMMAND_BUFFER, "DS",
9724 "vkCmdExecuteCommands(): Secondary Command Buffer "
9725 "(%#" PRIxLEAST64 ") cannot be submitted with a query in "
9726 "flight and inherited queries not "
9727 "supported on this device.",
9728 reinterpret_cast<uint64_t>(pCommandBuffers[i]));
9729 }
9730 pSubCB->primaryCommandBuffer = pCB->commandBuffer;
9731 pCB->secondaryCommandBuffers.insert(pSubCB->commandBuffer);
9732 dev_data->globalInFlightCmdBuffers.insert(pSubCB->commandBuffer);
9733 }
9734 skipCall |= validatePrimaryCommandBuffer(dev_data, pCB, "vkCmdExecuteComands");
9735 skipCall |= addCmd(dev_data, pCB, CMD_EXECUTECOMMANDS, "vkCmdExecuteComands()");
9736 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009737 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009738 if (!skipCall)
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009739 dev_data->device_dispatch_table->CmdExecuteCommands(commandBuffer, commandBuffersCount, pCommandBuffers);
9740}
9741
Dustin Graves8f1eab92016-04-05 09:41:17 -06009742static bool ValidateMapImageLayouts(VkDevice device, VkDeviceMemory mem) {
9743 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009744 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Tobin Ehlisb3593a42016-03-16 16:00:36 -06009745 auto mem_data = dev_data->memObjMap.find(mem);
9746 if ((mem_data != dev_data->memObjMap.end()) && (mem_data->second.image != VK_NULL_HANDLE)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009747 std::vector<VkImageLayout> layouts;
Tobin Ehlisb3593a42016-03-16 16:00:36 -06009748 if (FindLayouts(dev_data, mem_data->second.image, layouts)) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009749 for (auto layout : layouts) {
9750 if (layout != VK_IMAGE_LAYOUT_PREINITIALIZED && layout != VK_IMAGE_LAYOUT_GENERAL) {
9751 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
9752 __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS", "Cannot map an image with layout %s. Only "
9753 "GENERAL or PREINITIALIZED are supported.",
9754 string_VkImageLayout(layout));
9755 }
9756 }
9757 }
9758 }
9759 return skip_call;
9760}
9761
9762VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
9763vkMapMemory(VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkFlags flags, void **ppData) {
9764 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
9765
Dustin Graves8f1eab92016-04-05 09:41:17 -06009766 bool skip_call = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009767 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009768 std::unique_lock<std::mutex> lock(global_lock);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06009769#if MTMERGESOURCE
Tobin Ehlisb3593a42016-03-16 16:00:36 -06009770 DEVICE_MEM_INFO *pMemObj = get_mem_obj_info(dev_data, mem);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009771 if (pMemObj) {
9772 pMemObj->valid = true;
Tobin Ehlise54be7b2016-04-11 14:49:55 -06009773 if ((dev_data->phys_dev_mem_props.memoryTypes[pMemObj->allocInfo.memoryTypeIndex].propertyFlags &
9774 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009775 skip_call =
9776 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9777 (uint64_t)mem, __LINE__, MEMTRACK_INVALID_STATE, "MEM",
9778 "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT set: mem obj %#" PRIxLEAST64, (uint64_t)mem);
9779 }
9780 }
9781 skip_call |= validateMemRange(dev_data, mem, offset, size);
9782 storeMemRanges(dev_data, mem, offset, size);
9783#endif
Tobin Ehlisb3593a42016-03-16 16:00:36 -06009784 skip_call |= ValidateMapImageLayouts(device, mem);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009785 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009786
Dustin Graves8f1eab92016-04-05 09:41:17 -06009787 if (!skip_call) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009788 result = dev_data->device_dispatch_table->MapMemory(device, mem, offset, size, flags, ppData);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06009789#if MTMERGESOURCE
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009790 lock.lock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009791 initializeAndTrackMemory(dev_data, mem, size, ppData);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009792 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009793#endif
9794 }
9795 return result;
9796}
9797
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -06009798#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009799VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory mem) {
9800 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Dustin Graves8f1eab92016-04-05 09:41:17 -06009801 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009802
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009803 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009804 skipCall |= deleteMemRanges(my_data, mem);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009805 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009806 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009807 my_data->device_dispatch_table->UnmapMemory(device, mem);
9808 }
9809}
9810
Dustin Graves8f1eab92016-04-05 09:41:17 -06009811static bool validateMemoryIsMapped(layer_data *my_data, const char *funcName, uint32_t memRangeCount,
9812 const VkMappedMemoryRange *pMemRanges) {
9813 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009814 for (uint32_t i = 0; i < memRangeCount; ++i) {
9815 auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory);
9816 if (mem_element != my_data->memObjMap.end()) {
9817 if (mem_element->second.memRange.offset > pMemRanges[i].offset) {
9818 skipCall |= log_msg(
9819 my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9820 (uint64_t)pMemRanges[i].memory, __LINE__, MEMTRACK_INVALID_MAP, "MEM",
9821 "%s: Flush/Invalidate offset (" PRINTF_SIZE_T_SPECIFIER ") is less than Memory Object's offset "
9822 "(" PRINTF_SIZE_T_SPECIFIER ").",
9823 funcName, static_cast<size_t>(pMemRanges[i].offset), static_cast<size_t>(mem_element->second.memRange.offset));
9824 }
9825 if ((mem_element->second.memRange.size != VK_WHOLE_SIZE) &&
9826 ((mem_element->second.memRange.offset + mem_element->second.memRange.size) <
9827 (pMemRanges[i].offset + pMemRanges[i].size))) {
9828 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9829 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
9830 MEMTRACK_INVALID_MAP, "MEM", "%s: Flush/Invalidate upper-bound (" PRINTF_SIZE_T_SPECIFIER
9831 ") exceeds the Memory Object's upper-bound "
9832 "(" PRINTF_SIZE_T_SPECIFIER ").",
9833 funcName, static_cast<size_t>(pMemRanges[i].offset + pMemRanges[i].size),
9834 static_cast<size_t>(mem_element->second.memRange.offset + mem_element->second.memRange.size));
9835 }
9836 }
9837 }
9838 return skipCall;
9839}
9840
Dustin Graves8f1eab92016-04-05 09:41:17 -06009841static bool validateAndCopyNoncoherentMemoryToDriver(layer_data *my_data, uint32_t memRangeCount,
9842 const VkMappedMemoryRange *pMemRanges) {
9843 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009844 for (uint32_t i = 0; i < memRangeCount; ++i) {
9845 auto mem_element = my_data->memObjMap.find(pMemRanges[i].memory);
9846 if (mem_element != my_data->memObjMap.end()) {
9847 if (mem_element->second.pData) {
9848 VkDeviceSize size = mem_element->second.memRange.size;
9849 VkDeviceSize half_size = (size / 2);
9850 char *data = static_cast<char *>(mem_element->second.pData);
9851 for (auto j = 0; j < half_size; ++j) {
9852 if (data[j] != NoncoherentMemoryFillValue) {
9853 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9854 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
9855 MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64,
9856 (uint64_t)pMemRanges[i].memory);
9857 }
9858 }
9859 for (auto j = size + half_size; j < 2 * size; ++j) {
9860 if (data[j] != NoncoherentMemoryFillValue) {
9861 skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
9862 VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, (uint64_t)pMemRanges[i].memory, __LINE__,
9863 MEMTRACK_INVALID_MAP, "MEM", "Memory overflow was detected on mem obj %" PRIxLEAST64,
9864 (uint64_t)pMemRanges[i].memory);
9865 }
9866 }
9867 memcpy(mem_element->second.pDriverData, static_cast<void *>(data + (size_t)(half_size)), (size_t)(size));
9868 }
9869 }
9870 }
9871 return skipCall;
9872}
9873
9874VK_LAYER_EXPORT VkResult VKAPI_CALL
9875vkFlushMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) {
9876 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Dustin Graves8f1eab92016-04-05 09:41:17 -06009877 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009878 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
9879
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009880 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009881 skipCall |= validateAndCopyNoncoherentMemoryToDriver(my_data, memRangeCount, pMemRanges);
9882 skipCall |= validateMemoryIsMapped(my_data, "vkFlushMappedMemoryRanges", memRangeCount, pMemRanges);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009883 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009884 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009885 result = my_data->device_dispatch_table->FlushMappedMemoryRanges(device, memRangeCount, pMemRanges);
9886 }
9887 return result;
9888}
9889
9890VK_LAYER_EXPORT VkResult VKAPI_CALL
9891vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memRangeCount, const VkMappedMemoryRange *pMemRanges) {
9892 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Dustin Graves8f1eab92016-04-05 09:41:17 -06009893 bool skipCall = false;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009894 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
9895
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009896 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009897 skipCall |= validateMemoryIsMapped(my_data, "vkInvalidateMappedMemoryRanges", memRangeCount, pMemRanges);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009898 lock.unlock();
Dustin Graves8f1eab92016-04-05 09:41:17 -06009899 if (!skipCall) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009900 result = my_data->device_dispatch_table->InvalidateMappedMemoryRanges(device, memRangeCount, pMemRanges);
9901 }
9902 return result;
9903}
9904#endif
9905
9906VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) {
9907 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
9908 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Dustin Graves8f1eab92016-04-05 09:41:17 -06009909 bool skipCall = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009910 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisf263ba42016-04-05 13:33:00 -06009911 auto image_node = dev_data->imageMap.find(image);
9912 if (image_node != dev_data->imageMap.end()) {
9913 // Track objects tied to memory
Dustin Graves003b1722016-04-06 16:47:10 -06009914 uint64_t image_handle = reinterpret_cast<uint64_t&>(image);
Tobin Ehlisf263ba42016-04-05 13:33:00 -06009915 skipCall = set_mem_binding(dev_data, mem, image_handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, "vkBindImageMemory");
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009916 VkMemoryRequirements memRequirements;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009917 lock.unlock();
Tobin Ehlisf263ba42016-04-05 13:33:00 -06009918 dev_data->device_dispatch_table->GetImageMemoryRequirements(device, image, &memRequirements);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009919 lock.lock();
Tobin Ehlisb3593a42016-03-16 16:00:36 -06009920 skipCall |= validate_buffer_image_aliasing(dev_data, image_handle, mem, memoryOffset, memRequirements,
9921 dev_data->memObjMap[mem].imageRanges, dev_data->memObjMap[mem].bufferRanges,
9922 VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
Chris Forbes73b82b12016-04-06 15:16:26 +12009923 print_mem_list(dev_data);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009924 lock.unlock();
Tobin Ehlisf263ba42016-04-05 13:33:00 -06009925 if (!skipCall) {
9926 result = dev_data->device_dispatch_table->BindImageMemory(device, image, mem, memoryOffset);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009927 lock.lock();
Tobin Ehlisf263ba42016-04-05 13:33:00 -06009928 dev_data->memObjMap[mem].image = image;
9929 image_node->second.mem = mem;
9930 image_node->second.memOffset = memoryOffset;
9931 image_node->second.memSize = memRequirements.size;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009932 lock.unlock();
Tobin Ehlisf263ba42016-04-05 13:33:00 -06009933 }
9934 } else {
9935 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT,
9936 reinterpret_cast<const uint64_t &>(image), __LINE__, MEMTRACK_INVALID_OBJECT, "MT",
9937 "vkBindImageMemory: Cannot find invalid image %" PRIx64 ", has it already been deleted?",
9938 reinterpret_cast<const uint64_t &>(image));
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009939 }
9940 return result;
9941}
9942
9943VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event) {
Tobin Ehlis3f9e8f92016-04-13 16:18:28 -06009944 bool skip_call = false;
9945 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009946 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009947 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlis3f9e8f92016-04-13 16:18:28 -06009948 auto event_node = dev_data->eventMap.find(event);
9949 if (event_node != dev_data->eventMap.end()) {
9950 event_node->second.needsSignaled = false;
9951 event_node->second.stageMask = VK_PIPELINE_STAGE_HOST_BIT;
9952 if (event_node->second.in_use.load()) {
9953 skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT,
9954 reinterpret_cast<const uint64_t &>(event), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
9955 "Cannot call vkSetEvent() on event %" PRIxLEAST64 " that is already in use by a command buffer.",
9956 reinterpret_cast<const uint64_t &>(event));
9957 }
9958 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009959 lock.unlock();
Tobin Ehlise6ab6932016-04-07 11:35:46 -06009960 // Host setting event is visible to all queues immediately so update stageMask for any queue that's seen this event
9961 // TODO : For correctness this needs separate fix to verify that app doesn't make incorrect assumptions about the
9962 // ordering of this command in relation to vkCmd[Set|Reset]Events (see GH297)
9963 for (auto queue_data : dev_data->queueMap) {
9964 auto event_entry = queue_data.second.eventToStageMap.find(event);
9965 if (event_entry != queue_data.second.eventToStageMap.end()) {
9966 event_entry->second |= VK_PIPELINE_STAGE_HOST_BIT;
9967 }
9968 }
Tobin Ehlis3f9e8f92016-04-13 16:18:28 -06009969 if (!skip_call)
9970 result = dev_data->device_dispatch_table->SetEvent(device, event);
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009971 return result;
9972}
9973
9974VKAPI_ATTR VkResult VKAPI_CALL
9975vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) {
9976 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
9977 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
Dustin Graves8f1eab92016-04-05 09:41:17 -06009978 bool skip_call = false;
Jeremy Hayesda8797f2016-04-13 16:20:24 -06009979 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisb13975e2016-04-14 07:02:43 -06009980 // First verify that fence is not in use
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06009981 if (fence != VK_NULL_HANDLE) {
Michael Lentineef334d82016-04-29 17:46:35 -05009982 trackCommandBuffers(dev_data, queue, 0, nullptr, fence);
9983 auto fence_data = dev_data->fenceMap.find(fence);
9984 if ((bindInfoCount != 0) && fence_data->second.in_use.load()) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06009985 skip_call |=
9986 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
9987 reinterpret_cast<uint64_t &>(fence), __LINE__, DRAWSTATE_INVALID_FENCE, "DS",
9988 "Fence %#" PRIx64 " is already in use by another submission.", reinterpret_cast<uint64_t &>(fence));
9989 }
Michael Lentineef334d82016-04-29 17:46:35 -05009990 if (!fence_data->second.needsSignaled) {
Tobin Ehlisaff7ae92016-04-18 15:45:20 -06009991 skip_call |=
9992 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT,
9993 reinterpret_cast<uint64_t &>(fence), __LINE__, MEMTRACK_INVALID_FENCE_STATE, "MEM",
9994 "Fence %#" PRIxLEAST64 " submitted in SIGNALED state. Fences must be reset before being submitted",
9995 reinterpret_cast<uint64_t &>(fence));
9996 }
Tobin Ehlisb13975e2016-04-14 07:02:43 -06009997 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -07009998 for (uint32_t bindIdx = 0; bindIdx < bindInfoCount; ++bindIdx) {
9999 const VkBindSparseInfo &bindInfo = pBindInfo[bindIdx];
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010000 // Track objects tied to memory
10001 for (uint32_t j = 0; j < bindInfo.bufferBindCount; j++) {
10002 for (uint32_t k = 0; k < bindInfo.pBufferBinds[j].bindCount; k++) {
10003 if (set_sparse_mem_binding(dev_data, bindInfo.pBufferBinds[j].pBinds[k].memory,
10004 (uint64_t)bindInfo.pBufferBinds[j].buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
10005 "vkQueueBindSparse"))
10006 skip_call = true;
10007 }
10008 }
10009 for (uint32_t j = 0; j < bindInfo.imageOpaqueBindCount; j++) {
10010 for (uint32_t k = 0; k < bindInfo.pImageOpaqueBinds[j].bindCount; k++) {
10011 if (set_sparse_mem_binding(dev_data, bindInfo.pImageOpaqueBinds[j].pBinds[k].memory,
10012 (uint64_t)bindInfo.pImageOpaqueBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10013 "vkQueueBindSparse"))
10014 skip_call = true;
10015 }
10016 }
10017 for (uint32_t j = 0; j < bindInfo.imageBindCount; j++) {
10018 for (uint32_t k = 0; k < bindInfo.pImageBinds[j].bindCount; k++) {
10019 if (set_sparse_mem_binding(dev_data, bindInfo.pImageBinds[j].pBinds[k].memory,
10020 (uint64_t)bindInfo.pImageBinds[j].image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
10021 "vkQueueBindSparse"))
10022 skip_call = true;
10023 }
10024 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010025 for (uint32_t i = 0; i < bindInfo.waitSemaphoreCount; ++i) {
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010026 const VkSemaphore &semaphore = bindInfo.pWaitSemaphores[i];
10027 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
10028 if (dev_data->semaphoreMap[semaphore].signaled) {
10029 dev_data->semaphoreMap[semaphore].signaled = false;
10030 } else {
10031 skip_call |=
10032 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10033 reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10034 "vkQueueBindSparse: Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64
10035 " that has no way to be signaled.",
10036 reinterpret_cast<const uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
10037 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010038 }
10039 }
10040 for (uint32_t i = 0; i < bindInfo.signalSemaphoreCount; ++i) {
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010041 const VkSemaphore &semaphore = bindInfo.pSignalSemaphores[i];
10042 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
10043 if (dev_data->semaphoreMap[semaphore].signaled) {
10044 skip_call =
10045 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
10046 reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10047 "vkQueueBindSparse: Queue %#" PRIx64 " is signaling semaphore %#" PRIx64
10048 ", but that semaphore is already signaled.",
10049 reinterpret_cast<const uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
10050 }
10051 dev_data->semaphoreMap[semaphore].signaled = true;
10052 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010053 }
10054 }
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010055 print_mem_list(dev_data);
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010056 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010057
Dustin Graves8f1eab92016-04-05 09:41:17 -060010058 if (!skip_call)
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010059 return dev_data->device_dispatch_table->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010060
10061 return result;
10062}
10063
10064VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo,
10065 const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) {
10066 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10067 VkResult result = dev_data->device_dispatch_table->CreateSemaphore(device, pCreateInfo, pAllocator, pSemaphore);
10068 if (result == VK_SUCCESS) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010069 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010070 SEMAPHORE_NODE* sNode = &dev_data->semaphoreMap[*pSemaphore];
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010071 sNode->signaled = false;
Michael Lentined4f382b2016-03-17 16:34:32 -050010072 sNode->queue = VK_NULL_HANDLE;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010073 sNode->in_use.store(0);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010074 }
10075 return result;
10076}
10077
10078VKAPI_ATTR VkResult VKAPI_CALL
10079vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) {
10080 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10081 VkResult result = dev_data->device_dispatch_table->CreateEvent(device, pCreateInfo, pAllocator, pEvent);
10082 if (result == VK_SUCCESS) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010083 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010084 dev_data->eventMap[*pEvent].needsSignaled = false;
10085 dev_data->eventMap[*pEvent].in_use.store(0);
10086 dev_data->eventMap[*pEvent].stageMask = VkPipelineStageFlags(0);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010087 }
10088 return result;
10089}
10090
10091VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo,
10092 const VkAllocationCallbacks *pAllocator,
10093 VkSwapchainKHR *pSwapchain) {
10094 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10095 VkResult result = dev_data->device_dispatch_table->CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
10096
10097 if (VK_SUCCESS == result) {
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010098 SWAPCHAIN_NODE *psc_node = new SWAPCHAIN_NODE(pCreateInfo);
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010099 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010100 dev_data->device_extensions.swapchainMap[*pSwapchain] = psc_node;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010101 }
10102
10103 return result;
10104}
10105
10106VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
10107vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) {
10108 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10109 bool skipCall = false;
10110
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010111 std::unique_lock<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010112 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(swapchain);
10113 if (swapchain_data != dev_data->device_extensions.swapchainMap.end()) {
10114 if (swapchain_data->second->images.size() > 0) {
10115 for (auto swapchain_image : swapchain_data->second->images) {
10116 auto image_sub = dev_data->imageSubresourceMap.find(swapchain_image);
10117 if (image_sub != dev_data->imageSubresourceMap.end()) {
10118 for (auto imgsubpair : image_sub->second) {
10119 auto image_item = dev_data->imageLayoutMap.find(imgsubpair);
10120 if (image_item != dev_data->imageLayoutMap.end()) {
10121 dev_data->imageLayoutMap.erase(image_item);
10122 }
10123 }
10124 dev_data->imageSubresourceMap.erase(image_sub);
10125 }
Chris Forbes73b82b12016-04-06 15:16:26 +120010126 skipCall = clear_object_binding(dev_data, (uint64_t)swapchain_image,
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010127 VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT);
Tobin Ehlisf263ba42016-04-05 13:33:00 -060010128 dev_data->imageMap.erase(swapchain_image);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010129 }
10130 }
10131 delete swapchain_data->second;
10132 dev_data->device_extensions.swapchainMap.erase(swapchain);
10133 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010134 lock.unlock();
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010135 if (!skipCall)
10136 dev_data->device_dispatch_table->DestroySwapchainKHR(device, swapchain, pAllocator);
10137}
10138
10139VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
10140vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount, VkImage *pSwapchainImages) {
10141 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10142 VkResult result = dev_data->device_dispatch_table->GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
10143
10144 if (result == VK_SUCCESS && pSwapchainImages != NULL) {
10145 // This should never happen and is checked by param checker.
10146 if (!pCount)
10147 return result;
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010148 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010149 const size_t count = *pCount;
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010150 auto swapchain_node = dev_data->device_extensions.swapchainMap[swapchain];
10151 if (!swapchain_node->images.empty()) {
10152 // TODO : Not sure I like the memcmp here, but it works
10153 const bool mismatch = (swapchain_node->images.size() != count ||
10154 memcmp(&swapchain_node->images[0], pSwapchainImages, sizeof(swapchain_node->images[0]) * count));
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010155 if (mismatch) {
10156 // TODO: Verify against Valid Usage section of extension
10157 log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
10158 (uint64_t)swapchain, __LINE__, MEMTRACK_NONE, "SWAP_CHAIN",
10159 "vkGetSwapchainInfoKHR(%" PRIu64
10160 ", VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_KHR) returned mismatching data",
10161 (uint64_t)(swapchain));
10162 }
10163 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010164 for (uint32_t i = 0; i < *pCount; ++i) {
10165 IMAGE_LAYOUT_NODE image_layout_node;
10166 image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010167 image_layout_node.format = swapchain_node->createInfo.imageFormat;
Tobin Ehlisf263ba42016-04-05 13:33:00 -060010168 auto &image_node = dev_data->imageMap[pSwapchainImages[i]];
10169 image_node.createInfo.mipLevels = 1;
10170 image_node.createInfo.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
10171 image_node.createInfo.usage = swapchain_node->createInfo.imageUsage;
10172 image_node.valid = false;
10173 image_node.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010174 swapchain_node->images.push_back(pSwapchainImages[i]);
10175 ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
10176 dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
10177 dev_data->imageLayoutMap[subpair] = image_layout_node;
10178 dev_data->device_extensions.imageToSwapchainMap[pSwapchainImages[i]] = swapchain;
10179 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010180 }
10181 return result;
10182}
10183
10184VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
10185 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
10186 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10187 bool skip_call = false;
10188
10189 if (pPresentInfo) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010190 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010191 for (uint32_t i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) {
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010192 const VkSemaphore &semaphore = pPresentInfo->pWaitSemaphores[i];
10193 if (dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
10194 if (dev_data->semaphoreMap[semaphore].signaled) {
10195 dev_data->semaphoreMap[semaphore].signaled = false;
10196 } else {
10197 skip_call |=
10198 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
10199 VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
10200 "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.",
10201 reinterpret_cast<uint64_t &>(queue), reinterpret_cast<const uint64_t &>(semaphore));
10202 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010203 }
10204 }
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010205 VkDeviceMemory mem;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010206 for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
10207 auto swapchain_data = dev_data->device_extensions.swapchainMap.find(pPresentInfo->pSwapchains[i]);
10208 if (swapchain_data != dev_data->device_extensions.swapchainMap.end() &&
10209 pPresentInfo->pImageIndices[i] < swapchain_data->second->images.size()) {
10210 VkImage image = swapchain_data->second->images[pPresentInfo->pImageIndices[i]];
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -060010211#if MTMERGESOURCE
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010212 skip_call |=
Chris Forbes73b82b12016-04-06 15:16:26 +120010213 get_mem_binding_from_object(dev_data, (uint64_t)(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, &mem);
Tobin Ehlis43d7c522016-03-16 13:52:20 -060010214 skip_call |= validate_memory_is_valid(dev_data, mem, "vkQueuePresentKHR()", image);
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -060010215#endif
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010216 vector<VkImageLayout> layouts;
10217 if (FindLayouts(dev_data, image, layouts)) {
10218 for (auto layout : layouts) {
10219 if (layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
10220 skip_call |=
10221 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT,
10222 reinterpret_cast<uint64_t &>(queue), __LINE__, DRAWSTATE_INVALID_IMAGE_LAYOUT, "DS",
10223 "Images passed to present must be in layout "
10224 "PRESENT_SOURCE_KHR but is in %s",
10225 string_VkImageLayout(layout));
10226 }
10227 }
10228 }
10229 }
10230 }
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010231 }
10232
10233 if (!skip_call)
10234 result = dev_data->device_dispatch_table->QueuePresentKHR(queue, pPresentInfo);
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010235
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010236 return result;
10237}
10238
10239VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout,
10240 VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) {
10241 layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
10242 VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
10243 bool skipCall = false;
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010244
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010245 std::unique_lock<std::mutex> lock(global_lock);
Dominik Witczakf3ab9932016-03-30 13:59:48 +020010246 if (semaphore != VK_NULL_HANDLE &&
10247 dev_data->semaphoreMap.find(semaphore) != dev_data->semaphoreMap.end()) {
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010248 if (dev_data->semaphoreMap[semaphore].signaled) {
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010249 skipCall = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT,
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010250 reinterpret_cast<const uint64_t &>(semaphore), __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS",
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010251 "vkAcquireNextImageKHR: Semaphore must not be currently signaled or in a wait state");
10252 }
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010253 dev_data->semaphoreMap[semaphore].signaled = true;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010254 }
10255 auto fence_data = dev_data->fenceMap.find(fence);
10256 if (fence_data != dev_data->fenceMap.end()) {
10257 fence_data->second.swapchain = swapchain;
10258 }
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010259 lock.unlock();
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010260
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010261 if (!skipCall) {
10262 result =
10263 dev_data->device_dispatch_table->AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
10264 }
Tobin Ehlis9984f1e2016-04-12 10:49:41 -060010265
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010266 return result;
10267}
10268
10269VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
10270vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo,
10271 const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pMsgCallback) {
10272 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
10273 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
10274 VkResult res = pTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pMsgCallback);
10275 if (VK_SUCCESS == res) {
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010276 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010277 res = layer_create_msg_callback(my_data->report_data, pCreateInfo, pAllocator, pMsgCallback);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010278 }
10279 return res;
10280}
10281
10282VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance,
10283 VkDebugReportCallbackEXT msgCallback,
10284 const VkAllocationCallbacks *pAllocator) {
10285 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
10286 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
10287 pTable->DestroyDebugReportCallbackEXT(instance, msgCallback, pAllocator);
Jeremy Hayesda8797f2016-04-13 16:20:24 -060010288 std::lock_guard<std::mutex> lock(global_lock);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010289 layer_destroy_msg_callback(my_data->report_data, msgCallback, pAllocator);
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010290}
10291
10292VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL
10293vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t object,
10294 size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg) {
10295 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
10296 my_data->instance_dispatch_table->DebugReportMessageEXT(instance, flags, objType, object, location, msgCode, pLayerPrefix,
10297 pMsg);
10298}
10299
10300VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, const char *funcName) {
10301 if (!strcmp(funcName, "vkGetDeviceProcAddr"))
10302 return (PFN_vkVoidFunction)vkGetDeviceProcAddr;
10303 if (!strcmp(funcName, "vkDestroyDevice"))
10304 return (PFN_vkVoidFunction)vkDestroyDevice;
10305 if (!strcmp(funcName, "vkQueueSubmit"))
10306 return (PFN_vkVoidFunction)vkQueueSubmit;
10307 if (!strcmp(funcName, "vkWaitForFences"))
10308 return (PFN_vkVoidFunction)vkWaitForFences;
10309 if (!strcmp(funcName, "vkGetFenceStatus"))
10310 return (PFN_vkVoidFunction)vkGetFenceStatus;
10311 if (!strcmp(funcName, "vkQueueWaitIdle"))
10312 return (PFN_vkVoidFunction)vkQueueWaitIdle;
10313 if (!strcmp(funcName, "vkDeviceWaitIdle"))
10314 return (PFN_vkVoidFunction)vkDeviceWaitIdle;
10315 if (!strcmp(funcName, "vkGetDeviceQueue"))
10316 return (PFN_vkVoidFunction)vkGetDeviceQueue;
10317 if (!strcmp(funcName, "vkDestroyInstance"))
10318 return (PFN_vkVoidFunction)vkDestroyInstance;
10319 if (!strcmp(funcName, "vkDestroyDevice"))
10320 return (PFN_vkVoidFunction)vkDestroyDevice;
10321 if (!strcmp(funcName, "vkDestroyFence"))
10322 return (PFN_vkVoidFunction)vkDestroyFence;
10323 if (!strcmp(funcName, "vkResetFences"))
10324 return (PFN_vkVoidFunction)vkResetFences;
10325 if (!strcmp(funcName, "vkDestroySemaphore"))
10326 return (PFN_vkVoidFunction)vkDestroySemaphore;
10327 if (!strcmp(funcName, "vkDestroyEvent"))
10328 return (PFN_vkVoidFunction)vkDestroyEvent;
10329 if (!strcmp(funcName, "vkDestroyQueryPool"))
10330 return (PFN_vkVoidFunction)vkDestroyQueryPool;
10331 if (!strcmp(funcName, "vkDestroyBuffer"))
10332 return (PFN_vkVoidFunction)vkDestroyBuffer;
10333 if (!strcmp(funcName, "vkDestroyBufferView"))
10334 return (PFN_vkVoidFunction)vkDestroyBufferView;
10335 if (!strcmp(funcName, "vkDestroyImage"))
10336 return (PFN_vkVoidFunction)vkDestroyImage;
10337 if (!strcmp(funcName, "vkDestroyImageView"))
10338 return (PFN_vkVoidFunction)vkDestroyImageView;
10339 if (!strcmp(funcName, "vkDestroyShaderModule"))
10340 return (PFN_vkVoidFunction)vkDestroyShaderModule;
10341 if (!strcmp(funcName, "vkDestroyPipeline"))
10342 return (PFN_vkVoidFunction)vkDestroyPipeline;
10343 if (!strcmp(funcName, "vkDestroyPipelineLayout"))
10344 return (PFN_vkVoidFunction)vkDestroyPipelineLayout;
10345 if (!strcmp(funcName, "vkDestroySampler"))
10346 return (PFN_vkVoidFunction)vkDestroySampler;
10347 if (!strcmp(funcName, "vkDestroyDescriptorSetLayout"))
10348 return (PFN_vkVoidFunction)vkDestroyDescriptorSetLayout;
10349 if (!strcmp(funcName, "vkDestroyDescriptorPool"))
10350 return (PFN_vkVoidFunction)vkDestroyDescriptorPool;
10351 if (!strcmp(funcName, "vkDestroyFramebuffer"))
10352 return (PFN_vkVoidFunction)vkDestroyFramebuffer;
10353 if (!strcmp(funcName, "vkDestroyRenderPass"))
10354 return (PFN_vkVoidFunction)vkDestroyRenderPass;
10355 if (!strcmp(funcName, "vkCreateBuffer"))
10356 return (PFN_vkVoidFunction)vkCreateBuffer;
10357 if (!strcmp(funcName, "vkCreateBufferView"))
10358 return (PFN_vkVoidFunction)vkCreateBufferView;
10359 if (!strcmp(funcName, "vkCreateImage"))
10360 return (PFN_vkVoidFunction)vkCreateImage;
10361 if (!strcmp(funcName, "vkCreateImageView"))
10362 return (PFN_vkVoidFunction)vkCreateImageView;
10363 if (!strcmp(funcName, "vkCreateFence"))
10364 return (PFN_vkVoidFunction)vkCreateFence;
10365 if (!strcmp(funcName, "CreatePipelineCache"))
10366 return (PFN_vkVoidFunction)vkCreatePipelineCache;
10367 if (!strcmp(funcName, "DestroyPipelineCache"))
10368 return (PFN_vkVoidFunction)vkDestroyPipelineCache;
10369 if (!strcmp(funcName, "GetPipelineCacheData"))
10370 return (PFN_vkVoidFunction)vkGetPipelineCacheData;
10371 if (!strcmp(funcName, "MergePipelineCaches"))
10372 return (PFN_vkVoidFunction)vkMergePipelineCaches;
10373 if (!strcmp(funcName, "vkCreateGraphicsPipelines"))
10374 return (PFN_vkVoidFunction)vkCreateGraphicsPipelines;
10375 if (!strcmp(funcName, "vkCreateComputePipelines"))
10376 return (PFN_vkVoidFunction)vkCreateComputePipelines;
10377 if (!strcmp(funcName, "vkCreateSampler"))
10378 return (PFN_vkVoidFunction)vkCreateSampler;
10379 if (!strcmp(funcName, "vkCreateDescriptorSetLayout"))
10380 return (PFN_vkVoidFunction)vkCreateDescriptorSetLayout;
10381 if (!strcmp(funcName, "vkCreatePipelineLayout"))
10382 return (PFN_vkVoidFunction)vkCreatePipelineLayout;
10383 if (!strcmp(funcName, "vkCreateDescriptorPool"))
10384 return (PFN_vkVoidFunction)vkCreateDescriptorPool;
10385 if (!strcmp(funcName, "vkResetDescriptorPool"))
10386 return (PFN_vkVoidFunction)vkResetDescriptorPool;
10387 if (!strcmp(funcName, "vkAllocateDescriptorSets"))
10388 return (PFN_vkVoidFunction)vkAllocateDescriptorSets;
10389 if (!strcmp(funcName, "vkFreeDescriptorSets"))
10390 return (PFN_vkVoidFunction)vkFreeDescriptorSets;
10391 if (!strcmp(funcName, "vkUpdateDescriptorSets"))
10392 return (PFN_vkVoidFunction)vkUpdateDescriptorSets;
10393 if (!strcmp(funcName, "vkCreateCommandPool"))
10394 return (PFN_vkVoidFunction)vkCreateCommandPool;
10395 if (!strcmp(funcName, "vkDestroyCommandPool"))
10396 return (PFN_vkVoidFunction)vkDestroyCommandPool;
10397 if (!strcmp(funcName, "vkResetCommandPool"))
10398 return (PFN_vkVoidFunction)vkResetCommandPool;
10399 if (!strcmp(funcName, "vkCreateQueryPool"))
10400 return (PFN_vkVoidFunction)vkCreateQueryPool;
10401 if (!strcmp(funcName, "vkAllocateCommandBuffers"))
10402 return (PFN_vkVoidFunction)vkAllocateCommandBuffers;
10403 if (!strcmp(funcName, "vkFreeCommandBuffers"))
10404 return (PFN_vkVoidFunction)vkFreeCommandBuffers;
10405 if (!strcmp(funcName, "vkBeginCommandBuffer"))
10406 return (PFN_vkVoidFunction)vkBeginCommandBuffer;
10407 if (!strcmp(funcName, "vkEndCommandBuffer"))
10408 return (PFN_vkVoidFunction)vkEndCommandBuffer;
10409 if (!strcmp(funcName, "vkResetCommandBuffer"))
10410 return (PFN_vkVoidFunction)vkResetCommandBuffer;
10411 if (!strcmp(funcName, "vkCmdBindPipeline"))
10412 return (PFN_vkVoidFunction)vkCmdBindPipeline;
10413 if (!strcmp(funcName, "vkCmdSetViewport"))
10414 return (PFN_vkVoidFunction)vkCmdSetViewport;
10415 if (!strcmp(funcName, "vkCmdSetScissor"))
10416 return (PFN_vkVoidFunction)vkCmdSetScissor;
10417 if (!strcmp(funcName, "vkCmdSetLineWidth"))
10418 return (PFN_vkVoidFunction)vkCmdSetLineWidth;
10419 if (!strcmp(funcName, "vkCmdSetDepthBias"))
10420 return (PFN_vkVoidFunction)vkCmdSetDepthBias;
10421 if (!strcmp(funcName, "vkCmdSetBlendConstants"))
10422 return (PFN_vkVoidFunction)vkCmdSetBlendConstants;
10423 if (!strcmp(funcName, "vkCmdSetDepthBounds"))
10424 return (PFN_vkVoidFunction)vkCmdSetDepthBounds;
10425 if (!strcmp(funcName, "vkCmdSetStencilCompareMask"))
10426 return (PFN_vkVoidFunction)vkCmdSetStencilCompareMask;
10427 if (!strcmp(funcName, "vkCmdSetStencilWriteMask"))
10428 return (PFN_vkVoidFunction)vkCmdSetStencilWriteMask;
10429 if (!strcmp(funcName, "vkCmdSetStencilReference"))
10430 return (PFN_vkVoidFunction)vkCmdSetStencilReference;
10431 if (!strcmp(funcName, "vkCmdBindDescriptorSets"))
10432 return (PFN_vkVoidFunction)vkCmdBindDescriptorSets;
10433 if (!strcmp(funcName, "vkCmdBindVertexBuffers"))
10434 return (PFN_vkVoidFunction)vkCmdBindVertexBuffers;
10435 if (!strcmp(funcName, "vkCmdBindIndexBuffer"))
10436 return (PFN_vkVoidFunction)vkCmdBindIndexBuffer;
10437 if (!strcmp(funcName, "vkCmdDraw"))
10438 return (PFN_vkVoidFunction)vkCmdDraw;
10439 if (!strcmp(funcName, "vkCmdDrawIndexed"))
10440 return (PFN_vkVoidFunction)vkCmdDrawIndexed;
10441 if (!strcmp(funcName, "vkCmdDrawIndirect"))
10442 return (PFN_vkVoidFunction)vkCmdDrawIndirect;
10443 if (!strcmp(funcName, "vkCmdDrawIndexedIndirect"))
10444 return (PFN_vkVoidFunction)vkCmdDrawIndexedIndirect;
10445 if (!strcmp(funcName, "vkCmdDispatch"))
10446 return (PFN_vkVoidFunction)vkCmdDispatch;
10447 if (!strcmp(funcName, "vkCmdDispatchIndirect"))
10448 return (PFN_vkVoidFunction)vkCmdDispatchIndirect;
10449 if (!strcmp(funcName, "vkCmdCopyBuffer"))
10450 return (PFN_vkVoidFunction)vkCmdCopyBuffer;
10451 if (!strcmp(funcName, "vkCmdCopyImage"))
10452 return (PFN_vkVoidFunction)vkCmdCopyImage;
10453 if (!strcmp(funcName, "vkCmdBlitImage"))
10454 return (PFN_vkVoidFunction)vkCmdBlitImage;
10455 if (!strcmp(funcName, "vkCmdCopyBufferToImage"))
10456 return (PFN_vkVoidFunction)vkCmdCopyBufferToImage;
10457 if (!strcmp(funcName, "vkCmdCopyImageToBuffer"))
10458 return (PFN_vkVoidFunction)vkCmdCopyImageToBuffer;
10459 if (!strcmp(funcName, "vkCmdUpdateBuffer"))
10460 return (PFN_vkVoidFunction)vkCmdUpdateBuffer;
10461 if (!strcmp(funcName, "vkCmdFillBuffer"))
10462 return (PFN_vkVoidFunction)vkCmdFillBuffer;
10463 if (!strcmp(funcName, "vkCmdClearColorImage"))
10464 return (PFN_vkVoidFunction)vkCmdClearColorImage;
10465 if (!strcmp(funcName, "vkCmdClearDepthStencilImage"))
10466 return (PFN_vkVoidFunction)vkCmdClearDepthStencilImage;
10467 if (!strcmp(funcName, "vkCmdClearAttachments"))
10468 return (PFN_vkVoidFunction)vkCmdClearAttachments;
10469 if (!strcmp(funcName, "vkCmdResolveImage"))
10470 return (PFN_vkVoidFunction)vkCmdResolveImage;
10471 if (!strcmp(funcName, "vkCmdSetEvent"))
10472 return (PFN_vkVoidFunction)vkCmdSetEvent;
10473 if (!strcmp(funcName, "vkCmdResetEvent"))
10474 return (PFN_vkVoidFunction)vkCmdResetEvent;
10475 if (!strcmp(funcName, "vkCmdWaitEvents"))
10476 return (PFN_vkVoidFunction)vkCmdWaitEvents;
10477 if (!strcmp(funcName, "vkCmdPipelineBarrier"))
10478 return (PFN_vkVoidFunction)vkCmdPipelineBarrier;
10479 if (!strcmp(funcName, "vkCmdBeginQuery"))
10480 return (PFN_vkVoidFunction)vkCmdBeginQuery;
10481 if (!strcmp(funcName, "vkCmdEndQuery"))
10482 return (PFN_vkVoidFunction)vkCmdEndQuery;
10483 if (!strcmp(funcName, "vkCmdResetQueryPool"))
10484 return (PFN_vkVoidFunction)vkCmdResetQueryPool;
10485 if (!strcmp(funcName, "vkCmdCopyQueryPoolResults"))
10486 return (PFN_vkVoidFunction)vkCmdCopyQueryPoolResults;
10487 if (!strcmp(funcName, "vkCmdPushConstants"))
10488 return (PFN_vkVoidFunction)vkCmdPushConstants;
10489 if (!strcmp(funcName, "vkCmdWriteTimestamp"))
10490 return (PFN_vkVoidFunction)vkCmdWriteTimestamp;
10491 if (!strcmp(funcName, "vkCreateFramebuffer"))
10492 return (PFN_vkVoidFunction)vkCreateFramebuffer;
10493 if (!strcmp(funcName, "vkCreateShaderModule"))
10494 return (PFN_vkVoidFunction)vkCreateShaderModule;
10495 if (!strcmp(funcName, "vkCreateRenderPass"))
10496 return (PFN_vkVoidFunction)vkCreateRenderPass;
10497 if (!strcmp(funcName, "vkCmdBeginRenderPass"))
10498 return (PFN_vkVoidFunction)vkCmdBeginRenderPass;
10499 if (!strcmp(funcName, "vkCmdNextSubpass"))
10500 return (PFN_vkVoidFunction)vkCmdNextSubpass;
10501 if (!strcmp(funcName, "vkCmdEndRenderPass"))
10502 return (PFN_vkVoidFunction)vkCmdEndRenderPass;
10503 if (!strcmp(funcName, "vkCmdExecuteCommands"))
10504 return (PFN_vkVoidFunction)vkCmdExecuteCommands;
10505 if (!strcmp(funcName, "vkSetEvent"))
10506 return (PFN_vkVoidFunction)vkSetEvent;
10507 if (!strcmp(funcName, "vkMapMemory"))
10508 return (PFN_vkVoidFunction)vkMapMemory;
Mark Lobodzinskic84ff9b2016-03-23 14:33:02 -060010509#if MTMERGESOURCE
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010510 if (!strcmp(funcName, "vkUnmapMemory"))
10511 return (PFN_vkVoidFunction)vkUnmapMemory;
10512 if (!strcmp(funcName, "vkAllocateMemory"))
10513 return (PFN_vkVoidFunction)vkAllocateMemory;
10514 if (!strcmp(funcName, "vkFreeMemory"))
10515 return (PFN_vkVoidFunction)vkFreeMemory;
10516 if (!strcmp(funcName, "vkFlushMappedMemoryRanges"))
10517 return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges;
10518 if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges"))
10519 return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges;
10520 if (!strcmp(funcName, "vkBindBufferMemory"))
10521 return (PFN_vkVoidFunction)vkBindBufferMemory;
10522 if (!strcmp(funcName, "vkGetBufferMemoryRequirements"))
10523 return (PFN_vkVoidFunction)vkGetBufferMemoryRequirements;
10524 if (!strcmp(funcName, "vkGetImageMemoryRequirements"))
10525 return (PFN_vkVoidFunction)vkGetImageMemoryRequirements;
10526#endif
10527 if (!strcmp(funcName, "vkGetQueryPoolResults"))
10528 return (PFN_vkVoidFunction)vkGetQueryPoolResults;
10529 if (!strcmp(funcName, "vkBindImageMemory"))
10530 return (PFN_vkVoidFunction)vkBindImageMemory;
10531 if (!strcmp(funcName, "vkQueueBindSparse"))
10532 return (PFN_vkVoidFunction)vkQueueBindSparse;
10533 if (!strcmp(funcName, "vkCreateSemaphore"))
10534 return (PFN_vkVoidFunction)vkCreateSemaphore;
10535 if (!strcmp(funcName, "vkCreateEvent"))
10536 return (PFN_vkVoidFunction)vkCreateEvent;
10537
10538 if (dev == NULL)
10539 return NULL;
10540
10541 layer_data *dev_data;
10542 dev_data = get_my_data_ptr(get_dispatch_key(dev), layer_data_map);
10543
10544 if (dev_data->device_extensions.wsi_enabled) {
10545 if (!strcmp(funcName, "vkCreateSwapchainKHR"))
10546 return (PFN_vkVoidFunction)vkCreateSwapchainKHR;
10547 if (!strcmp(funcName, "vkDestroySwapchainKHR"))
10548 return (PFN_vkVoidFunction)vkDestroySwapchainKHR;
10549 if (!strcmp(funcName, "vkGetSwapchainImagesKHR"))
10550 return (PFN_vkVoidFunction)vkGetSwapchainImagesKHR;
10551 if (!strcmp(funcName, "vkAcquireNextImageKHR"))
10552 return (PFN_vkVoidFunction)vkAcquireNextImageKHR;
10553 if (!strcmp(funcName, "vkQueuePresentKHR"))
10554 return (PFN_vkVoidFunction)vkQueuePresentKHR;
10555 }
10556
10557 VkLayerDispatchTable *pTable = dev_data->device_dispatch_table;
10558 {
10559 if (pTable->GetDeviceProcAddr == NULL)
10560 return NULL;
10561 return pTable->GetDeviceProcAddr(dev, funcName);
10562 }
10563}
10564
10565VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *funcName) {
10566 if (!strcmp(funcName, "vkGetInstanceProcAddr"))
10567 return (PFN_vkVoidFunction)vkGetInstanceProcAddr;
10568 if (!strcmp(funcName, "vkGetDeviceProcAddr"))
10569 return (PFN_vkVoidFunction)vkGetDeviceProcAddr;
10570 if (!strcmp(funcName, "vkCreateInstance"))
10571 return (PFN_vkVoidFunction)vkCreateInstance;
10572 if (!strcmp(funcName, "vkCreateDevice"))
10573 return (PFN_vkVoidFunction)vkCreateDevice;
10574 if (!strcmp(funcName, "vkDestroyInstance"))
10575 return (PFN_vkVoidFunction)vkDestroyInstance;
Tobin Ehlisc96f8062016-03-09 16:12:48 -070010576 if (!strcmp(funcName, "vkEnumerateInstanceLayerProperties"))
10577 return (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties;
10578 if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties"))
10579 return (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties;
10580 if (!strcmp(funcName, "vkEnumerateDeviceLayerProperties"))
10581 return (PFN_vkVoidFunction)vkEnumerateDeviceLayerProperties;
10582 if (!strcmp(funcName, "vkEnumerateDeviceExtensionProperties"))
10583 return (PFN_vkVoidFunction)vkEnumerateDeviceExtensionProperties;
10584
10585 if (instance == NULL)
10586 return NULL;
10587
10588 PFN_vkVoidFunction fptr;
10589
10590 layer_data *my_data;
10591 my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
10592 fptr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
10593 if (fptr)
10594 return fptr;
10595
10596 VkLayerInstanceDispatchTable *pTable = my_data->instance_dispatch_table;
10597 if (pTable->GetInstanceProcAddr == NULL)
10598 return NULL;
10599 return pTable->GetInstanceProcAddr(instance, funcName);
10600}