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