1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Texture color conversion tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktYCbCrConversionTests.hpp"
25 
26 #include "vktShaderExecutor.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktYCbCrUtil.hpp"
30 
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 
38 #include "tcuInterval.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuTexture.hpp"
41 #include "tcuTextureUtil.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuVectorUtil.hpp"
44 #include "tcuFloatFormat.hpp"
45 #include "tcuFloat.hpp"
46 
47 #include "deRandom.hpp"
48 #include "deSTLUtil.hpp"
49 #include "deSharedPtr.hpp"
50 
51 #include "deMath.h"
52 #include "deFloat16.h"
53 
54 #include <vector>
55 #include <iomanip>
56 
57 // \todo When defined color conversion extension is not used and conversion is performed in the shader
58 // #define FAKE_COLOR_CONVERSION
59 
60 using tcu::Vec2;
61 using tcu::Vec4;
62 
63 using tcu::UVec2;
64 using tcu::UVec4;
65 
66 using tcu::IVec2;
67 using tcu::IVec3;
68 using tcu::IVec4;
69 
70 using tcu::TestLog;
71 using tcu::FloatFormat;
72 
73 using std::vector;
74 using std::string;
75 
76 using namespace vkt::shaderexecutor;
77 
78 namespace vkt
79 {
80 namespace ycbcr
81 {
82 namespace
83 {
84 typedef de::SharedPtr<vk::Unique<vk::VkBuffer> > VkBufferSp;
85 typedef de::SharedPtr<vk::Allocation> AllocationSp;
86 
createShaderSpec(void)87 ShaderSpec createShaderSpec (void)
88 {
89 	ShaderSpec spec;
90 
91 	spec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp sampler2D u_sampler;";
92 
93 	spec.inputs.push_back(Symbol("uv", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
94 	spec.outputs.push_back(Symbol("o_color", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
95 
96 	spec.source = "o_color = texture(u_sampler, uv);\n";
97 
98 	return spec;
99 }
100 
genTexCoords(std::vector<Vec2> & coords,const UVec2 & srcSize,const UVec2 & dstSize)101 void genTexCoords (std::vector<Vec2>&	coords,
102 				   const UVec2&			srcSize,
103 				   const UVec2&			dstSize)
104 {
105 	for (deUint32 y = 0; y < dstSize.y(); y++)
106 	for (deUint32 x = 0; x < dstSize.x(); x++)
107 	{
108 		const float	fx	= (float)x;
109 		const float	fy	= (float)y;
110 
111 		const float	fw	= (float)srcSize.x();
112 		const float	fh	= (float)srcSize.y();
113 
114 		const float	s	= 1.5f * ((fx * 1.5f * fw + fx) / (1.5f * fw * 1.5f * fw)) - 0.25f;
115 		const float	t	= 1.5f * ((fy * 1.5f * fh + fy) / (1.5f * fh * 1.5f * fh)) - 0.25f;
116 
117 		coords.push_back(Vec2(s, t));
118 	}
119 }
120 
genOneToOneTexCoords(std::vector<Vec2> & coords,const UVec2 & size)121 void genOneToOneTexCoords (std::vector<Vec2>&	coords,
122 						   const UVec2&			size)
123 {
124 	for (deUint32 y = 0; y < size.y(); y++)
125 	for (deUint32 x = 0; x < size.x(); x++)
126 	{
127 		const float s = ((float)x + 0.5f) / (float)size.x();
128 		const float t = ((float)y + 0.5f) / (float)size.y();
129 
130 		coords.push_back(Vec2(s, t));
131 	}
132 }
133 
134 struct TestConfig
135 {
TestConfigvkt::ycbcr::__anone4164d620111::TestConfig136 	TestConfig	(glu::ShaderType						shaderType_,
137 				 vk::VkFormat							format_,
138 				 vk::VkImageTiling						imageTiling_,
139 				 vk::VkFilter							textureFilter_,
140 				 vk::VkSamplerAddressMode				addressModeU_,
141 				 vk::VkSamplerAddressMode				addressModeV_,
142 
143 				 vk::VkFilter							chromaFilter_,
144 				 vk::VkChromaLocation					xChromaOffset_,
145 				 vk::VkChromaLocation					yChromaOffset_,
146 				 bool									explicitReconstruction_,
147 				 bool									disjoint_,
148 
149 				 vk::VkSamplerYcbcrRange				colorRange_,
150 				 vk::VkSamplerYcbcrModelConversion		colorModel_,
151 				 vk::VkComponentMapping					componentMapping_,
152 				 const UVec2							srcSize_,
153 				 const UVec2							dstSize_)
154 		: shaderType				(shaderType_)
155 		, format					(format_)
156 		, imageTiling				(imageTiling_)
157 		, textureFilter				(textureFilter_)
158 		, addressModeU				(addressModeU_)
159 		, addressModeV				(addressModeV_)
160 
161 		, chromaFilter				(chromaFilter_)
162 		, xChromaOffset				(xChromaOffset_)
163 		, yChromaOffset				(yChromaOffset_)
164 		, explicitReconstruction	(explicitReconstruction_)
165 		, disjoint					(disjoint_)
166 
167 		, colorRange				(colorRange_)
168 		, colorModel				(colorModel_)
169 		, componentMapping			(componentMapping_)
170 		, srcSize					(srcSize_)
171 		, dstSize					(dstSize_)
172 	{
173 	}
174 
175 	glu::ShaderType							shaderType;
176 	vk::VkFormat							format;
177 	vk::VkImageTiling						imageTiling;
178 	vk::VkFilter							textureFilter;
179 	vk::VkSamplerAddressMode				addressModeU;
180 	vk::VkSamplerAddressMode				addressModeV;
181 
182 	vk::VkFilter							chromaFilter;
183 	vk::VkChromaLocation					xChromaOffset;
184 	vk::VkChromaLocation					yChromaOffset;
185 	bool									explicitReconstruction;
186 	bool									disjoint;
187 
188 	vk::VkSamplerYcbcrRange					colorRange;
189 	vk::VkSamplerYcbcrModelConversion		colorModel;
190 	vk::VkComponentMapping					componentMapping;
191 	const UVec2								srcSize;
192 	const UVec2								dstSize;
193 };
194 
createDescriptorSetLayout(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkSampler sampler)195 vk::Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (const vk::DeviceInterface&	vkd,
196 															   vk::VkDevice					device,
197 															   vk::VkSampler				sampler)
198 {
199 	const vk::VkDescriptorSetLayoutBinding		layoutBindings[]	=
200 	{
201 		{
202 			0u,
203 			vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
204 			1u,
205 			vk::VK_SHADER_STAGE_ALL,
206 			&sampler
207 		}
208 	};
209 	const vk::VkDescriptorSetLayoutCreateInfo	layoutCreateInfo	=
210 	{
211 		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
212 		DE_NULL,
213 
214 		0u,
215 		DE_LENGTH_OF_ARRAY(layoutBindings),
216 		layoutBindings
217 	};
218 
219 	return vk::createDescriptorSetLayout(vkd, device, &layoutCreateInfo);
220 }
221 
createDescriptorPool(const vk::DeviceInterface & vkd,vk::VkDevice device)222 vk::Move<vk::VkDescriptorPool> createDescriptorPool (const vk::DeviceInterface&	vkd,
223 													 vk::VkDevice				device)
224 {
225 	const vk::VkDescriptorPoolSize			poolSizes[]					=
226 	{
227 		{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u, }
228 	};
229 	const vk::VkDescriptorPoolCreateInfo	descriptorPoolCreateInfo	=
230 	{
231 		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
232 		DE_NULL,
233 		vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
234 
235 		1u,
236 		DE_LENGTH_OF_ARRAY(poolSizes),
237 		poolSizes
238 	};
239 
240 	return createDescriptorPool(vkd, device, &descriptorPoolCreateInfo);
241 }
242 
createDescriptorSet(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkDescriptorPool descriptorPool,vk::VkDescriptorSetLayout layout,vk::VkSampler sampler,vk::VkImageView imageView)243 vk::Move<vk::VkDescriptorSet> createDescriptorSet (const vk::DeviceInterface&	vkd,
244 												   vk::VkDevice					device,
245 												   vk::VkDescriptorPool			descriptorPool,
246 												   vk::VkDescriptorSetLayout	layout,
247 												   vk::VkSampler				sampler,
248 												   vk::VkImageView				imageView)
249 {
250 	const vk::VkDescriptorSetAllocateInfo		descriptorSetAllocateInfo	=
251 	{
252 		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
253 		DE_NULL,
254 
255 		descriptorPool,
256 		1u,
257 		&layout
258 	};
259 	vk::Move<vk::VkDescriptorSet>	descriptorSet	(vk::allocateDescriptorSet(vkd, device, &descriptorSetAllocateInfo));
260 	const vk::VkDescriptorImageInfo	imageInfo		=
261 	{
262 		sampler,
263 		imageView,
264 		vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
265 	};
266 
267 	{
268 		const vk::VkWriteDescriptorSet	writes[]	=
269 		{
270 			{
271 				vk::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
272 				DE_NULL,
273 
274 				*descriptorSet,
275 				0u,
276 				0u,
277 				1u,
278 				vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
279 				&imageInfo,
280 				DE_NULL,
281 				DE_NULL
282 			}
283 		};
284 
285 		vkd.updateDescriptorSets(device, DE_LENGTH_OF_ARRAY(writes), writes, 0u, DE_NULL);
286 	}
287 
288 	return descriptorSet;
289 }
290 
createSampler(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFilter textureFilter,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,vk::VkSamplerYcbcrConversion conversion)291 vk::Move<vk::VkSampler> createSampler (const vk::DeviceInterface&		vkd,
292 									   vk::VkDevice						device,
293 									   vk::VkFilter						textureFilter,
294 									   vk::VkSamplerAddressMode			addressModeU,
295 									   vk::VkSamplerAddressMode			addressModeV,
296 									   vk::VkSamplerYcbcrConversion		conversion)
297 {
298 #if !defined(FAKE_COLOR_CONVERSION)
299 	const vk::VkSamplerYcbcrConversionInfo	samplerConversionInfo	=
300 	{
301 		vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
302 		DE_NULL,
303 		conversion
304 	};
305 #else
306 	DE_UNREF(conversion);
307 #endif
308 	const vk::VkSamplerCreateInfo	createInfo	=
309 	{
310 		vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
311 #if !defined(FAKE_COLOR_CONVERSION)
312 		&samplerConversionInfo,
313 #else
314 		DE_NULL,
315 #endif
316 
317 		0u,
318 		textureFilter,
319 		textureFilter,
320 		vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,
321 		addressModeU,
322 		addressModeV,
323 		vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
324 		0.0f,
325 		VK_FALSE,
326 		1.0f,
327 		VK_FALSE,
328 		vk::VK_COMPARE_OP_ALWAYS,
329 		0.0f,
330 		0.0f,
331 		vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
332 		VK_FALSE,
333 	};
334 
335 	return createSampler(vkd, device, &createInfo);
336 }
337 
createImage(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFormat format,const UVec2 & size,bool disjoint,vk::VkImageTiling tiling)338 vk::Move<vk::VkImage> createImage (const vk::DeviceInterface&	vkd,
339 								   vk::VkDevice					device,
340 								   vk::VkFormat					format,
341 								   const UVec2&					size,
342 								   bool							disjoint,
343 								   vk::VkImageTiling			tiling)
344 {
345 	const vk::VkImageCreateInfo createInfo =
346 	{
347 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
348 		DE_NULL,
349 		disjoint ? (vk::VkImageCreateFlags)vk::VK_IMAGE_CREATE_DISJOINT_BIT : (vk::VkImageCreateFlags)0u,
350 
351 		vk::VK_IMAGE_TYPE_2D,
352 		format,
353 		vk::makeExtent3D(size.x(), size.y(), 1u),
354 		1u,
355 		1u,
356 		vk::VK_SAMPLE_COUNT_1_BIT,
357 		tiling,
358 		vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT | vk::VK_IMAGE_USAGE_SAMPLED_BIT,
359 		vk::VK_SHARING_MODE_EXCLUSIVE,
360 		0u,
361 		(const deUint32*)DE_NULL,
362 		vk::VK_IMAGE_LAYOUT_PREINITIALIZED,
363 	};
364 
365 	return vk::createImage(vkd, device, &createInfo);
366 }
367 
createImageView(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,vk::VkFormat format,vk::VkSamplerYcbcrConversion conversion)368 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface&		vkd,
369 										   vk::VkDevice						device,
370 										   vk::VkImage						image,
371 										   vk::VkFormat						format,
372 										   vk::VkSamplerYcbcrConversion		conversion)
373 {
374 #if !defined(FAKE_COLOR_CONVERSION)
375 	const vk::VkSamplerYcbcrConversionInfo	conversionInfo	=
376 	{
377 		vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
378 		DE_NULL,
379 		conversion
380 	};
381 #else
382 	DE_UNREF(conversion);
383 #endif
384 	const vk::VkImageViewCreateInfo				viewInfo		=
385 	{
386 		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
387 #if defined(FAKE_COLOR_CONVERSION)
388 		DE_NULL,
389 #else
390 		&conversionInfo,
391 #endif
392 		(vk::VkImageViewCreateFlags)0,
393 
394 		image,
395 		vk::VK_IMAGE_VIEW_TYPE_2D,
396 		format,
397 		{
398 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
399 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
400 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
401 			vk::VK_COMPONENT_SWIZZLE_IDENTITY,
402 		},
403 		{ vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
404 	};
405 
406 	return vk::createImageView(vkd, device, &viewInfo);
407 }
408 
createConversion(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFormat format,vk::VkSamplerYcbcrModelConversion colorModel,vk::VkSamplerYcbcrRange colorRange,vk::VkChromaLocation xChromaOffset,vk::VkChromaLocation yChromaOffset,vk::VkFilter chromaFilter,const vk::VkComponentMapping & componentMapping,bool explicitReconstruction)409 vk::Move<vk::VkSamplerYcbcrConversion> createConversion (const vk::DeviceInterface&				vkd,
410 														 vk::VkDevice							device,
411 														 vk::VkFormat							format,
412 														 vk::VkSamplerYcbcrModelConversion		colorModel,
413 														 vk::VkSamplerYcbcrRange				colorRange,
414 														 vk::VkChromaLocation					xChromaOffset,
415 														 vk::VkChromaLocation					yChromaOffset,
416 														 vk::VkFilter							chromaFilter,
417 														 const vk::VkComponentMapping&			componentMapping,
418 														 bool									explicitReconstruction)
419 {
420 	const vk::VkSamplerYcbcrConversionCreateInfo	conversionInfo	=
421 	{
422 		vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
423 		DE_NULL,
424 
425 		format,
426 		colorModel,
427 		colorRange,
428 		componentMapping,
429 		xChromaOffset,
430 		yChromaOffset,
431 		chromaFilter,
432 		explicitReconstruction ? VK_TRUE : VK_FALSE
433 	};
434 
435 	return vk::createSamplerYcbcrConversion(vkd, device, &conversionInfo);
436 }
437 
evalShader(Context & context,glu::ShaderType shaderType,const MultiPlaneImageData & imageData,const UVec2 & size,vk::VkFormat format,vk::VkImageTiling imageTiling,bool disjoint,vk::VkFilter textureFilter,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,vk::VkSamplerYcbcrModelConversion colorModel,vk::VkSamplerYcbcrRange colorRange,vk::VkChromaLocation xChromaOffset,vk::VkChromaLocation yChromaOffset,vk::VkFilter chromaFilter,const vk::VkComponentMapping & componentMapping,bool explicitReconstruction,const vector<Vec2> & sts,vector<Vec4> & results)438 void evalShader (Context&								context,
439 				 glu::ShaderType						shaderType,
440 				 const MultiPlaneImageData&				imageData,
441 				 const UVec2&							size,
442 				 vk::VkFormat							format,
443 				 vk::VkImageTiling						imageTiling,
444 				 bool									disjoint,
445 				 vk::VkFilter							textureFilter,
446 				 vk::VkSamplerAddressMode				addressModeU,
447 				 vk::VkSamplerAddressMode				addressModeV,
448 				 vk::VkSamplerYcbcrModelConversion		colorModel,
449 				 vk::VkSamplerYcbcrRange				colorRange,
450 				 vk::VkChromaLocation					xChromaOffset,
451 				 vk::VkChromaLocation					yChromaOffset,
452 				 vk::VkFilter							chromaFilter,
453 				 const vk::VkComponentMapping&			componentMapping,
454 				 bool									explicitReconstruction,
455 				 const vector<Vec2>&					sts,
456 				 vector<Vec4>&							results)
457 {
458 	const vk::DeviceInterface&							vkd					(context.getDeviceInterface());
459 	const vk::VkDevice									device				(context.getDevice());
460 #if !defined(FAKE_COLOR_CONVERSION)
461 	const vk::Unique<vk::VkSamplerYcbcrConversion>		conversion			(createConversion(vkd, device, format, colorModel, colorRange, xChromaOffset, yChromaOffset, chromaFilter, componentMapping, explicitReconstruction));
462 	const vk::Unique<vk::VkSampler>						sampler				(createSampler(vkd, device, textureFilter, addressModeU, addressModeV, *conversion));
463 #else
464 	DE_UNREF(colorModel);
465 	DE_UNREF(colorRange);
466 	DE_UNREF(xChromaOffset);
467 	DE_UNREF(yChromaOffset);
468 	DE_UNREF(chromaFilter);
469 	DE_UNREF(explicitReconstruction);
470 	DE_UNREF(componentMapping);
471 	DE_UNREF(createConversion);
472 	const vk::Unique<vk::VkSampler>						sampler				(createSampler(vkd, device, textureFilter, addressModeU, addressModeV, (vk::VkSamplerYcbcrConversion)0u));
473 #endif
474 	const vk::Unique<vk::VkImage>						image				(createImage(vkd, device, format, size, disjoint, imageTiling));
475 	const vk::MemoryRequirement							memoryRequirement	(imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
476 																			? vk::MemoryRequirement::Any
477 																			: vk::MemoryRequirement::HostVisible);
478 	const vk::VkImageCreateFlags						createFlags			(disjoint ? vk::VK_IMAGE_CREATE_DISJOINT_BIT : (vk::VkImageCreateFlagBits)0u);
479 	const vector<AllocationSp>							imageMemory			(allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags, memoryRequirement));
480 #if defined(FAKE_COLOR_CONVERSION)
481 	const vk::Unique<vk::VkImageView>					imageView			(createImageView(vkd, device, *image, format, (vk::VkSamplerYcbcrConversion)0));
482 #else
483 	const vk::Unique<vk::VkImageView>					imageView			(createImageView(vkd, device, *image, format, *conversion));
484 #endif
485 
486 	const vk::Unique<vk::VkDescriptorSetLayout>			layout				(createDescriptorSetLayout(vkd, device, *sampler));
487 	const vk::Unique<vk::VkDescriptorPool>				descriptorPool		(createDescriptorPool(vkd, device));
488 	const vk::Unique<vk::VkDescriptorSet>				descriptorSet		(createDescriptorSet(vkd, device, *descriptorPool, *layout, *sampler, *imageView));
489 
490 	const ShaderSpec									spec				(createShaderSpec());
491 	const de::UniquePtr<ShaderExecutor>					executor			(createExecutor(context, shaderType, spec, *layout));
492 
493 	if (imageTiling == vk::VK_IMAGE_TILING_OPTIMAL)
494 		uploadImage(vkd, device, context.getUniversalQueueFamilyIndex(), context.getDefaultAllocator(), *image, imageData, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
495 	else
496 		fillImageMemory(vkd, device, context.getUniversalQueueFamilyIndex(), *image, imageMemory, imageData, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
497 
498 	results.resize(sts.size());
499 
500 	{
501 		const void* const	inputs[]	=
502 		{
503 			&sts[0]
504 		};
505 		void* const			outputs[]	=
506 		{
507 			&results[0]
508 		};
509 
510 		executor->execute((int)sts.size(), inputs, outputs, *descriptorSet);
511 	}
512 }
513 
logTestCaseInfo(TestLog & log,const TestConfig & config)514 void logTestCaseInfo (TestLog& log, const TestConfig& config)
515 {
516 	log << TestLog::Message << "ShaderType: " << config.shaderType << TestLog::EndMessage;
517 	log << TestLog::Message << "Format: "  << config.format << TestLog::EndMessage;
518 	log << TestLog::Message << "ImageTiling: " << config.imageTiling << TestLog::EndMessage;
519 	log << TestLog::Message << "TextureFilter: " << config.textureFilter << TestLog::EndMessage;
520 	log << TestLog::Message << "AddressModeU: " << config.addressModeU << TestLog::EndMessage;
521 	log << TestLog::Message << "AddressModeV: " << config.addressModeV << TestLog::EndMessage;
522 	log << TestLog::Message << "ChromaFilter: " << config.chromaFilter << TestLog::EndMessage;
523 	log << TestLog::Message << "XChromaOffset: " << config.xChromaOffset << TestLog::EndMessage;
524 	log << TestLog::Message << "YChromaOffset: " << config.yChromaOffset << TestLog::EndMessage;
525 	log << TestLog::Message << "ExplicitReconstruction: " << (config.explicitReconstruction ? "true" : "false") << TestLog::EndMessage;
526 	log << TestLog::Message << "Disjoint: " << (config.disjoint ? "true" : "false") << TestLog::EndMessage;
527 	log << TestLog::Message << "ColorRange: " << config.colorRange << TestLog::EndMessage;
528 	log << TestLog::Message << "ColorModel: " << config.colorModel << TestLog::EndMessage;
529 	log << TestLog::Message << "ComponentMapping: " << config.componentMapping << TestLog::EndMessage;
530 }
531 
checkSupport(Context & context,const TestConfig config)532 void checkSupport (Context& context, const TestConfig config)
533 {
534 #if !defined(FAKE_COLOR_CONVERSION)
535 	if (!vk::isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), "VK_KHR_sampler_ycbcr_conversion"))
536 		TCU_THROW(NotSupportedError, "Extension VK_KHR_sampler_ycbcr_conversion not supported");
537 
538 	try
539 	{
540 		const vk::VkFormatProperties	properties	(vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), config.format));
541 		const vk::VkFormatFeatureFlags	features	(config.imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
542 			? properties.optimalTilingFeatures
543 			: properties.linearTilingFeatures);
544 
545 		if ((features & (vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0)
546 			TCU_THROW(NotSupportedError, "Format doesn't support YCbCr conversions");
547 
548 		if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0)
549 			TCU_THROW(NotSupportedError, "Format doesn't support sampling");
550 
551 		if (config.textureFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0))
552 			TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
553 
554 		if (config.chromaFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) == 0))
555 			TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
556 
557 		if (config.chromaFilter != config.textureFilter && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0))
558 			TCU_THROW(NotSupportedError, "Format doesn't support different chroma and texture filters");
559 
560 		if (config.explicitReconstruction && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT) == 0))
561 			TCU_THROW(NotSupportedError, "Format doesn't support explicit chroma reconstruction");
562 
563 		if (config.disjoint && ((features & vk::VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
564 			TCU_THROW(NotSupportedError, "Format doesn't disjoint planes");
565 
566 		if (isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0))
567 			TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
568 
569 		if (isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0))
570 			TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
571 
572 		if (isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) == 0))
573 			TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
574 
575 		if (isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0))
576 			TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
577 	}
578 	catch (const vk::Error& err)
579 	{
580 		if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
581 			TCU_THROW(NotSupportedError, "Format not supported");
582 
583 		throw;
584 	}
585 #endif
586 }
587 
textureConversionTest(Context & context,const TestConfig config)588 tcu::TestStatus textureConversionTest (Context& context, const TestConfig config)
589 {
590 	const FloatFormat	filteringPrecision		(getYCbCrFilteringPrecision(config.format));
591 	const FloatFormat	conversionPrecision		(getYCbCrConversionPrecision(config.format));
592 	const deUint32		subTexelPrecisionBits	(vk::getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits.subTexelPrecisionBits);
593 	const tcu::UVec4	bitDepth				(getYCbCrBitDepth(config.format));
594 	TestLog&			log						(context.getTestContext().getLog());
595 	bool				explicitReconstruction	= config.explicitReconstruction;
596 	const UVec2			srcSize					= config.srcSize;
597 	const UVec2			dstSize					= config.dstSize;
598 	bool				isOk					= true;
599 
600 	logTestCaseInfo(log, config);
601 
602 #if !defined(FAKE_COLOR_CONVERSION)
603 	try
604 	{
605 		const vk::VkFormatProperties	properties	(vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), config.format));
606 		const vk::VkFormatFeatureFlags	features	(config.imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
607 													? properties.optimalTilingFeatures
608 													: properties.linearTilingFeatures);
609 
610 		if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT) != 0)
611 			explicitReconstruction = true;
612 
613 		log << TestLog::Message << "FormatFeatures: " << vk::getFormatFeatureFlagsStr(features) << TestLog::EndMessage;
614 	}
615 	catch (const vk::Error& err)
616 	{
617 		if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
618 			TCU_THROW(NotSupportedError, "Format not supported");
619 
620 		throw;
621 	}
622 #endif
623 
624 	{
625 		const vk::PlanarFormatDescription	planeInfo				(vk::getPlanarFormatDescription(config.format));
626 		MultiPlaneImageData					src						(config.format, srcSize);
627 
628 		deUint32							nullAccessData			(0u);
629 		ChannelAccess						nullAccess				(tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, IVec3(srcSize.x(), srcSize.y(), 1), IVec3(0, 0, 0), &nullAccessData, 0u);
630 		deUint32							nullAccessAlphaData		(~0u);
631 		ChannelAccess						nullAccessAlpha			(tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, IVec3(srcSize.x(), srcSize.y(), 1), IVec3(0, 0, 0), &nullAccessAlphaData, 0u);
632 		ChannelAccess						rChannelAccess			(planeInfo.hasChannelNdx(0) ? getChannelAccess(src, planeInfo, srcSize, 0) : nullAccess);
633 		ChannelAccess						gChannelAccess			(planeInfo.hasChannelNdx(1) ? getChannelAccess(src, planeInfo, srcSize, 1) : nullAccess);
634 		ChannelAccess						bChannelAccess			(planeInfo.hasChannelNdx(2) ? getChannelAccess(src, planeInfo, srcSize, 2) : nullAccess);
635 		ChannelAccess						aChannelAccess			(planeInfo.hasChannelNdx(3) ? getChannelAccess(src, planeInfo, srcSize, 3) : nullAccessAlpha);
636 		const bool							implicitNearestCosited	((config.chromaFilter == vk::VK_FILTER_NEAREST && !config.explicitReconstruction) &&
637 																	 (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR || config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR));
638 
639 		vector<Vec2>						sts;
640 		vector<Vec4>						results;
641 		vector<Vec4>						minBounds;
642 		vector<Vec4>						minMidpointBounds;
643 		vector<Vec4>						maxBounds;
644 		vector<Vec4>						maxMidpointBounds;
645 		vector<Vec4>						uvBounds;
646 		vector<IVec4>						ijBounds;
647 
648 		for (deUint32 planeNdx = 0; planeNdx < planeInfo.numPlanes; planeNdx++)
649 			deMemset(src.getPlanePtr(planeNdx), 0u, src.getPlaneSize(planeNdx));
650 
651 		// \todo Limit values to only values that produce defined values using selected colorRange and colorModel? The verification code handles those cases already correctly.
652 		if (planeInfo.hasChannelNdx(0))
653 		{
654 			for (int y = 0; y < rChannelAccess.getSize().y(); y++)
655 			for (int x = 0; x < rChannelAccess.getSize().x(); x++)
656 				rChannelAccess.setChannel(IVec3(x, y, 0), (float)x / (float)rChannelAccess.getSize().x());
657 		}
658 
659 		if (planeInfo.hasChannelNdx(1))
660 		{
661 			for (int y = 0; y < gChannelAccess.getSize().y(); y++)
662 			for (int x = 0; x < gChannelAccess.getSize().x(); x++)
663 				gChannelAccess.setChannel(IVec3(x, y, 0), (float)y / (float)gChannelAccess.getSize().y());
664 		}
665 
666 		if (planeInfo.hasChannelNdx(2))
667 		{
668 			for (int y = 0; y < bChannelAccess.getSize().y(); y++)
669 			for (int x = 0; x < bChannelAccess.getSize().x(); x++)
670 				bChannelAccess.setChannel(IVec3(x, y, 0), (float)(x + y) / (float)(bChannelAccess.getSize().x() + bChannelAccess.getSize().y()));
671 		}
672 
673 		if (planeInfo.hasChannelNdx(3))
674 		{
675 			for (int y = 0; y < aChannelAccess.getSize().y(); y++)
676 			for (int x = 0; x < aChannelAccess.getSize().x(); x++)
677 				aChannelAccess.setChannel(IVec3(x, y, 0), (float)(x * y) / (float)(aChannelAccess.getSize().x() * aChannelAccess.getSize().y()));
678 		}
679 
680 		if (dstSize.x() > srcSize.x() && dstSize.y() > srcSize.y())
681 			genTexCoords(sts, srcSize, dstSize);
682 		else
683 			genOneToOneTexCoords(sts, dstSize);
684 
685 		calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, sts, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, config.xChromaOffset, config.yChromaOffset, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, minBounds, maxBounds, uvBounds, ijBounds);
686 
687 		// Handle case: If implicit reconstruction and chromaFilter == NEAREST, an implementation may behave as if both chroma offsets are MIDPOINT.
688 		if (implicitNearestCosited)
689 		{
690 			calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, sts, 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, minMidpointBounds, maxMidpointBounds, uvBounds, ijBounds);
691 		}
692 
693 		if (vk::isYCbCrFormat(config.format))
694 		{
695 			tcu::TextureLevel	rImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), rChannelAccess.getSize().x(), rChannelAccess.getSize().y());
696 			tcu::TextureLevel	gImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), gChannelAccess.getSize().x(), gChannelAccess.getSize().y());
697 			tcu::TextureLevel	bImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), bChannelAccess.getSize().x(), bChannelAccess.getSize().y());
698 			tcu::TextureLevel	aImage	(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), aChannelAccess.getSize().x(), aChannelAccess.getSize().y());
699 
700 			for (int y = 0; y < (int)rChannelAccess.getSize().y(); y++)
701 			for (int x = 0; x < (int)rChannelAccess.getSize().x(); x++)
702 				rImage.getAccess().setPixel(Vec4(rChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
703 
704 			for (int y = 0; y < (int)gChannelAccess.getSize().y(); y++)
705 			for (int x = 0; x < (int)gChannelAccess.getSize().x(); x++)
706 				gImage.getAccess().setPixel(Vec4(gChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
707 
708 			for (int y = 0; y < (int)bChannelAccess.getSize().y(); y++)
709 			for (int x = 0; x < (int)bChannelAccess.getSize().x(); x++)
710 				bImage.getAccess().setPixel(Vec4(bChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
711 
712 			for (int y = 0; y < (int)aChannelAccess.getSize().y(); y++)
713 			for (int x = 0; x < (int)aChannelAccess.getSize().x(); x++)
714 				aImage.getAccess().setPixel(Vec4(aChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
715 
716 			{
717 				const Vec4	scale	(1.0f);
718 				const Vec4	bias	(0.0f);
719 
720 				log << TestLog::Image("SourceImageR", "SourceImageR", rImage.getAccess(), scale, bias);
721 				log << TestLog::Image("SourceImageG", "SourceImageG", gImage.getAccess(), scale, bias);
722 				log << TestLog::Image("SourceImageB", "SourceImageB", bImage.getAccess(), scale, bias);
723 				log << TestLog::Image("SourceImageA", "SourceImageA", aImage.getAccess(), scale, bias);
724 			}
725 		}
726 		else
727 		{
728 			tcu::TextureLevel	srcImage	(vk::mapVkFormat(config.format), srcSize.x(), srcSize.y());
729 
730 			for (int y = 0; y < (int)srcSize.y(); y++)
731 			for (int x = 0; x < (int)srcSize.x(); x++)
732 			{
733 				const IVec3 pos (x, y, 0);
734 				srcImage.getAccess().setPixel(Vec4(rChannelAccess.getChannel(pos), gChannelAccess.getChannel(pos), bChannelAccess.getChannel(pos), aChannelAccess.getChannel(pos)), x, y);
735 			}
736 
737 			log << TestLog::Image("SourceImage", "SourceImage", srcImage.getAccess());
738 		}
739 
740 		evalShader(context, config.shaderType, src, srcSize, config.format, config.imageTiling, config.disjoint, config.textureFilter, config.addressModeU, config.addressModeV, config.colorModel, config.colorRange, config.xChromaOffset, config.yChromaOffset, config.chromaFilter, config.componentMapping, config.explicitReconstruction, sts, results);
741 
742 		{
743 			tcu::TextureLevel	minImage			(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), dstSize.x(), dstSize.y());
744 			tcu::TextureLevel	maxImage			(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), dstSize.x(), dstSize.y());
745 			tcu::TextureLevel	minMidpointImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), dstSize.x(), dstSize.y());
746 			tcu::TextureLevel	maxMidpointImage	(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), dstSize.x(), dstSize.y());
747 			tcu::TextureLevel	resImage			(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), dstSize.x(), dstSize.y());
748 
749 			for (int y = 0; y < (int)(dstSize.y()); y++)
750 			for (int x = 0; x < (int)(dstSize.x()); x++)
751 			{
752 				const int ndx = x + y * (int)(dstSize.x());
753 				minImage.getAccess().setPixel(minBounds[ndx], x, y);
754 				maxImage.getAccess().setPixel(maxBounds[ndx], x, y);
755 			}
756 
757 			for (int y = 0; y < (int)(dstSize.y()); y++)
758 			for (int x = 0; x < (int)(dstSize.x()); x++)
759 			{
760 				const int ndx = x + y * (int)(dstSize.x());
761 				resImage.getAccess().setPixel(results[ndx], x, y);
762 			}
763 
764 			if (implicitNearestCosited)
765 			{
766 				for (int y = 0; y < (int)(dstSize.y()); y++)
767 				for (int x = 0; x < (int)(dstSize.x()); x++)
768 				{
769 					const int ndx = x + y * (int)(dstSize.x());
770 					minMidpointImage.getAccess().setPixel(minMidpointBounds[ndx], x, y);
771 					maxMidpointImage.getAccess().setPixel(maxMidpointBounds[ndx], x, y);
772 				}
773 			}
774 
775 			{
776 				const Vec4	scale	(1.0f);
777 				const Vec4	bias	(0.0f);
778 
779 				log << TestLog::Image("MinBoundImage", "MinBoundImage", minImage.getAccess(), scale, bias);
780 				log << TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage.getAccess(), scale, bias);
781 
782 				if (implicitNearestCosited)
783 				{
784 					log << TestLog::Image("MinMidpointBoundImage", "MinMidpointBoundImage", minMidpointImage.getAccess(), scale, bias);
785 					log << TestLog::Image("MaxMidpointBoundImage", "MaxMidpointBoundImage", maxMidpointImage.getAccess(), scale, bias);
786 				}
787 
788 				log << TestLog::Image("ResultImage", "ResultImage", resImage.getAccess(), scale, bias);
789 			}
790 		}
791 
792 		size_t errorCount = 0;
793 
794 		for (size_t ndx = 0; ndx < sts.size(); ndx++)
795 		{
796 			bool fail;
797 			if (implicitNearestCosited)
798 			{
799 				fail = (tcu::boolAny(tcu::lessThan(results[ndx], minMidpointBounds[ndx])) || tcu::boolAny(tcu::greaterThan(results[ndx], maxMidpointBounds[ndx]))) &&
800 						(tcu::boolAny(tcu::lessThan(results[ndx], minBounds[ndx])) || tcu::boolAny(tcu::greaterThan(results[ndx], maxBounds[ndx])));
801 			}
802 			else
803 			{
804 				fail = tcu::boolAny(tcu::lessThan(results[ndx], minBounds[ndx])) || tcu::boolAny(tcu::greaterThan(results[ndx], maxBounds[ndx]));
805 			}
806 
807 			if (fail)
808 			{
809 				log << TestLog::Message << "Fail: " << sts[ndx] << " " << results[ndx] << TestLog::EndMessage;
810 				log << TestLog::Message << "  Min : " << minBounds[ndx] << TestLog::EndMessage;
811 				log << TestLog::Message << "  Max : " << maxBounds[ndx] << TestLog::EndMessage;
812 				log << TestLog::Message << "  Threshold: " << (maxBounds[ndx] - minBounds[ndx]) << TestLog::EndMessage;
813 				log << TestLog::Message << "  UMin : " << uvBounds[ndx][0] << TestLog::EndMessage;
814 				log << TestLog::Message << "  UMax : " << uvBounds[ndx][1] << TestLog::EndMessage;
815 				log << TestLog::Message << "  VMin : " << uvBounds[ndx][2] << TestLog::EndMessage;
816 				log << TestLog::Message << "  VMax : " << uvBounds[ndx][3] << TestLog::EndMessage;
817 				log << TestLog::Message << "  IMin : " << ijBounds[ndx][0] << TestLog::EndMessage;
818 				log << TestLog::Message << "  IMax : " << ijBounds[ndx][1] << TestLog::EndMessage;
819 				log << TestLog::Message << "  JMin : " << ijBounds[ndx][2] << TestLog::EndMessage;
820 				log << TestLog::Message << "  JMax : " << ijBounds[ndx][3] << TestLog::EndMessage;
821 
822 				if (isXChromaSubsampled(config.format))
823 				{
824 					log << TestLog::Message << "  LumaAlphaValues : " << TestLog::EndMessage;
825 					log << TestLog::Message << "    Offset : (" << ijBounds[ndx][0] << ", " << ijBounds[ndx][2] << ")" << TestLog::EndMessage;
826 
827 					for (deInt32 j = ijBounds[ndx][2]; j <= ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++)
828 					{
829 						const deInt32		wrappedJ	= wrap(config.addressModeV, j, gChannelAccess.getSize().y());
830 						bool				first		= true;
831 						std::ostringstream	line;
832 
833 						for (deInt32 i = ijBounds[ndx][0]; i <= ijBounds[ndx][1] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); i++)
834 						{
835 							const deInt32	wrappedI	= wrap(config.addressModeU, i, gChannelAccess.getSize().x());
836 
837 							if (!first)
838 							{
839 								line << ", ";
840 								first = false;
841 							}
842 
843 							line << "(" << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
844 								<< ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0)) << ")";
845 						}
846 						log << TestLog::Message << "    " << line.str() << TestLog::EndMessage;
847 					}
848 
849 					{
850 						const IVec2 chromaIRange	(divFloor(ijBounds[ndx][0], 2) - 1, divFloor(ijBounds[ndx][1] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1);
851 						const IVec2 chromaJRange	(isYChromaSubsampled(config.format)
852 													? IVec2(divFloor(ijBounds[ndx][2], 2) - 1, divFloor(ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1)
853 													: IVec2(ijBounds[ndx][2], ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0)));
854 
855 						log << TestLog::Message << "  ChromaValues : " << TestLog::EndMessage;
856 						log << TestLog::Message << "    Offset : (" << chromaIRange[0] << ", " << chromaJRange[0] << ")" << TestLog::EndMessage;
857 
858 						for (deInt32 j = chromaJRange[0]; j <= chromaJRange[1]; j++)
859 						{
860 							const deInt32		wrappedJ	= wrap(config.addressModeV, j, rChannelAccess.getSize().y());
861 							bool				first		= true;
862 							std::ostringstream	line;
863 
864 							for (deInt32 i = chromaIRange[0]; i <= chromaIRange[1]; i++)
865 							{
866 								const deInt32	wrappedI	= wrap(config.addressModeU, i, rChannelAccess.getSize().x());
867 
868 								if (!first)
869 								{
870 									line << ", ";
871 									first = false;
872 								}
873 
874 								line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
875 									<< ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0)) << ")";
876 							}
877 							log << TestLog::Message << "    " << line.str() << TestLog::EndMessage;
878 						}
879 					}
880 				}
881 				else
882 				{
883 					log << TestLog::Message << "  Values : " << TestLog::EndMessage;
884 					log << TestLog::Message << "    Offset : (" << ijBounds[ndx][0] << ", " << ijBounds[ndx][2] << ")" << TestLog::EndMessage;
885 
886 					for (deInt32 j = ijBounds[ndx][2]; j <= ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++)
887 					{
888 						const deInt32		wrappedJ	= wrap(config.addressModeV, j, rChannelAccess.getSize().y());
889 						bool				first		= true;
890 						std::ostringstream	line;
891 
892 						for (deInt32 i = ijBounds[ndx][0]; i <= ijBounds[ndx][1] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); i++)
893 						{
894 							const deInt32	wrappedI	= wrap(config.addressModeU, i, rChannelAccess.getSize().x());
895 
896 							if (!first)
897 							{
898 								line << ", ";
899 								first = false;
900 							}
901 
902 							line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
903 								<< ", " << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
904 								<< ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
905 								<< ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0)) << ")";
906 						}
907 						log << TestLog::Message << "    " << line.str() << TestLog::EndMessage;
908 					}
909 				}
910 
911 				errorCount++;
912 				isOk = false;
913 
914 				if (errorCount > 30)
915 				{
916 					log << TestLog::Message << "Encountered " << errorCount << " errors. Omitting rest of the per result logs." << TestLog::EndMessage;
917 					break;
918 				}
919 			}
920 		}
921 	}
922 
923 	if (isOk)
924 		return tcu::TestStatus::pass("Pass");
925 	else
926 		return tcu::TestStatus::fail("Result comparison failed");
927 }
928 
929 #if defined(FAKE_COLOR_CONVERSION)
swizzleToCompName(const char * identity,vk::VkComponentSwizzle swizzle)930 const char* swizzleToCompName (const char* identity, vk::VkComponentSwizzle swizzle)
931 {
932 	switch (swizzle)
933 	{
934 		case vk::VK_COMPONENT_SWIZZLE_IDENTITY:	return identity;
935 		case vk::VK_COMPONENT_SWIZZLE_R:		return "r";
936 		case vk::VK_COMPONENT_SWIZZLE_G:		return "g";
937 		case vk::VK_COMPONENT_SWIZZLE_B:		return "b";
938 		case vk::VK_COMPONENT_SWIZZLE_A:		return "a";
939 		default:
940 			DE_FATAL("Unsupported swizzle");
941 			return DE_NULL;
942 	}
943 }
944 #endif
945 
createTestShaders(vk::SourceCollections & dst,TestConfig config)946 void createTestShaders (vk::SourceCollections& dst, TestConfig config)
947 {
948 #if !defined(FAKE_COLOR_CONVERSION)
949 	const ShaderSpec spec (createShaderSpec());
950 
951 	generateSources(config.shaderType, spec, dst);
952 #else
953 	const UVec4	bits	(getBitDepth(config.format));
954 	ShaderSpec	spec;
955 
956 	spec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp sampler2D u_sampler;";
957 
958 	spec.inputs.push_back(Symbol("uv", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
959 	spec.outputs.push_back(Symbol("o_color", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
960 
961 	std::ostringstream	source;
962 
963 	source << "highp vec4 inputColor = texture(u_sampler, uv);\n";
964 
965 	source << "highp float r = inputColor." << swizzleToCompName("r", config.componentMapping.r) << ";\n";
966 	source << "highp float g = inputColor." << swizzleToCompName("g", config.componentMapping.g) << ";\n";
967 	source << "highp float b = inputColor." << swizzleToCompName("b", config.componentMapping.b) << ";\n";
968 	source << "highp float a = inputColor." << swizzleToCompName("a", config.componentMapping.a) << ";\n";
969 
970 	switch (config.colorRange)
971 	{
972 		case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
973 			source << "highp float cr = r - (float(" << (0x1u << (bits[0] - 0x1u)) << ") / float(" << ((0x1u << bits[0]) - 1u) << "));\n";
974 			source << "highp float y  = g;\n";
975 			source << "highp float cb = b - (float(" << (0x1u << (bits[2] - 0x1u)) << ") / float(" << ((0x1u << bits[2]) - 1u) << "));\n";
976 			break;
977 
978 		case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
979 			source << "highp float cr = (r * float(" << ((0x1u << bits[0]) - 1u) << ") - float(" << (128u * (0x1u << (bits[0] - 8))) << ")) / float(" << (224u * (0x1u << (bits[0] - 8))) << ");\n";
980 			source << "highp float y  = (g * float(" << ((0x1u << bits[1]) - 1u) << ") - float(" << (16u * (0x1u << (bits[1] - 8))) << ")) / float(" << (219u * (0x1u << (bits[1] - 8))) << ");\n";
981 			source << "highp float cb = (b * float(" << ((0x1u << bits[2]) - 1u) << ") - float(" << (128u * (0x1u << (bits[2] - 8))) << ")) / float(" << (224u * (0x1u << (bits[2] - 8))) << ");\n";
982 			break;
983 
984 		default:
985 			DE_FATAL("Unknown color range");
986 	}
987 
988 	source << "highp vec4 color;\n";
989 
990 	switch (config.colorModel)
991 	{
992 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
993 			source << "color = vec4(r, g, b, a);\n";
994 			break;
995 
996 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
997 			source << "color = vec4(cr, y, cb, a);\n";
998 			break;
999 
1000 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
1001 			source << "color = vec4(y + 1.402 * cr, y - float(" << (0.202008 / 0.587) << ") * cb - float(" << (0.419198 / 0.587) << ") * cr, y + 1.772 * cb, a);\n";
1002 			break;
1003 
1004 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
1005 			source << "color = vec4(y + 1.5748 * cr, y - float(" << (0.13397432 / 0.7152) << ") * cb - float(" << (0.33480248 / 0.7152) << ") * cr, y + 1.8556 * cb, a);\n";
1006 			break;
1007 
1008 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
1009 			source << "color = vec4(y + 1.4746 * cr, (y - float(" << (0.11156702 / 0.6780) << ") * cb) - float(" << (0.38737742 / 0.6780) << ") * cr, y + 1.8814 * cb, a);\n";
1010 			break;
1011 
1012 		default:
1013 			DE_FATAL("Unknown color model");
1014 	};
1015 
1016 	source << "o_color = color;\n";
1017 
1018 	spec.source = source.str();
1019 	generateSources(config.shaderType, spec, dst);
1020 #endif
1021 }
1022 
1023 struct RangeNamePair
1024 {
1025 	const char*					name;
1026 	vk::VkSamplerYcbcrRange		value;
1027 };
1028 
1029 
1030 struct ChromaLocationNamePair
1031 {
1032 	const char*					name;
1033 	vk::VkChromaLocation		value;
1034 };
1035 
initTests(tcu::TestCaseGroup * testGroup)1036 void initTests (tcu::TestCaseGroup* testGroup)
1037 {
1038 	const vk::VkFormat noChromaSubsampledFormats[] =
1039 	{
1040 		vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1041 		vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1042 		vk::VK_FORMAT_R5G6B5_UNORM_PACK16,
1043 		vk::VK_FORMAT_B5G6R5_UNORM_PACK16,
1044 		vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1045 		vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1046 		vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1047 		vk::VK_FORMAT_R8G8B8_UNORM,
1048 		vk::VK_FORMAT_B8G8R8_UNORM,
1049 		vk::VK_FORMAT_R8G8B8A8_UNORM,
1050 		vk::VK_FORMAT_B8G8R8A8_UNORM,
1051 		vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1052 		vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1053 		vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1054 		vk::VK_FORMAT_R16G16B16_UNORM,
1055 		vk::VK_FORMAT_R16G16B16A16_UNORM,
1056 		vk::VK_FORMAT_R10X6_UNORM_PACK16,
1057 		vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
1058 		vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
1059 		vk::VK_FORMAT_R12X4_UNORM_PACK16,
1060 		vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
1061 		vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16,
1062 		vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
1063 		vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
1064 		vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16,
1065 		vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM
1066 	};
1067 	const vk::VkFormat xChromaSubsampledFormats[] =
1068 	{
1069 		vk::VK_FORMAT_G8B8G8R8_422_UNORM,
1070 		vk::VK_FORMAT_B8G8R8G8_422_UNORM,
1071 		vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
1072 		vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
1073 
1074 		vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,
1075 		vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
1076 		vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16,
1077 		vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
1078 		vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,
1079 		vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
1080 		vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16,
1081 		vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
1082 		vk::VK_FORMAT_G16B16G16R16_422_UNORM,
1083 		vk::VK_FORMAT_B16G16R16G16_422_UNORM,
1084 		vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM,
1085 		vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
1086 	};
1087 	const vk::VkFormat xyChromaSubsampledFormats[] =
1088 	{
1089 		vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
1090 		vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
1091 		vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16,
1092 		vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
1093 		vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16,
1094 		vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
1095 		vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM,
1096 		vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
1097 	};
1098 	const struct
1099 	{
1100 		const char* const							name;
1101 		const vk::VkSamplerYcbcrModelConversion	value;
1102 	} colorModels[] =
1103 	{
1104 		{ "rgb_identity",	vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY		},
1105 		{ "ycbcr_identity",	vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY	},
1106 		{ "ycbcr_709",		vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709			},
1107 		{ "ycbcr_601",		vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601			},
1108 		{ "ycbcr_2020",		vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020		}
1109 	};
1110 	const RangeNamePair colorRanges[]	=
1111 	{
1112 		{ "itu_full",		vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL		},
1113 		{ "itu_narrow",		vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW	}
1114 	};
1115 	const ChromaLocationNamePair chromaLocations[] =
1116 	{
1117 		{ "cosited",		vk::VK_CHROMA_LOCATION_COSITED_EVEN	},
1118 		{ "midpoint",		vk::VK_CHROMA_LOCATION_MIDPOINT		}
1119 	};
1120 	const struct
1121 	{
1122 		const char* const	name;
1123 		vk::VkFilter		value;
1124 	} textureFilters[] =
1125 	{
1126 		{ "linear",			vk::VK_FILTER_LINEAR	},
1127 		{ "nearest",		vk::VK_FILTER_NEAREST	}
1128 	};
1129 	// Used by the chroma reconstruction tests
1130 	const vk::VkSamplerYcbcrModelConversion		defaultColorModel		(vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY);
1131 	const vk::VkSamplerYcbcrRange				defaultColorRange		(vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL);
1132 	const vk::VkComponentMapping				identitySwizzle			=
1133 	{
1134 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1135 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1136 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1137 		vk::VK_COMPONENT_SWIZZLE_IDENTITY
1138 	};
1139 	const vk::VkComponentMapping				swappedChromaSwizzle	=
1140 	{
1141 		vk::VK_COMPONENT_SWIZZLE_B,
1142 		vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1143 		vk::VK_COMPONENT_SWIZZLE_R,
1144 		vk::VK_COMPONENT_SWIZZLE_IDENTITY
1145 	};
1146 	const glu::ShaderType						shaderTypes[]			=
1147 	{
1148 		glu::SHADERTYPE_VERTEX,
1149 		glu::SHADERTYPE_FRAGMENT,
1150 		glu::SHADERTYPE_COMPUTE
1151 	};
1152 	const struct
1153 	{
1154 		const char*			name;
1155 		vk::VkImageTiling	value;
1156 	}											imageTilings[]			=
1157 	{
1158 		{ "tiling_linear",	vk::VK_IMAGE_TILING_LINEAR },
1159 		{ "tiling_optimal",	vk::VK_IMAGE_TILING_OPTIMAL }
1160 	};
1161 	tcu::TestContext&							testCtx					(testGroup->getTestContext());
1162 	de::Random									rng						(1978765638u);
1163 
1164 	// Test formats without chroma reconstruction
1165 	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(noChromaSubsampledFormats); formatNdx++)
1166 	{
1167 		const vk::VkFormat						format					(noChromaSubsampledFormats[formatNdx]);
1168 		const std::string						formatName				(de::toLower(std::string(getFormatName(format)).substr(10)));
1169 		de::MovePtr<tcu::TestCaseGroup>			formatGroup				(new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
1170 		const UVec2								srcSize					(isXChromaSubsampled(format) ? 12 : 7,
1171 																		 isYChromaSubsampled(format) ?  8 : 13);
1172 		const UVec2								dstSize					(srcSize.x() + srcSize.x() / 2,
1173 																		 srcSize.y() + srcSize.y() / 2);
1174 
1175 		for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
1176 		{
1177 			const char* const						colorModelName		(colorModels[modelNdx].name);
1178 			const vk::VkSamplerYcbcrModelConversion	colorModel			(colorModels[modelNdx].value);
1179 
1180 			if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY && getYCbCrFormatChannelCount(format) < 3)
1181 				continue;
1182 
1183 			de::MovePtr<tcu::TestCaseGroup>			colorModelGroup		(new tcu::TestCaseGroup(testCtx, colorModelName, ("Tests for color model " + string(colorModelName)).c_str()));
1184 
1185 			if (colorModel == vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
1186 			{
1187 				for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
1188 				{
1189 					const char* const					textureFilterName	(textureFilters[textureFilterNdx].name);
1190 					const vk::VkFilter					textureFilter		(textureFilters[textureFilterNdx].value);
1191 
1192 					for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1193 					{
1194 						const vk::VkImageTiling			tiling				(imageTilings[tilingNdx].value);
1195 						const char* const				tilingName			(imageTilings[tilingNdx].name);
1196 						const glu::ShaderType			shaderType			(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1197 						const vk::VkSamplerYcbcrRange	colorRange			(rng.choose<RangeNamePair, const RangeNamePair*>(DE_ARRAY_BEGIN(colorRanges), DE_ARRAY_END(colorRanges)).value);
1198 						const vk::VkChromaLocation		chromaLocation		(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1199 
1200 						const TestConfig				config				(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1201 																				textureFilter, chromaLocation, chromaLocation, false, false,
1202 																				colorRange, colorModel, identitySwizzle, srcSize, dstSize);
1203 
1204 						addFunctionCaseWithPrograms(colorModelGroup.get(), std::string(textureFilterName) + "_" + tilingName, "", checkSupport, createTestShaders, textureConversionTest, config);
1205 					}
1206 				}
1207 			}
1208 			else
1209 			{
1210 				for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
1211 				{
1212 					const char* const				colorRangeName	(colorRanges[rangeNdx].name);
1213 					const vk::VkSamplerYcbcrRange	colorRange		(colorRanges[rangeNdx].value);
1214 
1215 					// Narrow range doesn't really work with formats that have less than 8 bits
1216 					if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW)
1217 					{
1218 						const UVec4					bitDepth		(getYCbCrBitDepth(format));
1219 
1220 						if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
1221 							continue;
1222 					}
1223 
1224 					de::MovePtr<tcu::TestCaseGroup>		colorRangeGroup	(new tcu::TestCaseGroup(testCtx, colorRangeName, ("Tests for color range " + string(colorRangeName)).c_str()));
1225 
1226 					for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
1227 					{
1228 						const char* const				textureFilterName	(textureFilters[textureFilterNdx].name);
1229 						const vk::VkFilter				textureFilter		(textureFilters[textureFilterNdx].value);
1230 
1231 						for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1232 						{
1233 							const vk::VkImageTiling		tiling				(imageTilings[tilingNdx].value);
1234 							const char* const			tilingName			(imageTilings[tilingNdx].name);
1235 							const glu::ShaderType		shaderType			(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1236 							const vk::VkChromaLocation	chromaLocation		(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1237 							const TestConfig			config				(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1238 																				textureFilter, chromaLocation, chromaLocation, false, false,
1239 																				colorRange, colorModel, identitySwizzle, srcSize, dstSize);
1240 
1241 							addFunctionCaseWithPrograms(colorRangeGroup.get(), std::string(textureFilterName) + "_" + tilingName, "", checkSupport, createTestShaders, textureConversionTest, config);
1242 						}
1243 					}
1244 
1245 					colorModelGroup->addChild(colorRangeGroup.release());
1246 				}
1247 			}
1248 
1249 			formatGroup->addChild(colorModelGroup.release());
1250 		}
1251 
1252 		testGroup->addChild(formatGroup.release());
1253 	}
1254 
1255 	// Test formats with x chroma reconstruction
1256 	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(xChromaSubsampledFormats); formatNdx++)
1257 	{
1258 		const vk::VkFormat				format		(xChromaSubsampledFormats[formatNdx]);
1259 		const std::string				formatName	(de::toLower(std::string(getFormatName(format)).substr(10)));
1260 		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
1261 		const UVec2						srcSize		(isXChromaSubsampled(format) ? 12 : 7,
1262 													 isYChromaSubsampled(format) ?  8 : 13);
1263 		const UVec2						dstSize		(srcSize.x() + srcSize.x() / 2,
1264 													 srcSize.y() + srcSize.y() / 2);
1265 
1266 		// Color conversion tests
1267 		{
1268 			de::MovePtr<tcu::TestCaseGroup>	conversionGroup	(new tcu::TestCaseGroup(testCtx, "color_conversion", ""));
1269 
1270 			for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
1271 			{
1272 				const char* const			xChromaOffsetName	(chromaLocations[xChromaOffsetNdx].name);
1273 				const vk::VkChromaLocation	xChromaOffset		(chromaLocations[xChromaOffsetNdx].value);
1274 
1275 				for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
1276 				{
1277 					const char* const						colorModelName	(colorModels[modelNdx].name);
1278 					const vk::VkSamplerYcbcrModelConversion	colorModel		(colorModels[modelNdx].value);
1279 
1280 					if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY && getYCbCrFormatChannelCount(format) < 3)
1281 						continue;
1282 
1283 
1284 					if (colorModel == vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
1285 					{
1286 						for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1287 						{
1288 							const vk::VkImageTiling			tiling			(imageTilings[tilingNdx].value);
1289 							const char* const				tilingName		(imageTilings[tilingNdx].name);
1290 							const vk::VkSamplerYcbcrRange	colorRange		(rng.choose<RangeNamePair, const RangeNamePair*>(DE_ARRAY_BEGIN(colorRanges), DE_ARRAY_END(colorRanges)).value);
1291 							const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1292 							const vk::VkChromaLocation		yChromaOffset	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1293 							const TestConfig				config			(shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1294 																			 vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, false, false,
1295 																			 colorRange, colorModel, identitySwizzle, srcSize, dstSize);
1296 
1297 							addFunctionCaseWithPrograms(conversionGroup.get(), std::string(colorModelName) + "_" + tilingName + "_" + xChromaOffsetName, "", checkSupport, createTestShaders, textureConversionTest, config);
1298 						}
1299 					}
1300 					else
1301 					{
1302 						for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
1303 						{
1304 							const char* const				colorRangeName	(colorRanges[rangeNdx].name);
1305 							const vk::VkSamplerYcbcrRange	colorRange		(colorRanges[rangeNdx].value);
1306 
1307 							// Narrow range doesn't really work with formats that have less than 8 bits
1308 							if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW)
1309 							{
1310 								const UVec4					bitDepth		(getYCbCrBitDepth(format));
1311 
1312 								if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
1313 									continue;
1314 							}
1315 
1316 							for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1317 							{
1318 								const vk::VkImageTiling		tiling			(imageTilings[tilingNdx].value);
1319 								const char* const			tilingName		(imageTilings[tilingNdx].name);
1320 								const glu::ShaderType		shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1321 								const vk::VkChromaLocation	yChromaOffset	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1322 								const TestConfig			config			(shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1323 																			 vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, false, false,
1324 																			 colorRange, colorModel, identitySwizzle, srcSize, dstSize);
1325 
1326 								addFunctionCaseWithPrograms(conversionGroup.get(), (string(colorModelName) + "_" + colorRangeName + "_" + tilingName + "_" + xChromaOffsetName).c_str(), "", checkSupport, createTestShaders, textureConversionTest, config);
1327 							}
1328 						}
1329 					}
1330 				}
1331 			}
1332 
1333 			formatGroup->addChild(conversionGroup.release());
1334 		}
1335 
1336 		// Chroma reconstruction tests
1337 		{
1338 			de::MovePtr<tcu::TestCaseGroup>	reconstrucGroup	(new tcu::TestCaseGroup(testCtx, "chroma_reconstruction", ""));
1339 
1340 			for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
1341 			{
1342 				const char* const				textureFilterName	(textureFilters[textureFilterNdx].name);
1343 				const vk::VkFilter				textureFilter		(textureFilters[textureFilterNdx].value);
1344 				de::MovePtr<tcu::TestCaseGroup>	textureFilterGroup	(new tcu::TestCaseGroup(testCtx, textureFilterName, textureFilterName));
1345 
1346 				for (size_t explicitReconstructionNdx = 0; explicitReconstructionNdx < 2; explicitReconstructionNdx++)
1347 				{
1348 					const bool	explicitReconstruction	(explicitReconstructionNdx == 1);
1349 
1350 					for (size_t disjointNdx = 0; disjointNdx < 2; disjointNdx++)
1351 					{
1352 						const bool	disjoint	(disjointNdx == 1);
1353 
1354 						for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
1355 						{
1356 							const vk::VkChromaLocation		xChromaOffset		(chromaLocations[xChromaOffsetNdx].value);
1357 							const char* const				xChromaOffsetName	(chromaLocations[xChromaOffsetNdx].name);
1358 
1359 							for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1360 							{
1361 								const vk::VkImageTiling		tiling				(imageTilings[tilingNdx].value);
1362 								const char* const			tilingName			(imageTilings[tilingNdx].name);
1363 
1364 								{
1365 									const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1366 									const vk::VkChromaLocation		yChromaOffset	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1367 									const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1368 																						vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1369 																						defaultColorRange, defaultColorModel, identitySwizzle, srcSize, dstSize);
1370 
1371 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", checkSupport, createTestShaders, textureConversionTest, config);
1372 								}
1373 
1374 								{
1375 									const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1376 									const vk::VkChromaLocation		yChromaOffset	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1377 									const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1378 																						vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1379 																						defaultColorRange, defaultColorModel, swappedChromaSwizzle, srcSize, dstSize);
1380 
1381 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", checkSupport, createTestShaders, textureConversionTest, config);
1382 								}
1383 
1384 								if (!explicitReconstruction)
1385 								{
1386 									{
1387 										const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1388 										const vk::VkChromaLocation		yChromaOffset	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1389 										const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1390 																							vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1391 																							defaultColorRange, defaultColorModel, identitySwizzle, srcSize, dstSize);
1392 
1393 										addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", checkSupport, createTestShaders, textureConversionTest, config);
1394 									}
1395 
1396 									{
1397 										const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1398 										const vk::VkChromaLocation		yChromaOffset	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1399 										const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1400 																							vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1401 																							defaultColorRange, defaultColorModel, swappedChromaSwizzle, srcSize, dstSize);
1402 
1403 										addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", checkSupport, createTestShaders, textureConversionTest, config);
1404 									}
1405 								}
1406 							}
1407 						}
1408 
1409 						if (explicitReconstruction)
1410 						{
1411 							for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1412 							{
1413 								const vk::VkImageTiling	tiling		(imageTilings[tilingNdx].value);
1414 								const char* const		tilingName	(imageTilings[tilingNdx].name);
1415 								{
1416 									const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1417 									const vk::VkChromaLocation		chromaLocation	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1418 									const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1419 																						vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
1420 																						defaultColorRange, defaultColorModel, identitySwizzle, srcSize, dstSize);
1421 
1422 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", checkSupport, createTestShaders, textureConversionTest, config);
1423 								}
1424 
1425 								{
1426 									const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1427 									const vk::VkChromaLocation		chromaLocation	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1428 									const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1429 																						vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
1430 																						defaultColorRange, defaultColorModel, swappedChromaSwizzle, srcSize, dstSize);
1431 
1432 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", checkSupport, createTestShaders, textureConversionTest, config);
1433 								}
1434 							}
1435 						}
1436 					}
1437 				}
1438 
1439 				reconstrucGroup->addChild(textureFilterGroup.release());
1440 			}
1441 
1442 			formatGroup->addChild(reconstrucGroup.release());
1443 		}
1444 
1445 		testGroup->addChild(formatGroup.release());
1446 	}
1447 
1448 	// Test formats with xy chroma reconstruction
1449 	for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(xyChromaSubsampledFormats); formatNdx++)
1450 	{
1451 		const vk::VkFormat				format		(xyChromaSubsampledFormats[formatNdx]);
1452 		const std::string				formatName	(de::toLower(std::string(getFormatName(format)).substr(10)));
1453 		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
1454 		const UVec2						srcSize		(isXChromaSubsampled(format) ? 12 : 7,
1455 													 isYChromaSubsampled(format) ?  8 : 13);
1456 		const UVec2						dstSize		(srcSize.x() + srcSize.x() / 2,
1457 													 srcSize.y() + srcSize.y() / 2);
1458 
1459 		// Color conversion tests
1460 		{
1461 			de::MovePtr<tcu::TestCaseGroup>	conversionGroup	(new tcu::TestCaseGroup(testCtx, "color_conversion", ""));
1462 
1463 			for (size_t chromaOffsetNdx = 0; chromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); chromaOffsetNdx++)
1464 			{
1465 				const char* const			chromaOffsetName	(chromaLocations[chromaOffsetNdx].name);
1466 				const vk::VkChromaLocation	chromaOffset		(chromaLocations[chromaOffsetNdx].value);
1467 
1468 				for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
1469 				{
1470 					const char* const							colorModelName	(colorModels[modelNdx].name);
1471 					const vk::VkSamplerYcbcrModelConversion		colorModel		(colorModels[modelNdx].value);
1472 
1473 					if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY && getYCbCrFormatChannelCount(format) < 3)
1474 						continue;
1475 
1476 					if (colorModel == vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
1477 					{
1478 						for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1479 						{
1480 							const vk::VkImageTiling				tiling			(imageTilings[tilingNdx].value);
1481 							const char* const					tilingName		(imageTilings[tilingNdx].name);
1482 							const vk::VkSamplerYcbcrRange		colorRange		(rng.choose<RangeNamePair, const RangeNamePair*>(DE_ARRAY_BEGIN(colorRanges), DE_ARRAY_END(colorRanges)).value);
1483 							const glu::ShaderType				shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1484 							const TestConfig					config			(shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1485 																				 vk::VK_FILTER_NEAREST, chromaOffset, chromaOffset, false, false,
1486 																				 colorRange, colorModel, identitySwizzle, srcSize, dstSize);
1487 
1488 							addFunctionCaseWithPrograms(conversionGroup.get(), std::string(colorModelName) + "_" + tilingName + "_" + chromaOffsetName, "", checkSupport, createTestShaders, textureConversionTest, config);
1489 						}
1490 					}
1491 					else
1492 					{
1493 						for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
1494 						{
1495 							const char* const					colorRangeName	(colorRanges[rangeNdx].name);
1496 							const vk::VkSamplerYcbcrRange		colorRange		(colorRanges[rangeNdx].value);
1497 
1498 							// Narrow range doesn't really work with formats that have less than 8 bits
1499 							if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW)
1500 							{
1501 								const UVec4	bitDepth	(getYCbCrBitDepth(format));
1502 
1503 								if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
1504 									continue;
1505 							}
1506 
1507 							for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1508 							{
1509 								const vk::VkImageTiling			tiling			(imageTilings[tilingNdx].value);
1510 								const char* const				tilingName		(imageTilings[tilingNdx].name);
1511 								const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1512 								const TestConfig				config			(shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1513 																					vk::VK_FILTER_NEAREST, chromaOffset, chromaOffset, false, false,
1514 																					colorRange, colorModel, identitySwizzle, srcSize, dstSize);
1515 
1516 								addFunctionCaseWithPrograms(conversionGroup.get(), (string(colorModelName) + "_" + colorRangeName + "_" + tilingName + "_" + chromaOffsetName).c_str(), "", checkSupport, createTestShaders, textureConversionTest, config);
1517 							}
1518 						}
1519 					}
1520 				}
1521 			}
1522 
1523 			formatGroup->addChild(conversionGroup.release());
1524 		}
1525 
1526 		// Chroma reconstruction tests
1527 		{
1528 			de::MovePtr<tcu::TestCaseGroup>	reconstrucGroup	(new tcu::TestCaseGroup(testCtx, "chroma_reconstruction", ""));
1529 
1530 			for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
1531 			{
1532 				const char* const				textureFilterName	(textureFilters[textureFilterNdx].name);
1533 				const vk::VkFilter				textureFilter		(textureFilters[textureFilterNdx].value);
1534 				de::MovePtr<tcu::TestCaseGroup>	textureFilterGroup	(new tcu::TestCaseGroup(testCtx, textureFilterName, textureFilterName));
1535 
1536 				for (size_t explicitReconstructionNdx = 0; explicitReconstructionNdx < 2; explicitReconstructionNdx++)
1537 				{
1538 					const bool	explicitReconstruction	(explicitReconstructionNdx == 1);
1539 
1540 					for (size_t disjointNdx = 0; disjointNdx < 2; disjointNdx++)
1541 					{
1542 						const bool	disjoint	(disjointNdx == 1);
1543 
1544 						for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
1545 						for (size_t yChromaOffsetNdx = 0; yChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); yChromaOffsetNdx++)
1546 						{
1547 							const vk::VkChromaLocation		xChromaOffset		(chromaLocations[xChromaOffsetNdx].value);
1548 							const char* const				xChromaOffsetName	(chromaLocations[xChromaOffsetNdx].name);
1549 
1550 							const vk::VkChromaLocation		yChromaOffset		(chromaLocations[yChromaOffsetNdx].value);
1551 							const char* const				yChromaOffsetName	(chromaLocations[yChromaOffsetNdx].name);
1552 
1553 							for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1554 							{
1555 								const vk::VkImageTiling	tiling		(imageTilings[tilingNdx].value);
1556 								const char* const		tilingName	(imageTilings[tilingNdx].name);
1557 								{
1558 									const glu::ShaderType	shaderType	(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1559 									const TestConfig		config		(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1560 																			vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1561 																			defaultColorRange, defaultColorModel, identitySwizzle, srcSize, dstSize);
1562 
1563 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", checkSupport, createTestShaders, textureConversionTest, config);
1564 								}
1565 
1566 								{
1567 									const glu::ShaderType	shaderType	(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1568 									const TestConfig		config		(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1569 																			vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1570 																			defaultColorRange, defaultColorModel, swappedChromaSwizzle, srcSize, dstSize);
1571 
1572 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", checkSupport, createTestShaders, textureConversionTest, config);
1573 								}
1574 
1575 								if (!explicitReconstruction)
1576 								{
1577 									{
1578 										const glu::ShaderType	shaderType	(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1579 										const TestConfig		config		(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1580 																				vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1581 																				defaultColorRange, defaultColorModel, identitySwizzle, srcSize, dstSize);
1582 
1583 										addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", checkSupport, createTestShaders, textureConversionTest, config);
1584 									}
1585 
1586 									{
1587 										const glu::ShaderType	shaderType	(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1588 										const TestConfig		config		(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1589 																				vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
1590 																				defaultColorRange, defaultColorModel, swappedChromaSwizzle, srcSize, dstSize);
1591 
1592 										addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", checkSupport, createTestShaders, textureConversionTest, config);
1593 									}
1594 								}
1595 							}
1596 						}
1597 
1598 						if (explicitReconstruction)
1599 						{
1600 							for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1601 							{
1602 								const vk::VkImageTiling	tiling		(imageTilings[tilingNdx].value);
1603 								const char* const		tilingName	(imageTilings[tilingNdx].name);
1604 								{
1605 									const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1606 									const vk::VkChromaLocation		chromaLocation	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1607 									const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1608 																						vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
1609 																						defaultColorRange, defaultColorModel, identitySwizzle, srcSize, dstSize);
1610 
1611 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", checkSupport, createTestShaders, textureConversionTest, config);
1612 								}
1613 
1614 								{
1615 									const glu::ShaderType			shaderType		(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1616 									const vk::VkChromaLocation		chromaLocation	(rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
1617 									const TestConfig				config			(shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1618 																						vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
1619 																						defaultColorRange, defaultColorModel, swappedChromaSwizzle, srcSize, dstSize);
1620 
1621 									addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", checkSupport, createTestShaders, textureConversionTest, config);
1622 								}
1623 							}
1624 						}
1625 					}
1626 				}
1627 
1628 				reconstrucGroup->addChild(textureFilterGroup.release());
1629 			}
1630 
1631 			formatGroup->addChild(reconstrucGroup.release());
1632 		}
1633 
1634 		testGroup->addChild(formatGroup.release());
1635 	}
1636 
1637 	{
1638 		const UVec2 imageSizes[] =
1639 		{
1640 			UVec2(16, 16),
1641 			UVec2(20, 12)
1642 		};
1643 
1644 		de::MovePtr<tcu::TestCaseGroup>				oneToOneGroup		(new tcu::TestCaseGroup(testCtx, "one_to_one", "Ycbcr images sampled to a frame buffer of the same dimentions."));
1645 
1646 		const vk::VkFormat							format				(vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR);
1647 		const vk::VkFilter							filter				(vk::VK_FILTER_NEAREST);
1648 
1649 		for (size_t sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(imageSizes); sizeNdx++)
1650 		{
1651 			const UVec2								srcSize				(imageSizes[sizeNdx]);
1652 
1653 			for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
1654 			{
1655 				const vk::VkChromaLocation			xChromaOffset		(chromaLocations[xChromaOffsetNdx].value);
1656 				const char* const					xChromaOffsetName	(chromaLocations[xChromaOffsetNdx].name);
1657 
1658 				for (size_t yChromaOffsetNdx = 0; yChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); yChromaOffsetNdx++)
1659 				{
1660 					const vk::VkChromaLocation		yChromaOffset		(chromaLocations[yChromaOffsetNdx].value);
1661 					const char* const				yChromaOffsetName	(chromaLocations[yChromaOffsetNdx].name);
1662 
1663 					for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
1664 					{
1665 						const vk::VkImageTiling		tiling				(imageTilings[tilingNdx].value);
1666 						const char* const			tilingName			(imageTilings[tilingNdx].name);
1667 
1668 						const glu::ShaderType		shaderType			(rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
1669 
1670 						const TestConfig			config				(shaderType, format, tiling, filter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1671 																		filter, xChromaOffset, yChromaOffset, false, false,
1672 																		defaultColorRange, defaultColorModel, identitySwizzle, srcSize, srcSize);
1673 						std::ostringstream			testName;
1674 						testName << string("implicit_nearest_") << srcSize.x() << "x" << srcSize.y() << "_" << tilingName << "_" << xChromaOffsetName << "_" << yChromaOffsetName;
1675 
1676 						addFunctionCaseWithPrograms(oneToOneGroup.get(), testName.str(), "", checkSupport, createTestShaders, textureConversionTest, config);
1677 					}
1678 				}
1679 			}
1680 		}
1681 
1682 		testGroup->addChild(oneToOneGroup.release());
1683 	}
1684 }
1685 
1686 } // anonymous
1687 
createConversionTests(tcu::TestContext & testCtx)1688 tcu::TestCaseGroup* createConversionTests (tcu::TestContext& testCtx)
1689 {
1690 	return createTestGroup(testCtx, "conversion", "Sampler YCbCr Conversion Tests", initTests);
1691 }
1692 
1693 } // ycbcr
1694 } // vkt
1695