• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 Google LLC.
6  *
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Test no-op image layout transitions in VK_KHR_synchronization2
23  *//*--------------------------------------------------------------------*/
24 
25 #include "deUniquePtr.hpp"
26 
27 #include "tcuTextureUtil.hpp"
28 #include "tcuImageCompare.hpp"
29 
30 #include "vkBarrierUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vktTestCaseUtil.hpp"
37 #include "vktSynchronizationUtil.hpp"
38 #include "tcuTestLog.hpp"
39 
40 #include <string>
41 
42 using namespace vk;
43 
44 namespace vkt
45 {
46 namespace synchronization
47 {
48 namespace
49 {
50 
51 using de::MovePtr;
52 using std::vector;
53 using tcu::TextureLevel;
54 using tcu::Vec4;
55 
56 const int WIDTH       = 64;
57 const int HEIGHT      = 64;
58 const VkFormat FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
59 
makeImageCreateInfo()60 inline VkImageCreateInfo makeImageCreateInfo()
61 {
62     const VkImageUsageFlags usage =
63         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
64     const VkImageCreateInfo imageParams = {
65         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, //  VkStructureType         sType;
66         DE_NULL,                             //  const void*             pNext;
67         0,                                   //  VkImageCreateFlags      flags;
68         VK_IMAGE_TYPE_2D,                    //  VkImageType             imageType;
69         FORMAT,                              //  VkFormat                format;
70         makeExtent3D(WIDTH, HEIGHT, 1u),     //  VkExtent3D              extent;
71         1u,                                  //  uint32_t                mipLevels;
72         1u,                                  //  uint32_t                arrayLayers;
73         VK_SAMPLE_COUNT_1_BIT,               //  VkSampleCountFlagBits   samples;
74         VK_IMAGE_TILING_OPTIMAL,             //  VkImageTiling           tiling;
75         usage,                               //  VkImageUsageFlags       usage;
76         VK_SHARING_MODE_EXCLUSIVE,           //  VkSharingMode           sharingMode;
77         0u,                                  //  uint32_t                queueFamilyIndexCount;
78         DE_NULL,                             //  const uint32_t*         pQueueFamilyIndices;
79         VK_IMAGE_LAYOUT_UNDEFINED,           //  VkImageLayout           initialLayout;
80     };
81 
82     return imageParams;
83 }
84 
makeVertexBuffer(const DeviceInterface & vk,const VkDevice device,const uint32_t queueFamilyIndex)85 Move<VkBuffer> makeVertexBuffer(const DeviceInterface &vk, const VkDevice device, const uint32_t queueFamilyIndex)
86 {
87     const VkBufferCreateInfo vertexBufferParams = {
88         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType      sType;
89         DE_NULL,                              // const void*          pNext;
90         0u,                                   // VkBufferCreateFlags  flags;
91         1024u,                                // VkDeviceSize         size;
92         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags   usage;
93         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode        sharingMode;
94         1u,                                   // uint32_t             queueFamilyIndexCount;
95         &queueFamilyIndex                     // const uint32_t*      pQueueFamilyIndices;
96     };
97 
98     Move<VkBuffer> vertexBuffer = createBuffer(vk, device, &vertexBufferParams);
99     ;
100     return vertexBuffer;
101 }
102 
103 class SynchronizationImageLayoutTransitionTestInstance : public TestInstance
104 {
105 public:
106     SynchronizationImageLayoutTransitionTestInstance(Context &context);
107     tcu::TestStatus iterate(void);
108 };
109 
SynchronizationImageLayoutTransitionTestInstance(Context & context)110 SynchronizationImageLayoutTransitionTestInstance::SynchronizationImageLayoutTransitionTestInstance(Context &context)
111     : TestInstance(context)
112 {
113 }
114 
115 template <typename T>
sizeInBytes(const vector<T> & vec)116 inline size_t sizeInBytes(const vector<T> &vec)
117 {
118     return vec.size() * sizeof(vec[0]);
119 }
120 
121 // Draw a quad covering the whole framebuffer
genFullQuadVertices(void)122 vector<Vec4> genFullQuadVertices(void)
123 {
124     vector<Vec4> vertices;
125     vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
126     vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
127     vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
128     vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
129     vertices.push_back(Vec4(1.0f, 1.0f, 0.0f, 1.0f));
130     vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
131 
132     return vertices;
133 }
134 
135 struct Vertex
136 {
Vertexvkt::synchronization::__anon273e365a0111::Vertex137     Vertex(Vec4 vertices_) : vertices(vertices_)
138     {
139     }
140     Vec4 vertices;
141 
142     static VkVertexInputBindingDescription getBindingDescription(void);
143     static vector<VkVertexInputAttributeDescription> getAttributeDescriptions(void);
144 };
145 
getBindingDescription(void)146 VkVertexInputBindingDescription Vertex::getBindingDescription(void)
147 {
148     static const VkVertexInputBindingDescription desc = {
149         0u,                                    // uint32_t             binding;
150         static_cast<uint32_t>(sizeof(Vertex)), // uint32_t             stride;
151         VK_VERTEX_INPUT_RATE_VERTEX,           // VkVertexInputRate    inputRate;
152     };
153 
154     return desc;
155 }
156 
getAttributeDescriptions(void)157 vector<VkVertexInputAttributeDescription> Vertex::getAttributeDescriptions(void)
158 {
159     static const vector<VkVertexInputAttributeDescription> desc = {
160         {
161             0u,                                                // uint32_t    location;
162             0u,                                                // uint32_t    binding;
163             VK_FORMAT_R32G32B32A32_SFLOAT,                     // VkFormat    format;
164             static_cast<uint32_t>(offsetof(Vertex, vertices)), // uint32_t    offset;
165         },
166     };
167 
168     return desc;
169 }
170 
iterate(void)171 tcu::TestStatus SynchronizationImageLayoutTransitionTestInstance::iterate(void)
172 {
173     const DeviceInterface &vk       = m_context.getDeviceInterface();
174     const VkDevice device           = m_context.getDevice();
175     Allocator &allocator            = m_context.getDefaultAllocator();
176     const VkQueue queue             = m_context.getUniversalQueue();
177     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
178     const VkDeviceSize bufferSize   = 16 * 1024;
179 
180     const VkExtent2D renderSize = {uint32_t(WIDTH), uint32_t(HEIGHT)};
181     const VkRect2D renderArea   = makeRect2D(makeExtent3D(WIDTH, HEIGHT, 1u));
182     const vector<VkRect2D> scissors(1u, renderArea);
183     const vector<VkViewport> viewports(1u, makeViewport(makeExtent3D(WIDTH, HEIGHT, 1u)));
184 
185     const vector<Vec4> vertices = genFullQuadVertices();
186     Move<VkBuffer> vertexBuffer = makeVertexBuffer(vk, device, queueFamilyIndex);
187     MovePtr<Allocation> vertexBufferAlloc =
188         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
189     const VkDeviceSize vertexBufferOffset = 0ull;
190 
191     deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], sizeInBytes(vertices));
192     flushAlloc(vk, device, *vertexBufferAlloc);
193 
194     const VkImageCreateInfo targetCreateInfo = makeImageCreateInfo();
195     const VkImageSubresourceRange targetSubresourceRange =
196         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
197     const ImageWithMemory targetImage(vk, device, m_context.getDefaultAllocator(), targetCreateInfo,
198                                       MemoryRequirement::Any);
199     Move<VkImageView> targetImageView =
200         makeImageView(vk, device, *targetImage, VK_IMAGE_VIEW_TYPE_2D, FORMAT, targetSubresourceRange);
201 
202     const Move<VkCommandPool> cmdPool =
203         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
204     const Move<VkCommandBuffer> cmdBuffer =
205         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
206 
207     Move<VkRenderPass> renderPass = makeRenderPass(vk, device, FORMAT, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD);
208     Move<VkFramebuffer> framebuffer =
209         makeFramebuffer(vk, device, *renderPass, targetImageView.get(), renderSize.width, renderSize.height);
210 
211     const Move<VkShaderModule> vertexModule =
212         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert1"), 0u);
213     const Move<VkShaderModule> fragmentModule =
214         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag1"), 0u);
215 
216     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, device, DE_NULL);
217 
218     const VkPipelineColorBlendAttachmentState clrBlendAttachmentState = {
219         VK_TRUE,                             // VkBool32                 blendEnable;
220         VK_BLEND_FACTOR_SRC_ALPHA,           // VkBlendFactor            srcColorBlendFactor;
221         VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // VkBlendFactor            dstColorBlendFactor;
222         VK_BLEND_OP_ADD,                     // VkBlendOp                colorBlendOp;
223         VK_BLEND_FACTOR_ONE,                 // VkBlendFactor            srcAlphaBlendFactor;
224         VK_BLEND_FACTOR_ONE,                 // VkBlendFactor            dstAlphaBlendFactor;
225         VK_BLEND_OP_MAX,                     // VkBlendOp                alphaBlendOp;
226         (VkColorComponentFlags)0xF           // VkColorComponentFlags    colorWriteMask;
227     };
228 
229     const VkPipelineColorBlendStateCreateInfo clrBlendStateCreateInfo = {
230         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType                               sType;
231         DE_NULL,                                  // const void*                                   pNext;
232         (VkPipelineColorBlendStateCreateFlags)0u, // VkPipelineColorBlendStateCreateFlags          flags;
233         VK_FALSE,                                 // VkBool32                                      logicOpEnable;
234         VK_LOGIC_OP_CLEAR,                        // VkLogicOp                                     logicOp;
235         1u,                                       // uint32_t                                      attachmentCount;
236         &clrBlendAttachmentState,                 // const VkPipelineColorBlendAttachmentState*    pAttachments;
237         {1.0f, 1.0f, 1.0f, 1.0f}                  // float                                         blendConstants[4];
238     };
239 
240     const VkVertexInputBindingDescription vtxBindingDescription = Vertex::getBindingDescription();
241     const auto vtxAttrDescriptions                              = Vertex::getAttributeDescriptions();
242 
243     const VkPipelineVertexInputStateCreateInfo vtxInputStateCreateInfo = {
244         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType;
245         DE_NULL,                                                   // const void*                                 pNext;
246         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags       flags;
247         1u,                     // uint32_t                                    vertexBindingDescriptionCount;
248         &vtxBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
249         static_cast<uint32_t>(
250             vtxAttrDescriptions.size()), // uint32_t                                    vertexAttributeDescriptionCount
251         vtxAttrDescriptions.data(),      // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
252     };
253 
254     const Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(
255         vk, device, pipelineLayout.get(), vertexModule.get(), DE_NULL, DE_NULL, DE_NULL, fragmentModule.get(),
256         renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, &vtxInputStateCreateInfo,
257         DE_NULL, DE_NULL, DE_NULL, &clrBlendStateCreateInfo);
258 
259     const VkBufferCreateInfo resultBufferCreateInfo =
260         makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
261     Move<VkBuffer> resultBuffer = createBuffer(vk, device, &resultBufferCreateInfo);
262     MovePtr<Allocation> resultBufferMemory =
263         allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
264     MovePtr<TextureLevel> resultImage(new TextureLevel(mapVkFormat(FORMAT), renderSize.width, renderSize.height, 1));
265 
266     VK_CHECK(
267         vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
268 
269     const Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f);
270 
271     clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(),
272                     targetImage.get(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
273                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 1);
274 
275     beginCommandBuffer(vk, *cmdBuffer);
276 
277     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
278     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
279 
280     beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT), 0, DE_NULL);
281     vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
282     endRenderPass(vk, *cmdBuffer);
283 
284     // Define an execution dependency and skip the layout transition. This is allowed when oldLayout
285     // and newLayout are both UNDEFINED. The test will fail if the driver discards the contents of
286     // the image.
287     const VkImageMemoryBarrier2KHR imageMemoryBarrier2 = makeImageMemoryBarrier2(
288         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags2KHR    srcStageMask
289         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags2KHR           srcAccessMask
290         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags2KHR    dstStageMask
291         VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,           // VkAccessFlags2KHR           dstAccessMask
292         VK_IMAGE_LAYOUT_UNDEFINED,                     // VkImageLayout               oldLayout
293         VK_IMAGE_LAYOUT_UNDEFINED,                     // VkImageLayout               newLayout
294         targetImage.get(),                             // VkImage                     image
295         targetSubresourceRange                         // VkImageSubresourceRange     subresourceRange
296     );
297     VkDependencyInfoKHR dependencyInfo = makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2);
298 #ifndef CTS_USES_VULKANSC
299     vk.cmdPipelineBarrier2(cmdBuffer.get(), &dependencyInfo);
300 #else
301     vk.cmdPipelineBarrier2KHR(cmdBuffer.get(), &dependencyInfo);
302 #endif // CTS_USES_VULKANSC
303 
304     beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT), 0, DE_NULL);
305     vk.cmdDraw(*cmdBuffer, static_cast<uint32_t>(vertices.size()), 1u, 0u, 0u);
306     endRenderPass(vk, *cmdBuffer);
307 
308     // Read the result buffer data
309     copyImageToBuffer(vk, *cmdBuffer, *targetImage, *resultBuffer, tcu::IVec2(WIDTH, HEIGHT),
310                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
311 
312     endCommandBuffer(vk, *cmdBuffer);
313     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
314 
315     invalidateAlloc(vk, device, *resultBufferMemory);
316 
317     tcu::clear(resultImage->getAccess(), tcu::IVec4(0));
318     tcu::copy(resultImage->getAccess(),
319               tcu::ConstPixelBufferAccess(resultImage.get()->getFormat(), resultImage.get()->getSize(),
320                                           resultBufferMemory->getHostPtr()));
321 
322     TextureLevel textureLevel(mapVkFormat(FORMAT), WIDTH, HEIGHT, 1);
323     const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
324 
325     const float alpha = 0.4f;
326     const float red   = (2.0f - alpha) * alpha;
327     const float green = red;
328     const float blue  = 0;
329     const Vec4 color  = Vec4(red, green, blue, alpha);
330 
331     for (int y = 0; y < HEIGHT; y++)
332         for (int x = 0; x < WIDTH; x++)
333             expectedImage.setPixel(color, x, y, 0);
334 
335     bool ok = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Image comparison", "", expectedImage,
336                                          resultImage->getAccess(), tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
337     return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
338 }
339 
340 class SynchronizationImageLayoutTransitionTest : public TestCase
341 {
342 public:
343     SynchronizationImageLayoutTransitionTest(tcu::TestContext &testCtx, const std::string &name);
344 
345     virtual void checkSupport(Context &context) const;
346     void initPrograms(SourceCollections &programCollection) const;
347     TestInstance *createInstance(Context &context) const;
348 };
349 
SynchronizationImageLayoutTransitionTest(tcu::TestContext & testCtx,const std::string & name)350 SynchronizationImageLayoutTransitionTest::SynchronizationImageLayoutTransitionTest(tcu::TestContext &testCtx,
351                                                                                    const std::string &name)
352     : TestCase(testCtx, name)
353 {
354 }
355 
initPrograms(SourceCollections & programCollection) const356 void SynchronizationImageLayoutTransitionTest::initPrograms(SourceCollections &programCollection) const
357 {
358     std::ostringstream vertexSrc;
359     vertexSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
360               << "layout(location = 0) in vec4 a_position;\n"
361               << "void main (void) {\n"
362               << "    gl_Position = a_position;\n"
363               << "}\n";
364 
365     std::ostringstream fragmentSrc;
366     fragmentSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
367                 << "layout(location = 0) out vec4 outColor;\n"
368                 << "void main() {\n"
369                 << "    outColor = vec4(1., 1., 0., .4);\n"
370                 << "}\n";
371 
372     programCollection.glslSources.add("vert1") << glu::VertexSource(vertexSrc.str());
373     programCollection.glslSources.add("frag1") << glu::FragmentSource(fragmentSrc.str());
374 }
375 
checkSupport(Context & context) const376 void SynchronizationImageLayoutTransitionTest::checkSupport(Context &context) const
377 {
378     context.requireDeviceFunctionality("VK_KHR_synchronization2");
379 }
380 
createInstance(Context & context) const381 TestInstance *SynchronizationImageLayoutTransitionTest::createInstance(Context &context) const
382 {
383     return new SynchronizationImageLayoutTransitionTestInstance(context);
384 }
385 
386 } // namespace
387 
createImageLayoutTransitionTests(tcu::TestContext & testCtx)388 tcu::TestCaseGroup *createImageLayoutTransitionTests(tcu::TestContext &testCtx)
389 {
390     // No-op image layout transition tests
391     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "layout_transition"));
392     testGroup->addChild(new SynchronizationImageLayoutTransitionTest(testCtx, "no_op"));
393 
394     return testGroup.release();
395 }
396 
397 } // namespace synchronization
398 } // namespace vkt
399