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