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