#ifndef _VKTSYNCHRONIZATIONUTIL_HPP #define _VKTSYNCHRONIZATIONUTIL_HPP /*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2016 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Synchronization tests utilities *//*--------------------------------------------------------------------*/ #include "vkDefs.hpp" #include "vkObjUtil.hpp" #include "vkQueryUtil.hpp" #include "vkMemUtil.hpp" #include "vkRefUtil.hpp" #include "vkPrograms.hpp" #include "tcuVector.hpp" #include "deMutex.hpp" #include #include "vkResourceInterface.hpp" #include "vktCustomInstancesDevices.hpp" namespace vkt { namespace synchronization { enum class SynchronizationType { LEGACY = 0, SYNCHRONIZATION2, }; #ifdef CTS_USES_VULKANSC #define VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR #define VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR #define VkDependencyInfo VkDependencyInfoKHR #define VkPipelineStageFlags2 VkPipelineStageFlags2KHR #define VkAccessFlags2 VkAccessFlags2KHR #define VkMemoryBarrier2 VkMemoryBarrier2KHR #define VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR #define VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR #define VkSubmitInfo2 VkSubmitInfo2KHR #endif // CTS_USES_VULKANSC class Buffer { public: Buffer (const vk::DeviceInterface& vk, const vk::VkDevice device, vk::Allocator& allocator, const vk::VkBufferCreateInfo& bufferCreateInfo, const vk::MemoryRequirement memoryRequirement) : m_buffer (createBuffer(vk, device, &bufferCreateInfo)) , m_allocation (allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), memoryRequirement)) { VK_CHECK(vk.bindBufferMemory(device, *m_buffer, m_allocation->getMemory(), m_allocation->getOffset())); } Buffer (vk::Move buffer, de::MovePtr allocation) : m_buffer (buffer) , m_allocation (allocation) { } const vk::VkBuffer& get (void) const { return *m_buffer; } const vk::VkBuffer& operator* (void) const { return get(); } vk::Allocation& getAllocation (void) const { return *m_allocation; } private: const vk::Unique m_buffer; const de::UniquePtr m_allocation; // "deleted" Buffer (const Buffer&); Buffer& operator= (const Buffer&); }; class Image { public: Image (const vk::DeviceInterface& vk, const vk::VkDevice device, vk::Allocator& allocator, const vk::VkImageCreateInfo& imageCreateInfo, const vk::MemoryRequirement memoryRequirement) : m_image (createImage(vk, device, &imageCreateInfo)) , m_allocation (allocator.allocate(getImageMemoryRequirements(vk, device, *m_image), memoryRequirement)) { VK_CHECK(vk.bindImageMemory(device, *m_image, m_allocation->getMemory(), m_allocation->getOffset())); } Image (vk::Move& image, de::MovePtr& allocation) : m_image (image) , m_allocation (allocation) { } const vk::VkImage& get (void) const { return *m_image; } const vk::VkImage& operator* (void) const { return get(); } vk::Allocation& getAllocation (void) const { return *m_allocation; } private: const vk::Unique m_image; const de::UniquePtr m_allocation; // "deleted" Image (const Image&); Image& operator= (const Image&); }; class PipelineCacheData { public: PipelineCacheData (void); ~PipelineCacheData (void); vk::Move createPipelineCache (const vk::DeviceInterface& vk, const vk::VkDevice device, de::SharedPtr resourceInterface) const; void setFromPipelineCache (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineCache pipelineCache); private: mutable de::Mutex m_lock; std::vector m_data; }; class GraphicsPipelineBuilder { public: GraphicsPipelineBuilder (void) : m_renderSize (0, 0) , m_shaderStageFlags (0u) , m_cullModeFlags (vk::VK_CULL_MODE_NONE) , m_frontFace (vk::VK_FRONT_FACE_COUNTER_CLOCKWISE) , m_patchControlPoints (1u) , m_blendEnable (false) , m_primitiveTopology (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) {} GraphicsPipelineBuilder& setRenderSize (const tcu::IVec2& size) { m_renderSize = size; return *this; } GraphicsPipelineBuilder& setShader (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary& binary, const vk::VkSpecializationInfo* specInfo); GraphicsPipelineBuilder& setPatchControlPoints (const deUint32 controlPoints) { m_patchControlPoints = controlPoints; return *this; } GraphicsPipelineBuilder& setCullModeFlags (const vk::VkCullModeFlags cullModeFlags) { m_cullModeFlags = cullModeFlags; return *this; } GraphicsPipelineBuilder& setFrontFace (const vk::VkFrontFace frontFace) { m_frontFace = frontFace; return *this; } GraphicsPipelineBuilder& setBlend (const bool enable) { m_blendEnable = enable; return *this; } //! Applies only to pipelines without tessellation shaders. GraphicsPipelineBuilder& setPrimitiveTopology (const vk::VkPrimitiveTopology topology) { m_primitiveTopology = topology; return *this; } GraphicsPipelineBuilder& addVertexBinding (const vk::VkVertexInputBindingDescription vertexBinding) { m_vertexInputBindings.push_back(vertexBinding); return *this; } GraphicsPipelineBuilder& addVertexAttribute (const vk::VkVertexInputAttributeDescription vertexAttribute) { m_vertexInputAttributes.push_back(vertexAttribute); return *this; } //! Basic vertex input configuration (uses biding 0, location 0, etc.) GraphicsPipelineBuilder& setVertexInputSingleAttribute (const vk::VkFormat vertexFormat, const deUint32 stride); vk::Move build(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass, PipelineCacheData& pipelineCacheData, de::SharedPtr resourceInterface); private: tcu::IVec2 m_renderSize; vk::Move m_vertexShaderModule; vk::Move m_fragmentShaderModule; vk::Move m_geometryShaderModule; vk::Move m_tessControlShaderModule; vk::Move m_tessEvaluationShaderModule; std::vector m_shaderStages; std::vector m_vertexInputBindings; std::vector m_vertexInputAttributes; vk::VkShaderStageFlags m_shaderStageFlags; vk::VkCullModeFlags m_cullModeFlags; vk::VkFrontFace m_frontFace; deUint32 m_patchControlPoints; bool m_blendEnable; vk::VkPrimitiveTopology m_primitiveTopology; GraphicsPipelineBuilder (const GraphicsPipelineBuilder&); // "deleted" GraphicsPipelineBuilder& operator= (const GraphicsPipelineBuilder&); }; // Base class that abstracts over legacy synchronization and synchronization changes // introduced with VK_KHR_synchronization2 extension. Since structures in // VK_KHR_synchronization2 have more features this wrapper uses them and when legacy // implementation is used in tests then data from new structures is used to fill legacy ones. class SynchronizationWrapperBase { public: SynchronizationWrapperBase(const vk::DeviceInterface& vk) : m_vk(vk) {} virtual ~SynchronizationWrapperBase() = default; virtual void addSubmitInfo (deUint32 waitSemaphoreInfoCount, const vk::VkSemaphoreSubmitInfo* pWaitSemaphoreInfos, deUint32 commandBufferInfoCount, const vk::VkCommandBufferSubmitInfo* pCommandBufferInfos, deUint32 signalSemaphoreInfoCount, const vk::VkSemaphoreSubmitInfo* pSignalSemaphoreInfos, bool usingWaitTimelineSemaphore = DE_FALSE, bool usingSignalTimelineSemaphore = DE_FALSE) = 0; virtual void cmdPipelineBarrier (vk::VkCommandBuffer commandBuffer, const vk::VkDependencyInfo* pDependencyInfo) const = 0; virtual void cmdSetEvent (vk::VkCommandBuffer commandBuffer, vk::VkEvent event, const vk::VkDependencyInfo* pDependencyInfo) const = 0; virtual void cmdResetEvent (vk::VkCommandBuffer commandBuffer, vk::VkEvent event, vk::VkPipelineStageFlags2 flag) const = 0; virtual void cmdWaitEvents (vk::VkCommandBuffer commandBuffer, deUint32 eventCount, const vk::VkEvent* pEvents, const vk::VkDependencyInfo* pDependencyInfo) const = 0; virtual vk::VkResult queueSubmit (vk::VkQueue queue, vk::VkFence fence) = 0; protected: const vk::DeviceInterface& m_vk; }; enum FeatureFlagBits { FEATURE_TESSELLATION_SHADER = 1u << 0, FEATURE_GEOMETRY_SHADER = 1u << 1, FEATURE_SHADER_FLOAT_64 = 1u << 2, FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS = 1u << 3, FEATURE_FRAGMENT_STORES_AND_ATOMICS = 1u << 4, FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 1u << 5, }; typedef deUint32 FeatureFlags; enum SyncPrimitive { SYNC_PRIMITIVE_FENCE, SYNC_PRIMITIVE_BINARY_SEMAPHORE, SYNC_PRIMITIVE_TIMELINE_SEMAPHORE, SYNC_PRIMITIVE_BARRIER, SYNC_PRIMITIVE_EVENT, }; enum ResourceType { RESOURCE_TYPE_BUFFER, RESOURCE_TYPE_IMAGE, RESOURCE_TYPE_INDIRECT_BUFFER_DRAW, RESOURCE_TYPE_INDIRECT_BUFFER_DRAW_INDEXED, RESOURCE_TYPE_INDIRECT_BUFFER_DISPATCH, RESOURCE_TYPE_INDEX_BUFFER, }; struct ResourceDescription { ResourceType type; tcu::IVec4 size; //!< unused components are 0, e.g. for buffers only x is meaningful vk::VkImageType imageType; vk::VkFormat imageFormat; vk::VkImageAspectFlags imageAspect; vk::VkSampleCountFlagBits imageSamples; }; struct BufferResource { BufferResource (vk::VkBuffer handle_, vk::VkDeviceSize offset_, vk::VkDeviceSize size_) : handle(handle_), offset(offset_), size(size_) {} vk::VkBuffer handle; vk::VkDeviceSize offset; vk::VkDeviceSize size; }; struct ImageResource { ImageResource ( vk::VkImage handle_, vk::VkExtent3D extent_, vk::VkImageType imageType_, vk::VkFormat format_, vk::VkImageSubresourceRange subresourceRange_, vk::VkImageSubresourceLayers subresourceLayers_, vk::VkImageTiling tiling_) : handle(handle_) , extent(extent_) , imageType(imageType_) , format(format_) , subresourceRange(subresourceRange_) , subresourceLayers(subresourceLayers_) , tiling(tiling_) {} vk::VkImage handle; vk::VkExtent3D extent; vk::VkImageType imageType; vk::VkFormat format; vk::VkImageSubresourceRange subresourceRange; vk::VkImageSubresourceLayers subresourceLayers; vk::VkImageTiling tiling; }; typedef std::shared_ptr SynchronizationWrapperPtr; SynchronizationWrapperPtr getSynchronizationWrapper (SynchronizationType type, const vk::DeviceInterface& vk, bool usingTimelineSemaphores, deUint32 submitInfoCount = 1u); void submitCommandsAndWait (SynchronizationWrapperPtr synchronizationWrapper, const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkQueue queue, const vk::VkCommandBuffer cmdBuffer); vk::VkImageCreateInfo makeImageCreateInfo (const vk::VkImageType imageType, const vk::VkExtent3D& extent, const vk::VkFormat format, const vk::VkImageUsageFlags usage, const vk::VkSampleCountFlagBits samples, const vk::VkImageTiling tiling); vk::Move makeCommandBuffer (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkCommandPool commandPool); vk::Move makeComputePipeline (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkShaderModule shaderModule, const vk::VkSpecializationInfo* specInfo, PipelineCacheData& pipelineCacheData, de::SharedPtr resourceInterface); void beginRenderPassWithRasterizationDisabled (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer); void requireFeatures (const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags); void requireStorageImageSupport (const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const vk::VkFormat fmt, const vk::VkImageTiling tiling); std::string getResourceName (const ResourceDescription& resource); bool isIndirectBuffer (const ResourceType type); vk::VkCommandBufferSubmitInfoKHR makeCommonCommandBufferSubmitInfo (const vk::VkCommandBuffer cmdBuf); vk::VkSemaphoreSubmitInfoKHR makeCommonSemaphoreSubmitInfo (vk::VkSemaphore semaphore, deUint64 value, vk::VkPipelineStageFlags2KHR stageMask); vk::VkDependencyInfoKHR makeCommonDependencyInfo (const vk::VkMemoryBarrier2KHR* pMemoryBarrier = DE_NULL, const vk::VkBufferMemoryBarrier2KHR* pBufferMemoryBarrier = DE_NULL, const vk::VkImageMemoryBarrier2KHR* pImageMemoryBarrier = DE_NULL, bool eventDependency = DE_FALSE); vk::VkDevice getSyncDevice (de::MovePtr& device, Context& context); const vk::DeviceInterface& getSyncDeviceInterface (de::MovePtr& device, Context& context); deUint32 getSyncQueueFamilyIndex (de::MovePtr& device, Context& context); vk::VkQueue getSyncQueue (de::MovePtr& device, Context& context); } // synchronization } // vkt #endif // _VKTSYNCHRONIZATIONUTIL_HPP