Home | History | Annotate | Download | only in layers
      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