1 #ifndef _VKTSYNCHRONIZATIONUTIL_HPP 2 #define _VKTSYNCHRONIZATIONUTIL_HPP 3 /*------------------------------------------------------------------------ 4 * Vulkan Conformance Tests 5 * ------------------------ 6 * 7 * Copyright (c) 2016 The Khronos Group Inc. 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Synchronization tests utilities 24 *//*--------------------------------------------------------------------*/ 25 26 #include "vkDefs.hpp" 27 #include "vkObjUtil.hpp" 28 #include "vkQueryUtil.hpp" 29 #include "vkMemUtil.hpp" 30 #include "vkRefUtil.hpp" 31 #include "vkPrograms.hpp" 32 #include "tcuVector.hpp" 33 #include "deMutex.hpp" 34 #include <memory> 35 #include "vkResourceInterface.hpp" 36 #include "vktCustomInstancesDevices.hpp" 37 38 namespace vkt 39 { 40 namespace synchronization 41 { 42 43 enum class SynchronizationType 44 { 45 LEGACY = 0, 46 SYNCHRONIZATION2, 47 }; 48 49 #ifdef CTS_USES_VULKANSC 50 #define VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR 51 #define VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR 52 #define VkDependencyInfo VkDependencyInfoKHR 53 #define VkPipelineStageFlags2 VkPipelineStageFlags2KHR 54 #define VkAccessFlags2 VkAccessFlags2KHR 55 #define VkMemoryBarrier2 VkMemoryBarrier2KHR 56 #define VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR 57 #define VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR 58 #define VkSubmitInfo2 VkSubmitInfo2KHR 59 #endif // CTS_USES_VULKANSC 60 61 class Buffer 62 { 63 public: Buffer(const vk::DeviceInterface & vk,const vk::VkDevice device,vk::Allocator & allocator,const vk::VkBufferCreateInfo & bufferCreateInfo,const vk::MemoryRequirement memoryRequirement)64 Buffer(const vk::DeviceInterface &vk, const vk::VkDevice device, vk::Allocator &allocator, 65 const vk::VkBufferCreateInfo &bufferCreateInfo, const vk::MemoryRequirement memoryRequirement) 66 : m_buffer(createBuffer(vk, device, &bufferCreateInfo)) 67 , m_allocation(allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), memoryRequirement)) 68 { 69 VK_CHECK(vk.bindBufferMemory(device, *m_buffer, m_allocation->getMemory(), m_allocation->getOffset())); 70 } 71 Buffer(vk::Move<vk::VkBuffer> buffer,de::MovePtr<vk::Allocation> allocation)72 Buffer(vk::Move<vk::VkBuffer> buffer, de::MovePtr<vk::Allocation> allocation) 73 : m_buffer(buffer) 74 , m_allocation(allocation) 75 { 76 } 77 get(void) const78 const vk::VkBuffer &get(void) const 79 { 80 return *m_buffer; 81 } operator *(void) const82 const vk::VkBuffer &operator*(void) const 83 { 84 return get(); 85 } getAllocation(void) const86 vk::Allocation &getAllocation(void) const 87 { 88 return *m_allocation; 89 } 90 91 private: 92 const vk::Unique<vk::VkBuffer> m_buffer; 93 const de::UniquePtr<vk::Allocation> m_allocation; 94 95 // "deleted" 96 Buffer(const Buffer &); 97 Buffer &operator=(const Buffer &); 98 }; 99 100 class Image 101 { 102 public: Image(const vk::DeviceInterface & vk,const vk::VkDevice device,vk::Allocator & allocator,const vk::VkImageCreateInfo & imageCreateInfo,const vk::MemoryRequirement memoryRequirement)103 Image(const vk::DeviceInterface &vk, const vk::VkDevice device, vk::Allocator &allocator, 104 const vk::VkImageCreateInfo &imageCreateInfo, const vk::MemoryRequirement memoryRequirement) 105 : m_image(createImage(vk, device, &imageCreateInfo)) 106 , m_allocation(allocator.allocate(getImageMemoryRequirements(vk, device, *m_image), memoryRequirement)) 107 { 108 VK_CHECK(vk.bindImageMemory(device, *m_image, m_allocation->getMemory(), m_allocation->getOffset())); 109 } Image(vk::Move<vk::VkImage> & image,de::MovePtr<vk::Allocation> & allocation)110 Image(vk::Move<vk::VkImage> &image, de::MovePtr<vk::Allocation> &allocation) 111 : m_image(image) 112 , m_allocation(allocation) 113 { 114 } 115 get(void) const116 const vk::VkImage &get(void) const 117 { 118 return *m_image; 119 } operator *(void) const120 const vk::VkImage &operator*(void) const 121 { 122 return get(); 123 } getAllocation(void) const124 vk::Allocation &getAllocation(void) const 125 { 126 return *m_allocation; 127 } 128 129 private: 130 const vk::Unique<vk::VkImage> m_image; 131 const de::UniquePtr<vk::Allocation> m_allocation; 132 133 // "deleted" 134 Image(const Image &); 135 Image &operator=(const Image &); 136 }; 137 138 class PipelineCacheData 139 { 140 public: 141 PipelineCacheData(void); 142 ~PipelineCacheData(void); 143 144 vk::Move<vk::VkPipelineCache> createPipelineCache(const vk::DeviceInterface &vk, const vk::VkDevice device, 145 de::SharedPtr<vk::ResourceInterface> resourceInterface) const; 146 void setFromPipelineCache(const vk::DeviceInterface &vk, const vk::VkDevice device, 147 const vk::VkPipelineCache pipelineCache); 148 149 private: 150 mutable de::Mutex m_lock; 151 std::vector<uint8_t> m_data; 152 }; 153 154 class GraphicsPipelineBuilder 155 { 156 public: GraphicsPipelineBuilder(void)157 GraphicsPipelineBuilder(void) 158 : m_renderSize(0, 0) 159 , m_shaderStageFlags(0u) 160 , m_cullModeFlags(vk::VK_CULL_MODE_NONE) 161 , m_frontFace(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE) 162 , m_patchControlPoints(1u) 163 , m_blendEnable(false) 164 , m_primitiveTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) 165 { 166 } 167 setRenderSize(const tcu::IVec2 & size)168 GraphicsPipelineBuilder &setRenderSize(const tcu::IVec2 &size) 169 { 170 m_renderSize = size; 171 return *this; 172 } 173 GraphicsPipelineBuilder &setShader(const vk::DeviceInterface &vk, const vk::VkDevice device, 174 const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary &binary, 175 const vk::VkSpecializationInfo *specInfo); setPatchControlPoints(const uint32_t controlPoints)176 GraphicsPipelineBuilder &setPatchControlPoints(const uint32_t controlPoints) 177 { 178 m_patchControlPoints = controlPoints; 179 return *this; 180 } setCullModeFlags(const vk::VkCullModeFlags cullModeFlags)181 GraphicsPipelineBuilder &setCullModeFlags(const vk::VkCullModeFlags cullModeFlags) 182 { 183 m_cullModeFlags = cullModeFlags; 184 return *this; 185 } setFrontFace(const vk::VkFrontFace frontFace)186 GraphicsPipelineBuilder &setFrontFace(const vk::VkFrontFace frontFace) 187 { 188 m_frontFace = frontFace; 189 return *this; 190 } setBlend(const bool enable)191 GraphicsPipelineBuilder &setBlend(const bool enable) 192 { 193 m_blendEnable = enable; 194 return *this; 195 } 196 197 //! Applies only to pipelines without tessellation shaders. setPrimitiveTopology(const vk::VkPrimitiveTopology topology)198 GraphicsPipelineBuilder &setPrimitiveTopology(const vk::VkPrimitiveTopology topology) 199 { 200 m_primitiveTopology = topology; 201 return *this; 202 } 203 addVertexBinding(const vk::VkVertexInputBindingDescription vertexBinding)204 GraphicsPipelineBuilder &addVertexBinding(const vk::VkVertexInputBindingDescription vertexBinding) 205 { 206 m_vertexInputBindings.push_back(vertexBinding); 207 return *this; 208 } addVertexAttribute(const vk::VkVertexInputAttributeDescription vertexAttribute)209 GraphicsPipelineBuilder &addVertexAttribute(const vk::VkVertexInputAttributeDescription vertexAttribute) 210 { 211 m_vertexInputAttributes.push_back(vertexAttribute); 212 return *this; 213 } 214 215 //! Basic vertex input configuration (uses biding 0, location 0, etc.) 216 GraphicsPipelineBuilder &setVertexInputSingleAttribute(const vk::VkFormat vertexFormat, const uint32_t stride); 217 218 vk::Move<vk::VkPipeline> build(const vk::DeviceInterface &vk, const vk::VkDevice device, 219 const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass, 220 PipelineCacheData &pipelineCacheData, 221 de::SharedPtr<vk::ResourceInterface> resourceInterface); 222 223 private: 224 tcu::IVec2 m_renderSize; 225 vk::Move<vk::VkShaderModule> m_vertexShaderModule; 226 vk::Move<vk::VkShaderModule> m_fragmentShaderModule; 227 vk::Move<vk::VkShaderModule> m_geometryShaderModule; 228 vk::Move<vk::VkShaderModule> m_tessControlShaderModule; 229 vk::Move<vk::VkShaderModule> m_tessEvaluationShaderModule; 230 std::vector<vk::VkPipelineShaderStageCreateInfo> m_shaderStages; 231 std::vector<vk::VkVertexInputBindingDescription> m_vertexInputBindings; 232 std::vector<vk::VkVertexInputAttributeDescription> m_vertexInputAttributes; 233 vk::VkShaderStageFlags m_shaderStageFlags; 234 vk::VkCullModeFlags m_cullModeFlags; 235 vk::VkFrontFace m_frontFace; 236 uint32_t m_patchControlPoints; 237 bool m_blendEnable; 238 vk::VkPrimitiveTopology m_primitiveTopology; 239 240 GraphicsPipelineBuilder(const GraphicsPipelineBuilder &); // "deleted" 241 GraphicsPipelineBuilder &operator=(const GraphicsPipelineBuilder &); 242 }; 243 244 // Base class that abstracts over legacy synchronization and synchronization changes 245 // introduced with VK_KHR_synchronization2 extension. Since structures in 246 // VK_KHR_synchronization2 have more features this wrapper uses them and when legacy 247 // implementation is used in tests then data from new structures is used to fill legacy ones. 248 class SynchronizationWrapperBase 249 { 250 public: SynchronizationWrapperBase(const vk::DeviceInterface & vk)251 SynchronizationWrapperBase(const vk::DeviceInterface &vk) : m_vk(vk) 252 { 253 } 254 255 virtual ~SynchronizationWrapperBase() = default; 256 257 virtual void addSubmitInfo(uint32_t waitSemaphoreInfoCount, const vk::VkSemaphoreSubmitInfo *pWaitSemaphoreInfos, 258 uint32_t commandBufferInfoCount, 259 const vk::VkCommandBufferSubmitInfo *pCommandBufferInfos, 260 uint32_t signalSemaphoreInfoCount, 261 const vk::VkSemaphoreSubmitInfo *pSignalSemaphoreInfos, 262 bool usingWaitTimelineSemaphore = false, bool usingSignalTimelineSemaphore = false) = 0; 263 264 virtual void cmdPipelineBarrier(vk::VkCommandBuffer commandBuffer, 265 const vk::VkDependencyInfo *pDependencyInfo) const = 0; 266 267 virtual void cmdSetEvent(vk::VkCommandBuffer commandBuffer, vk::VkEvent event, 268 const vk::VkDependencyInfo *pDependencyInfo) const = 0; 269 virtual void cmdResetEvent(vk::VkCommandBuffer commandBuffer, vk::VkEvent event, 270 vk::VkPipelineStageFlags2 flag) const = 0; 271 virtual void cmdWaitEvents(vk::VkCommandBuffer commandBuffer, uint32_t eventCount, const vk::VkEvent *pEvents, 272 const vk::VkDependencyInfo *pDependencyInfo) const = 0; 273 274 virtual vk::VkResult queueSubmit(vk::VkQueue queue, vk::VkFence fence) = 0; 275 276 protected: 277 const vk::DeviceInterface &m_vk; 278 }; 279 280 enum FeatureFlagBits 281 { 282 FEATURE_TESSELLATION_SHADER = 1u << 0, 283 FEATURE_GEOMETRY_SHADER = 1u << 1, 284 FEATURE_SHADER_FLOAT_64 = 1u << 2, 285 FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS = 1u << 3, 286 FEATURE_FRAGMENT_STORES_AND_ATOMICS = 1u << 4, 287 FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 1u << 5, 288 }; 289 typedef uint32_t FeatureFlags; 290 291 enum SyncPrimitive 292 { 293 SYNC_PRIMITIVE_FENCE, 294 SYNC_PRIMITIVE_BINARY_SEMAPHORE, 295 SYNC_PRIMITIVE_TIMELINE_SEMAPHORE, 296 SYNC_PRIMITIVE_BARRIER, 297 SYNC_PRIMITIVE_EVENT, 298 }; 299 300 enum ResourceType 301 { 302 RESOURCE_TYPE_BUFFER, 303 RESOURCE_TYPE_IMAGE, 304 RESOURCE_TYPE_INDIRECT_BUFFER_DRAW, 305 RESOURCE_TYPE_INDIRECT_BUFFER_DRAW_INDEXED, 306 RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH, 307 RESOURCE_TYPE_INDEX_BUFFER, 308 }; 309 310 struct ResourceDescription 311 { 312 ResourceType type; 313 tcu::IVec4 size; //!< unused components are 0, e.g. for buffers only x is meaningful 314 vk::VkImageType imageType; 315 vk::VkFormat imageFormat; 316 vk::VkImageAspectFlags imageAspect; 317 vk::VkSampleCountFlagBits imageSamples; 318 }; 319 320 struct BufferResource 321 { BufferResourcevkt::synchronization::BufferResource322 BufferResource(vk::VkBuffer handle_, vk::VkDeviceSize offset_, vk::VkDeviceSize size_) 323 : handle(handle_) 324 , offset(offset_) 325 , size(size_) 326 { 327 } 328 329 vk::VkBuffer handle; 330 vk::VkDeviceSize offset; 331 vk::VkDeviceSize size; 332 }; 333 334 struct ImageResource 335 { ImageResourcevkt::synchronization::ImageResource336 ImageResource(vk::VkImage handle_, vk::VkExtent3D extent_, vk::VkImageType imageType_, vk::VkFormat format_, 337 vk::VkImageSubresourceRange subresourceRange_, vk::VkImageSubresourceLayers subresourceLayers_, 338 vk::VkImageTiling tiling_) 339 : handle(handle_) 340 , extent(extent_) 341 , imageType(imageType_) 342 , format(format_) 343 , subresourceRange(subresourceRange_) 344 , subresourceLayers(subresourceLayers_) 345 , tiling(tiling_) 346 { 347 } 348 349 vk::VkImage handle; 350 vk::VkExtent3D extent; 351 vk::VkImageType imageType; 352 vk::VkFormat format; 353 vk::VkImageSubresourceRange subresourceRange; 354 vk::VkImageSubresourceLayers subresourceLayers; 355 vk::VkImageTiling tiling; 356 }; 357 358 typedef std::shared_ptr<SynchronizationWrapperBase> SynchronizationWrapperPtr; 359 SynchronizationWrapperPtr getSynchronizationWrapper(SynchronizationType type, const vk::DeviceInterface &vk, 360 bool usingTimelineSemaphores, uint32_t submitInfoCount = 1u); 361 void submitCommandsAndWait(SynchronizationWrapperPtr synchronizationWrapper, const vk::DeviceInterface &vk, 362 const vk::VkDevice device, const vk::VkQueue queue, const vk::VkCommandBuffer cmdBuffer); 363 vk::VkImageCreateInfo makeImageCreateInfo(const vk::VkImageType imageType, const vk::VkExtent3D &extent, 364 const vk::VkFormat format, const vk::VkImageUsageFlags usage, 365 const vk::VkSampleCountFlagBits samples, const vk::VkImageTiling tiling); 366 vk::Move<vk::VkCommandBuffer> makeCommandBuffer(const vk::DeviceInterface &vk, const vk::VkDevice device, 367 const vk::VkCommandPool commandPool); 368 vk::Move<vk::VkPipeline> makeComputePipeline(const vk::DeviceInterface &vk, const vk::VkDevice device, 369 const vk::VkPipelineLayout pipelineLayout, 370 const vk::VkShaderModule shaderModule, 371 const vk::VkSpecializationInfo *specInfo, 372 PipelineCacheData &pipelineCacheData, 373 de::SharedPtr<vk::ResourceInterface> resourceInterface); 374 void beginRenderPassWithRasterizationDisabled(const vk::DeviceInterface &vk, const vk::VkCommandBuffer commandBuffer, 375 const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer); 376 void requireFeatures(const vk::InstanceInterface &vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags); 377 void requireStorageImageSupport(const vk::InstanceInterface &vki, const vk::VkPhysicalDevice physDevice, 378 const vk::VkFormat fmt, const vk::VkImageTiling tiling); 379 std::string getResourceName(const ResourceDescription &resource); 380 bool isIndirectBuffer(const ResourceType type); 381 vk::VkCommandBufferSubmitInfoKHR makeCommonCommandBufferSubmitInfo(const vk::VkCommandBuffer cmdBuf); 382 vk::VkSemaphoreSubmitInfoKHR makeCommonSemaphoreSubmitInfo(vk::VkSemaphore semaphore, uint64_t value, 383 vk::VkPipelineStageFlags2KHR stageMask); 384 vk::VkDependencyInfoKHR makeCommonDependencyInfo(const vk::VkMemoryBarrier2KHR *pMemoryBarrier = DE_NULL, 385 const vk::VkBufferMemoryBarrier2KHR *pBufferMemoryBarrier = DE_NULL, 386 const vk::VkImageMemoryBarrier2KHR *pImageMemoryBarrier = DE_NULL, 387 bool eventDependency = false); 388 389 vk::VkDevice getSyncDevice(de::MovePtr<VideoDevice> &device, Context &context); 390 const vk::DeviceInterface &getSyncDeviceInterface(de::MovePtr<VideoDevice> &device, Context &context); 391 uint32_t getSyncQueueFamilyIndex(de::MovePtr<VideoDevice> &device, Context &context); 392 vk::VkQueue getSyncQueue(de::MovePtr<VideoDevice> &device, Context &context); 393 } // namespace synchronization 394 } // namespace vkt 395 396 #endif // _VKTSYNCHRONIZATIONUTIL_HPP 397