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, &copyRegion);
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