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