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 ©Region);
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