• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 YCbCr image conversion tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktProtectedMemYCbCrConversionTests.hpp"
26 
27 #include "tcuImageCompare.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "tcuTestLog.hpp"
30 
31 #include "vkBuilderUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkYCbCrImageWithMemory.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38 
39 #include "vktProtectedMemContext.hpp"
40 #include "vktProtectedMemUtils.hpp"
41 #include "vktTestCaseUtil.hpp"
42 #include "vktYCbCrUtil.hpp"
43 
44 
45 namespace vkt
46 {
47 namespace ProtectedMem
48 {
49 
50 namespace
51 {
52 static const vk::VkFormat	s_colorFormat	= vk::VK_FORMAT_R8G8B8A8_UNORM;
53 
54 enum {
55 	CHECK_SIZE	= 50,
56 };
57 
58 struct YCbCrValidationData {
59 	tcu::Vec4	coord;
60 	tcu::Vec4	minBound;
61 	tcu::Vec4	maxBound;
62 };
63 
computeVertexPositions(int numValues,const tcu::IVec2 & renderSize)64 std::vector<tcu::Vec2> computeVertexPositions (int numValues, const tcu::IVec2& renderSize)
65 {
66 	std::vector<tcu::Vec2> positions(numValues);
67 	for (int valNdx = 0; valNdx < numValues; valNdx++)
68 	{
69 		const int	ix	= valNdx % renderSize.x();
70 		const int	iy	= valNdx / renderSize.x();
71 		const float	fx	= -1.0f + 2.0f*((float(ix) + 0.5f) / float(renderSize.x()));
72 		const float	fy	= -1.0f + 2.0f*((float(iy) + 0.5f) / float(renderSize.y()));
73 
74 		positions[valNdx] = tcu::Vec2(fx, fy);
75 	}
76 
77 	return positions;
78 }
79 
genTexCoords(std::vector<tcu::Vec2> & coords,const tcu::UVec2 & size)80 void genTexCoords (std::vector<tcu::Vec2>& coords, const tcu::UVec2& size)
81 {
82 	for (deUint32 y = 0; y < size.y(); y++)
83 	for (deUint32 x = 0; x < size.x(); x++)
84 	{
85 		const float	fx	= (float)x;
86 		const float	fy	= (float)y;
87 
88 		const float	fw	= (float)size.x();
89 		const float	fh	= (float)size.y();
90 
91 		const float	s	= 1.5f * ((fx * 1.5f * fw + fx) / (1.5f * fw * 1.5f * fw)) - 0.25f;
92 		const float	t	= 1.5f * ((fy * 1.5f * fh + fy) / (1.5f * fh * 1.5f * fh)) - 0.25f;
93 
94 		coords.push_back(tcu::Vec2(s, t));
95 	}
96 }
97 
98 struct TestConfig
99 {
TestConfigvkt::ProtectedMem::__anon1cd3cec60111::TestConfig100 	TestConfig	(glu::ShaderType						shaderType_,
101 				 vk::VkFormat							format_,
102 				 vk::VkImageTiling						imageTiling_,
103 				 vk::VkFilter							textureFilter_,
104 				 vk::VkSamplerAddressMode				addressModeU_,
105 				 vk::VkSamplerAddressMode				addressModeV_,
106 
107 				 vk::VkFilter							chromaFilter_,
108 				 vk::VkChromaLocation					xChromaOffset_,
109 				 vk::VkChromaLocation					yChromaOffset_,
110 				 bool									explicitReconstruction_,
111 				 bool									disjoint_,
112 
113 				 vk::VkSamplerYcbcrRange				colorRange_,
114 				 vk::VkSamplerYcbcrModelConversion		colorModel_,
115 				 vk::VkComponentMapping					componentMapping_)
116 		: shaderType				(shaderType_)
117 		, format					(format_)
118 		, imageTiling				(imageTiling_)
119 		, textureFilter				(textureFilter_)
120 		, addressModeU				(addressModeU_)
121 		, addressModeV				(addressModeV_)
122 
123 		, chromaFilter				(chromaFilter_)
124 		, xChromaOffset				(xChromaOffset_)
125 		, yChromaOffset				(yChromaOffset_)
126 		, explicitReconstruction	(explicitReconstruction_)
127 		, disjoint					(disjoint_)
128 
129 		, colorRange				(colorRange_)
130 		, colorModel				(colorModel_)
131 		, componentMapping			(componentMapping_)
132 	{
133 	}
134 
135 	glu::ShaderType							shaderType;
136 	vk::VkFormat							format;
137 	vk::VkImageTiling						imageTiling;
138 	vk::VkFilter							textureFilter;
139 	vk::VkSamplerAddressMode				addressModeU;
140 	vk::VkSamplerAddressMode				addressModeV;
141 
142 	vk::VkFilter							chromaFilter;
143 	vk::VkChromaLocation					xChromaOffset;
144 	vk::VkChromaLocation					yChromaOffset;
145 	bool									explicitReconstruction;
146 	bool									disjoint;
147 
148 	vk::VkSamplerYcbcrRange					colorRange;
149 	vk::VkSamplerYcbcrModelConversion		colorModel;
150 	vk::VkComponentMapping					componentMapping;
151 };
152 
checkSupport(Context & context,const TestConfig)153 void checkSupport (Context& context, const TestConfig)
154 {
155 	checkProtectedQueueSupport(context);
156 }
157 
validateFormatSupport(ProtectedContext & context,TestConfig & config)158 void validateFormatSupport (ProtectedContext& context, TestConfig& config)
159 {
160 	tcu::TestLog&						log			(context.getTestContext().getLog());
161 
162 	try
163 	{
164 		const vk::VkFormatProperties	properties	(vk::getPhysicalDeviceFormatProperties(context.getInstanceDriver(), context.getPhysicalDevice(), config.format));
165 		const vk::VkFormatFeatureFlags	features	(config.imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
166 													? properties.optimalTilingFeatures
167 													: properties.linearTilingFeatures);
168 
169 		if ((features & (vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0)
170 			TCU_THROW(NotSupportedError, "Format doesn't support YCbCr conversions");
171 
172 		if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0)
173 			TCU_THROW(NotSupportedError, "Format doesn't support sampling");
174 
175 		if (config.textureFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0))
176 			TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
177 
178 		if (config.chromaFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0))
179 			TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
180 
181 		if (config.chromaFilter != config.textureFilter && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0))
182 			TCU_THROW(NotSupportedError, "Format doesn't support different chroma and texture filters");
183 
184 		if (config.explicitReconstruction && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT) == 0))
185 			TCU_THROW(NotSupportedError, "Format doesn't support explicit chroma reconstruction");
186 
187 		if (config.disjoint && ((features & vk::VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
188 			TCU_THROW(NotSupportedError, "Format doesn't disjoint planes");
189 
190 		if (ycbcr::isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0))
191 			TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
192 
193 		if (ycbcr::isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0))
194 			TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
195 
196 		if (ycbcr::isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0))
197 			TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
198 
199 		if (ycbcr::isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0))
200 			TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
201 
202 		if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT) != 0)
203 			config.explicitReconstruction = true;
204 
205 		log << tcu::TestLog::Message << "FormatFeatures: " << vk::getFormatFeatureFlagsStr(features) << tcu::TestLog::EndMessage;
206 	}
207 	catch (const vk::Error& err)
208 	{
209 		if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
210 			TCU_THROW(NotSupportedError, "Format not supported");
211 
212 		throw;
213 	}
214 }
215 
createSampler(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFilter textureFilter,const vk::VkSamplerAddressMode addressModeU,const vk::VkSamplerAddressMode addressModeV,const vk::VkSamplerYcbcrConversion conversion)216 vk::Move<vk::VkSampler> createSampler (const vk::DeviceInterface&				vkd,
217 									   const vk::VkDevice						device,
218 									   const vk::VkFilter						textureFilter,
219 									   const vk::VkSamplerAddressMode			addressModeU,
220 									   const vk::VkSamplerAddressMode			addressModeV,
221 									   const vk::VkSamplerYcbcrConversion		conversion)
222 {
223 	const vk::VkSamplerYcbcrConversionInfo		samplerConversionInfo	=
224 	{
225 		vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
226 		DE_NULL,
227 		conversion
228 	};
229 
230 	const vk::VkSamplerCreateInfo	createInfo	=
231 	{
232 		vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
233 		&samplerConversionInfo,
234 		0u,
235 		textureFilter,
236 		textureFilter,
237 		vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,
238 		addressModeU,
239 		addressModeV,
240 		vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
241 		0.0f,
242 		VK_FALSE,
243 		1.0f,
244 		VK_FALSE,
245 		vk::VK_COMPARE_OP_ALWAYS,
246 		0.0f,
247 		0.0f,
248 		vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
249 		VK_FALSE,
250 	};
251 
252 	return createSampler(vkd, device, &createInfo);
253 }
254 
createImageView(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkImage image,const vk::VkFormat format,const vk::VkSamplerYcbcrConversion conversion)255 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface&				vkd,
256 										   const vk::VkDevice						device,
257 										   const vk::VkImage						image,
258 										   const vk::VkFormat						format,
259 										   const vk::VkSamplerYcbcrConversion		conversion)
260 {
261 	const vk::VkSamplerYcbcrConversionInfo		conversionInfo	=
262 	{
263 		vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
264 		DE_NULL,
265 		conversion
266 	};
267 
268 	const vk::VkImageViewCreateInfo				viewInfo		=
269 	{
270 		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
271 		&conversionInfo,
272 		(vk::VkImageViewCreateFlags)0,
273 		image,
274 		vk::VK_IMAGE_VIEW_TYPE_2D,
275 		format,
276 		{
277 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
278 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
279 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
280 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
281 		},
282 		{ vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
283 	};
284 
285 	return vk::createImageView(vkd, device, &viewInfo);
286 }
287 
createConversion(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFormat format,const vk::VkSamplerYcbcrModelConversion colorModel,const vk::VkSamplerYcbcrRange colorRange,const vk::VkChromaLocation xChromaOffset,const vk::VkChromaLocation yChromaOffset,const vk::VkFilter chromaFilter,const vk::VkComponentMapping & componentMapping,const bool explicitReconstruction)288 vk::Move<vk::VkSamplerYcbcrConversion> createConversion (const vk::DeviceInterface&					vkd,
289 														const vk::VkDevice							device,
290 														const vk::VkFormat							format,
291 														const vk::VkSamplerYcbcrModelConversion		colorModel,
292 														const vk::VkSamplerYcbcrRange				colorRange,
293 														const vk::VkChromaLocation					xChromaOffset,
294 														const vk::VkChromaLocation					yChromaOffset,
295 														const vk::VkFilter							chromaFilter,
296 														const vk::VkComponentMapping&				componentMapping,
297 														const bool									explicitReconstruction)
298 {
299 	const vk::VkSamplerYcbcrConversionCreateInfo	conversionInfo	=
300 	{
301 		vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
302 		DE_NULL,
303 
304 		format,
305 		colorModel,
306 		colorRange,
307 		componentMapping,
308 		xChromaOffset,
309 		yChromaOffset,
310 		chromaFilter,
311 		explicitReconstruction ? VK_TRUE : VK_FALSE
312 	};
313 
314 	return vk::createSamplerYcbcrConversion(vkd, device, &conversionInfo);
315 }
316 
uploadYCbCrImage(ProtectedContext & ctx,const vk::VkImage image,const ycbcr::MultiPlaneImageData & imageData,const vk::VkAccessFlags nextAccess,const vk::VkImageLayout finalLayout)317 void uploadYCbCrImage (ProtectedContext&					ctx,
318 					   const vk::VkImage					image,
319 					   const ycbcr::MultiPlaneImageData&	imageData,
320 					   const vk::VkAccessFlags				nextAccess,
321 					   const vk::VkImageLayout				finalLayout)
322 {
323 	const vk::DeviceInterface&				vk					= ctx.getDeviceInterface();
324 	const vk::VkDevice						device				= ctx.getDevice();
325 	const vk::VkQueue						queue				= ctx.getQueue();
326 	const deUint32							queueFamilyIndex	= ctx.getQueueFamilyIndex();
327 
328 	const vk::Unique<vk::VkCommandPool>		cmdPool				(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
329 	const vk::Unique<vk::VkCommandBuffer>	cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
330 
331 	const vk::PlanarFormatDescription&		formatDesc			= imageData.getDescription();
332 
333 	std::vector<de::SharedPtr<de::MovePtr<vk::BufferWithMemory> > > stagingBuffers;
334 	std::vector<vk::VkBufferMemoryBarrier>	bufferBarriers;
335 
336 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
337 	{
338 		de::MovePtr<vk::BufferWithMemory> buffer	(makeBuffer(ctx,
339 																		PROTECTION_DISABLED,
340 																		queueFamilyIndex,
341 																		(deUint32)imageData.getPlaneSize(planeNdx),
342 																		vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT|vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
343 																		vk::MemoryRequirement::HostVisible));
344 
345 		const vk::VkBufferMemoryBarrier		bufferBarrier	=
346 		{
347 			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
348 			DE_NULL,
349 			(vk::VkAccessFlags)0,
350 			vk::VK_ACCESS_TRANSFER_READ_BIT,
351 			queueFamilyIndex,
352 			queueFamilyIndex,
353 			**buffer,
354 			0,
355 			(deUint32)imageData.getPlaneSize(planeNdx)
356 		};
357 		bufferBarriers.push_back(bufferBarrier);
358 
359 		deMemcpy(buffer->getAllocation().getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
360 		flushAlloc(vk, device, buffer->getAllocation());
361 		stagingBuffers.push_back(de::SharedPtr<de::MovePtr<vk::BufferWithMemory> >(new de::MovePtr<vk::BufferWithMemory>(buffer.release())));
362 	}
363 
364 
365 	beginCommandBuffer(vk, *cmdBuffer);
366 
367 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
368 	{
369 		const vk::VkImageAspectFlags	aspect	= formatDesc.numPlanes > 1
370 												? vk::getPlaneAspect(planeNdx)
371 												: vk::VK_IMAGE_ASPECT_COLOR_BIT;
372 
373 		const vk::VkImageMemoryBarrier		preCopyBarrier	=
374 		{
375 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
376 			DE_NULL,
377 			(vk::VkAccessFlags)0,
378 			vk::VK_ACCESS_TRANSFER_WRITE_BIT,
379 			vk::VK_IMAGE_LAYOUT_UNDEFINED,
380 			vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
381 			queueFamilyIndex,
382 			queueFamilyIndex,
383 			image,
384 			{ aspect, 0u, 1u, 0u, 1u }
385 		};
386 
387 		vk.cmdPipelineBarrier(*cmdBuffer,
388 								(vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_HOST_BIT,
389 								(vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
390 								(vk::VkDependencyFlags)0u,
391 								0u, (const vk::VkMemoryBarrier*)DE_NULL,
392 								(deUint32)bufferBarriers.size(), &bufferBarriers[0],
393 								1u, &preCopyBarrier);
394 	}
395 
396 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
397 	{
398 		const vk::VkImageAspectFlagBits	aspect	= (formatDesc.numPlanes > 1)
399 												? vk::getPlaneAspect(planeNdx)
400 												: vk::VK_IMAGE_ASPECT_COLOR_BIT;
401 		const deUint32					planeW	= (formatDesc.numPlanes > 1)
402 												? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
403 												: imageData.getSize().x();
404 		const deUint32					planeH	= (formatDesc.numPlanes > 1)
405 												? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
406 												: imageData.getSize().y();
407 		const vk::VkBufferImageCopy		copy	=
408 		{
409 			0u,		// bufferOffset
410 			0u,		// bufferRowLength
411 			0u,		// bufferImageHeight
412 			{ (vk::VkImageAspectFlags)aspect, 0u, 0u, 1u },
413 			vk::makeOffset3D(0u, 0u, 0u),
414 			vk::makeExtent3D(planeW, planeH, 1u),
415 		};
416 
417 		vk.cmdCopyBufferToImage(*cmdBuffer, ***stagingBuffers[planeNdx], image, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copy);
418 	}
419 
420 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
421 	{
422 		const vk::VkImageAspectFlags	aspect	= formatDesc.numPlanes > 1
423 												? vk::getPlaneAspect(planeNdx)
424 												: vk::VK_IMAGE_ASPECT_COLOR_BIT;
425 
426 		const vk::VkImageMemoryBarrier		postCopyBarrier	=
427 		{
428 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
429 			DE_NULL,
430 			vk::VK_ACCESS_TRANSFER_WRITE_BIT,
431 			nextAccess,
432 			vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
433 			finalLayout,
434 			VK_QUEUE_FAMILY_IGNORED,
435 			VK_QUEUE_FAMILY_IGNORED,
436 			image,
437 			{ aspect, 0u, 1u, 0u, 1u }
438 		};
439 
440 		vk.cmdPipelineBarrier(*cmdBuffer,
441 								(vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
442 								(vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
443 								(vk::VkDependencyFlags)0u,
444 								0u, (const vk::VkMemoryBarrier*)DE_NULL,
445 								0u, (const vk::VkBufferMemoryBarrier*)DE_NULL,
446 								1u, &postCopyBarrier);
447 	}
448 
449 	endCommandBuffer(vk, *cmdBuffer);
450 
451 	{
452 		const vk::Unique<vk::VkFence>	fence		(createFence(vk, device));
453 		VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
454 	}
455 }
456 
logTestCaseInfo(tcu::TestLog & log,const TestConfig & config)457 void logTestCaseInfo (tcu::TestLog& log, const TestConfig& config)
458 {
459 	log << tcu::TestLog::Message << "ShaderType: " << config.shaderType << tcu::TestLog::EndMessage;
460 	log << tcu::TestLog::Message << "Format: "  << config.format << tcu::TestLog::EndMessage;
461 	log << tcu::TestLog::Message << "ImageTiling: " << config.imageTiling << tcu::TestLog::EndMessage;
462 	log << tcu::TestLog::Message << "TextureFilter: " << config.textureFilter << tcu::TestLog::EndMessage;
463 	log << tcu::TestLog::Message << "AddressModeU: " << config.addressModeU << tcu::TestLog::EndMessage;
464 	log << tcu::TestLog::Message << "AddressModeV: " << config.addressModeV << tcu::TestLog::EndMessage;
465 	log << tcu::TestLog::Message << "ChromaFilter: " << config.chromaFilter << tcu::TestLog::EndMessage;
466 	log << tcu::TestLog::Message << "XChromaOffset: " << config.xChromaOffset << tcu::TestLog::EndMessage;
467 	log << tcu::TestLog::Message << "YChromaOffset: " << config.yChromaOffset << tcu::TestLog::EndMessage;
468 	log << tcu::TestLog::Message << "ExplicitReconstruction: " << (config.explicitReconstruction ? "true" : "false") << tcu::TestLog::EndMessage;
469 	log << tcu::TestLog::Message << "Disjoint: " << (config.disjoint ? "true" : "false") << tcu::TestLog::EndMessage;
470 	log << tcu::TestLog::Message << "ColorRange: " << config.colorRange << tcu::TestLog::EndMessage;
471 	log << tcu::TestLog::Message << "ColorModel: " << config.colorModel << tcu::TestLog::EndMessage;
472 	log << tcu::TestLog::Message << "ComponentMapping: " << config.componentMapping << tcu::TestLog::EndMessage;
473 }
474 
logBoundImages(tcu::TestLog & log,const tcu::UVec2 size,const std::vector<tcu::Vec4> & minBounds,const std::vector<tcu::Vec4> & maxBounds)475 void logBoundImages (tcu::TestLog& log, const tcu::UVec2 size, const std::vector<tcu::Vec4>& minBounds, const std::vector<tcu::Vec4>& maxBounds)
476 {
477 	tcu::TextureLevel	minImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x(), size.y());
478 	tcu::TextureLevel	maxImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x(), size.y());
479 
480 	for (int y = 0; y < (int)(size.y()); y++)
481 	for (int x = 0; x < (int)(size.x()); x++)
482 	{
483 		const int ndx = x + y * (int)(size.x());
484 		minImage.getAccess().setPixel(minBounds[ndx], x, y);
485 		maxImage.getAccess().setPixel(maxBounds[ndx], x, y);
486 	}
487 
488 	const tcu::Vec4	scale	(1.0f);
489 	const tcu::Vec4	bias	(0.0f);
490 
491 	log << tcu::TestLog::Image("MinBoundImage", "MinBoundImage", minImage.getAccess(), scale, bias);
492 	log << tcu::TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage.getAccess(), scale, bias);
493 }
494 
validateImage(ProtectedContext & ctx,const std::vector<YCbCrValidationData> & refData,const vk::VkSampler sampler,const vk::VkImageView imageView,const deUint32 combinedSamplerDescriptorCount)495 bool validateImage (ProtectedContext&							ctx,
496 					 const std::vector<YCbCrValidationData>&	refData,
497 					 const vk::VkSampler						sampler,
498 					 const vk::VkImageView						imageView,
499 					 const deUint32								combinedSamplerDescriptorCount)
500 {
501 	{
502 		tcu::TestLog&	log	(ctx.getTestContext().getLog());
503 
504 		log << tcu::TestLog::Message << "Reference values:" << tcu::TestLog::EndMessage;
505 		for (deUint32 ndx = 0; ndx < refData.size(); ndx++)
506 		{
507 			log << tcu::TestLog::Message << (ndx + 1) << refData[ndx].coord << ": [" << refData[ndx].minBound << ", " << refData[ndx].maxBound << "]" << tcu::TestLog::EndMessage;
508 		}
509 	}
510 
511 	const deUint64								oneSec				= 1000 * 1000 * 1000;
512 
513 	const vk::DeviceInterface&					vk					= ctx.getDeviceInterface();
514 	const vk::VkDevice							device				= ctx.getDevice();
515 	const vk::VkQueue							queue				= ctx.getQueue();
516 	const deUint32								queueFamilyIndex	= ctx.getQueueFamilyIndex();
517 
518 	DE_ASSERT(refData.size() >= CHECK_SIZE && CHECK_SIZE > 0);
519 	const deUint32								refUniformSize		= (deUint32)(sizeof(YCbCrValidationData) * refData.size());
520 	const de::UniquePtr<vk::BufferWithMemory>	refUniform			(makeBuffer(ctx,
521 																				PROTECTION_DISABLED,
522 																				queueFamilyIndex,
523 																				refUniformSize,
524 																				vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
525 																				vk::MemoryRequirement::HostVisible));
526 
527 	// Set the reference uniform data
528 	{
529 		deMemcpy(refUniform->getAllocation().getHostPtr(), &refData[0], refUniformSize);
530 		flushAlloc(vk, device, refUniform->getAllocation());
531 	}
532 
533 	const deUint32								helperBufferSize	= (deUint32)(2 * sizeof(deUint32));
534 	const de::MovePtr<vk::BufferWithMemory>		helperBuffer		(makeBuffer(ctx,
535 																				PROTECTION_ENABLED,
536 																				queueFamilyIndex,
537 																				helperBufferSize,
538 																				vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
539 																				vk::MemoryRequirement::Protected));
540 	const vk::Unique<vk::VkShaderModule>		resetSSBOShader		(vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ResetSSBO"), 0));
541 	const vk::Unique<vk::VkShaderModule>		validatorShader		(vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ImageValidator"), 0));
542 
543 	// Create descriptors
544 	const vk::Unique<vk::VkDescriptorSetLayout>	descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
545 		.addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_SHADER_STAGE_COMPUTE_BIT, &sampler)
546 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
547 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
548 		.build(vk, device));
549 	const vk::Unique<vk::VkDescriptorPool>		descriptorPool(vk::DescriptorPoolBuilder()
550 		.addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount)
551 		.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
552 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
553 		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
554 	const vk::Unique<vk::VkDescriptorSet>		descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
555 
556 	// Update descriptor set infirmation
557 	{
558 		vk::VkDescriptorBufferInfo	descRefUniform	= makeDescriptorBufferInfo(**refUniform, 0, refUniformSize);
559 		vk::VkDescriptorBufferInfo	descBuffer		= makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize);
560 		vk::VkDescriptorImageInfo	descSampledImg	= makeDescriptorImageInfo(sampler, imageView, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
561 
562 		vk::DescriptorSetUpdateBuilder()
563 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descSampledImg)
564 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
565 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBuffer)
566 			.update(vk, device);
567 	}
568 
569 	const vk::Unique<vk::VkPipelineLayout>		pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
570 	const vk::Unique<vk::VkCommandPool>			cmdPool				(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
571 
572 	// Reset helper SSBO
573 	{
574 		const vk::Unique<vk::VkFence>			fence				(vk::createFence(vk, device));
575 		const vk::Unique<vk::VkPipeline>		resetSSBOPipeline	(makeComputePipeline(vk, device, *pipelineLayout, *resetSSBOShader));
576 		const vk::Unique<vk::VkCommandBuffer>	resetCmdBuffer		(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
577 		beginCommandBuffer(vk, *resetCmdBuffer);
578 
579 		vk.cmdBindPipeline(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *resetSSBOPipeline);
580 		vk.cmdBindDescriptorSets(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
581 		vk.cmdDispatch(*resetCmdBuffer, 1u, 1u, 1u);
582 
583 		endCommandBuffer(vk, *resetCmdBuffer);
584 		VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *resetCmdBuffer, *fence, ~0ull));
585 	}
586 
587 	// Create validation compute commands & submit
588 	vk::VkResult							queueSubmitResult;
589 	{
590 		const vk::Unique<vk::VkFence>			fence				(vk::createFence(vk, device));
591 		const vk::Unique<vk::VkPipeline>		validationPipeline	(makeComputePipeline(vk, device, *pipelineLayout, *validatorShader));
592 		const vk::Unique<vk::VkCommandBuffer>	cmdBuffer			(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
593 
594 		beginCommandBuffer(vk, *cmdBuffer);
595 
596 		vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *validationPipeline);
597 		vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
598 		vk.cmdDispatch(*cmdBuffer, CHECK_SIZE, 1u, 1u);
599 
600 		endCommandBuffer(vk, *cmdBuffer);
601 
602 		queueSubmitResult = queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, oneSec * 5);
603 	}
604 
605 	// \todo do we need to check the fence status?
606 	if (queueSubmitResult == vk::VK_TIMEOUT)
607 		return false;
608 
609 	// at this point the submit result should be VK_TRUE
610 	VK_CHECK(queueSubmitResult);
611 	return true;
612 }
613 
testShaders(vk::SourceCollections & dst,const TestConfig config)614 void testShaders (vk::SourceCollections& dst, const TestConfig config)
615 {
616 	const char* const	shaderHeader		=
617 			"layout(constant_id = 1) const float threshold = 0.01f;\n"
618 			"layout(set = 0, binding = 0) uniform highp sampler2D protectedImage;\n"
619 			"\n"
620 			"struct validationData {\n"
621 			"    highp vec4 imageCoord;\n"
622 			"    highp vec4 imageRefMinBound;\n"
623 			"    highp vec4 imageRefMaxBound;\n"
624 			"};\n"
625 			"layout(std140, set = 0, binding = 1) uniform Data\n"
626 			"{\n"
627 			"    validationData ref[250];\n"
628 			"};\n";
629 
630 	const char* const	compareFunction	=
631 			"bool compare(highp vec4 value, highp vec4 minValue, highp vec4 maxValue)\n"
632 			"{\n"
633 			"    return all(greaterThanEqual(value, minValue - threshold)) && all(lessThanEqual(value, maxValue + threshold));\n"
634 			"}\n";
635 
636 	std::map<std::string, std::string> validatorSpec;
637 	validatorSpec["CHECK_SIZE"]			= de::toString((deUint32)CHECK_SIZE);
638 	validatorSpec["SHADER_HEADER"]		= shaderHeader;
639 	validatorSpec["COMPARE_FUNCTION"]	= compareFunction;
640 
641 	const char* const validatorShader =
642 		"#version 450\n"
643 		"\n"
644 		"${SHADER_HEADER}"
645 		"\n"
646 		"layout(std140, set = 0, binding = 2) buffer ProtectedHelper\n"
647 		"{\n"
648 		"    highp uint zero;\n"
649 		"    highp uint unusedOut;\n"
650 		"} helper;\n"
651 		"\n"
652 		"void error()\n"
653 		"{\n"
654 		"    for (uint x = 0u; x < 10u; x += helper.zero)\n"
655 		"        atomicAdd(helper.unusedOut, 1u);\n"
656 		"}\n"
657 		"\n"
658 		"${COMPARE_FUNCTION}"
659 		"\n"
660 		"void main(void)\n"
661 		"{\n"
662 		"    int idx = int(gl_GlobalInvocationID.x);\n"
663 		"    vec4 currentValue = texture(protectedImage, ref[idx].imageCoord.xy);\n"
664 		"    if (!compare(currentValue, ref[idx].imageRefMinBound, ref[idx].imageRefMaxBound))\n"
665 		"    {\n"
666 		"      error();\n"
667 		"    }\n"
668 		"}\n";
669 
670 	const char* const resetSSBOShader =
671 		"#version 450\n"
672 		"layout(local_size_x = 1) in;\n"
673 		"\n"
674 		"layout(std140, set=0, binding=2) buffer ProtectedHelper\n"
675 		"{\n"
676 		"    highp uint zero; // set to 0\n"
677 		"    highp uint unusedOut;\n"
678 		"} helper;\n"
679 		"\n"
680 		"void main (void)\n"
681 		"{\n"
682 		"    helper.zero = 0;\n"
683 		"    helper.unusedOut = 0;\n"
684 		"}\n";
685 
686 	dst.glslSources.add("ResetSSBO") << glu::ComputeSource(resetSSBOShader);
687 	dst.glslSources.add("ImageValidator") << glu::ComputeSource(tcu::StringTemplate(validatorShader).specialize(validatorSpec));
688 
689 	if (config.shaderType == glu::SHADERTYPE_COMPUTE)
690 		return; // Bail early as the YCbCr image validator already have the test programs set for compute tests
691 
692 	const char* const compareOperation =
693 			"    highp vec4 currentValue = texture(protectedImage, ref[v_idx].imageCoord.xy);\n"
694 			"    if (compare(currentValue, ref[v_idx].imageRefMinBound, ref[v_idx].imageRefMaxBound))\n"
695 			"    {\n"
696 			"        o_color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n"	// everything is ok, green
697 			"    }\n"
698 			"    else"
699 			"    {\n"
700 			"        o_color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
701 			"    }\n";
702 
703 	std::map<std::string, std::string>	shaderSpec;
704 	shaderSpec["SHADER_HEADER"]		= shaderHeader;
705 	shaderSpec["COMPARE_FUNCTION"]	= compareFunction;
706 	shaderSpec["COMPARE_OPERATION"]	= compareOperation;
707 
708 	if (config.shaderType == glu::SHADERTYPE_VERTEX)
709 	{
710 		const char* const vertexShader =
711 			"#version 450\n"
712 			"${SHADER_HEADER}\n"
713 			"\n"
714 			"layout(location = 0) in highp vec2 a_position;\n"
715 			"layout(location = 0) flat out highp vec4 o_color;\n"
716 			"\n"
717 			"${COMPARE_FUNCTION}"
718 			"\n"
719 			"void main(void)\n"
720 			"{\n"
721 			"    gl_Position = vec4(a_position, 0.0f, 1.0f);\n"
722 			"    gl_PointSize = 1.0f;\n"
723 			"    int v_idx = gl_VertexIndex;\n"
724 			"${COMPARE_OPERATION}"
725 			"}\n";
726 
727 		const char* const fragmentShader =
728 			"#version 450\n"
729 			"\n"
730 			"layout(location = 0) flat in highp vec4 v_color;\n"
731 			"layout(location = 0) out highp vec4 o_color;\n"
732 			"\n"
733 			"void main(void)\n"
734 			"{\n"
735 			"    o_color = v_color;\n"
736 			"}\n";
737 
738 		dst.glslSources.add("vert") << glu::VertexSource(tcu::StringTemplate(vertexShader).specialize(shaderSpec));
739 		dst.glslSources.add("frag") << glu::FragmentSource(fragmentShader);
740 	}
741 	else if (config.shaderType == glu::SHADERTYPE_FRAGMENT)
742 	{
743 		const char* const vertexShader =
744 			"#version 450\n"
745 			"layout(location = 0) in highp vec2 a_position;\n"
746 			"layout(location = 0) flat out highp int o_idx;\n"
747 			"\n"
748 			"void main(void)\n"
749 			"{\n"
750 			"    gl_Position = vec4(a_position, 0.0f, 1.0f);\n"
751 			"    gl_PointSize = 1.0f;\n"
752 			"    o_idx = gl_VertexIndex;\n"
753 			"}\n";
754 
755 		const char* const fragmentShader =
756 			"#version 450\n"
757 			"${SHADER_HEADER}\n"
758 			"\n"
759 			"layout(location = 0) flat in highp int v_idx;\n"
760 			"layout(location = 0) out highp vec4 o_color;\n"
761 			"\n"
762 			"${COMPARE_FUNCTION}"
763 			"\n"
764 			"void main(void)\n"
765 			"{\n"
766 			"${COMPARE_OPERATION}"
767 			"}\n";
768 
769 		dst.glslSources.add("vert") << glu::VertexSource(vertexShader);
770 		dst.glslSources.add("frag") << glu::FragmentSource(tcu::StringTemplate(fragmentShader).specialize(shaderSpec));
771 	}
772 }
773 
createYcbcrImage2D(ProtectedContext & context,const ProtectionMode protectionMode,const deUint32 width,const deUint32 height,const vk::VkFormat format,const vk::VkImageCreateFlags createFlags,const vk::VkImageUsageFlags usageFlags)774 de::MovePtr<vk::YCbCrImageWithMemory>	createYcbcrImage2D	(ProtectedContext&				context,
775 															 const ProtectionMode			protectionMode,
776 															 const deUint32					width,
777 															 const deUint32					height,
778 															 const vk::VkFormat				format,
779 															 const vk::VkImageCreateFlags	createFlags,
780 															 const vk::VkImageUsageFlags	usageFlags)
781 {
782 	const vk::DeviceInterface&	vk			= context.getDeviceInterface();
783 	const vk::VkDevice&			device		= context.getDevice();
784 	vk::Allocator&				allocator	= context.getDefaultAllocator();
785 	const deUint32				queueIdx	= context.getQueueFamilyIndex();
786 #ifndef NOT_PROTECTED
787 	const deUint32				flags		= (protectionMode == PROTECTION_ENABLED) ? vk::VK_IMAGE_CREATE_PROTECTED_BIT : 0x0;
788 	const vk::MemoryRequirement	memReq		= (protectionMode == PROTECTION_ENABLED) ? vk::MemoryRequirement::Protected : vk::MemoryRequirement::Any;
789 #else
790 	const deUint32				flags		= 0x0;
791 	const vk::MemoryRequirement	memReq		= vk::MemoryRequirement::Any;
792 	DE_UNREF(protectionMode);
793 #endif
794 
795 	const vk::VkImageCreateInfo	params		=
796 	{
797 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType			stype
798 		DE_NULL,										// const void*				pNext
799 		(vk::VkImageCreateFlags)(flags | createFlags),	// VkImageCreateFlags		flags
800 		vk::VK_IMAGE_TYPE_2D,							// VkImageType				imageType
801 		format,											// VkFormat					format
802 		{ width, height, 1 },							// VkExtent3D				extent
803 		1u,												// deUint32					mipLevels
804 		1u,												// deUint32					arrayLayers
805 		vk::VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits	samples
806 		vk::VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling			tiling
807 		usageFlags,										// VkImageUsageFlags		usage
808 		vk::VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode			sharingMode
809 		1u,												// deUint32					queueFamilyIndexCount
810 		&queueIdx,										// const deUint32*			pQueueFamilyIndices
811 		vk::VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			initialLayout
812 	};
813 
814 	return de::MovePtr<vk::YCbCrImageWithMemory>(new vk::YCbCrImageWithMemory(vk, device, allocator, params, memReq));
815 }
816 
817 
renderYCbCrToColor(ProtectedContext & ctx,const tcu::UVec2 size,const vk::VkSampler ycbcrSampler,const vk::VkImageView ycbcrImageView,const vk::VkImage colorImage,const vk::VkImageView colorImageView,const std::vector<YCbCrValidationData> & referenceData,const std::vector<tcu::Vec2> & posCoords,const deUint32 combinedSamplerDescriptorCount)818 void renderYCbCrToColor (ProtectedContext&							ctx,
819 						 const tcu::UVec2							size,
820 						 const vk::VkSampler						ycbcrSampler,
821 						 const vk::VkImageView						ycbcrImageView,
822 						 const vk::VkImage							colorImage,
823 						 const vk::VkImageView						colorImageView,
824 						 const std::vector<YCbCrValidationData>&	referenceData,
825 						 const std::vector<tcu::Vec2>&				posCoords,
826 						 const deUint32								combinedSamplerDescriptorCount)
827 {
828 	const vk::DeviceInterface&					vk					= ctx.getDeviceInterface();
829 	const vk::VkDevice							device				= ctx.getDevice();
830 	const vk::VkQueue							queue				= ctx.getQueue();
831 	const deUint32								queueFamilyIndex	= ctx.getQueueFamilyIndex();
832 
833 	const vk::Unique<vk::VkRenderPass>			renderPass			(createRenderPass(ctx, s_colorFormat));
834 	const vk::Unique<vk::VkFramebuffer>			framebuffer			(createFramebuffer(ctx, size.x(), size.y(), *renderPass, colorImageView));
835 	const vk::Unique<vk::VkShaderModule>		vertexShader		(createShaderModule(vk, device, ctx.getBinaryCollection().get("vert"), 0));
836 	const vk::Unique<vk::VkShaderModule>		fragmentShader		(createShaderModule(vk, device, ctx.getBinaryCollection().get("frag"), 0));
837 	const vk::Unique<vk::VkDescriptorSetLayout>	descriptorSetLayout (vk::DescriptorSetLayoutBuilder()
838 																		.addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
839 																							 vk::VK_SHADER_STAGE_ALL,
840 																							 &ycbcrSampler)
841 																		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL)
842 																		.build(vk, device));
843 	const vk::Unique<vk::VkDescriptorPool>		descriptorPool		(vk::DescriptorPoolBuilder()
844 																		.addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount)
845 																		.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
846 																		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
847 	const vk::Unique<vk::VkDescriptorSet>		descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
848 	const vk::Unique<vk::VkPipelineLayout>		pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
849 
850 
851 	const deUint32								refUniformSize		= (deUint32)(sizeof(YCbCrValidationData) * referenceData.size());
852 	const de::UniquePtr<vk::BufferWithMemory>	refUniform			(makeBuffer(ctx,
853 																				PROTECTION_DISABLED,
854 																				queueFamilyIndex,
855 																				refUniformSize,
856 																				vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
857 																				vk::MemoryRequirement::HostVisible));
858 
859 	// Set the reference uniform data
860 	{
861 		deMemcpy(refUniform->getAllocation().getHostPtr(), &referenceData[0], refUniformSize);
862 		flushAlloc(vk, device, refUniform->getAllocation());
863 	}
864 
865 	// Update descriptor set
866 	{
867 		vk::VkDescriptorImageInfo	ycbcrSampled	(makeDescriptorImageInfo(ycbcrSampler, ycbcrImageView, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
868 		vk::VkDescriptorBufferInfo	descRefUniform	= makeDescriptorBufferInfo(**refUniform, 0, refUniformSize);
869 		vk::DescriptorSetUpdateBuilder()
870 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &ycbcrSampled)
871 			.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
872 			.update(vk, device);
873 	}
874 
875 	VertexBindings							vertexBindings;
876 	VertexAttribs							vertexAttribs;
877 	de::MovePtr<vk::BufferWithMemory>		vertexBuffer;
878 	{
879 		const deUint32	bufferSize		= (deUint32)(sizeof(tcu::Vec2) * posCoords.size());
880 		{
881 			const vk::VkVertexInputBindingDescription	inputBinding	=
882 			{
883 				0u,									// deUint32					binding;
884 				sizeof(tcu::Vec2),					// deUint32					strideInBytes;
885 				vk::VK_VERTEX_INPUT_RATE_VERTEX		// VkVertexInputStepRate	inputRate;
886 			};
887 			const vk::VkVertexInputAttributeDescription	inputAttribute	=
888 			{
889 				0u,									// deUint32	location;
890 				0u,									// deUint32	binding;
891 				vk::VK_FORMAT_R32G32_SFLOAT,		// VkFormat	format;
892 				0u									// deUint32	offsetInBytes;
893 			};
894 
895 			vertexBindings.push_back(inputBinding);
896 			vertexAttribs.push_back(inputAttribute);
897 		}
898 
899 		vertexBuffer = makeBuffer(ctx,
900 								  PROTECTION_DISABLED,
901 								  queueFamilyIndex,
902 								  bufferSize,
903 								  vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
904 								  vk::MemoryRequirement::HostVisible);
905 
906 		deMemcpy(vertexBuffer->getAllocation().getHostPtr(), &posCoords[0], bufferSize);
907 		flushAlloc(vk, device, vertexBuffer->getAllocation());
908 	}
909 
910 	const vk::Unique<vk::VkPipeline>		pipeline			(makeGraphicsPipeline(vk,
911 																					  device,
912 																					  *pipelineLayout,
913 																					  *renderPass,
914 																					  *vertexShader,
915 																					  *fragmentShader,
916 																					  vertexBindings,
917 																					  vertexAttribs,
918 																					  size,
919 																					  vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST));
920 	const vk::Unique<vk::VkCommandPool>		cmdPool			(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
921 	const vk::Unique<vk::VkCommandBuffer>	cmdBuffer		(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
922 
923 	beginCommandBuffer(vk, *cmdBuffer);
924 	{
925 		const vk::VkImageMemoryBarrier	attachmentStartBarrier =
926 		{
927 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
928 			DE_NULL,
929 			0u,
930 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
931 			vk::VK_IMAGE_LAYOUT_UNDEFINED,
932 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
933 			queueFamilyIndex,
934 			queueFamilyIndex,
935 			colorImage,
936 			{ vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
937 		};
938 
939 		vk.cmdPipelineBarrier(*cmdBuffer,
940 							  (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
941 							  (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
942 							  (vk::VkDependencyFlags)0u,
943 							  0u, (const vk::VkMemoryBarrier*)DE_NULL,
944 							  0u, (const vk::VkBufferMemoryBarrier*)DE_NULL,
945 							  1u, &attachmentStartBarrier);
946 	}
947 
948 	beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, vk::makeRect2D(0, 0, size.x(), size.y()), tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f));
949 
950 	vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
951 	vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
952 
953 	{
954 		const vk::VkDeviceSize vertexBufferOffset = 0;
955 		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &**vertexBuffer, &vertexBufferOffset);
956 	}
957 
958 	vk.cmdDraw(*cmdBuffer, /*vertexCount*/ (deUint32)posCoords.size(), 1u, 0u, 0u);
959 
960 	endRenderPass(vk, *cmdBuffer);
961 
962 	// color attachment render end barrier
963 	{
964 		const vk::VkImageMemoryBarrier	attachmentEndBarrier =
965 		{
966 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
967 			DE_NULL,
968 			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
969 			vk::VK_ACCESS_SHADER_READ_BIT,
970 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
971 			vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
972 			queueFamilyIndex,
973 			queueFamilyIndex,
974 			colorImage,
975 			{ vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
976 		};
977 
978 		vk.cmdPipelineBarrier(*cmdBuffer,
979 							  (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
980 							  (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
981 							  (vk::VkDependencyFlags)0u,
982 							  0u, (const vk::VkMemoryBarrier*)DE_NULL,
983 							  0u, (const vk::VkBufferMemoryBarrier*)DE_NULL,
984 							  1u, &attachmentEndBarrier);
985 	}
986 
987 	endCommandBuffer(vk, *cmdBuffer);
988 
989 	// Submit command buffer
990 	{
991 		const vk::Unique<vk::VkFence>	fence		(vk::createFence(vk, device));
992 		VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
993 	}
994 }
995 
generateYCbCrImage(ProtectedContext & ctx,const TestConfig & config,const tcu::UVec2 size,const std::vector<tcu::Vec2> & texCoords,ycbcr::MultiPlaneImageData & ycbcrSrc,std::vector<tcu::Vec4> & ycbcrMinBounds,std::vector<tcu::Vec4> & ycbcrMaxBounds)996 void generateYCbCrImage (ProtectedContext&				ctx,
997 						const TestConfig&				config,
998 						const tcu::UVec2				size,
999 						const std::vector<tcu::Vec2>&	texCoords,
1000 						ycbcr::MultiPlaneImageData&		ycbcrSrc,
1001 						std::vector<tcu::Vec4>&			ycbcrMinBounds,
1002 						std::vector<tcu::Vec4>&			ycbcrMaxBounds)
1003 {
1004 	tcu::TestLog&						log						(ctx.getTestContext().getLog());
1005 	const std::vector<tcu::FloatFormat>	filteringPrecision		(ycbcr::getPrecision(config.format));
1006 	const std::vector<tcu::FloatFormat>	conversionPrecision		(ycbcr::getPrecision(config.format));
1007 	const tcu::UVec4					bitDepth				(ycbcr::getYCbCrBitDepth(config.format));
1008 	bool								explicitReconstruction	= config.explicitReconstruction;
1009 	const deUint32						subTexelPrecisionBits	(vk::getPhysicalDeviceProperties(ctx.getInstanceDriver(),
1010 																								 ctx.getPhysicalDevice()).limits.subTexelPrecisionBits);
1011 
1012 
1013 	const vk::PlanarFormatDescription	planeInfo				(vk::getPlanarFormatDescription(config.format));
1014 
1015 	deUint32							nullAccessData			(0u);
1016 	ycbcr::ChannelAccess				nullAccess				(tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(size.x(), size.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessData, 0u);
1017 	deUint32							nullAccessAlphaData		(~0u);
1018 	ycbcr::ChannelAccess				nullAccessAlpha			(tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(size.x(), size.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessAlphaData, 0u);
1019 	ycbcr::ChannelAccess				rChannelAccess			(planeInfo.hasChannelNdx(0) ? getChannelAccess(ycbcrSrc, planeInfo, size, 0) : nullAccess);
1020 	ycbcr::ChannelAccess				gChannelAccess			(planeInfo.hasChannelNdx(1) ? getChannelAccess(ycbcrSrc, planeInfo, size, 1) : nullAccess);
1021 	ycbcr::ChannelAccess				bChannelAccess			(planeInfo.hasChannelNdx(2) ? getChannelAccess(ycbcrSrc, planeInfo, size, 2) : nullAccess);
1022 	ycbcr::ChannelAccess				aChannelAccess			(planeInfo.hasChannelNdx(3) ? getChannelAccess(ycbcrSrc, planeInfo, size, 3) : nullAccessAlpha);
1023 	const bool							implicitNearestCosited	((config.chromaFilter == vk::VK_FILTER_NEAREST && !explicitReconstruction) &&
1024 																 (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN || config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN));
1025 
1026 	for (deUint32 planeNdx = 0; planeNdx < planeInfo.numPlanes; planeNdx++)
1027 		deMemset(ycbcrSrc.getPlanePtr(planeNdx), 0u, ycbcrSrc.getPlaneSize(planeNdx));
1028 
1029 	// \todo Limit values to only values that produce defined values using selected colorRange and colorModel? The verification code handles those cases already correctly.
1030 	if (planeInfo.hasChannelNdx(0))
1031 	{
1032 		for (int y = 0; y < rChannelAccess.getSize().y(); y++)
1033 		for (int x = 0; x < rChannelAccess.getSize().x(); x++)
1034 			rChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)x / (float)rChannelAccess.getSize().x());
1035 	}
1036 
1037 	if (planeInfo.hasChannelNdx(1))
1038 	{
1039 		for (int y = 0; y < gChannelAccess.getSize().y(); y++)
1040 		for (int x = 0; x < gChannelAccess.getSize().x(); x++)
1041 			gChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)y / (float)gChannelAccess.getSize().y());
1042 	}
1043 
1044 	if (planeInfo.hasChannelNdx(2))
1045 	{
1046 		for (int y = 0; y < bChannelAccess.getSize().y(); y++)
1047 		for (int x = 0; x < bChannelAccess.getSize().x(); x++)
1048 			bChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)(x + y) / (float)(bChannelAccess.getSize().x() + bChannelAccess.getSize().y()));
1049 	}
1050 
1051 	if (planeInfo.hasChannelNdx(3))
1052 	{
1053 		for (int y = 0; y < aChannelAccess.getSize().y(); y++)
1054 		for (int x = 0; x < aChannelAccess.getSize().x(); x++)
1055 			aChannelAccess.setChannel(tcu::IVec3(x, y, 0), (float)(x * y) / (float)(aChannelAccess.getSize().x() * aChannelAccess.getSize().y()));
1056 	}
1057 
1058 	std::vector<tcu::Vec4>				uvBounds;
1059 	std::vector<tcu::IVec4>				ijBounds;
1060 	ycbcr::calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, texCoords, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, config.xChromaOffset, config.yChromaOffset, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, ycbcrMinBounds, ycbcrMaxBounds, uvBounds, ijBounds);
1061 
1062 	// Handle case: If implicit reconstruction and chromaFilter == NEAREST, an implementation may behave as if both chroma offsets are MIDPOINT.
1063 	if (implicitNearestCosited)
1064 	{
1065 		std::vector<tcu::Vec4>			relaxedYcbcrMinBounds;
1066 		std::vector<tcu::Vec4>			relaxedYcbcrMaxBounds;
1067 
1068 		ycbcr::calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, texCoords, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, vk::VK_CHROMA_LOCATION_MIDPOINT, vk::VK_CHROMA_LOCATION_MIDPOINT, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, relaxedYcbcrMinBounds, relaxedYcbcrMaxBounds, uvBounds, ijBounds);
1069 
1070 		DE_ASSERT(relaxedYcbcrMinBounds.size() == ycbcrMinBounds.size());
1071 		DE_ASSERT(relaxedYcbcrMaxBounds.size() == ycbcrMaxBounds.size());
1072 
1073 		for (size_t i = 0; i < ycbcrMinBounds.size(); i++)
1074 		{
1075 			ycbcrMinBounds[i] = tcu::Vec4(de::min<float>(ycbcrMinBounds[i].x(), relaxedYcbcrMinBounds[i].x()),
1076 										  de::min<float>(ycbcrMinBounds[i].y(), relaxedYcbcrMinBounds[i].y()),
1077 										  de::min<float>(ycbcrMinBounds[i].z(), relaxedYcbcrMinBounds[i].z()),
1078 										  de::min<float>(ycbcrMinBounds[i].w(), relaxedYcbcrMinBounds[i].w()));
1079 
1080 			ycbcrMaxBounds[i] = tcu::Vec4(de::max<float>(ycbcrMaxBounds[i].x(), relaxedYcbcrMaxBounds[i].x()),
1081 										  de::max<float>(ycbcrMaxBounds[i].y(), relaxedYcbcrMaxBounds[i].y()),
1082 										  de::max<float>(ycbcrMaxBounds[i].z(), relaxedYcbcrMaxBounds[i].z()),
1083 										  de::max<float>(ycbcrMaxBounds[i].w(), relaxedYcbcrMaxBounds[i].w()));
1084 		}
1085 	}
1086 
1087 	if (vk::isYCbCrFormat(config.format))
1088 	{
1089 		tcu::TextureLevel	rImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), rChannelAccess.getSize().x(), rChannelAccess.getSize().y());
1090 		tcu::TextureLevel	gImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), gChannelAccess.getSize().x(), gChannelAccess.getSize().y());
1091 		tcu::TextureLevel	bImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), bChannelAccess.getSize().x(), bChannelAccess.getSize().y());
1092 		tcu::TextureLevel	aImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), aChannelAccess.getSize().x(), aChannelAccess.getSize().y());
1093 
1094 		for (int y = 0; y < (int)rChannelAccess.getSize().y(); y++)
1095 		for (int x = 0; x < (int)rChannelAccess.getSize().x(); x++)
1096 			rImage.getAccess().setPixel(tcu::Vec4(rChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1097 
1098 		for (int y = 0; y < (int)gChannelAccess.getSize().y(); y++)
1099 		for (int x = 0; x < (int)gChannelAccess.getSize().x(); x++)
1100 			gImage.getAccess().setPixel(tcu::Vec4(gChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1101 
1102 		for (int y = 0; y < (int)bChannelAccess.getSize().y(); y++)
1103 		for (int x = 0; x < (int)bChannelAccess.getSize().x(); x++)
1104 			bImage.getAccess().setPixel(tcu::Vec4(bChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1105 
1106 		for (int y = 0; y < (int)aChannelAccess.getSize().y(); y++)
1107 		for (int x = 0; x < (int)aChannelAccess.getSize().x(); x++)
1108 			aImage.getAccess().setPixel(tcu::Vec4(aChannelAccess.getChannel(tcu::IVec3(x, y, 0))), x, y);
1109 
1110 		{
1111 			const tcu::Vec4	scale	(1.0f);
1112 			const tcu::Vec4	bias	(0.0f);
1113 
1114 			log << tcu::TestLog::Image("SourceImageR", "SourceImageR", rImage.getAccess(), scale, bias);
1115 			log << tcu::TestLog::Image("SourceImageG", "SourceImageG", gImage.getAccess(), scale, bias);
1116 			log << tcu::TestLog::Image("SourceImageB", "SourceImageB", bImage.getAccess(), scale, bias);
1117 			log << tcu::TestLog::Image("SourceImageA", "SourceImageA", aImage.getAccess(), scale, bias);
1118 		}
1119 	}
1120 	else
1121 	{
1122 		tcu::TextureLevel	ycbcrSrcImage	(vk::mapVkFormat(config.format), size.x(), size.y());
1123 
1124 		for (int y = 0; y < (int)size.y(); y++)
1125 		for (int x = 0; x < (int)size.x(); x++)
1126 		{
1127 			const tcu::IVec3 pos (x, y, 0);
1128 			ycbcrSrcImage.getAccess().setPixel(tcu::Vec4(rChannelAccess.getChannel(pos),
1129 														 gChannelAccess.getChannel(pos),
1130 														 bChannelAccess.getChannel(pos),
1131 														 aChannelAccess.getChannel(pos)),
1132 											   x, y);
1133 		}
1134 
1135 		log << tcu::TestLog::Image("SourceImage", "SourceImage", ycbcrSrcImage.getAccess());
1136 	}
1137 }
1138 
conversionTest(Context & context,TestConfig config)1139 tcu::TestStatus conversionTest (Context& context, TestConfig config)
1140 {
1141 	std::vector<std::string>							requiredDevExt;
1142 	requiredDevExt.push_back("VK_KHR_sampler_ycbcr_conversion");
1143 	requiredDevExt.push_back("VK_KHR_get_memory_requirements2");
1144 	requiredDevExt.push_back("VK_KHR_bind_memory2");
1145 	requiredDevExt.push_back("VK_KHR_maintenance1");
1146 
1147 	const tcu::UVec2									size					(ycbcr::isXChromaSubsampled(config.format) ? 12 : 7,
1148 																				 ycbcr::isYChromaSubsampled(config.format) ?  8 : 13);
1149 
1150 	ProtectedContext									ctx						(context, std::vector<std::string>(), requiredDevExt);
1151 	const vk::DeviceInterface&							vk						= ctx.getDeviceInterface();
1152 	const vk::VkDevice									device					= ctx.getDevice();
1153 	const deUint32										queueFamilyIndex		= ctx.getQueueFamilyIndex();
1154 
1155 	tcu::TestLog&										log						(context.getTestContext().getLog());
1156 
1157 	validateFormatSupport(ctx, config);
1158 	logTestCaseInfo(log, config);
1159 
1160 	const vk::VkImageCreateFlagBits						ycbcrImageFlags			 = config.disjoint
1161 																					? vk::VK_IMAGE_CREATE_DISJOINT_BIT
1162 																					: (vk::VkImageCreateFlagBits)0u;
1163 	const de::MovePtr<vk::YCbCrImageWithMemory>			ycbcrImage				(createYcbcrImage2D(ctx, PROTECTION_ENABLED,
1164 																									size.x(), size.y(),
1165 																									config.format,
1166 																									ycbcrImageFlags,
1167 																									vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT
1168 																									 | vk::VK_IMAGE_USAGE_SAMPLED_BIT));
1169 	const vk::Unique<vk::VkSamplerYcbcrConversion>		conversion				(createConversion(vk,
1170 																								  device,
1171 																								  config.format,
1172 																								  config.colorModel,
1173 																								  config.colorRange,
1174 																								  config.xChromaOffset,
1175 																								  config.yChromaOffset,
1176 																								  config.chromaFilter,
1177 																								  config.componentMapping,
1178 																								  config.explicitReconstruction));
1179 	const vk::Unique<vk::VkSampler>						ycbcrSampler			(createSampler(vk,
1180 																							   device,
1181 																							   config.textureFilter,
1182 																							   config.addressModeU,
1183 																							   config.addressModeV,
1184 																							   *conversion));
1185 	const vk::Unique<vk::VkImageView>					ycbcrImageView			(createImageView(vk, device, **ycbcrImage, config.format, *conversion));
1186 
1187 	deUint32											combinedSamplerDescriptorCount = 1;
1188 	{
1189 		const vk::VkPhysicalDeviceImageFormatInfo2			imageFormatInfo				=
1190 		{
1191 			vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,	// sType
1192 			DE_NULL,													// pNext
1193 			config.format,												// format
1194 			vk::VK_IMAGE_TYPE_2D,										// type
1195 			vk::VK_IMAGE_TILING_OPTIMAL,								// tiling
1196 			vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1197 			vk::VK_IMAGE_USAGE_SAMPLED_BIT,								// usage
1198 			ycbcrImageFlags												// flags
1199 		};
1200 
1201 		vk::VkSamplerYcbcrConversionImageFormatProperties	samplerYcbcrConversionImage = {};
1202 		samplerYcbcrConversionImage.sType = vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
1203 		samplerYcbcrConversionImage.pNext = DE_NULL;
1204 
1205 		vk::VkImageFormatProperties2						imageFormatProperties		= {};
1206 		imageFormatProperties.sType = vk::VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
1207 		imageFormatProperties.pNext = &samplerYcbcrConversionImage;
1208 
1209 		VK_CHECK(context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties));
1210 		combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
1211 	}
1212 
1213 	// Input attributes
1214 	std::vector<tcu::Vec2>								texCoords;
1215 	std::vector<tcu::Vec2>								posCoords;
1216 	genTexCoords(texCoords, size);
1217 	posCoords = computeVertexPositions((deUint32)texCoords.size(), size.cast<int>());
1218 
1219 	// Input validation data
1220 	std::vector<tcu::Vec4>								ycbcrMinBounds;
1221 	std::vector<tcu::Vec4>								ycbcrMaxBounds;
1222 
1223 	// Generate input ycbcr image and conversion reference
1224 	{
1225 		ycbcr::MultiPlaneImageData						ycbcrSrc				(config.format, size);
1226 
1227 		generateYCbCrImage(ctx, config, size, texCoords, ycbcrSrc, ycbcrMinBounds, ycbcrMaxBounds);
1228 		logBoundImages(log, size, ycbcrMinBounds, ycbcrMaxBounds);
1229 		uploadYCbCrImage(ctx,
1230 						 **ycbcrImage,
1231 						 ycbcrSrc,
1232 						 vk::VK_ACCESS_SHADER_READ_BIT,
1233 						 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1234 	}
1235 
1236 	// Build up the reference data structure
1237 	DE_ASSERT(posCoords.size() == ycbcrMinBounds.size());
1238 	DE_ASSERT(posCoords.size() == ycbcrMaxBounds.size());
1239 	DE_ASSERT(texCoords.size() >= CHECK_SIZE);
1240 	std::vector<YCbCrValidationData>	referenceData;
1241 	std::vector<YCbCrValidationData>	colorReferenceData;
1242 
1243 	for (deUint32 ndx = 0; ndx < texCoords.size(); ++ndx)
1244 	{
1245 		YCbCrValidationData	data;
1246 		data.coord		= texCoords[ndx].toWidth<4>();
1247 		data.minBound	= ycbcrMinBounds[ndx];
1248 		data.maxBound	= ycbcrMaxBounds[ndx];
1249 
1250 		referenceData.push_back(data);
1251 
1252 		YCbCrValidationData	colorData;
1253 		colorData.coord		= posCoords[ndx].toWidth<4>();
1254 		colorData.minBound	= tcu::Vec4(0.0f, 0.9f, 0.0f, 1.0f);
1255 		colorData.maxBound	= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1256 
1257 		colorReferenceData.push_back(colorData);
1258 	}
1259 
1260 	if (config.shaderType == glu::SHADERTYPE_VERTEX
1261 		|| config.shaderType == glu::SHADERTYPE_FRAGMENT)
1262 	{
1263 		const de::UniquePtr<vk::ImageWithMemory>	colorImage			(createImage2D(ctx,
1264 																				   PROTECTION_ENABLED,
1265 																				   queueFamilyIndex,
1266 																				   size.x(),
1267 																				   size.y(),
1268 																				   s_colorFormat,
1269 																				   vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
1270 																				    | vk::VK_IMAGE_USAGE_SAMPLED_BIT));
1271 		const vk::Unique<vk::VkImageView>			colorImageView		(createImageView(ctx, **colorImage, s_colorFormat));
1272 		const vk::Unique<vk::VkSampler>				colorSampler		(makeSampler(vk, device));
1273 
1274 		renderYCbCrToColor(ctx, size, *ycbcrSampler, *ycbcrImageView, **colorImage, *colorImageView, referenceData, posCoords, combinedSamplerDescriptorCount);
1275 
1276 		if (!validateImage(ctx, colorReferenceData, *colorSampler, *colorImageView, combinedSamplerDescriptorCount))
1277 			return tcu::TestStatus::fail("YCbCr image conversion via fragment shader failed");
1278 	}
1279 	else if (config.shaderType == glu::SHADERTYPE_COMPUTE)
1280 	{
1281 		if (!validateImage(ctx, referenceData, *ycbcrSampler, *ycbcrImageView, combinedSamplerDescriptorCount))
1282 			return tcu::TestStatus::fail("YCbCr image conversion via compute shader failed");
1283 	}
1284 	else
1285 	{
1286 		TCU_THROW(NotSupportedError, "Unsupported shader test type");
1287 	}
1288 
1289 	return tcu::TestStatus::pass("YCbCr image conversion was OK");
1290 }
1291 
1292 } // anonymous
1293 
1294 
createYCbCrConversionTests(tcu::TestContext & testCtx)1295 tcu::TestCaseGroup*	createYCbCrConversionTests (tcu::TestContext& testCtx)
1296 {
1297 	de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "ycbcr", "YCbCr conversion tests"));
1298 
1299 	struct {
1300 		const char *			name;
1301 		const glu::ShaderType	type;
1302 	} shaderTypes[]	=
1303 	{
1304 		{ "fragment",	glu::SHADERTYPE_FRAGMENT	},
1305 		{ "compute",	glu::SHADERTYPE_COMPUTE		}
1306 	};
1307 
1308 	struct RangeNamePair
1309 	{
1310 		const char*					name;
1311 		vk::VkSamplerYcbcrRange		value;
1312 	};
1313 	struct ChromaLocationNamePair
1314 	{
1315 		const char*				name;
1316 		vk::VkChromaLocation	value;
1317 	};
1318 
1319 	const vk::VkComponentMapping			identitySwizzle		=
1320 	{
1321 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1322 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1323 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1324 		vk::VK_COMPONENT_SWIZZLE_IDENTITY
1325 	};
1326 
1327 	const RangeNamePair						colorRanges[]		=
1328 	{
1329 		{ "itu_full",		vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL		},
1330 		{ "itu_narrow",		vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW	}
1331 	};
1332 
1333 	const ChromaLocationNamePair			chromaLocations[] =
1334 	{
1335 		{ "cosited",		vk::VK_CHROMA_LOCATION_COSITED_EVEN		},
1336 		{ "midpoint",		vk::VK_CHROMA_LOCATION_MIDPOINT			}
1337 	};
1338 
1339 	const struct
1340 	{
1341 		const char* const							name;
1342 		const vk::VkSamplerYcbcrModelConversion		value;
1343 	}										colorModels[] =
1344 	{
1345 		{ "rgb_identity",	vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY		},
1346 		{ "ycbcr_identity",	vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY	},
1347 		{ "ycbcr_709",		vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709			},
1348 		{ "ycbcr_601",		vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601			},
1349 		{ "ycbcr_2020",		vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020		}
1350 	};
1351 
1352 	const struct
1353 	{
1354 		const char*			name;
1355 		vk::VkImageTiling	value;
1356 	}										imageTilings[] =
1357 	{
1358 		{ "tiling_linear",	vk::VK_IMAGE_TILING_LINEAR },
1359 		{ "tiling_optimal",	vk::VK_IMAGE_TILING_OPTIMAL }
1360 	};
1361 
1362 	const deUint32					tilingNdx				= 1;
1363 	const vk::VkImageTiling			tiling					= imageTilings[tilingNdx].value;
1364 	const char*						tilingName				= imageTilings[tilingNdx].name;
1365 
1366 	const vk::VkFormat testFormats[] =
1367 	{
1368 		// noChromaSubsampledFormats
1369 		vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1370 		vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1371 		vk::VK_FORMAT_R5G6B5_UNORM_PACK16,
1372 		vk::VK_FORMAT_B5G6R5_UNORM_PACK16,
1373 		vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1374 		vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1375 		vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1376 		vk::VK_FORMAT_R8G8B8_UNORM,
1377 		vk::VK_FORMAT_B8G8R8_UNORM,
1378 		vk::VK_FORMAT_R8G8B8A8_UNORM,
1379 		vk::VK_FORMAT_B8G8R8A8_UNORM,
1380 		vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1381 		vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1382 		vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1383 		vk::VK_FORMAT_R16G16B16_UNORM,
1384 		vk::VK_FORMAT_R16G16B16A16_UNORM,
1385 		vk::VK_FORMAT_R10X6_UNORM_PACK16,
1386 		vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
1387 		vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
1388 		vk::VK_FORMAT_R12X4_UNORM_PACK16,
1389 		vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
1390 		vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
1391 		vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
1392 		vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
1393 		vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
1394 		vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
1395 
1396 		// xChromaSubsampledFormats
1397 		vk::VK_FORMAT_G8B8G8R8_422_UNORM,
1398 		vk::VK_FORMAT_B8G8R8G8_422_UNORM,
1399 		vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
1400 		vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
1401 
1402 		vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
1403 		vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
1404 		vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
1405 		vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
1406 		vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
1407 		vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
1408 		vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
1409 		vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
1410 		vk::VK_FORMAT_G16B16G16R16_422_UNORM,
1411 		vk::VK_FORMAT_B16G16R16G16_422_UNORM,
1412 		vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
1413 		vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
1414 
1415 		// xyChromaSubsampledFormats
1416 		vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
1417 		vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
1418 		vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
1419 		vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
1420 		vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
1421 		vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
1422 		vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
1423 		vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
1424 
1425 		// Extended YCbCr formats
1426 		vk::VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT,
1427 		vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT,
1428 		vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT,
1429 		vk::VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT,
1430 	};
1431 
1432 	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(testFormats); formatNdx++)
1433 	{
1434 		const vk::VkFormat				format		(testFormats[formatNdx]);
1435 		const std::string				formatName	(de::toLower(std::string(getFormatName(format)).substr(10)));
1436 		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
1437 
1438 		for (size_t shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderNdx++)
1439 		{
1440 			const char*						shaderTypeName	= shaderTypes[shaderNdx].name;
1441 			de::MovePtr<tcu::TestCaseGroup>	shaderGroup (new tcu::TestCaseGroup(testCtx, shaderTypeName, "YCbCr conversion tests"));
1442 
1443 			for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
1444 			{
1445 				const char* const							colorModelName	(colorModels[modelNdx].name);
1446 				const vk::VkSamplerYcbcrModelConversion		colorModel		(colorModels[modelNdx].value);
1447 
1448 				if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY && ycbcr::getYCbCrFormatChannelCount(format) < 3)
1449 					continue;
1450 
1451 				de::MovePtr<tcu::TestCaseGroup> colorModelGroup (new tcu::TestCaseGroup(testCtx, colorModelName, "YCbCr conversion tests"));
1452 
1453 				for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
1454 				{
1455 					const char* const					colorRangeName	(colorRanges[rangeNdx].name);
1456 					const vk::VkSamplerYcbcrRange		colorRange		(colorRanges[rangeNdx].value);
1457 
1458 					// Narrow range doesn't really work with formats that have less than 8 bits
1459 					if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW)
1460 					{
1461 						const tcu::UVec4 bitDepth	(ycbcr::getYCbCrBitDepth(format));
1462 						if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
1463 							continue;
1464 					}
1465 
1466 					de::MovePtr<tcu::TestCaseGroup>		colorRangeGroup	(new tcu::TestCaseGroup(testCtx, colorRangeName, ("Tests for color range " + std::string(colorRangeName)).c_str()));
1467 
1468 					for (size_t chromaOffsetNdx = 0; chromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); chromaOffsetNdx++)
1469 					{
1470 						const char* const				chromaOffsetName	(chromaLocations[chromaOffsetNdx].name);
1471 						const vk::VkChromaLocation		chromaOffset		(chromaLocations[chromaOffsetNdx].value);
1472 
1473 
1474 						for (deUint32 disjointNdx = 0; disjointNdx < 2; ++disjointNdx)
1475 						{
1476 							bool				disjoint	= (disjointNdx == 1);
1477 							const TestConfig	config	(shaderTypes[shaderNdx].type,
1478 														 format,
1479 														 tiling,
1480 														 vk::VK_FILTER_NEAREST,
1481 														 vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1482 														 vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1483 														 vk::VK_FILTER_NEAREST,
1484 														 chromaOffset,
1485 														 chromaOffset,
1486 														 false,
1487 														 disjoint,
1488 														 colorRange,
1489 														 colorModel,
1490 														 identitySwizzle);
1491 
1492 							addFunctionCaseWithPrograms(colorRangeGroup.get(),
1493 														std::string(tilingName) + "_" + chromaOffsetName + (disjoint ? "_disjoint" : ""),
1494 														"",
1495 														checkSupport,
1496 														testShaders,
1497 														conversionTest,
1498 														config);
1499 						}
1500 					}
1501 
1502 					colorModelGroup->addChild(colorRangeGroup.release());
1503 				}
1504 
1505 				shaderGroup->addChild(colorModelGroup.release());
1506 			}
1507 
1508 			formatGroup->addChild(shaderGroup.release());
1509 
1510 		}
1511 		testGroup->addChild(formatGroup.release());
1512 	}
1513 
1514 	return testGroup.release();
1515 }
1516 
1517 } // ProtectedMem
1518 } // vkt
1519