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