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