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