| Karl Schultz | 7b024b4 | 2018-08-30 16:18:18 -0600 | [diff] [blame^] | 1 | /* Copyright (c) 2018-2019 The Khronos Group Inc. |
| 2 | * Copyright (c) 2018-2019 Valve Corporation |
| 3 | * Copyright (c) 2018-2019 LunarG, Inc. |
| 4 | * Copyright (C) 2018-2019 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 | */ |
| 19 | |
| 20 | #ifndef VULKAN_GPU_VALIDATION_H |
| 21 | #define VULKAN_GPU_VALIDATION_H |
| 22 | |
| 23 | // Class to encapsulate Vulkan Device Memory allocations. |
| 24 | // It allocates device memory in large chunks for efficiency and to avoid |
| 25 | // hitting the device limit of the number of allocations. |
| 26 | // This manager handles only fixed-sized blocks of "data_size" bytes. |
| 27 | // The interface allows the caller to "get" and "put back" blocks. |
| 28 | // The manager allocates and frees chunks as needed. |
| 29 | |
| 30 | class GpuDeviceMemoryManager { |
| 31 | public: |
| 32 | GpuDeviceMemoryManager(layer_data *dev_data, uint32_t data_size) { |
| 33 | uint32_t align = static_cast<uint32_t>(GetPhysicalDeviceProperties(dev_data)->limits.minStorageBufferOffsetAlignment); |
| 34 | if (0 == align) { |
| 35 | align = 1; |
| 36 | } |
| 37 | record_size_ = data_size; |
| 38 | // Round the requested size up to the next multiple of the storage buffer offset alignment |
| 39 | // so that we can address each block in the storage buffer using the offset. |
| 40 | block_size_ = ((record_size_ + align - 1) / align) * align; |
| 41 | blocks_per_chunk_ = kItemsPerChunk; |
| 42 | chunk_size_ = blocks_per_chunk_ * block_size_; |
| 43 | dev_data_ = dev_data; |
| 44 | } |
| 45 | |
| 46 | ~GpuDeviceMemoryManager() { |
| 47 | for (auto &chunk : chunk_list_) { |
| 48 | FreeMemoryChunk(chunk); |
| 49 | } |
| 50 | chunk_list_.clear(); |
| 51 | } |
| 52 | |
| 53 | uint32_t GetBlockSize() { return block_size_; } |
| 54 | |
| 55 | VkResult GetBlock(GpuDeviceMemoryBlock *block); |
| 56 | void PutBackBlock(VkBuffer buffer, VkDeviceMemory memory, uint32_t offset); |
| 57 | void PutBackBlock(GpuDeviceMemoryBlock &block); |
| 58 | |
| 59 | private: |
| 60 | // Define allocation granularity of Vulkan resources. |
| 61 | // Things like device memory and descriptors are allocated in "chunks". |
| 62 | // This number should be chosen to try to avoid too many chunk allocations |
| 63 | // and chunk allocations that are too large. |
| 64 | static const uint32_t kItemsPerChunk = 512; |
| 65 | |
| 66 | struct MemoryChunk { |
| 67 | VkBuffer buffer; |
| 68 | VkDeviceMemory memory; |
| 69 | std::vector<uint32_t> available_offsets; |
| 70 | }; |
| 71 | |
| 72 | layer_data *dev_data_; |
| 73 | uint32_t record_size_; |
| 74 | uint32_t block_size_; |
| 75 | uint32_t blocks_per_chunk_; |
| 76 | uint32_t chunk_size_; |
| 77 | std::list<MemoryChunk> chunk_list_; |
| 78 | |
| 79 | bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); |
| 80 | VkResult AllocMemoryChunk(MemoryChunk &chunk); |
| 81 | void FreeMemoryChunk(MemoryChunk &chunk); |
| 82 | }; |
| 83 | |
| 84 | // Class to encapsulate Descriptor Set allocation. This manager creates and destroys Descriptor Pools |
| 85 | // as needed to satisfy requests for descriptor sets. |
| 86 | class GpuDescriptorSetManager { |
| 87 | public: |
| 88 | GpuDescriptorSetManager(layer_data *dev_data) { dev_data_ = dev_data; } |
| 89 | |
| 90 | ~GpuDescriptorSetManager() { |
| 91 | for (auto &pool : desc_pool_map_) { |
| 92 | GetDispatchTable(dev_data_)->DestroyDescriptorPool(GetDevice(dev_data_), pool.first, NULL); |
| 93 | } |
| 94 | desc_pool_map_.clear(); |
| 95 | } |
| 96 | |
| 97 | VkResult GetDescriptorSets(uint32_t count, VkDescriptorPool *pool, std::vector<VkDescriptorSet> *desc_sets); |
| 98 | void PutBackDescriptorSet(VkDescriptorPool desc_pool, VkDescriptorSet desc_set); |
| 99 | |
| 100 | private: |
| 101 | static const uint32_t kItemsPerChunk = 512; |
| 102 | struct PoolTracker { |
| 103 | uint32_t size; |
| 104 | uint32_t used; |
| 105 | }; |
| 106 | |
| 107 | layer_data *dev_data_; |
| 108 | std::unordered_map<VkDescriptorPool, struct PoolTracker> desc_pool_map_; |
| 109 | }; |
| 110 | |
| 111 | using mutex_t = std::mutex; |
| 112 | using lock_guard_t = std::lock_guard<mutex_t>; |
| 113 | using unique_lock_t = std::unique_lock<mutex_t>; |
| 114 | |
| 115 | std::unique_ptr<safe_VkDeviceCreateInfo> GpuPreCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *create_info, |
| 116 | VkPhysicalDeviceFeatures *supported_features); |
| 117 | void GpuPostCallRecordCreateDevice(layer_data *dev_data); |
| 118 | void GpuPreCallRecordDestroyDevice(layer_data *dev_data); |
| 119 | void GpuPostCallRecordAllocateCommandBuffers(layer_data *dev_data, const VkCommandBufferAllocateInfo *pCreateInfo, |
| 120 | VkCommandBuffer *pCommandBuffer); |
| 121 | void GpuPreCallRecordFreeCommandBuffers(layer_data *dev_data, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers); |
| 122 | VkResult GpuOverrideDispatchCreateShaderModule(layer_data *dev_data, const VkShaderModuleCreateInfo *pCreateInfo, |
| 123 | const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule, |
| 124 | uint32_t *unique_shader_id); |
| 125 | VkResult GpuOverrideDispatchCreatePipelineLayout(layer_data *dev_data, const VkPipelineLayoutCreateInfo *pCreateInfo, |
| 126 | const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout); |
| 127 | void GpuPostCallDispatchCmdBindPipeline(layer_data *dev_data, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, |
| 128 | VkPipeline pipeline); |
| 129 | void GpuPostCallQueueSubmit(const layer_data *dev_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, |
| 130 | VkFence fence, mutex_t &global_lock); |
| 131 | void GpuPreCallValidateCmdWaitEvents(layer_data *dev_data, VkPipelineStageFlags sourceStageMask); |
| 132 | std::vector<safe_VkGraphicsPipelineCreateInfo> GpuPreCallRecordCreateGraphicsPipelines( |
| 133 | layer_data *dev_data, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo *pCreateInfos, |
| 134 | const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines, std::vector<std::unique_ptr<PIPELINE_STATE>> &pipe_state); |
| 135 | void GpuPostCallRecordCreateGraphicsPipelines(layer_data *dev_data, const uint32_t count, |
| 136 | const VkGraphicsPipelineCreateInfo *pCreateInfos, |
| 137 | const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); |
| 138 | void GpuPreCallRecordDestroyPipeline(layer_data *dev_data, const VkPipeline pipeline); |
| 139 | |
| 140 | #endif // VULKAN_GPU_VALIDATION_H |