Home | History | Annotate | Download | only in ycbcr
      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 OpImageQuery & YCbCr Tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktYCbCrImageQueryTests.hpp"
     25 #include "vktTestCaseUtil.hpp"
     26 #include "vktTestGroupUtil.hpp"
     27 #include "vktShaderExecutor.hpp"
     28 #include "vktYCbCrUtil.hpp"
     29 #include "vktDrawUtil.hpp"
     30 
     31 #include "vkStrUtil.hpp"
     32 #include "vkRef.hpp"
     33 #include "vkRefUtil.hpp"
     34 #include "vkTypeUtil.hpp"
     35 #include "vkQueryUtil.hpp"
     36 #include "vkMemUtil.hpp"
     37 #include "vkImageUtil.hpp"
     38 
     39 #include "tcuTestLog.hpp"
     40 #include "tcuVectorUtil.hpp"
     41 #include "tcuTexLookupVerifier.hpp"
     42 
     43 #include "deStringUtil.hpp"
     44 #include "deSharedPtr.hpp"
     45 #include "deUniquePtr.hpp"
     46 #include "deRandom.hpp"
     47 #include "deSTLUtil.hpp"
     48 
     49 namespace vkt
     50 {
     51 namespace ycbcr
     52 {
     53 namespace
     54 {
     55 
     56 using namespace vk;
     57 using namespace shaderexecutor;
     58 
     59 using tcu::UVec2;
     60 using tcu::Vec2;
     61 using tcu::Vec4;
     62 using tcu::TestLog;
     63 using de::MovePtr;
     64 using de::UniquePtr;
     65 using std::vector;
     66 using std::string;
     67 
     68 typedef de::SharedPtr<Allocation>				AllocationSp;
     69 typedef de::SharedPtr<vk::Unique<VkBuffer> >	VkBufferSp;
     70 
     71 enum QueryType
     72 {
     73 	QUERY_TYPE_IMAGE_SIZE_LOD,			// OpImageQuerySizeLod
     74 	QUERY_TYPE_IMAGE_LOD,				// OpImageQueryLod
     75 	QUERY_TYPE_IMAGE_LEVELS,			// OpImageQueryLevels
     76 
     77 	QUERY_TYPE_LAST
     78 };
     79 
     80 struct TestParameters
     81 {
     82 	QueryType			query;
     83 	VkFormat			format;
     84 	VkImageCreateFlags	flags;
     85 	glu::ShaderType		shaderType;
     86 
     87 	TestParameters (QueryType query_, VkFormat format_, VkImageCreateFlags flags_, glu::ShaderType shaderType_)
     88 		: query		(query_)
     89 		, format	(format_)
     90 		, flags		(flags_)
     91 		, shaderType(shaderType_)
     92 	{
     93 	}
     94 
     95 	TestParameters (void)
     96 		: query		(QUERY_TYPE_LAST)
     97 		, format	(VK_FORMAT_UNDEFINED)
     98 		, flags		(0u)
     99 		, shaderType(glu::SHADERTYPE_LAST)
    100 	{
    101 	}
    102 };
    103 
    104 ShaderSpec getShaderSpec (const TestParameters& params)
    105 {
    106 	ShaderSpec		spec;
    107 	const char*		expr		= DE_NULL;
    108 	glu::DataType	resultType	= glu::TYPE_LAST;
    109 
    110 	switch (params.query)
    111 	{
    112 		case QUERY_TYPE_IMAGE_SIZE_LOD:
    113 			expr		= "textureSize(u_image, lod)";
    114 			resultType	= glu::TYPE_INT_VEC2;
    115 			break;
    116 
    117 		case QUERY_TYPE_IMAGE_LEVELS:
    118 			expr		= "textureQueryLevels(u_image)";
    119 			resultType	= glu::TYPE_INT;
    120 			break;
    121 
    122 		default:
    123 			DE_FATAL("Unknown query");
    124 	}
    125 
    126 	spec.glslVersion = glu::GLSL_VERSION_450;
    127 
    128 	spec.inputs.push_back(Symbol("lod", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
    129 	spec.outputs.push_back(Symbol("result", glu::VarType(resultType, glu::PRECISION_HIGHP)));
    130 
    131 	spec.globalDeclarations =
    132 		"layout(binding = 0, set = 1) uniform highp sampler2D u_image;\n";
    133 
    134 	spec.source =
    135 		string("result = ") + expr + ";\n";
    136 
    137 	return spec;
    138 }
    139 
    140 Move<VkImage> createTestImage (const DeviceInterface&	vkd,
    141 							   VkDevice					device,
    142 							   VkFormat					format,
    143 							   const UVec2&				size,
    144 							   VkImageCreateFlags		createFlags)
    145 {
    146 	const VkImageCreateInfo		createInfo	=
    147 	{
    148 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
    149 		DE_NULL,
    150 		createFlags,
    151 		VK_IMAGE_TYPE_2D,
    152 		format,
    153 		makeExtent3D(size.x(), size.y(), 1u),
    154 		1u,		// mipLevels
    155 		1u,		// arrayLayers
    156 		VK_SAMPLE_COUNT_1_BIT,
    157 		VK_IMAGE_TILING_OPTIMAL,
    158 		VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT,
    159 		VK_SHARING_MODE_EXCLUSIVE,
    160 		0u,
    161 		(const deUint32*)DE_NULL,
    162 		VK_IMAGE_LAYOUT_UNDEFINED,
    163 	};
    164 
    165 	return createImage(vkd, device, &createInfo);
    166 }
    167 
    168 Move<VkImageView> createImageView (const DeviceInterface&	vkd,
    169 								   VkDevice					device,
    170 								   VkImage					image,
    171 								   VkFormat					format)
    172 {
    173 	const VkImageViewCreateInfo	viewInfo	=
    174 	{
    175 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
    176 		DE_NULL,
    177 		(VkImageViewCreateFlags)0,
    178 		image,
    179 		VK_IMAGE_VIEW_TYPE_2D,
    180 		format,
    181 		{
    182 			VK_COMPONENT_SWIZZLE_IDENTITY,
    183 			VK_COMPONENT_SWIZZLE_IDENTITY,
    184 			VK_COMPONENT_SWIZZLE_IDENTITY,
    185 			VK_COMPONENT_SWIZZLE_IDENTITY,
    186 		},
    187 		{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
    188 	};
    189 
    190 	return createImageView(vkd, device, &viewInfo);
    191 }
    192 
    193 class TestImage
    194 {
    195 public:
    196 								TestImage		(const DeviceInterface&		vkd,
    197 												 VkDevice					device,
    198 												 Allocator&					allocator,
    199 												 VkFormat					format,
    200 												 const UVec2&				size,
    201 												 const VkImageCreateFlags	createFlags);
    202 
    203 	const UVec2&				getSize			(void) const { return m_size;		}
    204 	VkImageView					getImageView	(void) const { return *m_imageView; }
    205 
    206 private:
    207 	const UVec2					m_size;
    208 	const Unique<VkImage>		m_image;
    209 	const vector<AllocationSp>	m_allocations;
    210 	const Unique<VkImageView>	m_imageView;
    211 };
    212 
    213 TestImage::TestImage (const DeviceInterface&	vkd,
    214 					  VkDevice					device,
    215 					  Allocator&				allocator,
    216 					  VkFormat					format,
    217 					  const UVec2&				size,
    218 					  const VkImageCreateFlags	createFlags)
    219 	: m_size		(size)
    220 	, m_image		(createTestImage(vkd, device, format, size, createFlags))
    221 	, m_allocations	(allocateAndBindImageMemory(vkd, device, allocator, *m_image, format, createFlags))
    222 	, m_imageView	(createImageView(vkd, device, *m_image, format))
    223 {
    224 }
    225 
    226 typedef de::SharedPtr<TestImage> TestImageSp;
    227 
    228 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler sampler)
    229 {
    230 	const VkDescriptorSetLayoutBinding		binding		=
    231 	{
    232 		0u,												// binding
    233 		VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
    234 		1u,												// descriptorCount
    235 		VK_SHADER_STAGE_ALL,
    236 		&sampler
    237 	};
    238 	const VkDescriptorSetLayoutCreateInfo	layoutInfo	=
    239 	{
    240 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
    241 		DE_NULL,
    242 		(VkDescriptorSetLayoutCreateFlags)0u,
    243 		1u,
    244 		&binding,
    245 	};
    246 
    247 	return createDescriptorSetLayout(vkd, device, &layoutInfo);
    248 }
    249 
    250 Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device)
    251 {
    252 	const VkDescriptorPoolSize			poolSizes[]	=
    253 	{
    254 		{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u	},
    255 	};
    256 	const VkDescriptorPoolCreateInfo	poolInfo	=
    257 	{
    258 		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
    259 		DE_NULL,
    260 		(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
    261 		1u,		// maxSets
    262 		DE_LENGTH_OF_ARRAY(poolSizes),
    263 		poolSizes,
    264 	};
    265 
    266 	return createDescriptorPool(vkd, device, & poolInfo);
    267 }
    268 
    269 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface&	vkd,
    270 										   VkDevice					device,
    271 										   VkDescriptorPool			descPool,
    272 										   VkDescriptorSetLayout	descLayout)
    273 {
    274 	const VkDescriptorSetAllocateInfo	allocInfo	=
    275 	{
    276 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
    277 		DE_NULL,
    278 		descPool,
    279 		1u,
    280 		&descLayout,
    281 	};
    282 
    283 	return allocateDescriptorSet(vkd, device, &allocInfo);
    284 }
    285 
    286 void bindImage (const DeviceInterface& vkd,
    287 				VkDevice device,
    288 				VkDescriptorSet descriptorSet,
    289 				VkImageView imageView,
    290 				VkSampler sampler)
    291 {
    292 	const VkDescriptorImageInfo		imageInfo			=
    293 	{
    294 		sampler,
    295 		imageView,
    296 		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
    297 	};
    298 	const VkWriteDescriptorSet		descriptorWrite		=
    299 	{
    300 		VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
    301 		DE_NULL,
    302 		descriptorSet,
    303 		0u,		// dstBinding
    304 		0u,		// dstArrayElement
    305 		1u,		// descriptorCount
    306 		VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
    307 		&imageInfo,
    308 		(const VkDescriptorBufferInfo*)DE_NULL,
    309 		(const VkBufferView*)DE_NULL,
    310 	};
    311 
    312 	vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
    313 }
    314 
    315 UVec2 getMaxPlaneDivisor (const PlanarFormatDescription& formatDesc)
    316 {
    317 	UVec2	maxDivisor	(1u, 1u);
    318 
    319 	for (deUint32 ndx = 0; ndx < formatDesc.numPlanes; ++ndx)
    320 	{
    321 		maxDivisor.x() = de::max<deUint32>(maxDivisor.x(), formatDesc.planes[ndx].widthDivisor);
    322 		maxDivisor.y() = de::max<deUint32>(maxDivisor.y(), formatDesc.planes[ndx].heightDivisor);
    323 	}
    324 
    325 	return maxDivisor;
    326 }
    327 
    328 tcu::TestStatus testImageQuery (Context& context, TestParameters params)
    329 {
    330 	const bool							isYCbCrImage	= isYCbCrFormat(params.format);
    331 
    332 	if (isYCbCrImage)
    333 		checkImageSupport(context, params.format, params.flags);
    334 
    335 	const DeviceInterface&				vkd				= context.getDeviceInterface();
    336 	const VkDevice						device			= context.getDevice();
    337 
    338 	const VkSamplerYcbcrConversionCreateInfoKHR			conversionInfo			=
    339 	{
    340 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR,
    341 		DE_NULL,
    342 		params.format,
    343 		VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR,
    344 		VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR,
    345 		{
    346 			VK_COMPONENT_SWIZZLE_IDENTITY,
    347 			VK_COMPONENT_SWIZZLE_IDENTITY,
    348 			VK_COMPONENT_SWIZZLE_IDENTITY,
    349 			VK_COMPONENT_SWIZZLE_IDENTITY,
    350 		},
    351 		VK_CHROMA_LOCATION_MIDPOINT_KHR,
    352 		VK_CHROMA_LOCATION_MIDPOINT_KHR,
    353 		VK_FILTER_NEAREST,
    354 		VK_FALSE,									// forceExplicitReconstruction
    355 	};
    356 	const Unique<VkSamplerYcbcrConversionKHR>			conversion				(isYCbCrImage
    357 																				 ? createSamplerYcbcrConversionKHR(vkd, device, &conversionInfo)
    358 																				 : Move<VkSamplerYcbcrConversionKHR>());
    359 
    360 	const VkSamplerYcbcrConversionInfoKHR				samplerConversionInfo	=
    361 	{
    362 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR,
    363 		DE_NULL,
    364 		*conversion,
    365 	};
    366 
    367 	const VkSamplerCreateInfo							samplerInfo				=
    368 	{
    369 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
    370 		isYCbCrImage ? &samplerConversionInfo : DE_NULL,
    371 		0u,
    372 		VK_FILTER_NEAREST,							// magFilter
    373 		VK_FILTER_NEAREST,							// minFilter
    374 		VK_SAMPLER_MIPMAP_MODE_NEAREST,				// mipmapMode
    375 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeU
    376 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeV
    377 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeW
    378 		0.0f,										// mipLodBias
    379 		VK_FALSE,									// anisotropyEnable
    380 		1.0f,										// maxAnisotropy
    381 		VK_FALSE,									// compareEnable
    382 		VK_COMPARE_OP_ALWAYS,						// compareOp
    383 		0.0f,										// minLod
    384 		0.0f,										// maxLod
    385 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// borderColor
    386 		VK_FALSE,									// unnormalizedCoords
    387 	};
    388 
    389 	const Unique<VkSampler>				sampler		(createSampler(vkd, device, &samplerInfo));
    390 	const Unique<VkDescriptorSetLayout>	descLayout	(createDescriptorSetLayout(vkd, device, *sampler));
    391 	const Unique<VkDescriptorPool>		descPool	(createDescriptorPool(vkd, device));
    392 	const Unique<VkDescriptorSet>		descSet		(createDescriptorSet(vkd, device, *descPool, *descLayout));
    393 
    394 	vector<TestImageSp>					testImages;
    395 
    396 	if (params.query == QUERY_TYPE_IMAGE_SIZE_LOD)
    397 	{
    398 		const PlanarFormatDescription&		formatDesc	= getPlanarFormatDescription(params.format);
    399 		const UVec2							maxDivisor	= getMaxPlaneDivisor(formatDesc);
    400 		vector<UVec2>						testSizes;
    401 
    402 		testSizes.push_back(maxDivisor);
    403 		testSizes.push_back(maxDivisor * UVec2(2u, 1u));
    404 		testSizes.push_back(maxDivisor * UVec2(1u, 2u));
    405 		testSizes.push_back(maxDivisor * UVec2(63u, 79u));
    406 		testSizes.push_back(maxDivisor * UVec2(99u, 1u));
    407 		testSizes.push_back(maxDivisor * UVec2(421u, 1117u));
    408 
    409 		testImages.resize(testSizes.size());
    410 
    411 		for (size_t ndx = 0; ndx < testSizes.size(); ++ndx)
    412 			testImages[ndx] = TestImageSp(new TestImage(vkd, device, context.getDefaultAllocator(), params.format, testSizes[ndx], params.flags));
    413 	}
    414 	else
    415 		testImages.push_back(TestImageSp(new TestImage(vkd, device, context.getDefaultAllocator(), params.format, UVec2(16, 18), params.flags)));
    416 
    417 	{
    418 		UniquePtr<ShaderExecutor>	executor	(createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
    419 		bool						allOk		= true;
    420 
    421 		for (size_t imageNdx = 0; imageNdx < testImages.size(); ++imageNdx)
    422 		{
    423 			const deUint32	lod			= 0u;
    424 			UVec2			result		(~0u, ~0u);
    425 			const void*		inputs[]	= { &lod };
    426 			void*			outputs[]	= { result.getPtr() };
    427 
    428 			bindImage(vkd, device, *descSet, testImages[imageNdx]->getImageView(), *sampler);
    429 
    430 			executor->execute(1, inputs, outputs, *descSet);
    431 
    432 			switch (params.query)
    433 			{
    434 				case QUERY_TYPE_IMAGE_SIZE_LOD:
    435 				{
    436 					const UVec2	reference	= testImages[imageNdx]->getSize();
    437 
    438 					if (result != reference)
    439 					{
    440 						context.getTestContext().getLog()
    441 							<< TestLog::Message << "ERROR: Image " << imageNdx
    442 												<< ": got " << result
    443 												<< ", expected " << reference
    444 							<< TestLog::EndMessage;
    445 						allOk = false;
    446 					}
    447 					break;
    448 				}
    449 
    450 				case QUERY_TYPE_IMAGE_LEVELS:
    451 				{
    452 					if (result.x() != 1u)
    453 					{
    454 						context.getTestContext().getLog()
    455 							<< TestLog::Message << "ERROR: Image " << imageNdx
    456 												<< ": got " << result.x()
    457 												<< ", expected " << 1
    458 							<< TestLog::EndMessage;
    459 						allOk = false;
    460 					}
    461 					break;
    462 				}
    463 
    464 				default:
    465 					DE_FATAL("Invalid query type");
    466 			}
    467 		}
    468 
    469 		if (allOk)
    470 			return tcu::TestStatus::pass("Queries passed");
    471 		else
    472 			return tcu::TestStatus::fail("Got invalid results");
    473 	}
    474 }
    475 
    476 tcu::TestStatus testImageQueryLod (Context& context, TestParameters params)
    477 {
    478 	const bool							isYCbCrImage	= isYCbCrFormat(params.format);
    479 
    480 	if (isYCbCrImage)
    481 		checkImageSupport(context, params.format, params.flags);
    482 
    483 	const DeviceInterface&				vkd				= context.getDeviceInterface();
    484 	const VkDevice						device			= context.getDevice();
    485 
    486 	const VkSamplerYcbcrConversionCreateInfoKHR			conversionInfo			=
    487 	{
    488 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR,
    489 		DE_NULL,
    490 		params.format,
    491 		VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR,
    492 		VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR,
    493 		{
    494 			VK_COMPONENT_SWIZZLE_IDENTITY,
    495 			VK_COMPONENT_SWIZZLE_IDENTITY,
    496 			VK_COMPONENT_SWIZZLE_IDENTITY,
    497 			VK_COMPONENT_SWIZZLE_IDENTITY,
    498 		},
    499 		VK_CHROMA_LOCATION_MIDPOINT_KHR,
    500 		VK_CHROMA_LOCATION_MIDPOINT_KHR,
    501 		VK_FILTER_NEAREST,
    502 		VK_FALSE,									// forceExplicitReconstruction
    503 	};
    504 	const Unique<VkSamplerYcbcrConversionKHR>			conversion				(isYCbCrImage
    505 																				 ? createSamplerYcbcrConversionKHR(vkd, device, &conversionInfo)
    506 																				 : Move<VkSamplerYcbcrConversionKHR>());
    507 
    508 	const VkSamplerYcbcrConversionInfoKHR				samplerConversionInfo	=
    509 	{
    510 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR,
    511 		DE_NULL,
    512 		*conversion,
    513 	};
    514 
    515 	const VkSamplerCreateInfo							samplerInfo				=
    516 	{
    517 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
    518 		isYCbCrImage ? &samplerConversionInfo : DE_NULL,
    519 		0u,
    520 		VK_FILTER_NEAREST,							// magFilter
    521 		VK_FILTER_NEAREST,							// minFilter
    522 		VK_SAMPLER_MIPMAP_MODE_NEAREST,				// mipmapMode
    523 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeU
    524 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeV
    525 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeW
    526 		0.0f,										// mipLodBias
    527 		VK_FALSE,									// anisotropyEnable
    528 		1.0f,										// maxAnisotropy
    529 		VK_FALSE,									// compareEnable
    530 		VK_COMPARE_OP_ALWAYS,						// compareOp
    531 		0.0f,										// minLod
    532 		0.0f,										// maxLod
    533 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// borderColor
    534 		VK_FALSE,									// unnormalizedCoords
    535 	};
    536 
    537 	const Unique<VkSampler>				sampler		(createSampler(vkd, device, &samplerInfo));
    538 	const Unique<VkDescriptorSetLayout>	descLayout	(createDescriptorSetLayout(vkd, device, *sampler));
    539 	const Unique<VkDescriptorPool>		descPool	(createDescriptorPool(vkd, device));
    540 	const Unique<VkDescriptorSet>		descSet		(createDescriptorSet(vkd, device, *descPool, *descLayout));
    541 
    542 	vector<TestImageSp>					testImages;
    543 
    544 	DE_ASSERT(params.query == QUERY_TYPE_IMAGE_LOD);
    545 	DE_ASSERT(params.shaderType == glu::SHADERTYPE_FRAGMENT);
    546 
    547 	{
    548 		const PlanarFormatDescription&		formatDesc	= getPlanarFormatDescription(params.format);
    549 		const UVec2							maxDivisor	= getMaxPlaneDivisor(formatDesc);
    550 		vector<UVec2>						testSizes;
    551 
    552 		testSizes.push_back(maxDivisor);
    553 		testSizes.push_back(maxDivisor * UVec2(2u, 1u));
    554 		testSizes.push_back(maxDivisor * UVec2(1u, 2u));
    555 		testSizes.push_back(maxDivisor * UVec2(4u, 123u));
    556 		testSizes.push_back(maxDivisor * UVec2(312u, 13u));
    557 		testSizes.push_back(maxDivisor * UVec2(841u, 917u));
    558 
    559 		testImages.resize(testSizes.size());
    560 
    561 		for (size_t ndx = 0; ndx < testSizes.size(); ++ndx)
    562 			testImages[ndx] = TestImageSp(new TestImage(vkd, device, context.getDefaultAllocator(), params.format, testSizes[ndx], params.flags));
    563 	}
    564 
    565 	{
    566 		using namespace drawutil;
    567 
    568 		struct LocalUtil
    569 		{
    570 			static DrawState getDrawState (UVec2 renderSize)
    571 			{
    572 				DrawState state(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, renderSize.x(), renderSize.y());
    573 				state.colorFormat = VK_FORMAT_R32G32_SFLOAT;
    574 				return state;
    575 			}
    576 
    577 			static vector<Vec4> getVertices (void)
    578 			{
    579 				vector<Vec4> vertices;
    580 
    581 				vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
    582 				vertices.push_back(Vec4(+1.0f, -1.0f, 0.0f, 1.0f));
    583 				vertices.push_back(Vec4(-1.0f, +1.0f, 0.0f, 1.0f));
    584 
    585 				vertices.push_back(Vec4(+1.0f, -1.0f, 0.0f, 1.0f));
    586 				vertices.push_back(Vec4(-1.0f, +1.0f, 0.0f, 1.0f));
    587 				vertices.push_back(Vec4(+1.0f, +1.0f, 0.0f, 1.0f));
    588 
    589 				return vertices;
    590 			}
    591 
    592 			static VulkanProgram getProgram (Context& ctx, VkDescriptorSetLayout descriptorLayout, VkDescriptorSet descriptorSet)
    593 			{
    594 				VulkanProgram	prog;
    595 
    596 				prog.shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT,		ctx.getBinaryCollection().get("vert")));
    597 				prog.shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT,	ctx.getBinaryCollection().get("frag")));
    598 
    599 				prog.descriptorSet			= descriptorSet;
    600 				prog.descriptorSetLayout	= descriptorLayout;
    601 
    602 				return prog;
    603 			}
    604 		};
    605 
    606 		const UVec2					renderSize	(128, 256);
    607 		const vector<Vec4>			vertices	(LocalUtil::getVertices());
    608 		const DrawState				drawState	(LocalUtil::getDrawState(renderSize));
    609 		const DrawCallData			drawCallData(vertices);
    610 		const VulkanProgram			program		(LocalUtil::getProgram(context, *descLayout, *descSet));
    611 
    612 		bool						allOk		= true;
    613 
    614 		context.getTestContext().getLog()
    615 			<< TestLog::Message << "Rendering " << renderSize << " quad" << TestLog::EndMessage;
    616 
    617 		for (size_t imageNdx = 0; imageNdx < testImages.size(); ++imageNdx)
    618 		{
    619 			context.getTestContext().getLog()
    620 				<< TestLog::Message << "Testing image size " << testImages[imageNdx]->getSize() << TestLog::EndMessage;
    621 
    622 			bindImage(vkd, device, *descSet, testImages[imageNdx]->getImageView(), *sampler);
    623 
    624 			VulkanDrawContext	renderer	(context, drawState, drawCallData, program);
    625 			renderer.draw();
    626 
    627 			{
    628 				// Only du/dx and dv/dy are non-zero
    629 				const Vec2					dtdp		= testImages[imageNdx]->getSize().cast<float>() / renderSize.cast<float>();
    630 				const tcu::LodPrecision		lodPrec		(16, 4); // Pretty lax since we are not verifying LOD precision
    631 				const Vec2					lodBounds	(tcu::computeLodBoundsFromDerivates(dtdp.x(), 0.0f, 0.0f, dtdp.y(), lodPrec));
    632 				tcu::ConstPixelBufferAccess	resultImg	(renderer.getColorPixels());
    633 				const int					maxErrors	= 5;
    634 				int							numErrors	= 0;
    635 
    636 				for (int y = 0; y < resultImg.getHeight(); ++y)
    637 				for (int x = 0; x < resultImg.getWidth(); ++x)
    638 				{
    639 					const Vec2	result		= resultImg.getPixel(x, y).swizzle(0,1);
    640 					const bool	levelOk		= result.x() == 0.0f;
    641 					const bool	lodOk		= de::inRange(result.y(), lodBounds.x(), lodBounds.y());
    642 
    643 					if (!levelOk || !lodOk)
    644 					{
    645 						if (numErrors < maxErrors)
    646 						{
    647 							context.getTestContext().getLog()
    648 								<< TestLog::Message << "ERROR: At (" << x << ", " << y << ")"
    649 													<< ": got " << result
    650 													<< ", expected (0, [" << lodBounds.x() << ", " << lodBounds.y() << "])"
    651 								<< TestLog::EndMessage;
    652 						}
    653 						else if (numErrors == maxErrors)
    654 							context.getTestContext().getLog() << TestLog::Message << "..." << TestLog::EndMessage;
    655 
    656 						numErrors += 1;
    657 					}
    658 				}
    659 
    660 				allOk = allOk && (numErrors  == 0);
    661 			}
    662 		}
    663 
    664 		if (allOk)
    665 			return tcu::TestStatus::pass("Queries passed");
    666 		else
    667 			return tcu::TestStatus::fail("Got invalid results");
    668 	}
    669 }
    670 
    671 void initImageQueryPrograms (SourceCollections& dst, TestParameters params)
    672 {
    673 	const ShaderSpec	spec	= getShaderSpec(params);
    674 
    675 	generateSources(params.shaderType, spec, dst);
    676 }
    677 
    678 void initImageQueryLodPrograms (SourceCollections& dst, TestParameters)
    679 {
    680 	dst.glslSources.add("vert")
    681 		<< glu::VertexSource("#version 450\n"
    682 							 "layout(location = 0) in highp vec4 a_position;\n"
    683 							 "layout(location = 0) out highp vec2 v_texCoord;\n"
    684 							 "\n"
    685 							 "void main (void)\n"
    686 							 "{\n"
    687 							 "	gl_Position = a_position;\n"
    688 							 "	v_texCoord = a_position.xy * 0.5 - 0.5;\n"
    689 							 "}\n");
    690 	dst.glslSources.add("frag")
    691 		<< glu::FragmentSource("#version 450\n"
    692 							   "layout(binding = 0, set = 0) uniform highp sampler2D u_image;\n"
    693 							   "layout(location = 0) in highp vec2 v_texCoord;\n"
    694 							   "layout(location = 0) out highp vec2 o_lod;\n"
    695 							   "\n"
    696 							   "void main (void)\n"
    697 							   "{\n"
    698 							   "	o_lod = textureQueryLod(u_image, v_texCoord);\n"
    699 							   "}\n");
    700 }
    701 
    702 void addImageQueryCase (tcu::TestCaseGroup* group, const TestParameters& params)
    703 {
    704 	std::string	name	= de::toLower(de::toString(params.format).substr(10));
    705 	const bool	isLod	= params.query == QUERY_TYPE_IMAGE_LOD;
    706 
    707 	if ((params.flags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0)
    708 		name += "_disjoint";
    709 
    710 	addFunctionCaseWithPrograms(group,
    711 								name,
    712 								"",
    713 								isLod ? initImageQueryLodPrograms : initImageQueryPrograms,
    714 								isLod ? testImageQueryLod : testImageQuery,
    715 								params);
    716 }
    717 
    718 struct QueryGroupParams
    719 {
    720 	QueryType		query;
    721 	glu::ShaderType	shaderType;
    722 
    723 	QueryGroupParams (QueryType query_, glu::ShaderType shaderType_)
    724 		: query		(query_)
    725 		, shaderType(shaderType_)
    726 	{}
    727 
    728 	QueryGroupParams (void)
    729 		: query		(QUERY_TYPE_LAST)
    730 		, shaderType(glu::SHADERTYPE_LAST)
    731 	{}
    732 };
    733 
    734 void populateQueryInShaderGroup (tcu::TestCaseGroup* group, QueryGroupParams params)
    735 {
    736 	// "Reference" formats for testing
    737 	addImageQueryCase(group, TestParameters(params.query, VK_FORMAT_R8G8B8A8_UNORM, 0u, params.shaderType));
    738 
    739 	for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
    740 	{
    741 		const VkFormat	format	= (VkFormat)formatNdx;
    742 
    743 		addImageQueryCase(group, TestParameters(params.query, format, 0u, params.shaderType));
    744 
    745 		if (getPlaneCount(format) > 1)
    746 			addImageQueryCase(group, TestParameters(params.query, format, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT_KHR, params.shaderType));
    747 	}
    748 }
    749 
    750 void populateQueryGroup (tcu::TestCaseGroup* group, QueryType query)
    751 {
    752 	for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; ++shaderTypeNdx)
    753 	{
    754 		const glu::ShaderType	shaderType	= (glu::ShaderType)shaderTypeNdx;
    755 
    756 		if (query == QUERY_TYPE_IMAGE_LOD && shaderType != glu::SHADERTYPE_FRAGMENT)
    757 			continue;
    758 
    759 		addTestGroup(group, glu::getShaderTypeName(shaderType), "", populateQueryInShaderGroup, QueryGroupParams(query, shaderType));
    760 	}
    761 }
    762 
    763 void populateImageQueryGroup (tcu::TestCaseGroup* group)
    764 {
    765 	addTestGroup(group, "size_lod",	"OpImageQuerySizeLod",	populateQueryGroup, QUERY_TYPE_IMAGE_SIZE_LOD);
    766 	addTestGroup(group, "lod",		"OpImageQueryLod",		populateQueryGroup, QUERY_TYPE_IMAGE_LOD);
    767 	addTestGroup(group, "levels",	"OpImageQueryLevels",	populateQueryGroup, QUERY_TYPE_IMAGE_LEVELS);
    768 }
    769 
    770 } // namespace
    771 
    772 tcu::TestCaseGroup* createImageQueryTests (tcu::TestContext& testCtx)
    773 {
    774 	return createTestGroup(testCtx, "query", "Image Query Tests", populateImageQueryGroup);
    775 }
    776 
    777 } // ycbcr
    778 } // vkt
    779