1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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 Protected content copy buffer to image tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktProtectedMemCopyBufferToImageTests.hpp"
26 
27 #include "deRandom.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuVector.hpp"
30 #include "tcuVectorUtil.hpp"
31 
32 #include "vkPrograms.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestGroupUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 
39 #include "vktProtectedMemContext.hpp"
40 #include "vktProtectedMemUtils.hpp"
41 #include "vktProtectedMemImageValidator.hpp"
42 
43 namespace vkt
44 {
45 namespace ProtectedMem
46 {
47 
48 namespace
49 {
50 
51 enum
52 {
53     BUFFER_SIZE   = 256,
54     RENDER_WIDTH  = 8,
55     RENDER_HEIGHT = 8,
56 };
57 
58 class CopyBufferToImageTestInstance : public ProtectedTestInstance
59 {
60 public:
61     CopyBufferToImageTestInstance(Context &ctx, const uint32_t fillValue, const ValidationData &refData,
62                                   const ImageValidator &validator, const CmdBufferType cmdBufferType);
63     virtual tcu::TestStatus iterate(void);
64 
65 private:
66     const vk::VkFormat m_imageFormat;
67     const uint32_t m_fillValue;
68     const ValidationData &m_refData;
69     const ImageValidator &m_validator;
70     const CmdBufferType m_cmdBufferType;
71 };
72 
73 class CopyBufferToImageTestCase : public TestCase
74 {
75 public:
CopyBufferToImageTestCase(tcu::TestContext & testCtx,const std::string & name,uint32_t fillValue,ValidationData data,CmdBufferType cmdBufferType)76     CopyBufferToImageTestCase(tcu::TestContext &testCtx, const std::string &name, uint32_t fillValue,
77                               ValidationData data, CmdBufferType cmdBufferType)
78         : TestCase(testCtx, name)
79         , m_fillValue(fillValue)
80         , m_refData(data)
81         , m_validator(vk::VK_FORMAT_R32G32B32A32_SFLOAT)
82         , m_cmdBufferType(cmdBufferType)
83     {
84     }
85 
~CopyBufferToImageTestCase(void)86     virtual ~CopyBufferToImageTestCase(void)
87     {
88     }
createInstance(Context & ctx) const89     virtual TestInstance *createInstance(Context &ctx) const
90     {
91         return new CopyBufferToImageTestInstance(ctx, m_fillValue, m_refData, m_validator, m_cmdBufferType);
92     }
initPrograms(vk::SourceCollections & programCollection) const93     virtual void initPrograms(vk::SourceCollections &programCollection) const
94     {
95         m_validator.initPrograms(programCollection);
96     }
checkSupport(Context & context) const97     virtual void checkSupport(Context &context) const
98     {
99         checkProtectedQueueSupport(context);
100 #ifdef CTS_USES_VULKANSC
101         if (m_cmdBufferType == CMD_BUFFER_SECONDARY &&
102             context.getDeviceVulkanSC10Properties().secondaryCommandBufferNullOrImagelessFramebuffer == VK_FALSE)
103             TCU_THROW(NotSupportedError, "secondaryCommandBufferNullFramebuffer is not supported");
104 #endif // CTS_USES_VULKANSC
105     }
106 
107 private:
108     uint32_t m_fillValue;
109     ValidationData m_refData;
110     ImageValidator m_validator;
111     CmdBufferType m_cmdBufferType;
112 };
113 
CopyBufferToImageTestInstance(Context & ctx,const uint32_t fillValue,const ValidationData & refData,const ImageValidator & validator,const CmdBufferType cmdBufferType)114 CopyBufferToImageTestInstance::CopyBufferToImageTestInstance(Context &ctx, const uint32_t fillValue,
115                                                              const ValidationData &refData,
116                                                              const ImageValidator &validator,
117                                                              const CmdBufferType cmdBufferType)
118     : ProtectedTestInstance(ctx)
119     , m_imageFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT)
120     , m_fillValue(fillValue)
121     , m_refData(refData)
122     , m_validator(validator)
123     , m_cmdBufferType(cmdBufferType)
124 {
125 }
126 
iterate()127 tcu::TestStatus CopyBufferToImageTestInstance::iterate()
128 {
129     ProtectedContext &ctx(m_protectedContext);
130     const vk::DeviceInterface &vk   = ctx.getDeviceInterface();
131     const vk::VkDevice device       = ctx.getDevice();
132     const vk::VkQueue queue         = ctx.getQueue();
133     const uint32_t queueFamilyIndex = ctx.getQueueFamilyIndex();
134 
135     // Create destination image
136     de::MovePtr<vk::ImageWithMemory> colorImage =
137         createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex, RENDER_WIDTH, RENDER_HEIGHT, m_imageFormat,
138                       vk::VK_IMAGE_USAGE_SAMPLED_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
139     de::MovePtr<vk::BufferWithMemory> srcBuffer(
140         makeBuffer(ctx, PROTECTION_ENABLED, queueFamilyIndex, (uint32_t)(BUFFER_SIZE * sizeof(uint32_t)),
141                    vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
142                        vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
143                    vk::MemoryRequirement::Protected));
144 
145     vk::Unique<vk::VkCommandPool> cmdPool(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
146     vk::Unique<vk::VkCommandBuffer> cmdBuffer(
147         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
148     vk::Unique<vk::VkCommandBuffer> secondaryCmdBuffer(
149         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
150     vk::VkCommandBuffer targetCmdBuffer = (m_cmdBufferType == CMD_BUFFER_SECONDARY) ? *secondaryCmdBuffer : *cmdBuffer;
151 
152     // Begin cmd buffer
153     beginCommandBuffer(vk, *cmdBuffer);
154 
155     if (m_cmdBufferType == CMD_BUFFER_SECONDARY)
156     {
157         // Begin secondary command buffer
158         const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo = {
159             vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // sType
160             DE_NULL,                                               // pNext
161             DE_NULL,                                               // renderPass
162             0u,                                                    // subpass
163             DE_NULL,                                               // framebuffer
164             VK_FALSE,                                              // occlusionQueryEnable
165             (vk::VkQueryControlFlags)0u,                           // queryFlags
166             (vk::VkQueryPipelineStatisticFlags)0u,                 // pipelineStatistics
167         };
168         beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, bufferInheritanceInfo);
169     }
170 
171     // Start src buffer barrier
172     {
173         const vk::VkBufferMemoryBarrier startBufferBarrier = {
174             vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType        sType
175             DE_NULL,                                     // const void*            pNext
176             0,                                           // VkAccessFlags        srcAccessMask
177             vk::VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags        dstAccessMask
178             queueFamilyIndex,                            // uint32_t                srcQueueFamilyIndex
179             queueFamilyIndex,                            // uint32_t                dstQueueFamilyIndex
180             **srcBuffer,                                 // VkBuffer                buffer
181             0u,                                          // VkDeviceSize            offset
182             VK_WHOLE_SIZE,                               // VkDeviceSize            size
183         };
184         vk.cmdPipelineBarrier(targetCmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
185                               vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkDependencyFlags)0, 0,
186                               (const vk::VkMemoryBarrier *)DE_NULL, 1, &startBufferBarrier, 0,
187                               (const vk::VkImageMemoryBarrier *)DE_NULL);
188     }
189     vk.cmdFillBuffer(targetCmdBuffer, **srcBuffer, 0u, VK_WHOLE_SIZE, m_fillValue);
190 
191     {
192         // Barrier to change accessMask to transfer read bit for source buffer
193         const vk::VkBufferMemoryBarrier startCopyBufferBarrier = {
194             vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType        sType
195             DE_NULL,                                     // const void*            pNext
196             vk::VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags        srcAccessMask
197             vk::VK_ACCESS_TRANSFER_READ_BIT,             // VkAccessFlags        dstAccessMask
198             queueFamilyIndex,                            // uint32_t                srcQueueFamilyIndex
199             queueFamilyIndex,                            // uint32_t                dstQueueFamilyIndex
200             **srcBuffer,                                 // VkBuffer                buffer
201             0u,                                          // VkDeviceSize            offset
202             VK_WHOLE_SIZE,                               // VkDeviceSize            size
203         };
204 
205         // Start image barrier for destination image.
206         const vk::VkImageMemoryBarrier startImgBarrier = {
207             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
208             DE_NULL,                                    // const void*            pNext
209             0,                                          // VkAccessFlags        srcAccessMask
210             vk::VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags        dstAccessMask
211             vk::VK_IMAGE_LAYOUT_UNDEFINED,              // VkImageLayout        oldLayout
212             vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,   // VkImageLayout        newLayout
213             queueFamilyIndex,                           // uint32_t                srcQueueFamilyIndex
214             queueFamilyIndex,                           // uint32_t                dstQueueFamilyIndex
215             **colorImage,                               // VkImage                image
216             {
217                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
218                 0u,                            // uint32_t                baseMipLevel
219                 1u,                            // uint32_t                mipLevels
220                 0u,                            // uint32_t                baseArraySlice
221                 1u,                            // uint32_t                subresourceRange
222             }};
223 
224         vk.cmdPipelineBarrier(targetCmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
225                               (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 1,
226                               &startCopyBufferBarrier, 1, &startImgBarrier);
227     }
228 
229     // Copy buffer to image
230     const vk::VkImageSubresourceLayers subresourceLayers = {
231         vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags        aspectMask
232         0u,                            // uint32_t                    mipLevel
233         0u,                            // uint32_t                    baseArrayLayer
234         1u,                            // uint32_t                    layerCount
235     };
236     const vk::VkOffset3D nullOffset        = {0u, 0u, 0u};
237     const vk::VkExtent3D imageExtent       = {(uint32_t)RENDER_WIDTH, (uint32_t)RENDER_HEIGHT, 1u};
238     const vk::VkBufferImageCopy copyRegion = {
239         0ull,              // VkDeviceSize srcOffset;
240         0,                 // uint32_t                    bufferRowLength
241         0,                 // uint32_t                    bufferImageHeight
242         subresourceLayers, // VkImageSubresourceLayers    imageSubresource
243         nullOffset,        // VkOffset3D                imageOffset
244         imageExtent,       // VkExtent3D                imageExtent
245     };
246     vk.cmdCopyBufferToImage(targetCmdBuffer, **srcBuffer, **colorImage, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
247                             &copyRegion);
248 
249     {
250         const vk::VkImageMemoryBarrier endImgBarrier = {
251             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType        sType
252             DE_NULL,                                      // const void*            pNext
253             vk::VK_ACCESS_TRANSFER_WRITE_BIT,             // VkAccessFlags        srcAccessMask
254             vk::VK_ACCESS_SHADER_READ_BIT,                // VkAccessFlags        dstAccessMask
255             vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,     // VkImageLayout        oldLayout
256             vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout        newLayout
257             queueFamilyIndex,                             // uint32_t                srcQueueFamilyIndex
258             queueFamilyIndex,                             // uint32_t                dstQueueFamilyIndex
259             **colorImage,                                 // VkImage                image
260             {
261                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
262                 0u,                            // uint32_t                baseMipLevel
263                 1u,                            // uint32_t                mipLevels
264                 0u,                            // uint32_t                baseArraySlice
265                 1u,                            // uint32_t                subresourceRange
266             }};
267         vk.cmdPipelineBarrier(targetCmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
268                               vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0,
269                               (const vk::VkMemoryBarrier *)DE_NULL, 0, (const vk::VkBufferMemoryBarrier *)DE_NULL, 1,
270                               &endImgBarrier);
271     }
272 
273     if (m_cmdBufferType == CMD_BUFFER_SECONDARY)
274     {
275         endCommandBuffer(vk, *secondaryCmdBuffer);
276         vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get());
277     }
278 
279     endCommandBuffer(vk, *cmdBuffer);
280 
281     // Submit command buffer
282     const vk::Unique<vk::VkFence> fence(vk::createFence(vk, device));
283     VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
284 
285     // Log out test data
286     ctx.getTestContext().getLog() << tcu::TestLog::Message << "Fill value: " << m_fillValue << tcu::TestLog::EndMessage;
287 
288     // Validate resulting image
289     if (m_validator.validateImage(ctx, m_refData, **colorImage, m_imageFormat,
290                                   vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))
291         return tcu::TestStatus::pass("Everything went OK");
292     else
293         return tcu::TestStatus::fail("Something went really wrong");
294 }
295 
createCopyBufferToImageTests(tcu::TestContext & testCtx,CmdBufferType cmdBufferType)296 tcu::TestCaseGroup *createCopyBufferToImageTests(tcu::TestContext &testCtx, CmdBufferType cmdBufferType)
297 {
298     struct
299     {
300         const union
301         {
302             float flt;
303             uint32_t uint;
304         } fillValue;
305         const ValidationData data;
306     } testData[] = {
307         {{0.0f},
308          {{
309               tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
310               tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
311               tcu::Vec4(0.1f, 0.1f, 0.0f, 0.0f),
312               tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
313           },
314           {
315               tcu::Vec4(0.0f),
316               tcu::Vec4(0.0f),
317               tcu::Vec4(0.0f),
318               tcu::Vec4(0.0f),
319           }}},
320         {{1.0f},
321          {{
322               tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
323               tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
324               tcu::Vec4(0.1f, 0.1f, 0.0f, 0.0f),
325               tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
326           },
327           {
328               tcu::Vec4(1.0f),
329               tcu::Vec4(1.0f),
330               tcu::Vec4(1.0f),
331               tcu::Vec4(1.0f),
332           }}},
333         {{0.2f},
334          {{
335               tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
336               tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
337               tcu::Vec4(0.1f, 0.1f, 0.0f, 0.0f),
338               tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
339           },
340           {
341               tcu::Vec4(0.2f),
342               tcu::Vec4(0.2f),
343               tcu::Vec4(0.2f),
344               tcu::Vec4(0.2f),
345           }}},
346         {{0.55f},
347          {{
348               tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
349               tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
350               tcu::Vec4(0.1f, 0.1f, 0.0f, 0.0f),
351               tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
352           },
353           {
354               tcu::Vec4(0.55f),
355               tcu::Vec4(0.55f),
356               tcu::Vec4(0.55f),
357               tcu::Vec4(0.55f),
358           }}},
359         {{0.82f},
360          {{
361               tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
362               tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
363               tcu::Vec4(0.1f, 0.1f, 0.0f, 0.0f),
364               tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
365           },
366           {
367               tcu::Vec4(0.82f),
368               tcu::Vec4(0.82f),
369               tcu::Vec4(0.82f),
370               tcu::Vec4(0.82f),
371           }}},
372         {{0.96f},
373          {{
374               tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
375               tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
376               tcu::Vec4(0.1f, 0.1f, 0.0f, 0.0f),
377               tcu::Vec4(0.5f, 0.5f, 0.0f, 0.0f),
378           },
379           {
380               tcu::Vec4(0.96f),
381               tcu::Vec4(0.96f),
382               tcu::Vec4(0.96f),
383               tcu::Vec4(0.96f),
384           }}},
385     };
386 
387     // Copy Buffer To Image Tests with static input
388     de::MovePtr<tcu::TestCaseGroup> copyStaticTests(new tcu::TestCaseGroup(testCtx, "static"));
389 
390     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testData); ++ndx)
391     {
392         const std::string name = "copy_" + de::toString(ndx + 1);
393         copyStaticTests->addChild(new CopyBufferToImageTestCase(testCtx, name.c_str(), testData[ndx].fillValue.uint,
394                                                                 testData[ndx].data, cmdBufferType));
395     }
396 
397     /* Add a few randomized tests */
398     // Copy Buffer To Image Tests with random input
399     de::MovePtr<tcu::TestCaseGroup> copyRandomTests(new tcu::TestCaseGroup(testCtx, "random"));
400     const int testCount = 10;
401     de::Random rnd(testCtx.getCommandLine().getBaseSeed());
402     for (int ndx = 0; ndx < testCount; ++ndx)
403     {
404         const std::string name = "copy_" + de::toString(ndx + 1);
405 
406         const union
407         {
408             float flt;
409             uint32_t uint;
410         } fillValue = {rnd.getFloat(0.0, 1.0f)};
411 
412         const tcu::Vec4 refValue(fillValue.flt);
413         const tcu::Vec4 vec0 = tcu::randomVec4(rnd);
414         const tcu::Vec4 vec1 = tcu::randomVec4(rnd);
415         const tcu::Vec4 vec2 = tcu::randomVec4(rnd);
416         const tcu::Vec4 vec3 = tcu::randomVec4(rnd);
417 
418         ValidationData data = {{vec0, vec1, vec2, vec3}, {refValue, refValue, refValue, refValue}};
419         copyRandomTests->addChild(
420             new CopyBufferToImageTestCase(testCtx, name.c_str(), fillValue.uint, data, cmdBufferType));
421     }
422 
423     std::string groupName = getCmdBufferTypeStr(cmdBufferType);
424     std::string groupDesc = "Copy Buffer To Image Tests with " + groupName + " command buffer";
425     de::MovePtr<tcu::TestCaseGroup> copyTests(new tcu::TestCaseGroup(testCtx, groupName.c_str()));
426     copyTests->addChild(copyStaticTests.release());
427     copyTests->addChild(copyRandomTests.release());
428     return copyTests.release();
429 }
430 
431 } // namespace
432 
createCopyBufferToImageTests(tcu::TestContext & testCtx)433 tcu::TestCaseGroup *createCopyBufferToImageTests(tcu::TestContext &testCtx)
434 {
435     de::MovePtr<tcu::TestCaseGroup> clearTests(new tcu::TestCaseGroup(testCtx, "copy_buffer_to_image"));
436 
437     clearTests->addChild(createCopyBufferToImageTests(testCtx, CMD_BUFFER_PRIMARY));
438     clearTests->addChild(createCopyBufferToImageTests(testCtx, CMD_BUFFER_SECONDARY));
439 
440     return clearTests.release();
441 }
442 
443 } // namespace ProtectedMem
444 } // namespace vkt
445