1 /* Copyright (c) 2015-2016 The Khronos Group Inc. 2 * Copyright (c) 2015-2016 Valve Corporation 3 * Copyright (c) 2015-2016 LunarG, Inc. 4 * Copyright (C) 2015-2016 Google Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Courtney Goeltzenleuchter <courtneygo (at) google.com> 19 * Author: Tobin Ehlis <tobine (at) google.com> 20 * Author: Chris Forbes <chrisf (at) ijw.co.nz> 21 * Author: Mark Lobodzinski <mark (at) lunarg.com> 22 */ 23 #ifndef CORE_VALIDATION_TYPES_H_ 24 #define CORE_VALIDATION_TYPES_H_ 25 26 // Check for noexcept support 27 #if defined(__clang__) 28 #if __has_feature(cxx_noexcept) 29 #define HAS_NOEXCEPT 30 #endif 31 #else 32 #if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 33 #define HAS_NOEXCEPT 34 #else 35 #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 && defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS 36 #define HAS_NOEXCEPT 37 #endif 38 #endif 39 #endif 40 41 #ifdef HAS_NOEXCEPT 42 #define NOEXCEPT noexcept 43 #else 44 #define NOEXCEPT 45 #endif 46 47 #include "vulkan/vulkan.h" 48 #include <atomic> 49 #include <string.h> 50 #include <unordered_set> 51 #include <unordered_map> 52 #include <vector> 53 #include <functional> 54 55 // Fwd declarations 56 namespace cvdescriptorset { 57 class DescriptorSet; 58 }; 59 60 class BASE_NODE { 61 public: 62 std::atomic_int in_use; 63 }; 64 65 class BUFFER_NODE : public BASE_NODE { 66 public: 67 using BASE_NODE::in_use; 68 VkDeviceMemory mem; 69 VkBufferCreateInfo createInfo; 70 BUFFER_NODE() : mem(VK_NULL_HANDLE), createInfo{} { in_use.store(0); }; 71 BUFFER_NODE(const VkBufferCreateInfo *pCreateInfo) : mem(VK_NULL_HANDLE), createInfo(*pCreateInfo) { in_use.store(0); }; 72 BUFFER_NODE(const BUFFER_NODE &rh_obj) : mem(rh_obj.mem), createInfo(rh_obj.createInfo) { in_use.store(rh_obj.in_use.load()); }; 73 }; 74 75 struct SAMPLER_NODE { 76 VkSampler sampler; 77 VkSamplerCreateInfo createInfo; 78 79 SAMPLER_NODE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci){}; 80 }; 81 82 class IMAGE_NODE : public BASE_NODE { 83 public: 84 using BASE_NODE::in_use; 85 VkImageCreateInfo createInfo; 86 VkDeviceMemory mem; 87 bool valid; // If this is a swapchain image backing memory track valid here as it doesn't have DEVICE_MEM_INFO 88 VkDeviceSize memOffset; 89 VkDeviceSize memSize; 90 IMAGE_NODE() : createInfo{}, mem(VK_NULL_HANDLE), valid(false), memOffset(0), memSize(0) { in_use.store(0); }; 91 IMAGE_NODE(const VkImageCreateInfo *pCreateInfo) 92 : createInfo(*pCreateInfo), mem(VK_NULL_HANDLE), valid(false), memOffset(0), memSize(0) { 93 in_use.store(0); 94 }; 95 IMAGE_NODE(const IMAGE_NODE &rh_obj) 96 : createInfo(rh_obj.createInfo), mem(rh_obj.mem), valid(rh_obj.valid), memOffset(rh_obj.memOffset), 97 memSize(rh_obj.memSize) { 98 in_use.store(rh_obj.in_use.load()); 99 }; 100 }; 101 102 // Simple struct to hold handle and type of object so they can be uniquely identified and looked up in appropriate map 103 struct MT_OBJ_HANDLE_TYPE { 104 uint64_t handle; 105 VkDebugReportObjectTypeEXT type; 106 }; 107 108 inline bool operator==(MT_OBJ_HANDLE_TYPE a, MT_OBJ_HANDLE_TYPE b) NOEXCEPT { return a.handle == b.handle && a.type == b.type; } 109 110 namespace std { 111 template <> struct hash<MT_OBJ_HANDLE_TYPE> { 112 size_t operator()(MT_OBJ_HANDLE_TYPE obj) const NOEXCEPT { return hash<uint64_t>()(obj.handle) ^ hash<uint32_t>()(obj.type); } 113 }; 114 } 115 116 struct MemRange { 117 VkDeviceSize offset; 118 VkDeviceSize size; 119 }; 120 121 struct MEMORY_RANGE { 122 uint64_t handle; 123 VkDeviceMemory memory; 124 VkDeviceSize start; 125 VkDeviceSize end; 126 }; 127 128 // Data struct for tracking memory object 129 struct DEVICE_MEM_INFO { 130 void *object; // Dispatchable object used to create this memory (device of swapchain) 131 bool valid; // Stores if the memory has valid data or not 132 VkDeviceMemory mem; 133 VkMemoryAllocateInfo allocInfo; 134 std::unordered_set<MT_OBJ_HANDLE_TYPE> objBindings; // objects bound to this memory 135 std::unordered_set<VkCommandBuffer> commandBufferBindings; // cmd buffers referencing this memory 136 std::vector<MEMORY_RANGE> bufferRanges; 137 std::vector<MEMORY_RANGE> imageRanges; 138 VkImage image; // If memory is bound to image, this will have VkImage handle, else VK_NULL_HANDLE 139 MemRange memRange; 140 void *pData, *pDriverData; 141 }; 142 143 class SWAPCHAIN_NODE { 144 public: 145 VkSwapchainCreateInfoKHR createInfo; 146 uint32_t *pQueueFamilyIndices; 147 std::vector<VkImage> images; 148 SWAPCHAIN_NODE(const VkSwapchainCreateInfoKHR *pCreateInfo) : createInfo(*pCreateInfo), pQueueFamilyIndices(NULL) { 149 if (pCreateInfo->queueFamilyIndexCount && pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) { 150 pQueueFamilyIndices = new uint32_t[pCreateInfo->queueFamilyIndexCount]; 151 memcpy(pQueueFamilyIndices, pCreateInfo->pQueueFamilyIndices, pCreateInfo->queueFamilyIndexCount * sizeof(uint32_t)); 152 createInfo.pQueueFamilyIndices = pQueueFamilyIndices; 153 } 154 } 155 ~SWAPCHAIN_NODE() { delete[] pQueueFamilyIndices; } 156 }; 157 158 enum DRAW_TYPE { 159 DRAW = 0, 160 DRAW_INDEXED = 1, 161 DRAW_INDIRECT = 2, 162 DRAW_INDEXED_INDIRECT = 3, 163 DRAW_BEGIN_RANGE = DRAW, 164 DRAW_END_RANGE = DRAW_INDEXED_INDIRECT, 165 NUM_DRAW_TYPES = (DRAW_END_RANGE - DRAW_BEGIN_RANGE + 1), 166 }; 167 168 class IMAGE_CMD_BUF_LAYOUT_NODE { 169 public: 170 IMAGE_CMD_BUF_LAYOUT_NODE() {} 171 IMAGE_CMD_BUF_LAYOUT_NODE(VkImageLayout initialLayoutInput, VkImageLayout layoutInput) 172 : initialLayout(initialLayoutInput), layout(layoutInput) {} 173 174 VkImageLayout initialLayout; 175 VkImageLayout layout; 176 }; 177 178 struct MT_PASS_ATTACHMENT_INFO { 179 uint32_t attachment; 180 VkAttachmentLoadOp load_op; 181 VkAttachmentStoreOp store_op; 182 }; 183 184 // Store the DAG. 185 struct DAGNode { 186 uint32_t pass; 187 std::vector<uint32_t> prev; 188 std::vector<uint32_t> next; 189 }; 190 191 struct RENDER_PASS_NODE { 192 VkRenderPass renderPass; 193 VkRenderPassCreateInfo const *pCreateInfo; 194 std::vector<bool> hasSelfDependency; 195 std::vector<DAGNode> subpassToNode; 196 std::vector<std::vector<VkFormat>> subpassColorFormats; 197 std::vector<MT_PASS_ATTACHMENT_INFO> attachments; 198 std::unordered_map<uint32_t, bool> attachment_first_read; 199 std::unordered_map<uint32_t, VkImageLayout> attachment_first_layout; 200 201 RENDER_PASS_NODE(VkRenderPassCreateInfo const *pCreateInfo) : pCreateInfo(pCreateInfo) { 202 uint32_t i; 203 204 subpassColorFormats.reserve(pCreateInfo->subpassCount); 205 for (i = 0; i < pCreateInfo->subpassCount; i++) { 206 const VkSubpassDescription *subpass = &pCreateInfo->pSubpasses[i]; 207 std::vector<VkFormat> color_formats; 208 uint32_t j; 209 210 color_formats.reserve(subpass->colorAttachmentCount); 211 for (j = 0; j < subpass->colorAttachmentCount; j++) { 212 const uint32_t att = subpass->pColorAttachments[j].attachment; 213 214 if (att != VK_ATTACHMENT_UNUSED) { 215 color_formats.push_back(pCreateInfo->pAttachments[att].format); 216 } 217 else { 218 color_formats.push_back(VK_FORMAT_UNDEFINED); 219 } 220 } 221 222 subpassColorFormats.push_back(color_formats); 223 } 224 } 225 }; 226 227 // Cmd Buffer Tracking 228 enum CMD_TYPE { 229 CMD_BINDPIPELINE, 230 CMD_BINDPIPELINEDELTA, 231 CMD_SETVIEWPORTSTATE, 232 CMD_SETSCISSORSTATE, 233 CMD_SETLINEWIDTHSTATE, 234 CMD_SETDEPTHBIASSTATE, 235 CMD_SETBLENDSTATE, 236 CMD_SETDEPTHBOUNDSSTATE, 237 CMD_SETSTENCILREADMASKSTATE, 238 CMD_SETSTENCILWRITEMASKSTATE, 239 CMD_SETSTENCILREFERENCESTATE, 240 CMD_BINDDESCRIPTORSETS, 241 CMD_BINDINDEXBUFFER, 242 CMD_BINDVERTEXBUFFER, 243 CMD_DRAW, 244 CMD_DRAWINDEXED, 245 CMD_DRAWINDIRECT, 246 CMD_DRAWINDEXEDINDIRECT, 247 CMD_DISPATCH, 248 CMD_DISPATCHINDIRECT, 249 CMD_COPYBUFFER, 250 CMD_COPYIMAGE, 251 CMD_BLITIMAGE, 252 CMD_COPYBUFFERTOIMAGE, 253 CMD_COPYIMAGETOBUFFER, 254 CMD_CLONEIMAGEDATA, 255 CMD_UPDATEBUFFER, 256 CMD_FILLBUFFER, 257 CMD_CLEARCOLORIMAGE, 258 CMD_CLEARATTACHMENTS, 259 CMD_CLEARDEPTHSTENCILIMAGE, 260 CMD_RESOLVEIMAGE, 261 CMD_SETEVENT, 262 CMD_RESETEVENT, 263 CMD_WAITEVENTS, 264 CMD_PIPELINEBARRIER, 265 CMD_BEGINQUERY, 266 CMD_ENDQUERY, 267 CMD_RESETQUERYPOOL, 268 CMD_COPYQUERYPOOLRESULTS, 269 CMD_WRITETIMESTAMP, 270 CMD_PUSHCONSTANTS, 271 CMD_INITATOMICCOUNTERS, 272 CMD_LOADATOMICCOUNTERS, 273 CMD_SAVEATOMICCOUNTERS, 274 CMD_BEGINRENDERPASS, 275 CMD_NEXTSUBPASS, 276 CMD_ENDRENDERPASS, 277 CMD_EXECUTECOMMANDS, 278 CMD_END, // Should be last command in any RECORDED cmd buffer 279 }; 280 281 // Data structure for holding sequence of cmds in cmd buffer 282 struct CMD_NODE { 283 CMD_TYPE type; 284 uint64_t cmdNumber; 285 }; 286 287 enum CB_STATE { 288 CB_NEW, // Newly created CB w/o any cmds 289 CB_RECORDING, // BeginCB has been called on this CB 290 CB_RECORDED, // EndCB has been called on this CB 291 CB_INVALID // CB had a bound descriptor set destroyed or updated 292 }; 293 294 // CB Status -- used to track status of various bindings on cmd buffer objects 295 typedef VkFlags CBStatusFlags; 296 enum CBStatusFlagBits { 297 // clang-format off 298 CBSTATUS_NONE = 0x00000000, // No status is set 299 CBSTATUS_VIEWPORT_SET = 0x00000001, // Viewport has been set 300 CBSTATUS_LINE_WIDTH_SET = 0x00000002, // Line width has been set 301 CBSTATUS_DEPTH_BIAS_SET = 0x00000004, // Depth bias has been set 302 CBSTATUS_BLEND_CONSTANTS_SET = 0x00000008, // Blend constants state has been set 303 CBSTATUS_DEPTH_BOUNDS_SET = 0x00000010, // Depth bounds state object has been set 304 CBSTATUS_STENCIL_READ_MASK_SET = 0x00000020, // Stencil read mask has been set 305 CBSTATUS_STENCIL_WRITE_MASK_SET = 0x00000040, // Stencil write mask has been set 306 CBSTATUS_STENCIL_REFERENCE_SET = 0x00000080, // Stencil reference has been set 307 CBSTATUS_INDEX_BUFFER_BOUND = 0x00000100, // Index buffer has been set 308 CBSTATUS_SCISSOR_SET = 0x00000200, // Scissor has been set 309 CBSTATUS_ALL = 0x000003FF, // All dynamic state set 310 // clang-format on 311 }; 312 313 struct QueryObject { 314 VkQueryPool pool; 315 uint32_t index; 316 }; 317 318 inline bool operator==(const QueryObject &query1, const QueryObject &query2) { 319 return (query1.pool == query2.pool && query1.index == query2.index); 320 } 321 322 namespace std { 323 template <> struct hash<QueryObject> { 324 size_t operator()(QueryObject query) const throw() { 325 return hash<uint64_t>()((uint64_t)(query.pool)) ^ hash<uint32_t>()(query.index); 326 } 327 }; 328 } 329 struct DRAW_DATA { std::vector<VkBuffer> buffers; }; 330 331 struct ImageSubresourcePair { 332 VkImage image; 333 bool hasSubresource; 334 VkImageSubresource subresource; 335 }; 336 337 inline bool operator==(const ImageSubresourcePair &img1, const ImageSubresourcePair &img2) { 338 if (img1.image != img2.image || img1.hasSubresource != img2.hasSubresource) 339 return false; 340 return !img1.hasSubresource || 341 (img1.subresource.aspectMask == img2.subresource.aspectMask && img1.subresource.mipLevel == img2.subresource.mipLevel && 342 img1.subresource.arrayLayer == img2.subresource.arrayLayer); 343 } 344 345 namespace std { 346 template <> struct hash<ImageSubresourcePair> { 347 size_t operator()(ImageSubresourcePair img) const throw() { 348 size_t hashVal = hash<uint64_t>()(reinterpret_cast<uint64_t &>(img.image)); 349 hashVal ^= hash<bool>()(img.hasSubresource); 350 if (img.hasSubresource) { 351 hashVal ^= hash<uint32_t>()(reinterpret_cast<uint32_t &>(img.subresource.aspectMask)); 352 hashVal ^= hash<uint32_t>()(img.subresource.mipLevel); 353 hashVal ^= hash<uint32_t>()(img.subresource.arrayLayer); 354 } 355 return hashVal; 356 } 357 }; 358 } 359 360 // Track last states that are bound per pipeline bind point (Gfx & Compute) 361 struct LAST_BOUND_STATE { 362 VkPipeline pipeline; 363 VkPipelineLayout pipelineLayout; 364 // Track each set that has been bound 365 // TODO : can unique be global per CB? (do we care about Gfx vs. Compute?) 366 std::unordered_set<cvdescriptorset::DescriptorSet *> uniqueBoundSets; 367 // Ordered bound set tracking where index is set# that given set is bound to 368 std::vector<cvdescriptorset::DescriptorSet *> boundDescriptorSets; 369 // one dynamic offset per dynamic descriptor bound to this CB 370 std::vector<std::vector<uint32_t>> dynamicOffsets; 371 372 void reset() { 373 pipeline = VK_NULL_HANDLE; 374 pipelineLayout = VK_NULL_HANDLE; 375 uniqueBoundSets.clear(); 376 boundDescriptorSets.clear(); 377 dynamicOffsets.clear(); 378 } 379 }; 380 // Cmd Buffer Wrapper Struct - TODO : This desperately needs its own class 381 struct GLOBAL_CB_NODE : public BASE_NODE { 382 VkCommandBuffer commandBuffer; 383 VkCommandBufferAllocateInfo createInfo; 384 VkCommandBufferBeginInfo beginInfo; 385 VkCommandBufferInheritanceInfo inheritanceInfo; 386 // VkFence fence; // fence tracking this cmd buffer 387 VkDevice device; // device this CB belongs to 388 uint64_t numCmds; // number of cmds in this CB 389 uint64_t drawCount[NUM_DRAW_TYPES]; // Count of each type of draw in this CB 390 CB_STATE state; // Track cmd buffer update state 391 uint64_t submitCount; // Number of times CB has been submitted 392 CBStatusFlags status; // Track status of various bindings on cmd buffer 393 std::vector<CMD_NODE> cmds; // vector of commands bound to this command buffer 394 // Currently storing "lastBound" objects on per-CB basis 395 // long-term may want to create caches of "lastBound" states and could have 396 // each individual CMD_NODE referencing its own "lastBound" state 397 // Store last bound state for Gfx & Compute pipeline bind points 398 LAST_BOUND_STATE lastBound[VK_PIPELINE_BIND_POINT_RANGE_SIZE]; 399 400 std::vector<VkViewport> viewports; 401 std::vector<VkRect2D> scissors; 402 VkRenderPassBeginInfo activeRenderPassBeginInfo; 403 uint64_t fenceId; 404 VkFence lastSubmittedFence; 405 VkQueue lastSubmittedQueue; 406 RENDER_PASS_NODE *activeRenderPass; 407 VkSubpassContents activeSubpassContents; 408 uint32_t activeSubpass; 409 VkFramebuffer activeFramebuffer; 410 std::unordered_set<VkFramebuffer> framebuffers; 411 // Track descriptor sets that are destroyed or updated while bound to CB 412 // TODO : These data structures relate to tracking resources that invalidate 413 // a cmd buffer that references them. Need to unify how we handle these 414 // cases so we don't have different tracking data for each type. 415 std::unordered_set<cvdescriptorset::DescriptorSet *> destroyedSets; 416 std::unordered_set<cvdescriptorset::DescriptorSet *> updatedSets; 417 std::unordered_set<VkFramebuffer> destroyedFramebuffers; 418 std::unordered_set<VkEvent> waitedEvents; 419 std::vector<VkEvent> writeEventsBeforeWait; 420 std::vector<VkSemaphore> semaphores; 421 std::vector<VkEvent> events; 422 std::unordered_map<QueryObject, std::unordered_set<VkEvent>> waitedEventsBeforeQueryReset; 423 std::unordered_map<QueryObject, bool> queryToStateMap; // 0 is unavailable, 1 is available 424 std::unordered_set<QueryObject> activeQueries; 425 std::unordered_set<QueryObject> startedQueries; 426 std::unordered_map<ImageSubresourcePair, IMAGE_CMD_BUF_LAYOUT_NODE> imageLayoutMap; 427 std::unordered_map<VkImage, std::vector<ImageSubresourcePair>> imageSubresourceMap; 428 std::unordered_map<VkEvent, VkPipelineStageFlags> eventToStageMap; 429 std::vector<DRAW_DATA> drawData; 430 DRAW_DATA currentDrawData; 431 VkCommandBuffer primaryCommandBuffer; 432 // Track images and buffers that are updated by this CB at the point of a draw 433 std::unordered_set<VkImageView> updateImages; 434 std::unordered_set<VkBuffer> updateBuffers; 435 // If cmd buffer is primary, track secondary command buffers pending 436 // execution 437 std::unordered_set<VkCommandBuffer> secondaryCommandBuffers; 438 // MTMTODO : Scrub these data fields and merge active sets w/ lastBound as appropriate 439 std::vector<std::function<bool()>> validate_functions; 440 std::unordered_set<VkDeviceMemory> memObjs; 441 std::vector<std::function<bool(VkQueue)>> eventUpdates; 442 std::vector<std::function<bool(VkQueue)>> queryUpdates; 443 444 ~GLOBAL_CB_NODE(); 445 }; 446 447 #endif // CORE_VALIDATION_TYPES_H_ 448