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 memory copy image to buffer tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktProtectedMemCopyImageToBufferTests.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 "vktProtectedMemBufferValidator.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     MAX_POSITION = BUFFER_SIZE / 4,
58 };
59 
60 template <typename T>
61 class CopyImageToBufferTestInstance : public ProtectedTestInstance
62 {
63 public:
64     CopyImageToBufferTestInstance(Context &ctx, const vk::VkClearColorValue fillValue,
65                                   const BufferValidator<T> &validator, const CmdBufferType cmdBufferType,
66                                   const std::vector<std::string> &extensions);
67     virtual tcu::TestStatus iterate(void);
68 
69 private:
70     const vk::VkFormat m_imageFormat;
71     const vk::VkClearColorValue m_fillValue;
72     const BufferValidator<T> &m_validator;
73     const CmdBufferType m_cmdBufferType;
74 };
75 
76 template <typename T>
77 class CopyImageToBufferTestCase : public TestCase
78 {
79 public:
CopyImageToBufferTestCase(tcu::TestContext & testCtx,const std::string & name,vk::VkClearColorValue fillValue,ValidationData<T> data,CmdBufferType cmdBufferType,vk::VkFormat format,bool pipelineProtectedAccess)80     CopyImageToBufferTestCase(tcu::TestContext &testCtx, const std::string &name, vk::VkClearColorValue fillValue,
81                               ValidationData<T> data, CmdBufferType cmdBufferType, vk::VkFormat format,
82                               bool pipelineProtectedAccess)
83         : TestCase(testCtx, name)
84         , m_fillValue(fillValue)
85         , m_validator(data, format)
86         , m_cmdBufferType(cmdBufferType)
87         , m_pipelineProtectedAccess(pipelineProtectedAccess)
88     {
89     }
90 
~CopyImageToBufferTestCase(void)91     virtual ~CopyImageToBufferTestCase(void)
92     {
93     }
createInstance(Context & ctx) const94     virtual TestInstance *createInstance(Context &ctx) const
95     {
96         std::vector<std::string> extensions;
97         if (m_pipelineProtectedAccess)
98         {
99             extensions.push_back("VK_EXT_pipeline_protected_access");
100         }
101         return new CopyImageToBufferTestInstance<T>(ctx, m_fillValue, m_validator, m_cmdBufferType, extensions);
102     }
initPrograms(vk::SourceCollections & programCollection) const103     virtual void initPrograms(vk::SourceCollections &programCollection) const
104     {
105         m_validator.initPrograms(programCollection);
106     }
checkSupport(Context & context) const107     virtual void checkSupport(Context &context) const
108     {
109         checkProtectedQueueSupport(context);
110 #ifdef CTS_USES_VULKANSC
111         if (m_cmdBufferType == CMD_BUFFER_SECONDARY &&
112             context.getDeviceVulkanSC10Properties().secondaryCommandBufferNullOrImagelessFramebuffer == VK_FALSE)
113             TCU_THROW(NotSupportedError, "secondaryCommandBufferNullFramebuffer is not supported");
114 #endif // CTS_USES_VULKANSC
115     }
116 
117 private:
118     vk::VkClearColorValue m_fillValue;
119     BufferValidator<T> m_validator;
120     CmdBufferType m_cmdBufferType;
121     bool m_pipelineProtectedAccess;
122 };
123 
124 template <typename T>
CopyImageToBufferTestInstance(Context & ctx,const vk::VkClearColorValue fillValue,const BufferValidator<T> & validator,const CmdBufferType cmdBufferType,const std::vector<std::string> & extensions)125 CopyImageToBufferTestInstance<T>::CopyImageToBufferTestInstance(Context &ctx, const vk::VkClearColorValue fillValue,
126                                                                 const BufferValidator<T> &validator,
127                                                                 const CmdBufferType cmdBufferType,
128                                                                 const std::vector<std::string> &extensions)
129     : ProtectedTestInstance(ctx, extensions)
130     , m_imageFormat(vk::VK_FORMAT_R32G32B32A32_UINT)
131     , m_fillValue(fillValue)
132     , m_validator(validator)
133     , m_cmdBufferType(cmdBufferType)
134 {
135 }
136 
137 template <typename T>
iterate()138 tcu::TestStatus CopyImageToBufferTestInstance<T>::iterate()
139 {
140     ProtectedContext &ctx(m_protectedContext);
141     const vk::DeviceInterface &vk   = ctx.getDeviceInterface();
142     const vk::VkDevice device       = ctx.getDevice();
143     const vk::VkQueue queue         = ctx.getQueue();
144     const uint32_t queueFamilyIndex = ctx.getQueueFamilyIndex();
145 
146     // Create image
147     de::MovePtr<vk::ImageWithMemory> colorImage =
148         createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex, RENDER_WIDTH, RENDER_HEIGHT, m_imageFormat,
149                       vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
150     de::MovePtr<vk::BufferWithMemory> dstBuffer(
151         makeBuffer(ctx, PROTECTION_ENABLED, queueFamilyIndex, (uint32_t)(BUFFER_SIZE * sizeof(uint32_t)),
152                    vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
153                    vk::MemoryRequirement::Protected));
154 
155     vk::Unique<vk::VkCommandPool> cmdPool(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
156     vk::Unique<vk::VkCommandBuffer> cmdBuffer(
157         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
158     vk::Unique<vk::VkCommandBuffer> secondaryCmdBuffer(
159         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
160     vk::VkCommandBuffer targetCmdBuffer = (m_cmdBufferType == CMD_BUFFER_SECONDARY) ? *secondaryCmdBuffer : *cmdBuffer;
161 
162     // Begin cmd buffer
163     beginCommandBuffer(vk, *cmdBuffer);
164 
165     if (m_cmdBufferType == CMD_BUFFER_SECONDARY)
166     {
167         // Begin secondary command buffer
168         const vk::VkCommandBufferInheritanceInfo secCmdBufInheritInfo = {
169             vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
170             DE_NULL,
171             (vk::VkRenderPass)0u,                  // renderPass
172             0u,                                    // subpass
173             (vk::VkFramebuffer)0u,                 // framebuffer
174             VK_FALSE,                              // occlusionQueryEnable
175             (vk::VkQueryControlFlags)0u,           // queryFlags
176             (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
177         };
178         beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, secCmdBufInheritInfo);
179     }
180 
181     // Start image barrier for source image.
182     {
183         const vk::VkImageMemoryBarrier startImgBarrier = {
184             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
185             DE_NULL,                                    // const void*            pNext
186             0,                                          // VkAccessFlags        srcAccessMask
187             vk::VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags        dstAccessMask
188             vk::VK_IMAGE_LAYOUT_UNDEFINED,              // VkImageLayout        oldLayout
189             vk::VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout        newLayout
190             queueFamilyIndex,                           // uint32_t                srcQueueFamilyIndex
191             queueFamilyIndex,                           // uint32_t                dstQueueFamilyIndex
192             **colorImage,                               // VkImage                image
193             {
194                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
195                 0u,                            // uint32_t                baseMipLevel
196                 1u,                            // uint32_t                mipLevels
197                 0u,                            // uint32_t                baseArraySlice
198                 1u,                            // uint32_t                subresourceRange
199             }};
200 
201         vk.cmdPipelineBarrier(targetCmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
202                               vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkDependencyFlags)0, 0,
203                               (const vk::VkMemoryBarrier *)DE_NULL, 0, (const vk::VkBufferMemoryBarrier *)DE_NULL, 1,
204                               &startImgBarrier);
205     }
206 
207     // Image clear
208     const vk::VkImageSubresourceRange subresourceRange = {
209         vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
210         0u,                            // uint32_t                baseMipLevel
211         1u,                            // uint32_t                levelCount
212         0u,                            // uint32_t                baseArrayLayer
213         1u,                            // uint32_t                layerCount
214     };
215 
216     vk.cmdClearColorImage(targetCmdBuffer, **colorImage, vk::VK_IMAGE_LAYOUT_GENERAL, &m_fillValue, 1,
217                           &subresourceRange);
218 
219     // Image barrier to change accessMask to transfer read bit for source image.
220     {
221         const vk::VkImageMemoryBarrier initializeBarrier = {
222             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
223             DE_NULL,                                    // const void*            pNext
224             vk::VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags        srcAccessMask
225             vk::VK_ACCESS_TRANSFER_READ_BIT,            // VkAccessFlags        dstAccessMask
226             vk::VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout        oldLayout
227             vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,   // VkImageLayout        newLayout
228             queueFamilyIndex,                           // uint32_t                srcQueueFamilyIndex
229             queueFamilyIndex,                           // uint32_t                dstQueueFamilyIndex
230             **colorImage,                               // VkImage                image
231             {
232                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
233                 0u,                            // uint32_t                baseMipLevel
234                 1u,                            // uint32_t                mipLevels
235                 0u,                            // uint32_t                baseArraySlice
236                 1u,                            // uint32_t                subresourceRange
237             }};
238 
239         vk.cmdPipelineBarrier(targetCmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
240                               (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 0,
241                               (const vk::VkBufferMemoryBarrier *)DE_NULL, 1, &initializeBarrier);
242     }
243 
244     // Copy image to buffer
245     const vk::VkImageSubresourceLayers subresourceLayers = {
246         vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
247         0u,                            // uint32_t                mipLevel
248         0u,                            // uint32_t                baseArrayLayer
249         1u,                            // uint32_t                layerCount
250     };
251     const vk::VkOffset3D nullOffset        = {0u, 0u, 0u};
252     const vk::VkExtent3D imageExtent       = {(uint32_t)RENDER_WIDTH, (uint32_t)RENDER_HEIGHT, 1u};
253     const vk::VkBufferImageCopy copyRegion = {
254         0ull,              // VkDeviceSize srcOffset;
255         0,                 // uint32_t                    bufferRowLength
256         0,                 // uint32_t                    bufferImageHeight
257         subresourceLayers, // VkImageSubresourceLayers    imageSubresource
258         nullOffset,        // VkOffset3D                imageOffset
259         imageExtent,       // VkExtent3D                imageExtent
260     };
261     vk.cmdCopyImageToBuffer(targetCmdBuffer, **colorImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **dstBuffer, 1u,
262                             &copyRegion);
263 
264     {
265         // Buffer validator reads buffer in compute shader
266         const vk::VkBufferMemoryBarrier endBufferBarrier = {
267             vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType        sType
268             DE_NULL,                                     // const void*            pNext
269             vk::VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags        srcAccessMask
270             vk::VK_ACCESS_SHADER_READ_BIT,               // VkAccessFlags        dstAccessMask
271             queueFamilyIndex,                            // uint32_t                srcQueueFamilyIndex
272             queueFamilyIndex,                            // uint32_t                dstQueueFamilyIndex
273             **dstBuffer,                                 // VkBuffer                buffer
274             0u,                                          // VkDeviceSize            offset
275             VK_WHOLE_SIZE,                               // VkDeviceSize            size
276         };
277         vk.cmdPipelineBarrier(targetCmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
278                               vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0,
279                               (const vk::VkMemoryBarrier *)DE_NULL, 1, &endBufferBarrier, 0,
280                               (const vk::VkImageMemoryBarrier *)DE_NULL);
281     }
282 
283     if (m_cmdBufferType == CMD_BUFFER_SECONDARY)
284     {
285         endCommandBuffer(vk, *secondaryCmdBuffer);
286         vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get());
287     }
288 
289     endCommandBuffer(vk, *cmdBuffer);
290 
291     // Submit command buffer
292     const vk::Unique<vk::VkFence> fence(vk::createFence(vk, device));
293     VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
294 
295     // Log out test data
296     ctx.getTestContext().getLog() << tcu::TestLog::Message << "Fill value: " << m_fillValue << tcu::TestLog::EndMessage;
297 
298     // Validate resulting buffer
299     if (m_validator.validateBuffer(ctx, **dstBuffer))
300         return tcu::TestStatus::pass("Everything went OK");
301     else
302         return tcu::TestStatus::fail("Something went really wrong");
303 }
304 
createCopyImageToFloatBufferTests(tcu::TestContext & testCtx,CmdBufferType cmdBufferType)305 tcu::TestCaseGroup *createCopyImageToFloatBufferTests(tcu::TestContext &testCtx, CmdBufferType cmdBufferType)
306 {
307     struct
308     {
309         const vk::VkClearColorValue fillValue;
310         const ValidationDataVec4 data;
311     } testData[] = {
312         {{{0.0f, 0.0f, 0.0f, 0.0f}},
313          {{tcu::IVec4(0), tcu::IVec4(1), tcu::IVec4(3), tcu::IVec4(7)},
314           {tcu::Vec4(0.0f), tcu::Vec4(0.0f), tcu::Vec4(0.0f), tcu::Vec4(0.0f)}}},
315         {{{1.0f, 1.0f, 1.0f, 1.0f}},
316          {{tcu::IVec4(2), tcu::IVec4(4), tcu::IVec4(16), tcu::IVec4(15)},
317           {tcu::Vec4(1.0f), tcu::Vec4(1.0f), tcu::Vec4(1.0f), tcu::Vec4(1.0f)}}},
318         {{{0.24f, 0.24f, 0.24f, 0.24f}},
319          {{tcu::IVec4(3), tcu::IVec4(7), tcu::IVec4(17), tcu::IVec4(37)},
320           {tcu::Vec4(0.24f), tcu::Vec4(0.24f), tcu::Vec4(0.24f), tcu::Vec4(0.24f)}}},
321         {{{0.68f, 0.68f, 0.68f, 0.68f}},
322          {{tcu::IVec4(7), tcu::IVec4(11), tcu::IVec4(21), tcu::IVec4(40)},
323           {tcu::Vec4(0.68f), tcu::Vec4(0.68f), tcu::Vec4(0.68f), tcu::Vec4(0.68f)}}},
324         {{{0.92f, 0.92f, 0.92f, 0.92f}},
325          {{tcu::IVec4(5), tcu::IVec4(21), tcu::IVec4(40), tcu::IVec4(57)},
326           {tcu::Vec4(0.92f), tcu::Vec4(0.92f), tcu::Vec4(0.92f), tcu::Vec4(0.92f)}}},
327         {{{0.49f, 0.49f, 0.49f, 0.49f}},
328          {{tcu::IVec4(23), tcu::IVec4(37), tcu::IVec4(51), tcu::IVec4(63)},
329           {tcu::Vec4(0.49f), tcu::Vec4(0.49f), tcu::Vec4(0.49f), tcu::Vec4(0.49f)}}},
330     };
331 
332     bool pipelineProtectedAccess[] = {
333         false,
334 #ifndef CTS_USES_VULKANSC
335         true,
336 #endif
337     };
338 
339     // Copy Image to Buffer Tests with static input
340     de::MovePtr<tcu::TestCaseGroup> copyStaticTests(new tcu::TestCaseGroup(testCtx, "static"));
341 
342     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testData); ++ndx)
343     {
344         for (int ppa = 0; ppa < DE_LENGTH_OF_ARRAY(pipelineProtectedAccess); ++ppa)
345         {
346             DE_ASSERT(testData[ndx].data.positions[0].x() < MAX_POSITION);
347             DE_ASSERT(testData[ndx].data.positions[1].x() < MAX_POSITION);
348             DE_ASSERT(testData[ndx].data.positions[2].x() < MAX_POSITION);
349             DE_ASSERT(testData[ndx].data.positions[3].x() < MAX_POSITION);
350 
351             const std::string name =
352                 "copy_" + de::toString(ndx + 1) + (pipelineProtectedAccess[ppa] ? "_protected_access" : "");
353             ;
354             copyStaticTests->addChild(new CopyImageToBufferTestCase<tcu::Vec4>(
355                 testCtx, name.c_str(), testData[ndx].fillValue, testData[ndx].data, cmdBufferType,
356                 vk::VK_FORMAT_R32G32B32A32_SFLOAT, pipelineProtectedAccess[ppa]));
357         }
358     }
359 
360     /* Add a few randomized tests */
361     // Copy Image to Buffer Tests with random input
362     de::MovePtr<tcu::TestCaseGroup> copyRandomTests(new tcu::TestCaseGroup(testCtx, "random"));
363     const int testCount = 10;
364     de::Random rnd(testCtx.getCommandLine().getBaseSeed());
365     for (int ndx = 0; ndx < testCount; ++ndx)
366     {
367         for (int ppa = 0; ppa < DE_LENGTH_OF_ARRAY(pipelineProtectedAccess); ++ppa)
368         {
369             const std::string name =
370                 "copy_" + de::toString(ndx + 1) + (pipelineProtectedAccess[ppa] ? "_protected_access" : "");
371             vk::VkClearValue clearValue = vk::makeClearValueColorVec4(tcu::randomVec4(rnd));
372             const tcu::Vec4 refValue(clearValue.color.float32[0], clearValue.color.float32[1],
373                                      clearValue.color.float32[2], clearValue.color.float32[3]);
374             const tcu::IVec4 vec0 = tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1));
375             const tcu::IVec4 vec1 = tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1));
376             const tcu::IVec4 vec2 = tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1));
377             const tcu::IVec4 vec3 = tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1));
378 
379             ValidationDataVec4 data = {{vec0, vec1, vec2, vec3}, {refValue, refValue, refValue, refValue}};
380 
381             DE_ASSERT(data.positions[0].x() < MAX_POSITION);
382             DE_ASSERT(data.positions[1].x() < MAX_POSITION);
383             DE_ASSERT(data.positions[2].x() < MAX_POSITION);
384             DE_ASSERT(data.positions[3].x() < MAX_POSITION);
385 
386             copyRandomTests->addChild(new CopyImageToBufferTestCase<tcu::Vec4>(
387                 testCtx, name.c_str(), clearValue.color, data, cmdBufferType, vk::VK_FORMAT_R32G32B32A32_SFLOAT,
388                 pipelineProtectedAccess[ppa]));
389         }
390     }
391 
392     std::string groupName = getCmdBufferTypeStr(cmdBufferType);
393     std::string groupDesc = "Copy Image to Buffer Tests with " + groupName + " command buffer";
394     de::MovePtr<tcu::TestCaseGroup> copyTests(new tcu::TestCaseGroup(testCtx, groupName.c_str()));
395     copyTests->addChild(copyStaticTests.release());
396     copyTests->addChild(copyRandomTests.release());
397     return copyTests.release();
398 }
399 
400 } // namespace
401 
createCopyImageToFloatBufferTests(tcu::TestContext & testCtx)402 tcu::TestCaseGroup *createCopyImageToFloatBufferTests(tcu::TestContext &testCtx)
403 {
404     de::MovePtr<tcu::TestCaseGroup> copyTests(new tcu::TestCaseGroup(testCtx, "copy_image_to_float_buffer"));
405 
406     copyTests->addChild(createCopyImageToFloatBufferTests(testCtx, CMD_BUFFER_PRIMARY));
407     copyTests->addChild(createCopyImageToFloatBufferTests(testCtx, CMD_BUFFER_SECONDARY));
408 
409     return copyTests.release();
410 }
411 
412 } // namespace ProtectedMem
413 } // namespace vkt
414