• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 YCbCr Image View Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktYCbCrViewTests.hpp"
25 #include "vktYCbCrUtil.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktShaderExecutor.hpp"
29 
30 #include "vkStrUtil.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 
39 #include "tcuTestLog.hpp"
40 #include "tcuVectorUtil.hpp"
41 
42 #include "deStringUtil.hpp"
43 #include "deSharedPtr.hpp"
44 #include "deUniquePtr.hpp"
45 #include "deRandom.hpp"
46 #include "deSTLUtil.hpp"
47 
48 namespace vkt
49 {
50 namespace ycbcr
51 {
52 namespace
53 {
54 
55 using namespace vk;
56 using namespace shaderexecutor;
57 
58 using tcu::UVec2;
59 using tcu::Vec2;
60 using tcu::Vec4;
61 using tcu::IVec4;
62 using tcu::UVec4;
63 using tcu::TestLog;
64 using de::MovePtr;
65 using de::UniquePtr;
66 using std::vector;
67 using std::string;
68 
69 // List of some formats compatible with formats listed in "Plane Format Compatibility Table".
70 const VkFormat s_compatible_formats[] =
71 {
72 	// 8-bit compatibility class
73 	// Compatible format for VK_FORMAT_R8_UNORM
74 	VK_FORMAT_R4G4_UNORM_PACK8,
75 	VK_FORMAT_R8_UINT,
76 	VK_FORMAT_R8_SINT,
77 	// 16-bit compatibility class
78 	// Compatible formats with VK_FORMAT_R8G8_UNORM, VK_FORMAT_R10X6_UNORM_PACK16, VK_FORMAT_R12X4_UNORM_PACK16 and VK_FORMAT_R16_UNORM
79 	VK_FORMAT_R8G8_UNORM,
80 	VK_FORMAT_R8G8_UINT,
81 	VK_FORMAT_R10X6_UNORM_PACK16,
82 	VK_FORMAT_R12X4_UNORM_PACK16,
83 	VK_FORMAT_R16_UNORM,
84 	VK_FORMAT_R16_UINT,
85 	VK_FORMAT_R16_SINT,
86 	VK_FORMAT_R4G4B4A4_UNORM_PACK16,
87 	// 32-bit compatibility class
88 	// Compatible formats for VK_FORMAT_R10X6G10X6_UNORM_2PACK16, VK_FORMAT_R12X4G12X4_UNORM_2PACK16 and VK_FORMAT_R16G16_UNORM
89 	VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
90 	VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
91 	VK_FORMAT_R16G16_UNORM,
92 	VK_FORMAT_R8G8B8A8_UNORM,
93 	VK_FORMAT_R8G8B8A8_UINT,
94 	VK_FORMAT_R32_UINT,
95 };
96 
formatsAreCompatible(const VkFormat format0,const VkFormat format1)97 inline bool formatsAreCompatible (const VkFormat format0, const VkFormat format1)
98 {
99 	return format0 == format1 || mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize();
100 }
101 
createTestImage(const DeviceInterface & vkd,VkDevice device,VkFormat format,const UVec2 & size,VkImageCreateFlags createFlags)102 Move<VkImage> createTestImage (const DeviceInterface&	vkd,
103 							   VkDevice					device,
104 							   VkFormat					format,
105 							   const UVec2&				size,
106 							   VkImageCreateFlags		createFlags)
107 {
108 	const VkImageCreateInfo		createInfo	=
109 	{
110 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
111 		DE_NULL,
112 		createFlags,
113 		VK_IMAGE_TYPE_2D,
114 		format,
115 		makeExtent3D(size.x(), size.y(), 1u),
116 		1u,		// mipLevels
117 		1u,		// arrayLayers
118 		VK_SAMPLE_COUNT_1_BIT,
119 		VK_IMAGE_TILING_OPTIMAL,
120 		VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT,
121 		VK_SHARING_MODE_EXCLUSIVE,
122 		0u,
123 		(const deUint32*)DE_NULL,
124 		VK_IMAGE_LAYOUT_UNDEFINED,
125 	};
126 
127 	return createImage(vkd, device, &createInfo);
128 }
129 
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format,VkImageAspectFlagBits imageAspect,const VkSamplerYcbcrConversionInfo * samplerConversionInfo)130 Move<VkImageView> createImageView (const DeviceInterface&				vkd,
131 								   VkDevice								device,
132 								   VkImage								image,
133 								   VkFormat								format,
134 								   VkImageAspectFlagBits				imageAspect,
135 								   const VkSamplerYcbcrConversionInfo*	samplerConversionInfo)
136 {
137 	const VkImageViewCreateInfo				viewInfo	=
138 	{
139 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
140 		samplerConversionInfo,
141 		(VkImageViewCreateFlags)0,
142 		image,
143 		VK_IMAGE_VIEW_TYPE_2D,
144 		format,
145 		{
146 			VK_COMPONENT_SWIZZLE_IDENTITY,
147 			VK_COMPONENT_SWIZZLE_IDENTITY,
148 			VK_COMPONENT_SWIZZLE_IDENTITY,
149 			VK_COMPONENT_SWIZZLE_IDENTITY,
150 		},
151 		{ (VkImageAspectFlags)imageAspect, 0u, 1u, 0u, 1u },
152 	};
153 
154 	return createImageView(vkd, device, &viewInfo);
155 }
156 
157 // Descriptor layout for set 1:
158 // 0: Plane view bound as COMBINED_IMAGE_SAMPLER
159 // 1: "Whole" image bound as COMBINED_IMAGE_SAMPLER
160 //    + immutable sampler (required for color conversion)
161 
createDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkSampler conversionSampler)162 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler conversionSampler)
163 {
164 	const VkDescriptorSetLayoutBinding		bindings[]	=
165 	{
166 		{
167 			0u,												// binding
168 			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
169 			1u,												// descriptorCount
170 			VK_SHADER_STAGE_ALL,
171 			(const VkSampler*)DE_NULL
172 		},
173 		{
174 			1u,												// binding
175 			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
176 			1u,												// descriptorCount
177 			VK_SHADER_STAGE_ALL,
178 			&conversionSampler
179 		}
180 	};
181 	const VkDescriptorSetLayoutCreateInfo	layoutInfo	=
182 	{
183 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
184 		DE_NULL,
185 		(VkDescriptorSetLayoutCreateFlags)0u,
186 		DE_LENGTH_OF_ARRAY(bindings),
187 		bindings,
188 	};
189 
190 	return createDescriptorSetLayout(vkd, device, &layoutInfo);
191 }
192 
createDescriptorPool(const DeviceInterface & vkd,VkDevice device,const deUint32 combinedSamplerDescriptorCount)193 Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device, const deUint32 combinedSamplerDescriptorCount)
194 {
195 	const VkDescriptorPoolSize			poolSizes[]	=
196 	{
197 		{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	2u * combinedSamplerDescriptorCount	},
198 	};
199 	const VkDescriptorPoolCreateInfo	poolInfo	=
200 	{
201 		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
202 		DE_NULL,
203 		(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
204 		1u,		// maxSets
205 		DE_LENGTH_OF_ARRAY(poolSizes),
206 		poolSizes,
207 	};
208 
209 	return createDescriptorPool(vkd, device, & poolInfo);
210 }
211 
createDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorPool descPool,VkDescriptorSetLayout descLayout,VkImageView planeView,VkSampler planeViewSampler,VkImageView wholeView,VkSampler wholeViewSampler)212 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface&	vkd,
213 										   VkDevice					device,
214 										   VkDescriptorPool			descPool,
215 										   VkDescriptorSetLayout	descLayout,
216 										   VkImageView				planeView,
217 										   VkSampler				planeViewSampler,
218 										   VkImageView				wholeView,
219 										   VkSampler				wholeViewSampler)
220 {
221 	Move<VkDescriptorSet>	descSet;
222 
223 	{
224 		const VkDescriptorSetAllocateInfo	allocInfo	=
225 		{
226 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
227 			DE_NULL,
228 			descPool,
229 			1u,
230 			&descLayout,
231 		};
232 
233 		descSet = allocateDescriptorSet(vkd, device, &allocInfo);
234 	}
235 
236 	{
237 		const VkDescriptorImageInfo		imageInfo0			=
238 		{
239 			planeViewSampler,
240 			planeView,
241 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
242 		};
243 		const VkDescriptorImageInfo		imageInfo1			=
244 		{
245 			wholeViewSampler,
246 			wholeView,
247 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
248 		};
249 		const VkWriteDescriptorSet		descriptorWrites[]		=
250 		{
251 			{
252 				VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
253 				DE_NULL,
254 				*descSet,
255 				0u,		// dstBinding
256 				0u,		// dstArrayElement
257 				1u,		// descriptorCount
258 				VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
259 				&imageInfo0,
260 				(const VkDescriptorBufferInfo*)DE_NULL,
261 				(const VkBufferView*)DE_NULL,
262 			},
263 			{
264 				VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
265 				DE_NULL,
266 				*descSet,
267 				1u,		// dstBinding
268 				0u,		// dstArrayElement
269 				1u,		// descriptorCount
270 				VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
271 				&imageInfo1,
272 				(const VkDescriptorBufferInfo*)DE_NULL,
273 				(const VkBufferView*)DE_NULL,
274 			}
275 		};
276 
277 		vkd.updateDescriptorSets(device, DE_LENGTH_OF_ARRAY(descriptorWrites), descriptorWrites, 0u, DE_NULL);
278 	}
279 
280 	return descSet;
281 }
282 
executeImageBarrier(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,VkPipelineStageFlags srcStage,VkPipelineStageFlags dstStage,const VkImageMemoryBarrier & barrier)283 void executeImageBarrier (const DeviceInterface&		vkd,
284 						  VkDevice						device,
285 						  deUint32						queueFamilyNdx,
286 						  VkPipelineStageFlags			srcStage,
287 						  VkPipelineStageFlags			dstStage,
288 						  const VkImageMemoryBarrier&	barrier)
289 {
290 	const VkQueue					queue		= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
291 	const Unique<VkCommandPool>		cmdPool		(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
292 	const Unique<VkCommandBuffer>	cmdBuffer	(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
293 
294 	beginCommandBuffer(vkd, *cmdBuffer);
295 
296 	vkd.cmdPipelineBarrier(*cmdBuffer,
297 						   srcStage,
298 						   dstStage,
299 						   (VkDependencyFlags)0u,
300 						   0u,
301 						   (const VkMemoryBarrier*)DE_NULL,
302 						   0u,
303 						   (const VkBufferMemoryBarrier*)DE_NULL,
304 						   1u,
305 						   &barrier);
306 
307 	endCommandBuffer(vkd, *cmdBuffer);
308 
309 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
310 }
311 
312 struct TestParameters
313 {
314 	enum ViewType
315 	{
316 		VIEWTYPE_IMAGE_VIEW	= 0,
317 		VIEWTYPE_MEMORY_ALIAS,
318 
319 		VIEWTYPE_LAST
320 	};
321 
322 	ViewType			viewType;
323 	VkFormat			format;
324 	UVec2				size;
325 	VkImageCreateFlags	createFlags;
326 	deUint32			planeNdx;
327 	VkFormat			planeCompatibleFormat;
328 	glu::ShaderType		shaderType;
329 	deBool				isCompatibilityFormat;
330 
TestParametersvkt::ycbcr::__anon76ba627c0111::TestParameters331 	TestParameters (ViewType viewType_, VkFormat format_, const UVec2& size_, VkImageCreateFlags createFlags_, deUint32 planeNdx_, VkFormat planeCompatibleFormat_, glu::ShaderType shaderType_, deBool isCompatibilityFormat_)
332 		: viewType				(viewType_)
333 		, format				(format_)
334 		, size					(size_)
335 		, createFlags			(createFlags_)
336 		, planeNdx				(planeNdx_)
337 		, planeCompatibleFormat	(planeCompatibleFormat_)
338 		, shaderType			(shaderType_)
339 		, isCompatibilityFormat	(isCompatibilityFormat_)
340 	{
341 	}
342 
TestParametersvkt::ycbcr::__anon76ba627c0111::TestParameters343 	TestParameters (void)
344 		: viewType				(VIEWTYPE_LAST)
345 		, format				(VK_FORMAT_UNDEFINED)
346 		, createFlags			(0u)
347 		, planeNdx				(0u)
348 		, planeCompatibleFormat	(VK_FORMAT_UNDEFINED)
349 		, shaderType			(glu::SHADERTYPE_LAST)
350 		, isCompatibilityFormat	(false)
351 	{
352 	}
353 };
354 
getDataType(VkFormat f)355 static glu::DataType getDataType(VkFormat f) {
356 	if (isIntFormat(f))			return glu::TYPE_INT_VEC4;
357 	else if (isUintFormat(f))	return glu::TYPE_UINT_VEC4;
358 	else						return glu::TYPE_FLOAT_VEC4;
359 }
360 
getSamplerDecl(VkFormat f)361 static std::string getSamplerDecl(VkFormat f) {
362 	if (isIntFormat(f))			return "isampler2D";
363 	else if (isUintFormat(f))	return "usampler2D";
364 	else						return "sampler2D";
365 }
366 
getVecType(VkFormat f)367 static std::string getVecType(VkFormat f) {
368 	if (isIntFormat(f))			return "ivec4";
369 	else if (isUintFormat(f))	return "uvec4";
370 	else						return "vec4";
371 }
372 
getShaderSpec(const TestParameters & params)373 ShaderSpec getShaderSpec (const TestParameters& params)
374 {
375 	ShaderSpec spec;
376 
377 	spec.inputs.push_back(Symbol("texCoord", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
378 	spec.outputs.push_back(Symbol("result0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
379 	spec.outputs.push_back(Symbol("result1", glu::VarType(getDataType(params.planeCompatibleFormat), glu::PRECISION_HIGHP)));
380 
381 	const std::string sampler = getSamplerDecl(params.planeCompatibleFormat);
382 	spec.globalDeclarations =
383 		"layout(binding = 1, set = 1) uniform highp sampler2D u_image;\n"
384 		"layout(binding = 0, set = 1) uniform highp " + sampler + " u_planeView;\n";
385 
386 	spec.source =
387 		"result0 = texture(u_image, texCoord);\n"
388 		"result1 = " + getVecType(params.planeCompatibleFormat) + "(texture(u_planeView, texCoord));\n";
389 
390 	return spec;
391 }
392 
393 
generateLookupCoordinates(const UVec2 & imageSize,size_t numCoords,de::Random * rnd,vector<Vec2> * dst)394 void generateLookupCoordinates (const UVec2& imageSize, size_t numCoords, de::Random* rnd, vector<Vec2>* dst)
395 {
396 	dst->resize(numCoords);
397 
398 	for (size_t coordNdx = 0; coordNdx < numCoords; ++coordNdx)
399 	{
400 		const deUint32	texelX	= rnd->getUint32() % imageSize.x();
401 		const deUint32	texelY	= rnd->getUint32() % imageSize.y();
402 		const float		x		= ((float)texelX + 0.5f) / (float)imageSize.x();
403 		const float		y		= ((float)texelY + 0.5f) / (float)imageSize.y();
404 
405 		(*dst)[coordNdx] = Vec2(x, y);
406 	}
407 }
408 
checkImageFeatureSupport(Context & context,VkFormat format,VkFormatFeatureFlags req)409 void checkImageFeatureSupport (Context& context, VkFormat format, VkFormatFeatureFlags req)
410 {
411 	const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(	context.getInstanceInterface(),
412 																					context.getPhysicalDevice(),
413 																					format);
414 
415 	if (req & ~formatProperties.optimalTilingFeatures)
416 		TCU_THROW(NotSupportedError, "Format doesn't support required features");
417 }
418 
checkSupport(Context & context,TestParameters params)419 void checkSupport(Context& context, TestParameters params)
420 {
421 	checkImageSupport(context, params.format, params.createFlags);
422 	checkImageFeatureSupport(context, params.format,				VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT);
423 	checkImageFeatureSupport(context, params.planeCompatibleFormat,	VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
424 }
425 
castResult(Vec4 result,VkFormat f)426 Vec4 castResult(Vec4 result, VkFormat f) {
427 	union {
428 		Vec4 vec;
429 		IVec4 ivec;
430 		UVec4 uvec;
431 	} cast = { result };
432 
433 	if (isIntFormat(f)) {
434 		IVec4 ivec = cast.ivec;
435 		return Vec4((float)ivec.x(), (float)ivec.y(), (float)ivec.z(), (float)ivec.w());
436 	}
437 	else if (isUintFormat(f)) {
438 		UVec4 uvec = cast.uvec;
439 		return Vec4((float)uvec.x(), (float)uvec.y(), (float)uvec.z(), (float)uvec.w());
440 	}
441 	else {
442 		return result;
443 	}
444 }
445 
testPlaneView(Context & context,TestParameters params)446 tcu::TestStatus testPlaneView (Context& context, TestParameters params)
447 {
448 	de::Random						randomGen		(deInt32Hash((deUint32)params.format)	^
449 													 deInt32Hash((deUint32)params.planeNdx)	^
450 													 deInt32Hash((deUint32)params.shaderType));
451 
452 	const InstanceInterface&		vk				= context.getInstanceInterface();
453 	const DeviceInterface&			vkd				= context.getDeviceInterface();
454 	const VkDevice					device			= context.getDevice();
455 
456 	const VkFormat					format			= params.format;
457 	const VkImageCreateFlags		createFlags		= params.createFlags;
458 	const PlanarFormatDescription	formatInfo		= getPlanarFormatDescription(format);
459 	const UVec2						size			= params.size;
460 	const UVec2						planeExtent		= getPlaneExtent(formatInfo, size, params.planeNdx, 0);
461 	const Unique<VkImage>			image			(createTestImage(vkd, device, format, size, createFlags));
462 	const Unique<VkImage>			imageAlias		((params.viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS)
463 													 ? createTestImage(vkd, device, params.planeCompatibleFormat, planeExtent, createFlags)
464 													 : Move<VkImage>());
465 	const vector<AllocationSp>		allocations		(allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags));
466 
467 	if (imageAlias)
468 	{
469 		if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
470 		{
471 			VkBindImagePlaneMemoryInfo	planeInfo	=
472 			{
473 				VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO,
474 				DE_NULL,
475 				VK_IMAGE_ASPECT_PLANE_0_BIT
476 			};
477 
478 			VkBindImageMemoryInfo coreInfo	=
479 			{
480 				VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
481 				&planeInfo,
482 				*imageAlias,
483 				allocations[params.planeNdx]->getMemory(),
484 				allocations[params.planeNdx]->getOffset(),
485 			};
486 
487 			VK_CHECK(vkd.bindImageMemory2(device, 1, &coreInfo));
488 		}
489 		else
490 		{
491 			VK_CHECK(vkd.bindImageMemory(device, *imageAlias, allocations[params.planeNdx]->getMemory(), allocations[params.planeNdx]->getOffset()));
492 		}
493 	}
494 
495 	const VkSamplerYcbcrConversionCreateInfo	conversionInfo	=
496 	{
497 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
498 		DE_NULL,
499 		format,
500 		VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
501 		VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
502 		{
503 			VK_COMPONENT_SWIZZLE_IDENTITY,
504 			VK_COMPONENT_SWIZZLE_IDENTITY,
505 			VK_COMPONENT_SWIZZLE_IDENTITY,
506 			VK_COMPONENT_SWIZZLE_IDENTITY,
507 		},
508 		VK_CHROMA_LOCATION_MIDPOINT,
509 		VK_CHROMA_LOCATION_MIDPOINT,
510 		VK_FILTER_NEAREST,
511 		VK_FALSE,									// forceExplicitReconstruction
512 	};
513 	const Unique<VkSamplerYcbcrConversion>		conversion	(createSamplerYcbcrConversion(vkd, device, &conversionInfo));
514 	const VkSamplerYcbcrConversionInfo			samplerConversionInfo	=
515 	{
516 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
517 		DE_NULL,
518 		*conversion,
519 	};
520 	const Unique<VkImageView>					wholeView	(createImageView(vkd, device, *image, format, VK_IMAGE_ASPECT_COLOR_BIT, &samplerConversionInfo));
521 	const Unique<VkImageView>					planeView	(createImageView(vkd,
522 																			 device,
523 																			 !imageAlias ? *image : *imageAlias,
524 																			 params.planeCompatibleFormat,
525 																			 !imageAlias ? getPlaneAspect(params.planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT,
526 																			 DE_NULL));
527 
528 	const VkSamplerCreateInfo					wholeSamplerInfo		=
529 	{
530 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
531 		&samplerConversionInfo,
532 		0u,
533 		VK_FILTER_NEAREST,							// magFilter
534 		VK_FILTER_NEAREST,							// minFilter
535 		VK_SAMPLER_MIPMAP_MODE_NEAREST,				// mipmapMode
536 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeU
537 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeV
538 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeW
539 		0.0f,										// mipLodBias
540 		VK_FALSE,									// anisotropyEnable
541 		1.0f,										// maxAnisotropy
542 		VK_FALSE,									// compareEnable
543 		VK_COMPARE_OP_ALWAYS,						// compareOp
544 		0.0f,										// minLod
545 		0.0f,										// maxLod
546 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// borderColor
547 		VK_FALSE,									// unnormalizedCoords
548 	};
549 	const VkSamplerCreateInfo					planeSamplerInfo		=
550 	{
551 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
552 		DE_NULL,
553 		0u,
554 		VK_FILTER_NEAREST,							// magFilter
555 		VK_FILTER_NEAREST,							// minFilter
556 		VK_SAMPLER_MIPMAP_MODE_NEAREST,				// mipmapMode
557 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeU
558 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeV
559 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeW
560 		0.0f,										// mipLodBias
561 		VK_FALSE,									// anisotropyEnable
562 		1.0f,										// maxAnisotropy
563 		VK_FALSE,									// compareEnable
564 		VK_COMPARE_OP_ALWAYS,						// compareOp
565 		0.0f,										// minLod
566 		0.0f,										// maxLod
567 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// borderColor
568 		VK_FALSE,									// unnormalizedCoords
569 	};
570 
571 	deUint32									combinedSamplerDescriptorCount = 1;
572 	{
573 		const VkPhysicalDeviceImageFormatInfo2			imageFormatInfo				=
574 		{
575 			VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,	// sType;
576 			DE_NULL,												// pNext;
577 			format,													// format;
578 			VK_IMAGE_TYPE_2D,										// type;
579 			VK_IMAGE_TILING_OPTIMAL,								// tiling;
580 			VK_IMAGE_USAGE_TRANSFER_DST_BIT |
581 			VK_IMAGE_USAGE_SAMPLED_BIT,								// usage;
582 			createFlags												// flags;
583 		};
584 
585 		VkSamplerYcbcrConversionImageFormatProperties	samplerYcbcrConversionImage = {};
586 		samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
587 		samplerYcbcrConversionImage.pNext = DE_NULL;
588 
589 		VkImageFormatProperties2						imageFormatProperties		= {};
590 		imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
591 		imageFormatProperties.pNext = &samplerYcbcrConversionImage;
592 
593 		VkResult result = vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties);
594 		if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
595 			TCU_THROW(NotSupportedError, "Format not supported.");
596 		VK_CHECK(result);
597 		combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
598 	}
599 
600 	const Unique<VkSampler>					wholeSampler(createSampler(vkd, device, &wholeSamplerInfo));
601 	const Unique<VkSampler>					planeSampler(createSampler(vkd, device, &planeSamplerInfo));
602 
603 	const Unique<VkDescriptorSetLayout>		descLayout	(createDescriptorSetLayout(vkd, device, *wholeSampler));
604 	const Unique<VkDescriptorPool>			descPool	(createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
605 	const Unique<VkDescriptorSet>			descSet		(createDescriptorSet(vkd, device, *descPool, *descLayout, *planeView, *planeSampler, *wholeView, *wholeSampler));
606 
607 	MultiPlaneImageData						imageData	(format, size);
608 
609 	// Prepare texture data
610 	fillRandom(&randomGen, &imageData);
611 
612 	if (imageAlias)
613 	{
614 		// Transition alias to right layout first
615 		const VkImageMemoryBarrier		initAliasBarrier	=
616 		{
617 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
618 			DE_NULL,
619 			(VkAccessFlags)0,
620 			VK_ACCESS_SHADER_READ_BIT,
621 			VK_IMAGE_LAYOUT_UNDEFINED,
622 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
623 			VK_QUEUE_FAMILY_IGNORED,
624 			VK_QUEUE_FAMILY_IGNORED,
625 			*imageAlias,
626 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
627 		};
628 
629 		executeImageBarrier(vkd,
630 							device,
631 							context.getUniversalQueueFamilyIndex(),
632 							(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
633 							(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
634 							initAliasBarrier);
635 	}
636 
637 	// Upload and prepare image
638 	uploadImage(vkd,
639 				device,
640 				context.getUniversalQueueFamilyIndex(),
641 				context.getDefaultAllocator(),
642 				*image,
643 				imageData,
644 				(VkAccessFlags)VK_ACCESS_SHADER_READ_BIT,
645 				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
646 
647 	{
648 		const size_t	numValues		= 500;
649 		vector<Vec2>	texCoord		(numValues);
650 		vector<Vec4>	resultWhole		(numValues);
651 		vector<Vec4>	resultPlane		(numValues);
652 		vector<Vec4>	referenceWhole	(numValues);
653 		vector<Vec4>	referencePlane	(numValues);
654 		bool			allOk			= true;
655 		Vec4			threshold		(0.02f);
656 
657 		generateLookupCoordinates(size, numValues, &randomGen, &texCoord);
658 
659 		{
660 			UniquePtr<ShaderExecutor>	executor	(createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
661 			const void*					inputs[]	= { texCoord[0].getPtr() };
662 			void*						outputs[]	= { resultWhole[0].getPtr(), resultPlane[0].getPtr() };
663 
664 			executor->execute((int)numValues, inputs, outputs, *descSet);
665 		}
666 
667 		// Whole image sampling reference
668 		for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
669 		{
670 			if (formatInfo.hasChannelNdx(channelNdx))
671 			{
672 				const tcu::ConstPixelBufferAccess	channelAccess	= imageData.getChannelAccess(channelNdx);
673 				const tcu::Sampler					refSampler		= mapVkSampler(wholeSamplerInfo);
674 				const tcu::Texture2DView			refTexView		(1u, &channelAccess);
675 
676 				for (size_t ndx = 0; ndx < numValues; ++ndx)
677 				{
678 					const Vec2&	coord	= texCoord[ndx];
679 					referenceWhole[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0];
680 				}
681 			}
682 			else
683 			{
684 				for (size_t ndx = 0; ndx < numValues; ++ndx)
685 					referenceWhole[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f;
686 			}
687 		}
688 
689 		// Plane view sampling reference
690 		{
691 			const tcu::ConstPixelBufferAccess	planeAccess		(mapVkFormat(params.planeCompatibleFormat),
692 																 tcu::IVec3((int)planeExtent.x(), (int)planeExtent.y(), 1),
693 																 imageData.getPlanePtr(params.planeNdx));
694 			const tcu::Sampler					refSampler		= mapVkSampler(planeSamplerInfo);
695 			const tcu::Texture2DView			refTexView		(1u, &planeAccess);
696 
697 			for (size_t ndx = 0; ndx < numValues; ++ndx)
698 			{
699 				const Vec2&	coord	= texCoord[ndx];
700 				referencePlane[ndx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f);
701 			}
702 		}
703 
704 		for (int viewNdx = 0; viewNdx < 2; ++viewNdx)
705 		{
706 			const char* const	viewName	= (viewNdx == 0) ? "complete image"	: "plane view";
707 			const vector<Vec4>&	reference	= (viewNdx == 0) ? referenceWhole	: referencePlane;
708 			const vector<Vec4>&	result		= (viewNdx == 0) ? resultWhole		: resultPlane;
709 
710 			for (size_t ndx = 0; ndx < numValues; ++ndx)
711 			{
712 				const Vec4 resultValue = (viewNdx == 0) ? result[ndx] : castResult(result[ndx], params.planeCompatibleFormat);
713 				if (boolAny(greaterThanEqual(abs(resultValue - reference[ndx]), threshold)))
714 				{
715 					context.getTestContext().getLog()
716 						<< TestLog::Message << "ERROR: When sampling " << viewName << " at " << texCoord[ndx]
717 											<< ": got " << result[ndx]
718 											<< ", expected " << reference[ndx]
719 						<< TestLog::EndMessage;
720 					allOk = false;
721 				}
722 			}
723 		}
724 
725 		if (allOk)
726 			return tcu::TestStatus::pass("All samples passed");
727 		else
728 			return tcu::TestStatus::fail("Got invalid results");
729 	}
730 }
731 
initPrograms(SourceCollections & dst,TestParameters params)732 void initPrograms (SourceCollections& dst, TestParameters params)
733 {
734 	const ShaderSpec	spec	= getShaderSpec(params);
735 
736 	generateSources(params.shaderType, spec, dst);
737 }
738 
addPlaneViewCase(tcu::TestCaseGroup * group,const TestParameters & params)739 void addPlaneViewCase (tcu::TestCaseGroup* group, const TestParameters& params)
740 {
741 	std::ostringstream name;
742 
743 	name << de::toLower(de::toString(params.format).substr(10));
744 
745 	if ((params.viewType != TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
746 		((params.createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0))
747 		name << "_disjoint";
748 
749 	name << "_plane_" << params.planeNdx;
750 
751 	if (params.isCompatibilityFormat)
752 	{
753 		name << "_compatible_format_" << de::toLower(de::toString(params.planeCompatibleFormat).substr(10));
754 	}
755 
756 	addFunctionCaseWithPrograms(group, name.str(), "", checkSupport, initPrograms, testPlaneView, params);
757 }
758 
populateViewTypeGroup(tcu::TestCaseGroup * group,TestParameters::ViewType viewType)759 void populateViewTypeGroup (tcu::TestCaseGroup* group, TestParameters::ViewType viewType)
760 {
761 	const glu::ShaderType		shaderType	= glu::SHADERTYPE_FRAGMENT;
762 	const UVec2					size		(32, 58);
763 	const VkImageCreateFlags	baseFlags	= (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
764 											| (viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS ? (VkImageCreateFlags)VK_IMAGE_CREATE_ALIAS_BIT : 0u);
765 
766 	auto addTests = [&](int formatNdx)
767 	{
768 		const VkFormat	format		= (VkFormat)formatNdx;
769 		const deUint32	numPlanes	= getPlaneCount(format);
770 
771 		if (numPlanes == 1)
772 			return; // Plane views not possible
773 
774 		for (int isDisjoint = 0; isDisjoint < 2; ++isDisjoint)
775 		{
776 			const VkImageCreateFlags	flags	= baseFlags | (isDisjoint == 1 ? (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT : 0u);
777 
778 			if ((viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
779 				((flags & VK_IMAGE_CREATE_DISJOINT_BIT) == 0))
780 				continue; // Memory alias cases require disjoint planes
781 
782 			for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
783 			{
784 				const VkFormat planeFormat = getPlaneCompatibleFormat(format, planeNdx);
785 				// Add test case using image view with a format taken from the "Plane Format Compatibility Table"
786 				addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, planeFormat, shaderType, DE_FALSE));
787 
788 				// Add test cases using image view with a format that is compatible with the plane's format.
789 				// For example: VK_FORMAT_R4G4_UNORM_PACK8 is compatible with VK_FORMAT_R8_UNORM.
790 				for (const auto& compatibleFormat : s_compatible_formats)
791 				{
792 					if (compatibleFormat == planeFormat)
793 						continue;
794 
795 					if (!formatsAreCompatible(planeFormat, compatibleFormat))
796 						continue;
797 
798 					addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, compatibleFormat, shaderType, DE_TRUE));
799 				}
800 			}
801 		}
802 	};
803 
804 	for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
805 	{
806 		addTests(formatNdx);
807 	}
808 
809 	for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx < VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT; formatNdx++)
810 	{
811 		addTests(formatNdx);
812 	}
813 }
814 
populateViewGroup(tcu::TestCaseGroup * group)815 void populateViewGroup (tcu::TestCaseGroup* group)
816 {
817 	addTestGroup(group, "image_view",	"Plane View via VkImageView",		populateViewTypeGroup,	TestParameters::VIEWTYPE_IMAGE_VIEW);
818 	addTestGroup(group, "memory_alias",	"Plane View via Memory Aliasing",	populateViewTypeGroup,	TestParameters::VIEWTYPE_MEMORY_ALIAS);
819 }
820 
821 } // anonymous
822 
createViewTests(tcu::TestContext & testCtx)823 tcu::TestCaseGroup* createViewTests (tcu::TestContext& testCtx)
824 {
825 	return createTestGroup(testCtx, "plane_view", "YCbCr Plane View Tests", populateViewGroup);
826 }
827 
828 } // ycbcr
829 
830 } // vkt
831 
832