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