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::TestLog;
62 using de::MovePtr;
63 using de::UniquePtr;
64 using std::vector;
65 using std::string;
66 
67 typedef de::SharedPtr<Allocation>				AllocationSp;
68 typedef de::SharedPtr<vk::Unique<VkBuffer> >	VkBufferSp;
69 
getPlaneCompatibleFormat(VkFormat multiPlanarFormat,deUint32 planeNdx)70 VkFormat getPlaneCompatibleFormat (VkFormat multiPlanarFormat, deUint32 planeNdx)
71 {
72 	switch (multiPlanarFormat)
73 	{
74 		case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
75 		case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
76 		case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
77 			if (de::inRange(planeNdx, 0u, 2u))
78 				return VK_FORMAT_R8_UNORM;
79 			else
80 				break;
81 
82 		case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
83 		case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
84 			if (planeNdx == 0)
85 				return VK_FORMAT_R8_UNORM;
86 			else if (planeNdx == 1)
87 				return VK_FORMAT_R8G8_UNORM;
88 			else
89 				break;
90 
91 		case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
92 		case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
93 		case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
94 			if (de::inRange(planeNdx, 0u, 2u))
95 				return VK_FORMAT_R10X6_UNORM_PACK16;
96 			else
97 				break;
98 
99 		case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
100 		case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
101 			if (planeNdx == 0)
102 				return VK_FORMAT_R10X6_UNORM_PACK16;
103 			else if (planeNdx == 1)
104 				return VK_FORMAT_R10X6G10X6_UNORM_2PACK16;
105 			else
106 				break;
107 
108 		case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
109 		case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
110 		case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
111 			if (de::inRange(planeNdx, 0u, 2u))
112 				return VK_FORMAT_R12X4_UNORM_PACK16;
113 			else
114 				break;
115 
116 		case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
117 		case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
118 			if (planeNdx == 0)
119 				return VK_FORMAT_R12X4_UNORM_PACK16;
120 			else if (planeNdx == 1)
121 				return VK_FORMAT_R12X4G12X4_UNORM_2PACK16;
122 			else
123 				break;
124 
125 		case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
126 		case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
127 		case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
128 			if (de::inRange(planeNdx, 0u, 2u))
129 				return VK_FORMAT_R16_UNORM;
130 			else
131 				break;
132 
133 		case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
134 		case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
135 			if (planeNdx == 0)
136 				return VK_FORMAT_R16_UNORM;
137 			else if (planeNdx == 1)
138 				return VK_FORMAT_R16G16_UNORM;
139 			else
140 				break;
141 
142 		default:
143 			break;
144 	}
145 
146 	DE_FATAL("Invalid format and plane index combination");
147 	return VK_FORMAT_UNDEFINED;
148 }
149 
createTestImage(const DeviceInterface & vkd,VkDevice device,VkFormat format,const UVec2 & size,VkImageCreateFlags createFlags)150 Move<VkImage> createTestImage (const DeviceInterface&	vkd,
151 							   VkDevice					device,
152 							   VkFormat					format,
153 							   const UVec2&				size,
154 							   VkImageCreateFlags		createFlags)
155 {
156 	const VkImageCreateInfo		createInfo	=
157 	{
158 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
159 		DE_NULL,
160 		createFlags,
161 		VK_IMAGE_TYPE_2D,
162 		format,
163 		makeExtent3D(size.x(), size.y(), 1u),
164 		1u,		// mipLevels
165 		1u,		// arrayLayers
166 		VK_SAMPLE_COUNT_1_BIT,
167 		VK_IMAGE_TILING_OPTIMAL,
168 		VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT,
169 		VK_SHARING_MODE_EXCLUSIVE,
170 		0u,
171 		(const deUint32*)DE_NULL,
172 		VK_IMAGE_LAYOUT_UNDEFINED,
173 	};
174 
175 	return createImage(vkd, device, &createInfo);
176 }
177 
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format,VkImageAspectFlagBits imageAspect,VkSamplerYcbcrConversion conversion)178 Move<VkImageView> createImageView (const DeviceInterface&		vkd,
179 								   VkDevice						device,
180 								   VkImage						image,
181 								   VkFormat						format,
182 								   VkImageAspectFlagBits		imageAspect,
183 								   VkSamplerYcbcrConversion		conversion)
184 {
185 	const VkSamplerYcbcrConversionInfo	samplerConversionInfo	=
186 	{
187 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
188 		DE_NULL,
189 		conversion
190 	};
191 	const VkImageViewCreateInfo				viewInfo	=
192 	{
193 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
194 		&samplerConversionInfo,
195 		(VkImageViewCreateFlags)0,
196 		image,
197 		VK_IMAGE_VIEW_TYPE_2D,
198 		format,
199 		{
200 			VK_COMPONENT_SWIZZLE_IDENTITY,
201 			VK_COMPONENT_SWIZZLE_IDENTITY,
202 			VK_COMPONENT_SWIZZLE_IDENTITY,
203 			VK_COMPONENT_SWIZZLE_IDENTITY,
204 		},
205 		{ (VkImageAspectFlags)imageAspect, 0u, 1u, 0u, 1u },
206 	};
207 
208 	return createImageView(vkd, device, &viewInfo);
209 }
210 
211 // Descriptor layout for set 1:
212 // 0: Plane view bound as COMBINED_IMAGE_SAMPLER
213 // 1: "Whole" image bound as COMBINED_IMAGE_SAMPLER
214 //    + immutable sampler (required for color conversion)
215 
createDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkSampler conversionSampler)216 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler conversionSampler)
217 {
218 	const VkDescriptorSetLayoutBinding		bindings[]	=
219 	{
220 		{
221 			0u,												// binding
222 			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
223 			1u,												// descriptorCount
224 			VK_SHADER_STAGE_ALL,
225 			(const VkSampler*)DE_NULL
226 		},
227 		{
228 			1u,												// binding
229 			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
230 			1u,												// descriptorCount
231 			VK_SHADER_STAGE_ALL,
232 			&conversionSampler
233 		}
234 	};
235 	const VkDescriptorSetLayoutCreateInfo	layoutInfo	=
236 	{
237 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
238 		DE_NULL,
239 		(VkDescriptorSetLayoutCreateFlags)0u,
240 		DE_LENGTH_OF_ARRAY(bindings),
241 		bindings,
242 	};
243 
244 	return createDescriptorSetLayout(vkd, device, &layoutInfo);
245 }
246 
createDescriptorPool(const DeviceInterface & vkd,VkDevice device)247 Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device)
248 {
249 	const VkDescriptorPoolSize			poolSizes[]	=
250 	{
251 		{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	2u	},
252 	};
253 	const VkDescriptorPoolCreateInfo	poolInfo	=
254 	{
255 		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
256 		DE_NULL,
257 		(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
258 		1u,		// maxSets
259 		DE_LENGTH_OF_ARRAY(poolSizes),
260 		poolSizes,
261 	};
262 
263 	return createDescriptorPool(vkd, device, & poolInfo);
264 }
265 
createDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorPool descPool,VkDescriptorSetLayout descLayout,VkImageView planeView,VkSampler planeViewSampler,VkImageView wholeView,VkSampler wholeViewSampler)266 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface&	vkd,
267 										   VkDevice					device,
268 										   VkDescriptorPool			descPool,
269 										   VkDescriptorSetLayout	descLayout,
270 										   VkImageView				planeView,
271 										   VkSampler				planeViewSampler,
272 										   VkImageView				wholeView,
273 										   VkSampler				wholeViewSampler)
274 {
275 	Move<VkDescriptorSet>	descSet;
276 
277 	{
278 		const VkDescriptorSetAllocateInfo	allocInfo	=
279 		{
280 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
281 			DE_NULL,
282 			descPool,
283 			1u,
284 			&descLayout,
285 		};
286 
287 		descSet = allocateDescriptorSet(vkd, device, &allocInfo);
288 	}
289 
290 	{
291 		const VkDescriptorImageInfo		imageInfo0			=
292 		{
293 			planeViewSampler,
294 			planeView,
295 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
296 		};
297 		const VkDescriptorImageInfo		imageInfo1			=
298 		{
299 			wholeViewSampler,
300 			wholeView,
301 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
302 		};
303 		const VkWriteDescriptorSet		descriptorWrites[]		=
304 		{
305 			{
306 				VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
307 				DE_NULL,
308 				*descSet,
309 				0u,		// dstBinding
310 				0u,		// dstArrayElement
311 				1u,		// descriptorCount
312 				VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
313 				&imageInfo0,
314 				(const VkDescriptorBufferInfo*)DE_NULL,
315 				(const VkBufferView*)DE_NULL,
316 			},
317 			{
318 				VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
319 				DE_NULL,
320 				*descSet,
321 				1u,		// dstBinding
322 				0u,		// dstArrayElement
323 				1u,		// descriptorCount
324 				VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
325 				&imageInfo1,
326 				(const VkDescriptorBufferInfo*)DE_NULL,
327 				(const VkBufferView*)DE_NULL,
328 			}
329 		};
330 
331 		vkd.updateDescriptorSets(device, DE_LENGTH_OF_ARRAY(descriptorWrites), descriptorWrites, 0u, DE_NULL);
332 	}
333 
334 	return descSet;
335 }
336 
executeImageBarrier(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,VkPipelineStageFlags srcStage,VkPipelineStageFlags dstStage,const VkImageMemoryBarrier & barrier)337 void executeImageBarrier (const DeviceInterface&		vkd,
338 						  VkDevice						device,
339 						  deUint32						queueFamilyNdx,
340 						  VkPipelineStageFlags			srcStage,
341 						  VkPipelineStageFlags			dstStage,
342 						  const VkImageMemoryBarrier&	barrier)
343 {
344 	const VkQueue					queue		= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
345 	const Unique<VkCommandPool>		cmdPool		(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
346 	const Unique<VkCommandBuffer>	cmdBuffer	(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
347 
348 	beginCommandBuffer(vkd, *cmdBuffer);
349 
350 	vkd.cmdPipelineBarrier(*cmdBuffer,
351 						   srcStage,
352 						   dstStage,
353 						   (VkDependencyFlags)0u,
354 						   0u,
355 						   (const VkMemoryBarrier*)DE_NULL,
356 						   0u,
357 						   (const VkBufferMemoryBarrier*)DE_NULL,
358 						   1u,
359 						   &barrier);
360 
361 	endCommandBuffer(vkd, *cmdBuffer);
362 
363 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
364 }
365 
366 struct TestParameters
367 {
368 	enum ViewType
369 	{
370 		VIEWTYPE_IMAGE_VIEW	= 0,
371 		VIEWTYPE_MEMORY_ALIAS,
372 
373 		VIEWTYPE_LAST
374 	};
375 
376 	ViewType			viewType;
377 	VkFormat			format;
378 	UVec2				size;
379 	VkImageCreateFlags	createFlags;
380 	deUint32			planeNdx;
381 	glu::ShaderType		shaderType;
382 
TestParametersvkt::ycbcr::__anonc8b025170111::TestParameters383 	TestParameters (ViewType viewType_, VkFormat format_, const UVec2& size_, VkImageCreateFlags createFlags_, deUint32 planeNdx_, glu::ShaderType shaderType_)
384 		: viewType		(viewType_)
385 		, format		(format_)
386 		, size			(size_)
387 		, createFlags	(createFlags_)
388 		, planeNdx		(planeNdx_)
389 		, shaderType	(shaderType_)
390 	{
391 	}
392 
TestParametersvkt::ycbcr::__anonc8b025170111::TestParameters393 	TestParameters (void)
394 		: viewType		(VIEWTYPE_LAST)
395 		, format		(VK_FORMAT_UNDEFINED)
396 		, createFlags	(0u)
397 		, planeNdx		(0u)
398 		, shaderType	(glu::SHADERTYPE_LAST)
399 	{
400 	}
401 };
402 
getShaderSpec(const TestParameters &)403 ShaderSpec getShaderSpec (const TestParameters&)
404 {
405 	ShaderSpec spec;
406 
407 	spec.inputs.push_back(Symbol("texCoord", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
408 	spec.outputs.push_back(Symbol("result0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
409 	spec.outputs.push_back(Symbol("result1", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
410 
411 	spec.globalDeclarations =
412 		"layout(binding = 1, set = 1) uniform highp sampler2D u_image;\n"
413 		"layout(binding = 0, set = 1) uniform highp sampler2D u_planeView;\n";
414 
415 	spec.source =
416 		"result0 = texture(u_image, texCoord);\n"
417 		"result1 = texture(u_planeView, texCoord);\n";
418 
419 	return spec;
420 }
421 
422 
generateLookupCoordinates(const UVec2 & imageSize,size_t numCoords,de::Random * rnd,vector<Vec2> * dst)423 void generateLookupCoordinates (const UVec2& imageSize, size_t numCoords, de::Random* rnd, vector<Vec2>* dst)
424 {
425 	dst->resize(numCoords);
426 
427 	for (size_t coordNdx = 0; coordNdx < numCoords; ++coordNdx)
428 	{
429 		const deUint32	texelX	= rnd->getUint32() % imageSize.x();
430 		const deUint32	texelY	= rnd->getUint32() % imageSize.y();
431 		const float		x		= ((float)texelX + 0.5f) / (float)imageSize.x();
432 		const float		y		= ((float)texelY + 0.5f) / (float)imageSize.y();
433 
434 		(*dst)[coordNdx] = Vec2(x, y);
435 	}
436 }
437 
checkImageUsageSupport(Context & context,VkFormat format,VkImageUsageFlags usage)438 void checkImageUsageSupport (Context&			context,
439 							 VkFormat			format,
440 							 VkImageUsageFlags	usage)
441 {
442 	{
443 		const VkFormatProperties	formatProperties	= getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
444 																							context.getPhysicalDevice(),
445 																							format);
446 		const VkFormatFeatureFlags	featureFlags		= formatProperties.optimalTilingFeatures;
447 
448 		if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0
449 			&& (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0)
450 		{
451 			TCU_THROW(NotSupportedError, "Format doesn't support sampling");
452 		}
453 
454 		// Other image usages are not handled currently
455 		DE_ASSERT((usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT)) == 0);
456 	}
457 }
458 
checkSupport(Context & context,TestParameters params)459 void checkSupport(Context& context, TestParameters params)
460 {
461 	const VkFormat					planeViewFormat	= getPlaneCompatibleFormat(params.format, params.planeNdx);
462 	const VkImageUsageFlags			usage			= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
463 
464 	checkImageSupport(context, params.format, params.createFlags);
465 	checkImageUsageSupport(context, params.format, usage);
466 	checkImageUsageSupport(context, planeViewFormat, usage);
467 }
468 
testPlaneView(Context & context,TestParameters params)469 tcu::TestStatus testPlaneView (Context& context, TestParameters params)
470 {
471 	de::Random						randomGen		(deInt32Hash((deUint32)params.format)	^
472 													 deInt32Hash((deUint32)params.planeNdx)	^
473 													 deInt32Hash((deUint32)params.shaderType));
474 
475 	const DeviceInterface&			vkd				= context.getDeviceInterface();
476 	const VkDevice					device			= context.getDevice();
477 
478 	const VkFormat					format			= params.format;
479 	const VkImageCreateFlags		createFlags		= params.createFlags;
480 	const VkFormat					planeViewFormat	= getPlaneCompatibleFormat(format, params.planeNdx);
481 	const PlanarFormatDescription	formatInfo		= getPlanarFormatDescription(format);
482 	const UVec2						size			= params.size;
483 	const UVec2						planeSize		(size.x() / formatInfo.planes[params.planeNdx].widthDivisor,
484 													 size.y() / formatInfo.planes[params.planeNdx].heightDivisor);
485 
486 	const Unique<VkImage>			image			(createTestImage(vkd, device, format, size, createFlags));
487 	const Unique<VkImage>			imageAlias		((params.viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS)
488 													 ? createTestImage(vkd, device, planeViewFormat, planeSize, createFlags)
489 													 : Move<VkImage>());
490 	const vector<AllocationSp>		allocations		(allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags));
491 
492 	if (imageAlias)
493 		VK_CHECK(vkd.bindImageMemory(device, *imageAlias, allocations[params.planeNdx]->getMemory(), allocations[params.planeNdx]->getOffset()));
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 Unique<VkImageView>					wholeView	(createImageView(vkd, device, *image, format, VK_IMAGE_ASPECT_COLOR_BIT, *conversion));
515 	const Unique<VkImageView>					planeView	(createImageView(vkd,
516 																			 device,
517 																			 !imageAlias ? *image : *imageAlias,
518 																			 planeViewFormat,
519 																			 !imageAlias ? getPlaneAspect(params.planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT,
520 																			 *conversion));
521 
522 	const VkSamplerYcbcrConversionInfo			samplerConversionInfo	=
523 	{
524 		VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
525 		DE_NULL,
526 		*conversion,
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 	const Unique<VkSampler>					wholeSampler(createSampler(vkd, device, &wholeSamplerInfo));
572 	const Unique<VkSampler>					planeSampler(createSampler(vkd, device, &planeSamplerInfo));
573 
574 	const Unique<VkDescriptorSetLayout>		descLayout	(createDescriptorSetLayout(vkd, device, *wholeSampler));
575 	const Unique<VkDescriptorPool>			descPool	(createDescriptorPool(vkd, device));
576 	const Unique<VkDescriptorSet>			descSet		(createDescriptorSet(vkd, device, *descPool, *descLayout, *planeView, *planeSampler, *wholeView, *wholeSampler));
577 
578 	MultiPlaneImageData						imageData	(format, size);
579 
580 	// Prepare texture data
581 	fillRandom(&randomGen, &imageData);
582 
583 	if (imageAlias)
584 	{
585 		// Transition alias to right layout first
586 		const VkImageMemoryBarrier		initAliasBarrier	=
587 		{
588 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
589 			DE_NULL,
590 			(VkAccessFlags)0,
591 			VK_ACCESS_SHADER_READ_BIT,
592 			VK_IMAGE_LAYOUT_UNDEFINED,
593 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
594 			VK_QUEUE_FAMILY_IGNORED,
595 			VK_QUEUE_FAMILY_IGNORED,
596 			*imageAlias,
597 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
598 		};
599 
600 		executeImageBarrier(vkd,
601 							device,
602 							context.getUniversalQueueFamilyIndex(),
603 							(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
604 							(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
605 							initAliasBarrier);
606 	}
607 
608 	// Upload and prepare image
609 	uploadImage(vkd,
610 				device,
611 				context.getUniversalQueueFamilyIndex(),
612 				context.getDefaultAllocator(),
613 				*image,
614 				imageData,
615 				(VkAccessFlags)VK_ACCESS_SHADER_READ_BIT,
616 				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
617 
618 	{
619 		const size_t	numValues		= 500;
620 		vector<Vec2>	texCoord		(numValues);
621 		vector<Vec4>	resultWhole		(numValues);
622 		vector<Vec4>	resultPlane		(numValues);
623 		vector<Vec4>	referenceWhole	(numValues);
624 		vector<Vec4>	referencePlane	(numValues);
625 		bool			allOk			= true;
626 		Vec4			threshold		(0.02f);
627 
628 		generateLookupCoordinates(size, numValues, &randomGen, &texCoord);
629 
630 		{
631 			UniquePtr<ShaderExecutor>	executor	(createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
632 			const void*					inputs[]	= { texCoord[0].getPtr() };
633 			void*						outputs[]	= { resultWhole[0].getPtr(), resultPlane[0].getPtr() };
634 
635 			executor->execute((int)numValues, inputs, outputs, *descSet);
636 		}
637 
638 		// Whole image sampling reference
639 		for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
640 		{
641 			if (formatInfo.hasChannelNdx(channelNdx))
642 			{
643 				const tcu::ConstPixelBufferAccess	channelAccess	= imageData.getChannelAccess(channelNdx);
644 				const tcu::Sampler					refSampler		= mapVkSampler(wholeSamplerInfo);
645 				const tcu::Texture2DView			refTexView		(1u, &channelAccess);
646 
647 				for (size_t ndx = 0; ndx < numValues; ++ndx)
648 				{
649 					const Vec2&	coord	= texCoord[ndx];
650 					referenceWhole[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0];
651 				}
652 			}
653 			else
654 			{
655 				for (size_t ndx = 0; ndx < numValues; ++ndx)
656 					referenceWhole[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f;
657 			}
658 		}
659 
660 		// Plane view sampling reference
661 		{
662 			const tcu::ConstPixelBufferAccess	planeAccess		(mapVkFormat(planeViewFormat),
663 																 tcu::IVec3((int)planeSize.x(), (int)planeSize.y(), 1),
664 																 imageData.getPlanePtr(params.planeNdx));
665 			const tcu::Sampler					refSampler		= mapVkSampler(planeSamplerInfo);
666 			const tcu::Texture2DView			refTexView		(1u, &planeAccess);
667 
668 			for (size_t ndx = 0; ndx < numValues; ++ndx)
669 			{
670 				const Vec2&	coord	= texCoord[ndx];
671 				referencePlane[ndx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f);
672 			}
673 		}
674 
675 		for (int viewNdx = 0; viewNdx < 2; ++viewNdx)
676 		{
677 			const char* const	viewName	= (viewNdx == 0) ? "complete image"	: "plane view";
678 			const vector<Vec4>&	reference	= (viewNdx == 0) ? referenceWhole	: referencePlane;
679 			const vector<Vec4>&	result		= (viewNdx == 0) ? resultWhole		: resultPlane;
680 
681 			for (size_t ndx = 0; ndx < numValues; ++ndx)
682 			{
683 				if (boolAny(greaterThanEqual(abs(result[ndx] - reference[ndx]), threshold)))
684 				{
685 					context.getTestContext().getLog()
686 						<< TestLog::Message << "ERROR: When sampling " << viewName << " at " << texCoord[ndx]
687 											<< ": got " << result[ndx]
688 											<< ", expected " << reference[ndx]
689 						<< TestLog::EndMessage;
690 					allOk = false;
691 				}
692 			}
693 		}
694 
695 		if (allOk)
696 			return tcu::TestStatus::pass("All samples passed");
697 		else
698 			return tcu::TestStatus::fail("Got invalid results");
699 	}
700 }
701 
initPrograms(SourceCollections & dst,TestParameters params)702 void initPrograms (SourceCollections& dst, TestParameters params)
703 {
704 	const ShaderSpec	spec	= getShaderSpec(params);
705 
706 	generateSources(params.shaderType, spec, dst);
707 }
708 
addPlaneViewCase(tcu::TestCaseGroup * group,const TestParameters & params)709 void addPlaneViewCase (tcu::TestCaseGroup* group, const TestParameters& params)
710 {
711 	std::ostringstream name;
712 
713 	name << de::toLower(de::toString(params.format).substr(10));
714 
715 	if ((params.viewType != TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
716 		((params.createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0))
717 		name << "_disjoint";
718 
719 	name << "_plane_" << params.planeNdx;
720 
721 	addFunctionCaseWithPrograms(group, name.str(), "", checkSupport, initPrograms, testPlaneView, params);
722 }
723 
populateViewTypeGroup(tcu::TestCaseGroup * group,TestParameters::ViewType viewType)724 void populateViewTypeGroup (tcu::TestCaseGroup* group, TestParameters::ViewType viewType)
725 {
726 	const glu::ShaderType		shaderType	= glu::SHADERTYPE_FRAGMENT;
727 	const UVec2					size		(32, 58);
728 	const VkImageCreateFlags	baseFlags	= (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
729 											| (viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS ? (VkImageCreateFlags)VK_IMAGE_CREATE_ALIAS_BIT : 0u);
730 
731 	for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
732 	{
733 		const VkFormat	format		= (VkFormat)formatNdx;
734 		const deUint32	numPlanes	= getPlaneCount(format);
735 
736 		if (numPlanes == 1)
737 			continue; // Plane views not possible
738 
739 		for (int isDisjoint = 0; isDisjoint < 2; ++isDisjoint)
740 		{
741 			const VkImageCreateFlags	flags	= baseFlags | (isDisjoint == 1 ? (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT : 0u);
742 
743 			if ((viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
744 				((flags & VK_IMAGE_CREATE_DISJOINT_BIT) == 0))
745 				continue; // Memory alias cases require disjoint planes
746 
747 			for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
748 				addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, shaderType));
749 		}
750 	}
751 }
752 
populateViewGroup(tcu::TestCaseGroup * group)753 void populateViewGroup (tcu::TestCaseGroup* group)
754 {
755 	addTestGroup(group, "image_view",	"Plane View via VkImageView",		populateViewTypeGroup,	TestParameters::VIEWTYPE_IMAGE_VIEW);
756 	addTestGroup(group, "memory_alias",	"Plane View via Memory Aliasing",	populateViewTypeGroup,	TestParameters::VIEWTYPE_MEMORY_ALIAS);
757 }
758 
759 } // anonymous
760 
createViewTests(tcu::TestContext & testCtx)761 tcu::TestCaseGroup* createViewTests (tcu::TestContext& testCtx)
762 {
763 	// \todo [2017-05-24 pyry] Extend with memory alias views
764 	return createTestGroup(testCtx, "plane_view", "YCbCr Plane View Tests", populateViewGroup);
765 }
766 
767 } // ycbcr
768 } // vkt
769 
770