• 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::__anonac7b84a30111::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::__anonac7b84a30111::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 	if (isIntFormat(f)) {
428 		IVec4* result_ptr = reinterpret_cast<IVec4*>(&result);
429 		IVec4 ivec = *(result_ptr);
430 		return Vec4((float)ivec.x(), (float)ivec.y(), (float)ivec.z(), (float)ivec.w());
431 	}
432 	else if (isUintFormat(f)) {
433 		UVec4* result_ptr = reinterpret_cast<UVec4*>(&result);
434 		UVec4 uvec = *(result_ptr);
435 		return Vec4((float)uvec.x(), (float)uvec.y(), (float)uvec.z(), (float)uvec.w());
436 	}
437 	else {
438 		return result;
439 	}
440 }
441 
testPlaneView(Context & context,TestParameters params)442 tcu::TestStatus testPlaneView (Context& context, TestParameters params)
443 {
444 	de::Random						randomGen		(deInt32Hash((deUint32)params.format)	^
445 													 deInt32Hash((deUint32)params.planeNdx)	^
446 													 deInt32Hash((deUint32)params.shaderType));
447 
448 	const InstanceInterface&		vk				= context.getInstanceInterface();
449 	const DeviceInterface&			vkd				= context.getDeviceInterface();
450 	const VkDevice					device			= context.getDevice();
451 
452 	const VkFormat					format			= params.format;
453 	const VkImageCreateFlags		createFlags		= params.createFlags;
454 	const PlanarFormatDescription	formatInfo		= getPlanarFormatDescription(format);
455 	const UVec2						size			= params.size;
456 	const UVec2						planeExtent		= getPlaneExtent(formatInfo, size, params.planeNdx, 0);
457 	const Unique<VkImage>			image			(createTestImage(vkd, device, format, size, createFlags));
458 	const Unique<VkImage>			imageAlias		((params.viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS)
459 													 ? createTestImage(vkd, device, params.planeCompatibleFormat, planeExtent, createFlags)
460 													 : Move<VkImage>());
461 	const vector<AllocationSp>		allocations		(allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags));
462 
463 	if (imageAlias)
464 	{
465 		if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
466 		{
467 			VkBindImagePlaneMemoryInfo	planeInfo	=
468 			{
469 				VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO,
470 				DE_NULL,
471 				VK_IMAGE_ASPECT_PLANE_0_BIT
472 			};
473 
474 			VkBindImageMemoryInfo coreInfo	=
475 			{
476 				VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
477 				&planeInfo,
478 				*imageAlias,
479 				allocations[params.planeNdx]->getMemory(),
480 				allocations[params.planeNdx]->getOffset(),
481 			};
482 
483 			VK_CHECK(vkd.bindImageMemory2(device, 1, &coreInfo));
484 		}
485 		else
486 		{
487 			VK_CHECK(vkd.bindImageMemory(device, *imageAlias, allocations[params.planeNdx]->getMemory(), allocations[params.planeNdx]->getOffset()));
488 		}
489 	}
490 
491 	const VkSamplerYcbcrConversionCreateInfo	conversionInfo	=
492 	{
493 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
494 		DE_NULL,
495 		format,
496 		VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
497 		VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
498 		{
499 			VK_COMPONENT_SWIZZLE_IDENTITY,
500 			VK_COMPONENT_SWIZZLE_IDENTITY,
501 			VK_COMPONENT_SWIZZLE_IDENTITY,
502 			VK_COMPONENT_SWIZZLE_IDENTITY,
503 		},
504 		VK_CHROMA_LOCATION_MIDPOINT,
505 		VK_CHROMA_LOCATION_MIDPOINT,
506 		VK_FILTER_NEAREST,
507 		VK_FALSE,									// forceExplicitReconstruction
508 	};
509 	const Unique<VkSamplerYcbcrConversion>		conversion	(createSamplerYcbcrConversion(vkd, device, &conversionInfo));
510 	const VkSamplerYcbcrConversionInfo			samplerConversionInfo	=
511 	{
512 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
513 		DE_NULL,
514 		*conversion,
515 	};
516 	const Unique<VkImageView>					wholeView	(createImageView(vkd, device, *image, format, VK_IMAGE_ASPECT_COLOR_BIT, &samplerConversionInfo));
517 	const Unique<VkImageView>					planeView	(createImageView(vkd,
518 																			 device,
519 																			 !imageAlias ? *image : *imageAlias,
520 																			 params.planeCompatibleFormat,
521 																			 !imageAlias ? getPlaneAspect(params.planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT,
522 																			 DE_NULL));
523 
524 	const VkSamplerCreateInfo					wholeSamplerInfo		=
525 	{
526 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
527 		&samplerConversionInfo,
528 		0u,
529 		VK_FILTER_NEAREST,							// magFilter
530 		VK_FILTER_NEAREST,							// minFilter
531 		VK_SAMPLER_MIPMAP_MODE_NEAREST,				// mipmapMode
532 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeU
533 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeV
534 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeW
535 		0.0f,										// mipLodBias
536 		VK_FALSE,									// anisotropyEnable
537 		1.0f,										// maxAnisotropy
538 		VK_FALSE,									// compareEnable
539 		VK_COMPARE_OP_ALWAYS,						// compareOp
540 		0.0f,										// minLod
541 		0.0f,										// maxLod
542 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// borderColor
543 		VK_FALSE,									// unnormalizedCoords
544 	};
545 	const VkSamplerCreateInfo					planeSamplerInfo		=
546 	{
547 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
548 		DE_NULL,
549 		0u,
550 		VK_FILTER_NEAREST,							// magFilter
551 		VK_FILTER_NEAREST,							// minFilter
552 		VK_SAMPLER_MIPMAP_MODE_NEAREST,				// mipmapMode
553 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeU
554 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeV
555 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// addressModeW
556 		0.0f,										// mipLodBias
557 		VK_FALSE,									// anisotropyEnable
558 		1.0f,										// maxAnisotropy
559 		VK_FALSE,									// compareEnable
560 		VK_COMPARE_OP_ALWAYS,						// compareOp
561 		0.0f,										// minLod
562 		0.0f,										// maxLod
563 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// borderColor
564 		VK_FALSE,									// unnormalizedCoords
565 	};
566 
567 	deUint32									combinedSamplerDescriptorCount = 1;
568 	{
569 		const VkPhysicalDeviceImageFormatInfo2			imageFormatInfo				=
570 		{
571 			VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,	// sType;
572 			DE_NULL,												// pNext;
573 			format,													// format;
574 			VK_IMAGE_TYPE_2D,										// type;
575 			VK_IMAGE_TILING_OPTIMAL,								// tiling;
576 			VK_IMAGE_USAGE_TRANSFER_DST_BIT |
577 			VK_IMAGE_USAGE_SAMPLED_BIT,								// usage;
578 			createFlags												// flags;
579 		};
580 
581 		VkSamplerYcbcrConversionImageFormatProperties	samplerYcbcrConversionImage = {};
582 		samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
583 		samplerYcbcrConversionImage.pNext = DE_NULL;
584 
585 		VkImageFormatProperties2						imageFormatProperties		= {};
586 		imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
587 		imageFormatProperties.pNext = &samplerYcbcrConversionImage;
588 
589 		VkResult result = vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties);
590 		if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
591 			TCU_THROW(NotSupportedError, "Format not supported.");
592 		VK_CHECK(result);
593 		combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
594 	}
595 
596 	const Unique<VkSampler>					wholeSampler(createSampler(vkd, device, &wholeSamplerInfo));
597 	const Unique<VkSampler>					planeSampler(createSampler(vkd, device, &planeSamplerInfo));
598 
599 	const Unique<VkDescriptorSetLayout>		descLayout	(createDescriptorSetLayout(vkd, device, *wholeSampler));
600 	const Unique<VkDescriptorPool>			descPool	(createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
601 	const Unique<VkDescriptorSet>			descSet		(createDescriptorSet(vkd, device, *descPool, *descLayout, *planeView, *planeSampler, *wholeView, *wholeSampler));
602 
603 	MultiPlaneImageData						imageData	(format, size);
604 
605 	// Prepare texture data
606 	fillRandom(&randomGen, &imageData);
607 
608 	if (imageAlias)
609 	{
610 		// Transition alias to right layout first
611 		const VkImageMemoryBarrier		initAliasBarrier	=
612 		{
613 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
614 			DE_NULL,
615 			(VkAccessFlags)0,
616 			VK_ACCESS_SHADER_READ_BIT,
617 			VK_IMAGE_LAYOUT_UNDEFINED,
618 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
619 			VK_QUEUE_FAMILY_IGNORED,
620 			VK_QUEUE_FAMILY_IGNORED,
621 			*imageAlias,
622 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
623 		};
624 
625 		executeImageBarrier(vkd,
626 							device,
627 							context.getUniversalQueueFamilyIndex(),
628 							(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
629 							(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
630 							initAliasBarrier);
631 	}
632 
633 	// Upload and prepare image
634 	uploadImage(vkd,
635 				device,
636 				context.getUniversalQueueFamilyIndex(),
637 				context.getDefaultAllocator(),
638 				*image,
639 				imageData,
640 				(VkAccessFlags)VK_ACCESS_SHADER_READ_BIT,
641 				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
642 
643 	{
644 		const size_t	numValues		= 500;
645 		vector<Vec2>	texCoord		(numValues);
646 		vector<Vec4>	resultWhole		(numValues);
647 		vector<Vec4>	resultPlane		(numValues);
648 		vector<Vec4>	referenceWhole	(numValues);
649 		vector<Vec4>	referencePlane	(numValues);
650 		bool			allOk			= true;
651 		Vec4			threshold		(0.02f);
652 
653 		generateLookupCoordinates(size, numValues, &randomGen, &texCoord);
654 
655 		{
656 			UniquePtr<ShaderExecutor>	executor	(createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
657 			const void*					inputs[]	= { texCoord[0].getPtr() };
658 			void*						outputs[]	= { resultWhole[0].getPtr(), resultPlane[0].getPtr() };
659 
660 			executor->execute((int)numValues, inputs, outputs, *descSet);
661 		}
662 
663 		// Whole image sampling reference
664 		for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
665 		{
666 			if (formatInfo.hasChannelNdx(channelNdx))
667 			{
668 				const tcu::ConstPixelBufferAccess	channelAccess	= imageData.getChannelAccess(channelNdx);
669 				const tcu::Sampler					refSampler		= mapVkSampler(wholeSamplerInfo);
670 				const tcu::Texture2DView			refTexView		(1u, &channelAccess);
671 
672 				for (size_t ndx = 0; ndx < numValues; ++ndx)
673 				{
674 					const Vec2&	coord	= texCoord[ndx];
675 					referenceWhole[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0];
676 				}
677 			}
678 			else
679 			{
680 				for (size_t ndx = 0; ndx < numValues; ++ndx)
681 					referenceWhole[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f;
682 			}
683 		}
684 
685 		// Plane view sampling reference
686 		{
687 			const tcu::ConstPixelBufferAccess	planeAccess		(mapVkFormat(params.planeCompatibleFormat),
688 																 tcu::IVec3((int)planeExtent.x(), (int)planeExtent.y(), 1),
689 																 imageData.getPlanePtr(params.planeNdx));
690 			const tcu::Sampler					refSampler		= mapVkSampler(planeSamplerInfo);
691 			const tcu::Texture2DView			refTexView		(1u, &planeAccess);
692 
693 			for (size_t ndx = 0; ndx < numValues; ++ndx)
694 			{
695 				const Vec2&	coord	= texCoord[ndx];
696 				referencePlane[ndx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f);
697 			}
698 		}
699 
700 		for (int viewNdx = 0; viewNdx < 2; ++viewNdx)
701 		{
702 			const char* const	viewName	= (viewNdx == 0) ? "complete image"	: "plane view";
703 			const vector<Vec4>&	reference	= (viewNdx == 0) ? referenceWhole	: referencePlane;
704 			const vector<Vec4>&	result		= (viewNdx == 0) ? resultWhole		: resultPlane;
705 
706 			for (size_t ndx = 0; ndx < numValues; ++ndx)
707 			{
708 				const Vec4 resultValue = (viewNdx == 0) ? result[ndx] : castResult(result[ndx], params.planeCompatibleFormat);
709 				if (boolAny(greaterThanEqual(abs(resultValue - reference[ndx]), threshold)))
710 				{
711 					context.getTestContext().getLog()
712 						<< TestLog::Message << "ERROR: When sampling " << viewName << " at " << texCoord[ndx]
713 											<< ": got " << result[ndx]
714 											<< ", expected " << reference[ndx]
715 						<< TestLog::EndMessage;
716 					allOk = false;
717 				}
718 			}
719 		}
720 
721 		if (allOk)
722 			return tcu::TestStatus::pass("All samples passed");
723 		else
724 			return tcu::TestStatus::fail("Got invalid results");
725 	}
726 }
727 
initPrograms(SourceCollections & dst,TestParameters params)728 void initPrograms (SourceCollections& dst, TestParameters params)
729 {
730 	const ShaderSpec	spec	= getShaderSpec(params);
731 
732 	generateSources(params.shaderType, spec, dst);
733 }
734 
addPlaneViewCase(tcu::TestCaseGroup * group,const TestParameters & params)735 void addPlaneViewCase (tcu::TestCaseGroup* group, const TestParameters& params)
736 {
737 	std::ostringstream name;
738 
739 	name << de::toLower(de::toString(params.format).substr(10));
740 
741 	if ((params.viewType != TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
742 		((params.createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0))
743 		name << "_disjoint";
744 
745 	name << "_plane_" << params.planeNdx;
746 
747 	if (params.isCompatibilityFormat)
748 	{
749 		name << "_compatible_format_" << de::toLower(de::toString(params.planeCompatibleFormat).substr(10));
750 	}
751 
752 	addFunctionCaseWithPrograms(group, name.str(), "", checkSupport, initPrograms, testPlaneView, params);
753 }
754 
populateViewTypeGroup(tcu::TestCaseGroup * group,TestParameters::ViewType viewType)755 void populateViewTypeGroup (tcu::TestCaseGroup* group, TestParameters::ViewType viewType)
756 {
757 	const glu::ShaderType		shaderType	= glu::SHADERTYPE_FRAGMENT;
758 	const UVec2					size		(32, 58);
759 	const VkImageCreateFlags	baseFlags	= (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
760 											| (viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS ? (VkImageCreateFlags)VK_IMAGE_CREATE_ALIAS_BIT : 0u);
761 
762 	auto addTests = [&](int formatNdx)
763 	{
764 		const VkFormat	format		= (VkFormat)formatNdx;
765 		const deUint32	numPlanes	= getPlaneCount(format);
766 
767 		if (numPlanes == 1)
768 			return; // Plane views not possible
769 
770 		for (int isDisjoint = 0; isDisjoint < 2; ++isDisjoint)
771 		{
772 			const VkImageCreateFlags	flags	= baseFlags | (isDisjoint == 1 ? (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT : 0u);
773 
774 			if ((viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
775 				((flags & VK_IMAGE_CREATE_DISJOINT_BIT) == 0))
776 				continue; // Memory alias cases require disjoint planes
777 
778 			for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
779 			{
780 				const VkFormat planeFormat = getPlaneCompatibleFormat(format, planeNdx);
781 				// Add test case using image view with a format taken from the "Plane Format Compatibility Table"
782 				addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, planeFormat, shaderType, DE_FALSE));
783 
784 				// Add test cases using image view with a format that is compatible with the plane's format.
785 				// For example: VK_FORMAT_R4G4_UNORM_PACK8 is compatible with VK_FORMAT_R8_UNORM.
786 				for (const auto& compatibleFormat : s_compatible_formats)
787 				{
788 					if (compatibleFormat == planeFormat)
789 						continue;
790 
791 					if (!formatsAreCompatible(planeFormat, compatibleFormat))
792 						continue;
793 
794 					addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, compatibleFormat, shaderType, DE_TRUE));
795 				}
796 			}
797 		}
798 	};
799 
800 	for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
801 	{
802 		addTests(formatNdx);
803 	}
804 
805 	for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx < VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT; formatNdx++)
806 	{
807 		addTests(formatNdx);
808 	}
809 }
810 
populateViewGroup(tcu::TestCaseGroup * group)811 void populateViewGroup (tcu::TestCaseGroup* group)
812 {
813 	addTestGroup(group, "image_view",	"Plane View via VkImageView",		populateViewTypeGroup,	TestParameters::VIEWTYPE_IMAGE_VIEW);
814 	addTestGroup(group, "memory_alias",	"Plane View via Memory Aliasing",	populateViewTypeGroup,	TestParameters::VIEWTYPE_MEMORY_ALIAS);
815 }
816 
817 } // anonymous
818 
createViewTests(tcu::TestContext & testCtx)819 tcu::TestCaseGroup* createViewTests (tcu::TestContext& testCtx)
820 {
821 	return createTestGroup(testCtx, "plane_view", "YCbCr Plane View Tests", populateViewGroup);
822 }
823 
824 } // ycbcr
825 
826 } // vkt
827 
828