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