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