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