1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Imagination Technologies Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Image sampling case
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineImageSamplingInstance.hpp"
26 #include "vktPipelineClearUtil.hpp"
27 #include "vktPipelineReferenceRenderer.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkImageUtil.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkObjUtil.hpp"
37 #include "tcuTexLookupVerifier.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuTestLog.hpp"
40 #include "deSTLUtil.hpp"
41 
42 namespace vkt
43 {
44 namespace pipeline
45 {
46 
47 using namespace vk;
48 using de::MovePtr;
49 using de::UniquePtr;
50 
51 namespace
52 {
allocateBuffer(const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkBuffer& buffer, const MemoryRequirement requirement, Allocator& allocator, AllocationKind allocationKind)53 de::MovePtr<Allocation> allocateBuffer (const InstanceInterface&	vki,
54 										const DeviceInterface&		vkd,
55 										const VkPhysicalDevice&		physDevice,
56 										const VkDevice				device,
57 										const VkBuffer&				buffer,
58 										const MemoryRequirement		requirement,
59 										Allocator&					allocator,
60 										AllocationKind				allocationKind)
61 {
62 	switch (allocationKind)
63 	{
64 		case ALLOCATION_KIND_SUBALLOCATED:
65 		{
66 			const VkMemoryRequirements	memoryRequirements	= getBufferMemoryRequirements(vkd, device, buffer);
67 
68 			return allocator.allocate(memoryRequirements, requirement);
69 		}
70 
71 		case ALLOCATION_KIND_DEDICATED:
72 		{
73 			return allocateDedicated(vki, vkd, physDevice, device, buffer, requirement);
74 		}
75 
76 		default:
77 		{
78 			TCU_THROW(InternalError, "Invalid allocation kind");
79 		}
80 	}
81 }
82 
allocateImage(const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkImage& image, const MemoryRequirement requirement, Allocator& allocator, AllocationKind allocationKind)83 de::MovePtr<Allocation> allocateImage (const InstanceInterface&		vki,
84 									   const DeviceInterface&		vkd,
85 									   const VkPhysicalDevice&		physDevice,
86 									   const VkDevice				device,
87 									   const VkImage&				image,
88 									   const MemoryRequirement		requirement,
89 									   Allocator&					allocator,
90 									   AllocationKind				allocationKind)
91 {
92 	switch (allocationKind)
93 	{
94 		case ALLOCATION_KIND_SUBALLOCATED:
95 		{
96 			const VkMemoryRequirements	memoryRequirements	= getImageMemoryRequirements(vkd, device, image);
97 
98 			return allocator.allocate(memoryRequirements, requirement);
99 		}
100 
101 		case ALLOCATION_KIND_DEDICATED:
102 		{
103 			return allocateDedicated(vki, vkd, physDevice, device, image, requirement);
104 		}
105 
106 		default:
107 		{
108 			TCU_THROW(InternalError, "Invalid allocation kind");
109 		}
110 	}
111 }
112 
getCompatibleImageType(VkImageViewType viewType)113 static VkImageType getCompatibleImageType (VkImageViewType viewType)
114 {
115 	switch (viewType)
116 	{
117 		case VK_IMAGE_VIEW_TYPE_1D:				return VK_IMAGE_TYPE_1D;
118 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:		return VK_IMAGE_TYPE_1D;
119 		case VK_IMAGE_VIEW_TYPE_2D:				return VK_IMAGE_TYPE_2D;
120 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:		return VK_IMAGE_TYPE_2D;
121 		case VK_IMAGE_VIEW_TYPE_3D:				return VK_IMAGE_TYPE_3D;
122 		case VK_IMAGE_VIEW_TYPE_CUBE:			return VK_IMAGE_TYPE_2D;
123 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:		return VK_IMAGE_TYPE_2D;
124 		default:
125 			break;
126 	}
127 
128 	DE_ASSERT(false);
129 	return VK_IMAGE_TYPE_1D;
130 }
131 
132 template<typename TcuFormatType>
createTestTexture(const TcuFormatType format, VkImageViewType viewType, const tcu::IVec3& size, int layerCount)133 static MovePtr<TestTexture> createTestTexture (const TcuFormatType format, VkImageViewType viewType, const tcu::IVec3& size, int layerCount)
134 {
135 	MovePtr<TestTexture>	texture;
136 	const VkImageType		imageType = getCompatibleImageType(viewType);
137 
138 	switch (imageType)
139 	{
140 		case VK_IMAGE_TYPE_1D:
141 			if (layerCount == 1)
142 				texture = MovePtr<TestTexture>(new TestTexture1D(format, size.x()));
143 			else
144 				texture = MovePtr<TestTexture>(new TestTexture1DArray(format, size.x(), layerCount));
145 
146 			break;
147 
148 		case VK_IMAGE_TYPE_2D:
149 			if (layerCount == 1)
150 			{
151 				texture = MovePtr<TestTexture>(new TestTexture2D(format, size.x(), size.y()));
152 			}
153 			else
154 			{
155 				if (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
156 				{
157 					if (layerCount == tcu::CUBEFACE_LAST && viewType == VK_IMAGE_VIEW_TYPE_CUBE)
158 					{
159 						texture = MovePtr<TestTexture>(new TestTextureCube(format, size.x()));
160 					}
161 					else
162 					{
163 						DE_ASSERT(layerCount % tcu::CUBEFACE_LAST == 0);
164 
165 						texture = MovePtr<TestTexture>(new TestTextureCubeArray(format, size.x(), layerCount));
166 					}
167 				}
168 				else
169 				{
170 					texture = MovePtr<TestTexture>(new TestTexture2DArray(format, size.x(), size.y(), layerCount));
171 				}
172 			}
173 
174 			break;
175 
176 		case VK_IMAGE_TYPE_3D:
177 			texture = MovePtr<TestTexture>(new TestTexture3D(format, size.x(), size.y(), size.z()));
178 			break;
179 
180 		default:
181 			DE_ASSERT(false);
182 	}
183 
184 	return texture;
185 }
186 
187 } // anonymous
188 
checkSupportImageSamplingInstance(Context& context, ImageSamplingInstanceParams params)189 void checkSupportImageSamplingInstance (Context& context, ImageSamplingInstanceParams params)
190 {
191 
192 	if (de::abs(params.samplerParams.mipLodBias) > context.getDeviceProperties().limits.maxSamplerLodBias)
193 		TCU_THROW(NotSupportedError, "Unsupported sampler Lod bias value");
194 
195 	if (!isSupportedSamplableFormat(context.getInstanceInterface(), context.getPhysicalDevice(), params.imageFormat))
196 		throw tcu::NotSupportedError(std::string("Unsupported format for sampling: ") + getFormatName(params.imageFormat));
197 
198 	if ((deUint32)params.imageCount > context.getDeviceProperties().limits.maxColorAttachments)
199 		throw tcu::NotSupportedError(std::string("Unsupported render target count: ") + de::toString(params.imageCount));
200 
201 	if ((params.samplerParams.minFilter == VK_FILTER_LINEAR ||
202 		 params.samplerParams.magFilter == VK_FILTER_LINEAR ||
203 		 params.samplerParams.mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR) &&
204 		!isLinearFilteringSupported(context.getInstanceInterface(), context.getPhysicalDevice(), params.imageFormat, VK_IMAGE_TILING_OPTIMAL))
205 		throw tcu::NotSupportedError(std::string("Unsupported format for linear filtering: ") + getFormatName(params.imageFormat));
206 
207 	if (params.separateStencilUsage)
208 	{
209 		context.requireDeviceFunctionality("VK_EXT_separate_stencil_usage");
210 		context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
211 
212 		const VkImageStencilUsageCreateInfo  stencilUsage	=
213 		{
214 			VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO,
215 			DE_NULL,
216 			VK_IMAGE_USAGE_TRANSFER_DST_BIT
217 		};
218 
219 		const VkPhysicalDeviceImageFormatInfo2	formatInfo2		=
220 		{
221 			VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,		//	VkStructureType			sType
222 			params.separateStencilUsage ? &stencilUsage
223 										: DE_NULL,						//	const void*				pNext
224 			params.imageFormat,											//	VkFormat				format
225 			getCompatibleImageType(params.imageViewType),				//	VkImageType				type
226 			VK_IMAGE_TILING_OPTIMAL,									//	VkImageTiling			tiling
227 			VK_IMAGE_USAGE_SAMPLED_BIT
228 			| VK_IMAGE_USAGE_TRANSFER_DST_BIT,							//	VkImageUsageFlags		usage
229 			(VkImageCreateFlags)0u										//	VkImageCreateFlags		flags
230 		};
231 
232 		VkImageFormatProperties2				extProperties	=
233 		{
234 			VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
235 			DE_NULL,
236 			{
237 				{
238 					0,	// width
239 					0,	// height
240 					0,	// depth
241 				},
242 				0u,		// maxMipLevels
243 				0u,		// maxArrayLayers
244 				0,		// sampleCounts
245 				0u,		// maxResourceSize
246 			},
247 		};
248 
249 		if ((context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &formatInfo2, &extProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
250 			|| extProperties.imageFormatProperties.maxExtent.width < (deUint32)params.imageSize.x()
251 			|| extProperties.imageFormatProperties.maxExtent.height < (deUint32)params.imageSize.y())
252 		{
253 			TCU_THROW(NotSupportedError, "Image format not supported");
254 		}
255 	}
256 
257 	void const* pNext = params.samplerParams.pNext;
258 	while (pNext != DE_NULL)
259 	{
260 		const VkStructureType nextType = *reinterpret_cast<const VkStructureType*>(pNext);
261 		switch (nextType)
262 		{
263 			case VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO:
264 			{
265 				context.requireDeviceFunctionality("VK_EXT_sampler_filter_minmax");
266 
267 				if (!isMinMaxFilteringSupported(context.getInstanceInterface(), context.getPhysicalDevice(), params.imageFormat, VK_IMAGE_TILING_OPTIMAL))
268 					throw tcu::NotSupportedError(std::string("Unsupported format for min/max filtering: ") + getFormatName(params.imageFormat));
269 
270 				pNext = reinterpret_cast<const VkSamplerReductionModeCreateInfo*>(pNext)->pNext;
271 				break;
272 			}
273 			case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO:
274 				context.requireDeviceFunctionality("VK_KHR_sampler_ycbcr_conversion");
275 
276 				pNext = reinterpret_cast<const VkSamplerYcbcrConversionInfo*>(pNext)->pNext;
277 				break;
278 			case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT:
279 				pNext = reinterpret_cast<const VkSamplerCustomBorderColorCreateInfoEXT*>(pNext)->pNext;
280 
281 				if (!context.getCustomBorderColorFeaturesEXT().customBorderColors)
282 				{
283 					throw tcu::NotSupportedError("customBorderColors feature is not supported");
284 				}
285 
286 				break;
287 			default:
288 				TCU_FAIL("Unrecognized sType in chained sampler create info");
289 		}
290 	}
291 
292 	if (params.samplerParams.addressModeU == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
293 		params.samplerParams.addressModeV == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
294 		params.samplerParams.addressModeW == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE)
295 	{
296 		context.requireDeviceFunctionality("VK_KHR_sampler_mirror_clamp_to_edge");
297 	}
298 
299 	if ((isCompressedFormat(params.imageFormat) || isDepthStencilFormat(params.imageFormat)) && params.imageViewType == VK_IMAGE_VIEW_TYPE_3D)
300 	{
301 		// \todo [2016-01-22 pyry] Mandate VK_ERROR_FORMAT_NOT_SUPPORTED
302 		try
303 		{
304 			const VkImageFormatProperties	formatProperties	= getPhysicalDeviceImageFormatProperties(context.getInstanceInterface(),
305 																										 context.getPhysicalDevice(),
306 																										 params.imageFormat,
307 																										 VK_IMAGE_TYPE_3D,
308 																										 VK_IMAGE_TILING_OPTIMAL,
309 																										 VK_IMAGE_USAGE_SAMPLED_BIT,
310 																										 (VkImageCreateFlags)0);
311 
312 			if (formatProperties.maxExtent.width == 0 &&
313 				formatProperties.maxExtent.height == 0 &&
314 				formatProperties.maxExtent.depth == 0)
315 				TCU_THROW(NotSupportedError, "3D compressed or depth format not supported");
316 		}
317 		catch (const Error&)
318 		{
319 			TCU_THROW(NotSupportedError, "3D compressed or depth format not supported");
320 		}
321 	}
322 
323 	if (params.imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
324 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
325 
326 	if (params.allocationKind == ALLOCATION_KIND_DEDICATED)
327 		context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
328 
329 #ifndef CTS_USES_VULKANSC
330 	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
331 	{
332 		const auto portabilitySubsetFeatures	= context.getPortabilitySubsetFeatures();
333 		const auto componentMapping				= params.componentMapping;
334 		if (!portabilitySubsetFeatures.imageViewFormatSwizzle &&
335 			((componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY) ||
336 			 (componentMapping.g != VK_COMPONENT_SWIZZLE_IDENTITY) ||
337 			 (componentMapping.b != VK_COMPONENT_SWIZZLE_IDENTITY) ||
338 			 (componentMapping.a != VK_COMPONENT_SWIZZLE_IDENTITY)))
339 		{
340 			TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support remapping format components");
341 		}
342 	}
343 
344 	bool formatRgba10x6WithoutYCbCrSampler = context.getRGBA10X6FormatsFeaturesEXT().formatRgba10x6WithoutYCbCrSampler;
345 #else
346 	bool formatRgba10x6WithoutYCbCrSampler = VK_FALSE;
347 #endif // CTS_USES_VULKANSC
348 
349 	if ((params.imageFormat == VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) && (params.subresourceRange.levelCount > 1) && (formatRgba10x6WithoutYCbCrSampler == VK_FALSE))
350 	{
351 		TCU_THROW(NotSupportedError, "formatRgba10x6WithoutYCbCrSampler not supported");
352 	}
353 }
354 
ImageSamplingInstance(Context& context, ImageSamplingInstanceParams params)355 ImageSamplingInstance::ImageSamplingInstance (Context&						context,
356 											  ImageSamplingInstanceParams	params)
357 	: vkt::TestInstance				(context)
358 	, m_allocationKind				(params.allocationKind)
359 	, m_samplingType				(params.samplingType)
360 	, m_imageViewType				(params.imageViewType)
361 	, m_imageFormat					(params.imageFormat)
362 	, m_imageSize					(params.imageSize)
363 	, m_layerCount					(params.layerCount)
364 	, m_imageCount					(params.imageCount)
365 	, m_componentMapping			(params.componentMapping)
366 	, m_componentMask				(true)
367 	, m_subresourceRange			(params.subresourceRange)
368 	, m_samplerParams				(params.samplerParams)
369 	, m_samplerLod					(params.samplerLod)
370 	, m_renderSize					(params.renderSize)
371 	, m_colorFormat					(VK_FORMAT_R8G8B8A8_UNORM)
372 	, m_vertices					(params.vertices)
373 	, m_graphicsPipeline			(context.getDeviceInterface(), context.getDevice(), params.pipelineConstructionType, params.pipelineCreateFlags)
374 	, m_pipelineConstructionType	(params.pipelineConstructionType)
375 	, m_imageLayout					(params.imageLayout)
376 {
377 }
378 
setup()379 void ImageSamplingInstance::setup ()
380 {
381 	const InstanceInterface&				vki						= m_context.getInstanceInterface();
382 	const DeviceInterface&					vk						= m_context.getDeviceInterface();
383 	const VkPhysicalDevice					physDevice				= m_context.getPhysicalDevice();
384 	const VkDevice							vkDevice				= m_context.getDevice();
385 	const VkQueue							queue					= m_context.getUniversalQueue();
386 	const deUint32							queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
387 	SimpleAllocator							memAlloc				(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
388 	const VkComponentMapping				componentMappingRGBA	= { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
389 
390 	void const* pNext = m_samplerParams.pNext;
391 	while (pNext != DE_NULL)
392 	{
393 		const VkStructureType nextType = *reinterpret_cast<const VkStructureType*>(pNext);
394 		switch (nextType)
395 		{
396 			case VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO:
397 			{
398 				VkPhysicalDeviceSamplerFilterMinmaxProperties	physicalDeviceSamplerMinMaxProperties =
399 				{
400 					VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES,
401 					DE_NULL,
402 					DE_FALSE,
403 					DE_FALSE
404 				};
405 				VkPhysicalDeviceProperties2						physicalDeviceProperties;
406 				physicalDeviceProperties.sType	= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
407 				physicalDeviceProperties.pNext	= &physicalDeviceSamplerMinMaxProperties;
408 
409 				vki.getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &physicalDeviceProperties);
410 
411 				if (physicalDeviceSamplerMinMaxProperties.filterMinmaxImageComponentMapping != VK_TRUE)
412 				{
413 					// If filterMinmaxImageComponentMapping is VK_FALSE the component mapping of the image
414 					// view used with min/max filtering must have been created with the r component set to
415 					// VK_COMPONENT_SWIZZLE_IDENTITY. Only the r component of the sampled image value is
416 					// defined and the other component values are undefined
417 
418 					m_componentMask = tcu::BVec4(true, false, false, false);
419 
420 					if (m_componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY && m_componentMapping.r != VK_COMPONENT_SWIZZLE_R)
421 					{
422 						TCU_THROW(NotSupportedError, "filterMinmaxImageComponentMapping is not supported (R mapping is not IDENTITY)");
423 					}
424 				}
425 				pNext = reinterpret_cast<const VkSamplerReductionModeCreateInfo*>(pNext)->pNext;
426 			}
427 			break;
428 			case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO:
429 				pNext = reinterpret_cast<const VkSamplerYcbcrConversionInfo*>(pNext)->pNext;
430 				break;
431 			case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT:
432 			{
433 				const VkSamplerCustomBorderColorCreateInfoEXT customBorderColorCreateInfo = *reinterpret_cast<const VkSamplerCustomBorderColorCreateInfoEXT*>(pNext);
434 
435 				VkPhysicalDeviceCustomBorderColorFeaturesEXT	physicalDeviceCustomBorderColorFeatures =
436 				{
437 					VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT,
438 					DE_NULL,
439 					DE_FALSE,
440 					DE_FALSE
441 				};
442 				VkPhysicalDeviceFeatures2						physicalDeviceFeatures;
443 				physicalDeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
444 				physicalDeviceFeatures.pNext = &physicalDeviceCustomBorderColorFeatures;
445 
446 				vki.getPhysicalDeviceFeatures2(m_context.getPhysicalDevice(), &physicalDeviceFeatures);
447 
448 				if (physicalDeviceCustomBorderColorFeatures.customBorderColors != VK_TRUE)
449 				{
450 					TCU_THROW(NotSupportedError, "customBorderColors are not supported");
451 				}
452 
453 				if (physicalDeviceCustomBorderColorFeatures.customBorderColorWithoutFormat != VK_TRUE &&
454 					customBorderColorCreateInfo.format == VK_FORMAT_UNDEFINED)
455 				{
456 					TCU_THROW(NotSupportedError, "customBorderColorWithoutFormat is not supported");
457 				}
458 
459 				pNext = reinterpret_cast<const VkSamplerCustomBorderColorCreateInfoEXT*>(pNext)->pNext;
460 			}
461 			break;
462 			default:
463 				TCU_FAIL("Unrecognized sType in chained sampler create info");
464 		}
465 	}
466 
467 	// Create texture images, views and samplers
468 	{
469 		VkImageCreateFlags			imageFlags			= 0u;
470 
471 		if (m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE || m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
472 			imageFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
473 
474 		// Initialize texture data
475 		if (isCompressedFormat(m_imageFormat))
476 			m_texture = createTestTexture(mapVkCompressedFormat(m_imageFormat), m_imageViewType, m_imageSize, m_layerCount);
477 		else
478 			m_texture = createTestTexture(mapVkFormat(m_imageFormat), m_imageViewType, m_imageSize, m_layerCount);
479 
480 		const VkImageCreateInfo	imageParams =
481 		{
482 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,							// VkStructureType			sType;
483 			DE_NULL,														// const void*				pNext;
484 			imageFlags,														// VkImageCreateFlags		flags;
485 			getCompatibleImageType(m_imageViewType),						// VkImageType				imageType;
486 			m_imageFormat,													// VkFormat					format;
487 			{																// VkExtent3D				extent;
488 				(deUint32)m_imageSize.x(),
489 				(deUint32)m_imageSize.y(),
490 				(deUint32)m_imageSize.z()
491 			},
492 			(deUint32)m_texture->getNumLevels(),							// deUint32					mipLevels;
493 			(deUint32)m_layerCount,											// deUint32					arrayLayers;
494 			VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits	samples;
495 			VK_IMAGE_TILING_OPTIMAL,										// VkImageTiling			tiling;
496 			VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,	// VkImageUsageFlags		usage;
497 			VK_SHARING_MODE_EXCLUSIVE,										// VkSharingMode			sharingMode;
498 			1u,																// deUint32					queueFamilyIndexCount;
499 			&queueFamilyIndex,												// const deUint32*			pQueueFamilyIndices;
500 			VK_IMAGE_LAYOUT_UNDEFINED										// VkImageLayout			initialLayout;
501 		};
502 
503 		m_images.resize(m_imageCount);
504 		m_imageAllocs.resize(m_imageCount);
505 		m_imageViews.resize(m_imageCount);
506 
507 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
508 		{
509 			m_images[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &imageParams)));
510 			m_imageAllocs[imgNdx] = SharedAllocPtr(new UniqueAlloc(allocateImage(vki, vk, physDevice, vkDevice, **m_images[imgNdx], MemoryRequirement::Any, memAlloc, m_allocationKind)));
511 			VK_CHECK(vk.bindImageMemory(vkDevice, **m_images[imgNdx], (*m_imageAllocs[imgNdx])->getMemory(), (*m_imageAllocs[imgNdx])->getOffset()));
512 
513 			// Upload texture data
514 			uploadTestTexture(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_texture, **m_images[imgNdx]);
515 
516 			// Create image view and sampler
517 			const VkImageViewCreateInfo imageViewParams =
518 			{
519 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType			sType;
520 				DE_NULL,									// const void*				pNext;
521 				0u,											// VkImageViewCreateFlags	flags;
522 				**m_images[imgNdx],							// VkImage					image;
523 				m_imageViewType,							// VkImageViewType			viewType;
524 				m_imageFormat,								// VkFormat					format;
525 				m_componentMapping,							// VkComponentMapping		components;
526 				m_subresourceRange,							// VkImageSubresourceRange	subresourceRange;
527 			};
528 
529 			m_imageViews[imgNdx] = SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &imageViewParams)));
530 		}
531 
532 		m_sampler	= createSampler(vk, vkDevice, &m_samplerParams);
533 	}
534 
535 	// Create descriptor set for image and sampler
536 	{
537 		DescriptorPoolBuilder descriptorPoolBuilder;
538 		if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
539 			descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER, 1u);
540 		descriptorPoolBuilder.addType(m_samplingType, m_imageCount);
541 		m_descriptorPool = descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
542 			m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? m_imageCount + 1u : m_imageCount);
543 
544 		DescriptorSetLayoutBuilder setLayoutBuilder;
545 		if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
546 			setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
547 		setLayoutBuilder.addArrayBinding(m_samplingType, m_imageCount, VK_SHADER_STAGE_FRAGMENT_BIT);
548 		m_descriptorSetLayout = setLayoutBuilder.build(vk, vkDevice);
549 
550 		const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
551 		{
552 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
553 			DE_NULL,											// const void*					pNext;
554 			*m_descriptorPool,									// VkDescriptorPool				descriptorPool;
555 			1u,													// deUint32						setLayoutCount;
556 			&m_descriptorSetLayout.get()						// const VkDescriptorSetLayout*	pSetLayouts;
557 		};
558 
559 		m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocateInfo);
560 
561 		const VkSampler sampler = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? DE_NULL : *m_sampler;
562 		std::vector<VkDescriptorImageInfo> descriptorImageInfo(m_imageCount);
563 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
564 		{
565 			descriptorImageInfo[imgNdx].sampler		= sampler;									// VkSampler		sampler;
566 			descriptorImageInfo[imgNdx].imageView	= **m_imageViews[imgNdx];					// VkImageView		imageView;
567 			descriptorImageInfo[imgNdx].imageLayout	= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;	// VkImageLayout	imageLayout;
568 		}
569 
570 		DescriptorSetUpdateBuilder setUpdateBuilder;
571 		if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
572 		{
573 			const VkDescriptorImageInfo descriptorSamplerInfo =
574 			{
575 				*m_sampler,									// VkSampler		sampler;
576 				DE_NULL,									// VkImageView		imageView;
577 				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL	// VkImageLayout	imageLayout;
578 			};
579 			setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_SAMPLER, &descriptorSamplerInfo);
580 		}
581 
582 		const deUint32 binding = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? 1u : 0u;
583 		setUpdateBuilder.writeArray(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(binding), m_samplingType, m_imageCount, descriptorImageInfo.data());
584 		setUpdateBuilder.update(vk, vkDevice);
585 	}
586 
587 	// Create color images and views
588 	{
589 		const VkImageCreateInfo colorImageParams =
590 		{
591 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
592 			DE_NULL,																	// const void*				pNext;
593 			0u,																			// VkImageCreateFlags		flags;
594 			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
595 			m_colorFormat,																// VkFormat					format;
596 			{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y(), 1u },				// VkExtent3D				extent;
597 			1u,																			// deUint32					mipLevels;
598 			1u,																			// deUint32					arrayLayers;
599 			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
600 			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
601 			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,		// VkImageUsageFlags		usage;
602 			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
603 			1u,																			// deUint32					queueFamilyIndexCount;
604 			&queueFamilyIndex,															// const deUint32*			pQueueFamilyIndices;
605 			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout			initialLayout;
606 		};
607 
608 		m_colorImages.resize(m_imageCount);
609 		m_colorImageAllocs.resize(m_imageCount);
610 		m_colorAttachmentViews.resize(m_imageCount);
611 
612 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
613 		{
614 			m_colorImages[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &colorImageParams)));
615 			m_colorImageAllocs[imgNdx] = SharedAllocPtr(new UniqueAlloc(allocateImage(vki, vk, physDevice, vkDevice, **m_colorImages[imgNdx], MemoryRequirement::Any, memAlloc, m_allocationKind)));
616 			VK_CHECK(vk.bindImageMemory(vkDevice, **m_colorImages[imgNdx], (*m_colorImageAllocs[imgNdx])->getMemory(), (*m_colorImageAllocs[imgNdx])->getOffset()));
617 
618 			const VkImageViewCreateInfo colorAttachmentViewParams =
619 			{
620 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType			sType;
621 				DE_NULL,											// const void*				pNext;
622 				0u,													// VkImageViewCreateFlags	flags;
623 				**m_colorImages[imgNdx],							// VkImage					image;
624 				VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType			viewType;
625 				m_colorFormat,										// VkFormat					format;
626 				componentMappingRGBA,								// VkComponentMapping		components;
627 				{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }		// VkImageSubresourceRange	subresourceRange;
628 			};
629 
630 			m_colorAttachmentViews[imgNdx] = SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &colorAttachmentViewParams)));
631 		}
632 	}
633 
634 	// Create render pass
635 	{
636 		std::vector<VkAttachmentDescription>	colorAttachmentDescriptions(m_imageCount);
637 		std::vector<VkAttachmentReference>		colorAttachmentReferences(m_imageCount);
638 
639 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
640 		{
641 			colorAttachmentDescriptions[imgNdx].flags			= 0u;										// VkAttachmentDescriptionFlags		flags;
642 			colorAttachmentDescriptions[imgNdx].format			= m_colorFormat;							// VkFormat							format;
643 			colorAttachmentDescriptions[imgNdx].samples			= VK_SAMPLE_COUNT_1_BIT;					// VkSampleCountFlagBits			samples;
644 			colorAttachmentDescriptions[imgNdx].loadOp			= VK_ATTACHMENT_LOAD_OP_CLEAR;				// VkAttachmentLoadOp				loadOp;
645 			colorAttachmentDescriptions[imgNdx].storeOp			= VK_ATTACHMENT_STORE_OP_STORE;				// VkAttachmentStoreOp				storeOp;
646 			colorAttachmentDescriptions[imgNdx].stencilLoadOp	= VK_ATTACHMENT_LOAD_OP_DONT_CARE;			// VkAttachmentLoadOp				stencilLoadOp;
647 			colorAttachmentDescriptions[imgNdx].stencilStoreOp	= VK_ATTACHMENT_STORE_OP_DONT_CARE;			// VkAttachmentStoreOp				stencilStoreOp;
648 			colorAttachmentDescriptions[imgNdx].initialLayout	= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout					initialLayout;
649 			colorAttachmentDescriptions[imgNdx].finalLayout		= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout					finalLayout;
650 
651 			colorAttachmentReferences[imgNdx].attachment		= (deUint32)imgNdx;							// deUint32							attachment;
652 			colorAttachmentReferences[imgNdx].layout			= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout					layout;
653 		}
654 
655 		const VkSubpassDescription subpassDescription =
656 		{
657 			0u,													// VkSubpassDescriptionFlags	flags;
658 			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint			pipelineBindPoint;
659 			0u,													// deUint32						inputAttachmentCount;
660 			DE_NULL,											// const VkAttachmentReference*	pInputAttachments;
661 			(deUint32)m_imageCount,								// deUint32						colorAttachmentCount;
662 			&colorAttachmentReferences[0],						// const VkAttachmentReference*	pColorAttachments;
663 			DE_NULL,											// const VkAttachmentReference*	pResolveAttachments;
664 			DE_NULL,											// const VkAttachmentReference*	pDepthStencilAttachment;
665 			0u,													// deUint32						preserveAttachmentCount;
666 			DE_NULL												// const VkAttachmentReference*	pPreserveAttachments;
667 		};
668 
669 		const VkRenderPassCreateInfo renderPassParams =
670 		{
671 			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
672 			DE_NULL,											// const void*						pNext;
673 			0u,													// VkRenderPassCreateFlags			flags;
674 			(deUint32)m_imageCount,								// deUint32							attachmentCount;
675 			&colorAttachmentDescriptions[0],					// const VkAttachmentDescription*	pAttachments;
676 			1u,													// deUint32							subpassCount;
677 			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
678 			0u,													// deUint32							dependencyCount;
679 			DE_NULL												// const VkSubpassDependency*		pDependencies;
680 		};
681 
682 		m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
683 	}
684 
685 	// Create framebuffer
686 	{
687 		std::vector<VkImageView> pAttachments(m_imageCount);
688 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
689 			pAttachments[imgNdx] = m_colorAttachmentViews[imgNdx]->get();
690 
691 		const VkFramebufferCreateInfo framebufferParams =
692 		{
693 			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType			sType;
694 			DE_NULL,											// const void*				pNext;
695 			0u,													// VkFramebufferCreateFlags	flags;
696 			*m_renderPass,										// VkRenderPass				renderPass;
697 			(deUint32)m_imageCount,								// deUint32					attachmentCount;
698 			&pAttachments[0],									// const VkImageView*		pAttachments;
699 			(deUint32)m_renderSize.x(),							// deUint32					width;
700 			(deUint32)m_renderSize.y(),							// deUint32					height;
701 			1u													// deUint32					layers;
702 		};
703 
704 		m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
705 	}
706 
707 	// Create pipeline layout
708 	{
709 #ifndef CTS_USES_VULKANSC
710 		VkPipelineLayoutCreateFlags pipelineLayoutFlags = (m_pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC) ? 0u : deUint32(VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
711 #else
712 		VkPipelineLayoutCreateFlags pipelineLayoutFlags = 0u;
713 #endif // CTS_USES_VULKANSC
714 		VkPipelineLayoutCreateInfo	pipelineLayoutParams
715 		{
716 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
717 			DE_NULL,											// const void*					pNext;
718 			pipelineLayoutFlags,								// VkPipelineLayoutCreateFlags	flags;
719 			0u,													// deUint32						setLayoutCount;
720 			DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
721 			0u,													// deUint32						pushConstantRangeCount;
722 			DE_NULL												// const VkPushConstantRange*	pPushConstantRanges;
723 		};
724 
725 		m_preRasterizationStatePipelineLayout	= createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
726 		pipelineLayoutParams.setLayoutCount		= 1u;
727 		pipelineLayoutParams.pSetLayouts		= &m_descriptorSetLayout.get();
728 		m_fragmentStatePipelineLayout			= createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
729 	}
730 
731 	m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tex_vert"), 0);
732 	m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tex_frag"), 0);
733 
734 	// Create pipeline
735 	{
736 		const VkVertexInputBindingDescription vertexInputBindingDescription =
737 		{
738 			0u,									// deUint32					binding;
739 			sizeof(Vertex4Tex4),				// deUint32					strideInBytes;
740 			VK_VERTEX_INPUT_RATE_VERTEX			// VkVertexInputStepRate	inputRate;
741 		};
742 
743 		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
744 		{
745 			{
746 				0u,										// deUint32	location;
747 				0u,										// deUint32	binding;
748 				VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
749 				0u										// deUint32	offset;
750 			},
751 			{
752 				1u,										// deUint32	location;
753 				0u,										// deUint32	binding;
754 				VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
755 				DE_OFFSET_OF(Vertex4Tex4, texCoord),	// deUint32	offset;
756 			}
757 		};
758 
759 		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
760 		{
761 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
762 			DE_NULL,														// const void*								pNext;
763 			0u,																// VkPipelineVertexInputStateCreateFlags	flags;
764 			1u,																// deUint32									vertexBindingDescriptionCount;
765 			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
766 			2u,																// deUint32									vertexAttributeDescriptionCount;
767 			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
768 		};
769 
770 		const std::vector<VkViewport>	viewports	{ makeViewport(m_renderSize) };
771 		const std::vector<VkRect2D>		scissors	{ makeRect2D(m_renderSize) };
772 
773 		std::vector<VkPipelineColorBlendAttachmentState>	colorBlendAttachmentStates(m_imageCount);
774 
775 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
776 		{
777 			colorBlendAttachmentStates[imgNdx].blendEnable			= false;												// VkBool32					blendEnable;
778 			colorBlendAttachmentStates[imgNdx].srcColorBlendFactor	= VK_BLEND_FACTOR_ONE;									// VkBlendFactor			srcColorBlendFactor;
779 			colorBlendAttachmentStates[imgNdx].dstColorBlendFactor	= VK_BLEND_FACTOR_ZERO;									// VkBlendFactor			dstColorBlendFactor;
780 			colorBlendAttachmentStates[imgNdx].colorBlendOp			= VK_BLEND_OP_ADD;										// VkBlendOp				colorBlendOp;
781 			colorBlendAttachmentStates[imgNdx].srcAlphaBlendFactor	= VK_BLEND_FACTOR_ONE;									// VkBlendFactor			srcAlphaBlendFactor;
782 			colorBlendAttachmentStates[imgNdx].dstAlphaBlendFactor	= VK_BLEND_FACTOR_ZERO;									// VkBlendFactor			dstAlphaBlendFactor;
783 			colorBlendAttachmentStates[imgNdx].alphaBlendOp			= VK_BLEND_OP_ADD;										// VkBlendOp				alphaBlendOp;
784 			colorBlendAttachmentStates[imgNdx].colorWriteMask		= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |	// VkColorComponentFlags	colorWriteMask;
785 																		VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
786 		}
787 
788 		const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
789 		{
790 			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
791 			DE_NULL,													// const void*									pNext;
792 			0u,															// VkPipelineColorBlendStateCreateFlags			flags;
793 			false,														// VkBool32										logicOpEnable;
794 			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
795 			(deUint32)m_imageCount,										// deUint32										attachmentCount;
796 			&colorBlendAttachmentStates[0],								// const VkPipelineColorBlendAttachmentState*	pAttachments;
797 			{ 0.0f, 0.0f, 0.0f, 0.0f }									// float										blendConstants[4];
798 		};
799 
800 		m_graphicsPipeline.setMonolithicPipelineLayout(*m_fragmentStatePipelineLayout)
801 						  .setDefaultDepthStencilState()
802 						  .setDefaultRasterizationState()
803 						  .setDefaultMultisampleState()
804 						  .setupVertexInputState(&vertexInputStateParams)
805 						  .setupPreRasterizationShaderState(viewports,
806 														scissors,
807 														*m_preRasterizationStatePipelineLayout,
808 														*m_renderPass,
809 														0u,
810 														*m_vertexShaderModule)
811 						  .setupFragmentShaderState(*m_fragmentStatePipelineLayout, *m_renderPass, 0u, *m_fragmentShaderModule)
812 						  .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
813 						  .buildPipeline();
814 	}
815 
816 	// Create vertex buffer
817 	{
818 		const VkDeviceSize			vertexBufferSize	= (VkDeviceSize)(m_vertices.size() * sizeof(Vertex4Tex4));
819 		const VkBufferCreateInfo	vertexBufferParams	=
820 		{
821 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
822 			DE_NULL,									// const void*			pNext;
823 			0u,											// VkBufferCreateFlags	flags;
824 			vertexBufferSize,							// VkDeviceSize			size;
825 			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
826 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
827 			1u,											// deUint32				queueFamilyIndexCount;
828 			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
829 		};
830 
831 		DE_ASSERT(vertexBufferSize > 0);
832 
833 		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
834 		m_vertexBufferAlloc = allocateBuffer(vki, vk, physDevice, vkDevice, *m_vertexBuffer, MemoryRequirement::HostVisible, memAlloc, m_allocationKind);
835 		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
836 
837 		// Load vertices into vertex buffer
838 		deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], (size_t)vertexBufferSize);
839 		flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
840 	}
841 
842 	// Create command pool
843 	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
844 
845 	// Create command buffer
846 	{
847 		const std::vector<VkClearValue> attachmentClearValues (m_imageCount, defaultClearValue(m_colorFormat));
848 
849 		std::vector<VkImageMemoryBarrier> preAttachmentBarriers(m_imageCount);
850 
851 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
852 		{
853 			preAttachmentBarriers[imgNdx].sType								= VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;	// VkStructureType			sType;
854 			preAttachmentBarriers[imgNdx].pNext								= DE_NULL;									// const void*				pNext;
855 			preAttachmentBarriers[imgNdx].srcAccessMask						= 0u;										// VkAccessFlags			srcAccessMask;
856 			preAttachmentBarriers[imgNdx].dstAccessMask						= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;		// VkAccessFlags			dstAccessMask;
857 			preAttachmentBarriers[imgNdx].oldLayout							= VK_IMAGE_LAYOUT_UNDEFINED;				// VkImageLayout			oldLayout;
858 			preAttachmentBarriers[imgNdx].newLayout							= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout			newLayout;
859 			preAttachmentBarriers[imgNdx].srcQueueFamilyIndex				= VK_QUEUE_FAMILY_IGNORED;					// deUint32					srcQueueFamilyIndex;
860 			preAttachmentBarriers[imgNdx].dstQueueFamilyIndex				= VK_QUEUE_FAMILY_IGNORED;					// deUint32					dstQueueFamilyIndex;
861 			preAttachmentBarriers[imgNdx].image								= **m_colorImages[imgNdx];					// VkImage					image;
862 			preAttachmentBarriers[imgNdx].subresourceRange.aspectMask		= VK_IMAGE_ASPECT_COLOR_BIT;				// VkImageSubresourceRange	subresourceRange;
863 			preAttachmentBarriers[imgNdx].subresourceRange.baseMipLevel		= 0u;
864 			preAttachmentBarriers[imgNdx].subresourceRange.levelCount		= 1u;
865 			preAttachmentBarriers[imgNdx].subresourceRange.baseArrayLayer	= 0u;
866 			preAttachmentBarriers[imgNdx].subresourceRange.layerCount		= 1u;
867 		}
868 
869 		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
870 
871 		beginCommandBuffer(vk, *m_cmdBuffer, 0u);
872 
873 		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0,
874 			0u, DE_NULL, 0u, DE_NULL, (deUint32)m_imageCount, &preAttachmentBarriers[0]);
875 
876 		beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), (deUint32)attachmentClearValues.size(), &attachmentClearValues[0]);
877 
878 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline.getPipeline());
879 
880 		vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_fragmentStatePipelineLayout, 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
881 
882 		const VkDeviceSize vertexBufferOffset = 0;
883 		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
884 		vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
885 
886 		endRenderPass(vk, *m_cmdBuffer);
887 		endCommandBuffer(vk, *m_cmdBuffer);
888 	}
889 }
890 
~ImageSamplingInstance(void)891 ImageSamplingInstance::~ImageSamplingInstance (void)
892 {
893 }
894 
iterate(void)895 tcu::TestStatus ImageSamplingInstance::iterate (void)
896 {
897 	const DeviceInterface&		vk			= m_context.getDeviceInterface();
898 	const VkDevice				vkDevice	= m_context.getDevice();
899 	const VkQueue				queue		= m_context.getUniversalQueue();
900 
901 	setup();
902 
903 	submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
904 
905 	return verifyImage();
906 }
907 
908 namespace
909 {
910 
isLookupResultValid(const tcu::Texture1DView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)911 bool isLookupResultValid (const tcu::Texture1DView&		texture,
912 						  const tcu::Sampler&			sampler,
913 						  const tcu::LookupPrecision&	precision,
914 						  const tcu::Vec4&				coords,
915 						  const tcu::Vec2&				lodBounds,
916 						  const tcu::Vec4&				result)
917 {
918 	return tcu::isLookupResultValid(texture, sampler, precision, coords.x(), lodBounds, result);
919 }
920 
isLookupResultValid(const tcu::Texture1DArrayView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)921 bool isLookupResultValid (const tcu::Texture1DArrayView&	texture,
922 						  const tcu::Sampler&				sampler,
923 						  const tcu::LookupPrecision&		precision,
924 						  const tcu::Vec4&					coords,
925 						  const tcu::Vec2&					lodBounds,
926 						  const tcu::Vec4&					result)
927 {
928 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1), lodBounds, result);
929 }
930 
isLookupResultValid(const tcu::Texture2DView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)931 bool isLookupResultValid (const tcu::Texture2DView&		texture,
932 						  const tcu::Sampler&			sampler,
933 						  const tcu::LookupPrecision&	precision,
934 						  const tcu::Vec4&				coords,
935 						  const tcu::Vec2&				lodBounds,
936 						  const tcu::Vec4&				result)
937 {
938 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1), lodBounds, result);
939 }
940 
isLookupResultValid(const tcu::Texture2DArrayView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)941 bool isLookupResultValid (const tcu::Texture2DArrayView&	texture,
942 						  const tcu::Sampler&				sampler,
943 						  const tcu::LookupPrecision&		precision,
944 						  const tcu::Vec4&					coords,
945 						  const tcu::Vec2&					lodBounds,
946 						  const tcu::Vec4&					result)
947 {
948 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
949 }
950 
isLookupResultValid(const tcu::TextureCubeView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)951 bool isLookupResultValid (const tcu::TextureCubeView&	texture,
952 						  const tcu::Sampler&			sampler,
953 						  const tcu::LookupPrecision&	precision,
954 						  const tcu::Vec4&				coords,
955 						  const tcu::Vec2&				lodBounds,
956 						  const tcu::Vec4&				result)
957 {
958 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
959 }
960 
isLookupResultValid(const tcu::TextureCubeArrayView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)961 bool isLookupResultValid (const tcu::TextureCubeArrayView&	texture,
962 						  const tcu::Sampler&				sampler,
963 						  const tcu::LookupPrecision&		precision,
964 						  const tcu::Vec4&					coords,
965 						  const tcu::Vec2&					lodBounds,
966 						  const tcu::Vec4&					result)
967 {
968 	return tcu::isLookupResultValid(texture, sampler, precision, tcu::IVec4(precision.coordBits.x()), coords, lodBounds, result);
969 }
970 
isLookupResultValid(const tcu::Texture3DView& texture, const tcu::Sampler& sampler, const tcu::LookupPrecision& precision, const tcu::Vec4& coords, const tcu::Vec2& lodBounds, const tcu::Vec4& result)971 bool isLookupResultValid(const tcu::Texture3DView&		texture,
972 						 const tcu::Sampler&			sampler,
973 						 const tcu::LookupPrecision&	precision,
974 						 const tcu::Vec4&				coords,
975 						 const tcu::Vec2&				lodBounds,
976 						 const tcu::Vec4&				result)
977 {
978 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
979 }
980 
981 template<typename TextureViewType>
validateResultImage(const TextureViewType& texture, const tcu::Sampler& sampler, const tcu::ConstPixelBufferAccess& texCoords, const tcu::Vec2& lodBounds, const tcu::LookupPrecision& lookupPrecision, const tcu::Vec4& lookupScale, const tcu::Vec4& lookupBias, const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)982 bool validateResultImage (const TextureViewType&				texture,
983 						  const tcu::Sampler&					sampler,
984 						  const tcu::ConstPixelBufferAccess&	texCoords,
985 						  const tcu::Vec2&						lodBounds,
986 						  const tcu::LookupPrecision&			lookupPrecision,
987 						  const tcu::Vec4&						lookupScale,
988 						  const tcu::Vec4&						lookupBias,
989 						  const tcu::ConstPixelBufferAccess&	result,
990 						  const tcu::PixelBufferAccess&			errorMask)
991 {
992 	const int	w		= result.getWidth();
993 	const int	h		= result.getHeight();
994 	bool		allOk	= true;
995 
996 	for (int y = 0; y < h; ++y)
997 	{
998 		for (int x = 0; x < w; ++x)
999 		{
1000 			const tcu::Vec4		resultPixel	= result.getPixel(x, y);
1001 			const tcu::Vec4		resultColor	= (resultPixel - lookupBias) / lookupScale;
1002 			const tcu::Vec4		texCoord	= texCoords.getPixel(x, y);
1003 			const bool			pixelOk		= isLookupResultValid(texture, sampler, lookupPrecision, texCoord, lodBounds, resultColor);
1004 
1005 			errorMask.setPixel(tcu::Vec4(pixelOk?0.0f:1.0f, pixelOk?1.0f:0.0f, 0.0f, 1.0f), x, y);
1006 
1007 			if (!pixelOk)
1008 				allOk = false;
1009 		}
1010 	}
1011 
1012 	return allOk;
1013 }
1014 
1015 template<typename ScalarType>
getSwizzledComp(const tcu::Vector<ScalarType, 4>& vec, vk::VkComponentSwizzle comp, int identityNdx)1016 ScalarType getSwizzledComp (const tcu::Vector<ScalarType, 4>& vec, vk::VkComponentSwizzle comp, int identityNdx)
1017 {
1018 	if (comp == vk::VK_COMPONENT_SWIZZLE_IDENTITY)
1019 		return vec[identityNdx];
1020 	else if (comp == vk::VK_COMPONENT_SWIZZLE_ZERO)
1021 		return ScalarType(0);
1022 	else if (comp == vk::VK_COMPONENT_SWIZZLE_ONE)
1023 		return ScalarType(1);
1024 	else
1025 		return vec[comp - vk::VK_COMPONENT_SWIZZLE_R];
1026 }
1027 
1028 template<typename ScalarType>
swizzle(const tcu::Vector<ScalarType, 4>& vec, const vk::VkComponentMapping& swz)1029 tcu::Vector<ScalarType, 4> swizzle (const tcu::Vector<ScalarType, 4>& vec, const vk::VkComponentMapping& swz)
1030 {
1031 	return tcu::Vector<ScalarType, 4>(getSwizzledComp(vec, swz.r, 0),
1032 									  getSwizzledComp(vec, swz.g, 1),
1033 									  getSwizzledComp(vec, swz.b, 2),
1034 									  getSwizzledComp(vec, swz.a, 3));
1035 }
1036 
1037 /*--------------------------------------------------------------------*//*!
1038 * \brief Swizzle scale or bias vector by given mapping
1039 *
1040 * \param vec scale or bias vector
1041 * \param swz swizzle component mapping, may include ZERO, ONE, or IDENTITY
1042 * \param zeroOrOneValue vector value for component swizzled as ZERO or ONE
1043 * \return swizzled vector
1044 *//*--------------------------------------------------------------------*/
swizzleScaleBias(const tcu::Vec4& vec, const vk::VkComponentMapping& swz, float zeroOrOneValue)1045 tcu::Vec4 swizzleScaleBias (const tcu::Vec4& vec, const vk::VkComponentMapping& swz, float zeroOrOneValue)
1046 {
1047 
1048 	// Remove VK_COMPONENT_SWIZZLE_IDENTITY to avoid addressing channelValues[0]
1049 	const vk::VkComponentMapping nonIdentitySwz =
1050 	{
1051 		swz.r == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_R : swz.r,
1052 		swz.g == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_G : swz.g,
1053 		swz.b == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_B : swz.b,
1054 		swz.a == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_A : swz.a
1055 	};
1056 
1057 	const float channelValues[] =
1058 	{
1059 		-1.0f,				// impossible
1060 		zeroOrOneValue,		// SWIZZLE_ZERO
1061 		zeroOrOneValue,		// SWIZZLE_ONE
1062 		vec.x(),
1063 		vec.y(),
1064 		vec.z(),
1065 		vec.w(),
1066 	};
1067 
1068 	return tcu::Vec4(channelValues[nonIdentitySwz.r], channelValues[nonIdentitySwz.g], channelValues[nonIdentitySwz.b], channelValues[nonIdentitySwz.a]);
1069 }
1070 
1071 template<typename ScalarType>
swizzleT(const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)1072 void swizzleT (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
1073 {
1074 	for (int z = 0; z < dst.getDepth(); ++z)
1075 	for (int y = 0; y < dst.getHeight(); ++y)
1076 	for (int x = 0; x < dst.getWidth(); ++x)
1077 		dst.setPixel(swizzle(src.getPixelT<ScalarType>(x, y, z), swz), x, y, z);
1078 }
1079 
swizzleFromSRGB(const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)1080 void swizzleFromSRGB (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
1081 {
1082 	for (int z = 0; z < dst.getDepth(); ++z)
1083 	for (int y = 0; y < dst.getHeight(); ++y)
1084 	for (int x = 0; x < dst.getWidth(); ++x)
1085 		dst.setPixel(swizzle(tcu::sRGBToLinear(src.getPixelT<float>(x, y, z)), swz), x, y, z);
1086 }
1087 
swizzle(const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)1088 void swizzle (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
1089 {
1090 	const tcu::TextureChannelClass	chnClass	= tcu::getTextureChannelClass(dst.getFormat().type);
1091 
1092 	DE_ASSERT(src.getWidth() == dst.getWidth() &&
1093 			  src.getHeight() == dst.getHeight() &&
1094 			  src.getDepth() == dst.getDepth());
1095 
1096 	if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
1097 		swizzleT<deInt32>(src, dst, swz);
1098 	else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1099 		swizzleT<deUint32>(src, dst, swz);
1100 	else if (tcu::isSRGB(src.getFormat()) && !tcu::isSRGB(dst.getFormat()))
1101 		swizzleFromSRGB(src, dst, swz);
1102 	else
1103 		swizzleT<float>(src, dst, swz);
1104 }
1105 
isIdentitySwizzle(const vk::VkComponentMapping& swz)1106 bool isIdentitySwizzle (const vk::VkComponentMapping& swz)
1107 {
1108 	return (swz.r == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.r == vk::VK_COMPONENT_SWIZZLE_R) &&
1109 		   (swz.g == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.g == vk::VK_COMPONENT_SWIZZLE_G) &&
1110 		   (swz.b == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.b == vk::VK_COMPONENT_SWIZZLE_B) &&
1111 		   (swz.a == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.a == vk::VK_COMPONENT_SWIZZLE_A);
1112 }
1113 
1114 template<typename TextureViewType> struct TexViewTraits;
1115 
1116 template<> struct TexViewTraits<tcu::Texture1DView>			{ typedef tcu::Texture1D		TextureType; };
1117 template<> struct TexViewTraits<tcu::Texture1DArrayView>	{ typedef tcu::Texture1DArray	TextureType; };
1118 template<> struct TexViewTraits<tcu::Texture2DView>			{ typedef tcu::Texture2D		TextureType; };
1119 template<> struct TexViewTraits<tcu::Texture2DArrayView>	{ typedef tcu::Texture2DArray	TextureType; };
1120 template<> struct TexViewTraits<tcu::TextureCubeView>		{ typedef tcu::TextureCube		TextureType; };
1121 template<> struct TexViewTraits<tcu::TextureCubeArrayView>	{ typedef tcu::TextureCubeArray	TextureType; };
1122 template<> struct TexViewTraits<tcu::Texture3DView>			{ typedef tcu::Texture3D		TextureType; };
1123 
1124 template<typename TextureViewType>
1125 typename TexViewTraits<TextureViewType>::TextureType* createSkeletonClone (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0);
1126 
getSwizzleTargetFormat(tcu::TextureFormat format)1127 tcu::TextureFormat getSwizzleTargetFormat (tcu::TextureFormat format)
1128 {
1129 	// Swizzled texture needs to hold all four channels
1130 	// \todo [2016-09-21 pyry] We could save some memory by using smaller formats
1131 	//						   when possible (for example U8).
1132 
1133 	const tcu::TextureChannelClass	chnClass	= tcu::getTextureChannelClass(format.type);
1134 
1135 	if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
1136 		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
1137 	else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1138 		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
1139 	else
1140 		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1141 }
1142 
1143 template<>
createSkeletonClone(tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)1144 tcu::Texture1D* createSkeletonClone<tcu::Texture1DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1145 {
1146 	return new tcu::Texture1D(format, level0.getWidth());
1147 }
1148 
1149 template<>
createSkeletonClone(tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)1150 tcu::Texture1DArray* createSkeletonClone<tcu::Texture1DArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1151 {
1152 	return new tcu::Texture1DArray(format, level0.getWidth(), level0.getHeight());
1153 }
1154 
1155 template<>
createSkeletonClone(tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)1156 tcu::Texture2D* createSkeletonClone<tcu::Texture2DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1157 {
1158 	return new tcu::Texture2D(format, level0.getWidth(), level0.getHeight());
1159 }
1160 
1161 template<>
createSkeletonClone(tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)1162 tcu::Texture2DArray* createSkeletonClone<tcu::Texture2DArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1163 {
1164 	return new tcu::Texture2DArray(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
1165 }
1166 
1167 template<>
createSkeletonClone(tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)1168 tcu::Texture3D* createSkeletonClone<tcu::Texture3DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1169 {
1170 	return new tcu::Texture3D(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
1171 }
1172 
1173 template<>
createSkeletonClone(tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)1174 tcu::TextureCubeArray* createSkeletonClone<tcu::TextureCubeArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1175 {
1176 	return new tcu::TextureCubeArray(format, level0.getWidth(), level0.getDepth());
1177 }
1178 
1179 template<typename TextureViewType>
createSwizzledCopy(const TextureViewType& texture, const vk::VkComponentMapping& swz)1180 MovePtr<typename TexViewTraits<TextureViewType>::TextureType> createSwizzledCopy (const TextureViewType& texture, const vk::VkComponentMapping& swz)
1181 {
1182 	MovePtr<typename TexViewTraits<TextureViewType>::TextureType>	copy	(createSkeletonClone<TextureViewType>(getSwizzleTargetFormat(texture.getLevel(0).getFormat()), texture.getLevel(0)));
1183 
1184 	for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
1185 	{
1186 		copy->allocLevel(levelNdx);
1187 		swizzle(texture.getLevel(levelNdx), copy->getLevel(levelNdx), swz);
1188 	}
1189 
1190 	return copy;
1191 }
1192 
1193 template<>
createSwizzledCopy(const tcu::TextureCubeView& texture, const vk::VkComponentMapping& swz)1194 MovePtr<tcu::TextureCube> createSwizzledCopy (const tcu::TextureCubeView& texture, const vk::VkComponentMapping& swz)
1195 {
1196 	MovePtr<tcu::TextureCube>	copy	(new tcu::TextureCube(getSwizzleTargetFormat(texture.getLevelFace(0, tcu::CUBEFACE_NEGATIVE_X).getFormat()), texture.getSize()));
1197 
1198 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1199 	{
1200 		for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
1201 		{
1202 			copy->allocLevel((tcu::CubeFace)faceNdx, levelNdx);
1203 			swizzle(texture.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), copy->getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), swz);
1204 		}
1205 	}
1206 
1207 	return copy;
1208 }
1209 
1210 template<typename TextureViewType>
validateResultImage(const TextureViewType& texture, const tcu::Sampler& sampler, const vk::VkComponentMapping& swz, const tcu::ConstPixelBufferAccess& texCoords, const tcu::Vec2& lodBounds, const tcu::LookupPrecision& lookupPrecision, const tcu::Vec4& lookupScale, const tcu::Vec4& lookupBias, const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)1211 bool validateResultImage (const TextureViewType&				texture,
1212 						  const tcu::Sampler&					sampler,
1213 						  const vk::VkComponentMapping&			swz,
1214 						  const tcu::ConstPixelBufferAccess&	texCoords,
1215 						  const tcu::Vec2&						lodBounds,
1216 						  const tcu::LookupPrecision&			lookupPrecision,
1217 						  const tcu::Vec4&						lookupScale,
1218 						  const tcu::Vec4&						lookupBias,
1219 						  const tcu::ConstPixelBufferAccess&	result,
1220 						  const tcu::PixelBufferAccess&			errorMask)
1221 {
1222 	if (isIdentitySwizzle(swz))
1223 		return validateResultImage(texture, sampler, texCoords, lodBounds, lookupPrecision, lookupScale, lookupBias, result, errorMask);
1224 	else
1225 	{
1226 		// There is (currently) no way to handle swizzling inside validation loop
1227 		// and thus we need to pre-swizzle the texture.
1228 		UniquePtr<typename TexViewTraits<TextureViewType>::TextureType>	swizzledTex	(createSwizzledCopy(texture, swz));
1229 
1230 		return validateResultImage(*swizzledTex, sampler, texCoords, lodBounds, lookupPrecision, swizzleScaleBias(lookupScale, swz, 1.0f), swizzleScaleBias(lookupBias, swz, 0.0f), result, errorMask);
1231 	}
1232 }
1233 
resolveSubresourceRange(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource)1234 vk::VkImageSubresourceRange resolveSubresourceRange (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource)
1235 {
1236 	vk::VkImageSubresourceRange	resolved					= subresource;
1237 
1238 	if (subresource.levelCount == VK_REMAINING_MIP_LEVELS)
1239 		resolved.levelCount = testTexture.getNumLevels()-subresource.baseMipLevel;
1240 
1241 	if (subresource.layerCount == VK_REMAINING_ARRAY_LAYERS)
1242 		resolved.layerCount = testTexture.getArraySize()-subresource.baseArrayLayer;
1243 
1244 	return resolved;
1245 }
1246 
getTexture1DView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1247 MovePtr<tcu::Texture1DView> getTexture1DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1248 {
1249 	DE_ASSERT(subresource.layerCount == 1);
1250 
1251 	levels.resize(subresource.levelCount);
1252 
1253 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1254 	{
1255 		const tcu::ConstPixelBufferAccess& srcLevel = testTexture.getLevel((int)subresource.baseMipLevel+levelNdx, subresource.baseArrayLayer);
1256 
1257 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, 0, srcLevel.getWidth(), 1, 1);
1258 	}
1259 
1260 	return MovePtr<tcu::Texture1DView>(new tcu::Texture1DView((int)levels.size(), &levels[0]));
1261 }
1262 
getTexture1DArrayView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1263 MovePtr<tcu::Texture1DArrayView> getTexture1DArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1264 {
1265 	const TestTexture1D*		tex1D		= dynamic_cast<const TestTexture1D*>(&testTexture);
1266 	const TestTexture1DArray*	tex1DArray	= dynamic_cast<const TestTexture1DArray*>(&testTexture);
1267 
1268 	DE_ASSERT(!!tex1D != !!tex1DArray);
1269 	DE_ASSERT(tex1DArray || subresource.baseArrayLayer == 0);
1270 
1271 	levels.resize(subresource.levelCount);
1272 
1273 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1274 	{
1275 		const tcu::ConstPixelBufferAccess& srcLevel = tex1D ? tex1D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1276 															: tex1DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1277 
1278 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, (int)subresource.baseArrayLayer, 0, srcLevel.getWidth(), (int)subresource.layerCount, 1);
1279 	}
1280 
1281 	return MovePtr<tcu::Texture1DArrayView>(new tcu::Texture1DArrayView((int)levels.size(), &levels[0]));
1282 }
1283 
getTexture2DView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1284 MovePtr<tcu::Texture2DView> getTexture2DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1285 {
1286 	const TestTexture2D*		tex2D		= dynamic_cast<const TestTexture2D*>(&testTexture);
1287 	const TestTexture2DArray*	tex2DArray	= dynamic_cast<const TestTexture2DArray*>(&testTexture);
1288 
1289 	DE_ASSERT(subresource.layerCount == 1);
1290 	DE_ASSERT(!!tex2D != !!tex2DArray);
1291 	DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
1292 
1293 	levels.resize(subresource.levelCount);
1294 
1295 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1296 	{
1297 		const tcu::ConstPixelBufferAccess& srcLevel = tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1298 															: tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1299 
1300 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), 1);
1301 	}
1302 
1303 	return MovePtr<tcu::Texture2DView>(new tcu::Texture2DView((int)levels.size(), &levels[0]));
1304 }
1305 
getTexture2DArrayView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1306 MovePtr<tcu::Texture2DArrayView> getTexture2DArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1307 {
1308 	const TestTexture2D*		tex2D		= dynamic_cast<const TestTexture2D*>(&testTexture);
1309 	const TestTexture2DArray*	tex2DArray	= dynamic_cast<const TestTexture2DArray*>(&testTexture);
1310 
1311 	DE_ASSERT(!!tex2D != !!tex2DArray);
1312 	DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
1313 
1314 	levels.resize(subresource.levelCount);
1315 
1316 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1317 	{
1318 		const tcu::ConstPixelBufferAccess& srcLevel = tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1319 															: tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1320 
1321 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), (int)subresource.layerCount);
1322 	}
1323 
1324 	return MovePtr<tcu::Texture2DArrayView>(new tcu::Texture2DArrayView((int)levels.size(), &levels[0]));
1325 }
1326 
getTextureCubeView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1327 MovePtr<tcu::TextureCubeView> getTextureCubeView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1328 {
1329 	const static tcu::CubeFace s_faceMap[tcu::CUBEFACE_LAST] =
1330 	{
1331 		tcu::CUBEFACE_POSITIVE_X,
1332 		tcu::CUBEFACE_NEGATIVE_X,
1333 		tcu::CUBEFACE_POSITIVE_Y,
1334 		tcu::CUBEFACE_NEGATIVE_Y,
1335 		tcu::CUBEFACE_POSITIVE_Z,
1336 		tcu::CUBEFACE_NEGATIVE_Z
1337 	};
1338 
1339 	const TestTextureCube*		texCube			= dynamic_cast<const TestTextureCube*>(&testTexture);
1340 	const TestTextureCubeArray*	texCubeArray	= dynamic_cast<const TestTextureCubeArray*>(&testTexture);
1341 
1342 	DE_ASSERT(!!texCube != !!texCubeArray);
1343 	DE_ASSERT(subresource.layerCount == 6);
1344 	DE_ASSERT(texCubeArray || subresource.baseArrayLayer == 0);
1345 
1346 	levels.resize(subresource.levelCount*tcu::CUBEFACE_LAST);
1347 
1348 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1349 	{
1350 		for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
1351 		{
1352 			const tcu::ConstPixelBufferAccess& srcLevel = texCubeArray ? texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1353 																	   : texCube->getTexture().getLevelFace(levelNdx, s_faceMap[faceNdx]);
1354 
1355 			levels[faceNdx*subresource.levelCount + levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer + (texCubeArray ? faceNdx : 0), srcLevel.getWidth(), srcLevel.getHeight(), 1);
1356 		}
1357 	}
1358 
1359 	{
1360 		const tcu::ConstPixelBufferAccess*	reordered[tcu::CUBEFACE_LAST];
1361 
1362 		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1363 			reordered[s_faceMap[faceNdx]] = &levels[faceNdx*subresource.levelCount];
1364 
1365 		return MovePtr<tcu::TextureCubeView>(new tcu::TextureCubeView((int)subresource.levelCount, reordered));
1366 	}
1367 }
1368 
getTextureCubeArrayView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1369 MovePtr<tcu::TextureCubeArrayView> getTextureCubeArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1370 {
1371 	const TestTextureCubeArray*	texCubeArray	= dynamic_cast<const TestTextureCubeArray*>(&testTexture);
1372 
1373 	DE_ASSERT(texCubeArray);
1374 	DE_ASSERT(subresource.layerCount%6 == 0);
1375 
1376 	levels.resize(subresource.levelCount);
1377 
1378 	for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
1379 	{
1380 		const tcu::ConstPixelBufferAccess& srcLevel = texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1381 
1382 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), (int)subresource.layerCount);
1383 	}
1384 
1385 	return MovePtr<tcu::TextureCubeArrayView>(new tcu::TextureCubeArrayView((int)levels.size(), &levels[0]));
1386 }
1387 
getTexture3DView(const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)1388 MovePtr<tcu::Texture3DView> getTexture3DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1389 {
1390 	DE_ASSERT(subresource.baseArrayLayer == 0 && subresource.layerCount == 1);
1391 
1392 	levels.resize(subresource.levelCount);
1393 
1394 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1395 		levels[levelNdx] = testTexture.getLevel((int)subresource.baseMipLevel+levelNdx, subresource.baseArrayLayer);
1396 
1397 	return MovePtr<tcu::Texture3DView>(new tcu::Texture3DView((int)levels.size(), &levels[0]));
1398 }
1399 
validateResultImage(const TestTexture& texture, const VkImageViewType imageViewType, const VkImageSubresourceRange& subresource, const tcu::Sampler& sampler, const vk::VkComponentMapping& componentMapping, const tcu::ConstPixelBufferAccess& coordAccess, const tcu::Vec2& lodBounds, const tcu::LookupPrecision& lookupPrecision, const tcu::Vec4& lookupScale, const tcu::Vec4& lookupBias, const tcu::ConstPixelBufferAccess& resultAccess, const tcu::PixelBufferAccess& errorAccess)1400 bool validateResultImage (const TestTexture&					texture,
1401 						  const VkImageViewType					imageViewType,
1402 						  const VkImageSubresourceRange&		subresource,
1403 						  const tcu::Sampler&					sampler,
1404 						  const vk::VkComponentMapping&			componentMapping,
1405 						  const tcu::ConstPixelBufferAccess&	coordAccess,
1406 						  const tcu::Vec2&						lodBounds,
1407 						  const tcu::LookupPrecision&			lookupPrecision,
1408 						  const tcu::Vec4&						lookupScale,
1409 						  const tcu::Vec4&						lookupBias,
1410 						  const tcu::ConstPixelBufferAccess&	resultAccess,
1411 						  const tcu::PixelBufferAccess&			errorAccess)
1412 {
1413 	std::vector<tcu::ConstPixelBufferAccess>	levels;
1414 
1415 	switch (imageViewType)
1416 	{
1417 		case VK_IMAGE_VIEW_TYPE_1D:
1418 		{
1419 			UniquePtr<tcu::Texture1DView>			texView(getTexture1DView(texture, subresource, levels));
1420 
1421 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1422 		}
1423 
1424 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
1425 		{
1426 			UniquePtr<tcu::Texture1DArrayView>		texView(getTexture1DArrayView(texture, subresource, levels));
1427 
1428 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1429 		}
1430 
1431 		case VK_IMAGE_VIEW_TYPE_2D:
1432 		{
1433 			UniquePtr<tcu::Texture2DView>			texView(getTexture2DView(texture, subresource, levels));
1434 
1435 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1436 		}
1437 
1438 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
1439 		{
1440 			UniquePtr<tcu::Texture2DArrayView>		texView(getTexture2DArrayView(texture, subresource, levels));
1441 
1442 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1443 		}
1444 
1445 		case VK_IMAGE_VIEW_TYPE_CUBE:
1446 		{
1447 			UniquePtr<tcu::TextureCubeView>			texView(getTextureCubeView(texture, subresource, levels));
1448 
1449 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1450 		}
1451 
1452 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
1453 		{
1454 			UniquePtr<tcu::TextureCubeArrayView>	texView(getTextureCubeArrayView(texture, subresource, levels));
1455 
1456 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1457 		}
1458 
1459 		case VK_IMAGE_VIEW_TYPE_3D:
1460 		{
1461 			UniquePtr<tcu::Texture3DView>			texView(getTexture3DView(texture, subresource, levels));
1462 
1463 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1464 		}
1465 
1466 		default:
1467 			DE_ASSERT(false);
1468 			return false;
1469 	}
1470 }
1471 
1472 } // anonymous
1473 
verifyImage(void)1474 tcu::TestStatus ImageSamplingInstance::verifyImage (void)
1475 {
1476 	const VkPhysicalDeviceLimits&		limits					= m_context.getDeviceProperties().limits;
1477 	// \note Color buffer is used to capture coordinates - not sampled texture values
1478 	const tcu::TextureFormat			colorFormat				(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1479 	const tcu::TextureFormat			depthStencilFormat;		// Undefined depth/stencil format.
1480 	const CoordinateCaptureProgram		coordCaptureProgram;
1481 	const rr::Program					rrProgram				= coordCaptureProgram.getReferenceProgram();
1482 	ReferenceRenderer					refRenderer				(m_renderSize.x(), m_renderSize.y(), 1, colorFormat, depthStencilFormat, &rrProgram);
1483 	const bool							useStencilAspect		= (m_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT);
1484 
1485 	bool								compareOkAll			= true;
1486 
1487 	tcu::Vec4							lookupScale				(1.0f);
1488 	tcu::Vec4							lookupBias				(0.0f);
1489 
1490 	getLookupScaleBias(m_imageFormat, lookupScale, lookupBias, useStencilAspect);
1491 
1492 	// Render out coordinates
1493 	{
1494 		const rr::RenderState renderState(refRenderer.getViewportState(), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
1495 		refRenderer.draw(renderState, rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
1496 	}
1497 
1498 	// Verify results
1499 	{
1500 		const tcu::Sampler					sampler			= mapVkSampler(m_samplerParams);
1501 		const float							referenceLod	= de::clamp(m_samplerParams.mipLodBias + m_samplerLod, m_samplerParams.minLod, m_samplerParams.maxLod);
1502 		const float							lodError		= 1.0f / static_cast<float>((1u << limits.mipmapPrecisionBits) - 1u);
1503 		const tcu::Vec2						lodBounds		(referenceLod - lodError, referenceLod + lodError);
1504 		const vk::VkImageSubresourceRange	subresource		= resolveSubresourceRange(*m_texture, m_subresourceRange);
1505 
1506 		const tcu::ConstPixelBufferAccess	coordAccess		= refRenderer.getAccess();
1507 		tcu::TextureLevel					errorMask		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), (int)m_renderSize.x(), (int)m_renderSize.y());
1508 		const tcu::PixelBufferAccess		errorAccess		= errorMask.getAccess();
1509 
1510 		const bool							isNearestOnly	= (m_samplerParams.minFilter == VK_FILTER_NEAREST && m_samplerParams.magFilter == VK_FILTER_NEAREST);
1511 
1512 		tcu::LookupPrecision				lookupPrecision;
1513 
1514 		// Set precision requirements - very low for these tests as
1515 		// the point of the test is not to validate accuracy.
1516 		lookupPrecision.coordBits		= tcu::IVec3(17, 17, 17);
1517 		lookupPrecision.uvwBits			= tcu::IVec3(5, 5, 5);
1518 		lookupPrecision.colorMask		= m_componentMask;
1519 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(max((tcu::IVec4(8, 8, 8, 8) - (isNearestOnly ? 1 : 2)), tcu::IVec4(0))) / swizzleScaleBias(lookupScale, m_componentMapping, 1.0f);
1520 
1521 		if (tcu::isSRGB(m_texture->getTextureFormat()))
1522 			lookupPrecision.colorThreshold += tcu::Vec4(4.f / 255.f);
1523 
1524 		de::MovePtr<TestTexture>			textureCopy;
1525 		TestTexture*						texture			= DE_NULL;
1526 
1527 		if (isCombinedDepthStencilType(m_texture->getTextureFormat().type))
1528 		{
1529 			// Verification loop does not support reading from combined depth stencil texture levels.
1530 			// Get rid of stencil component.
1531 
1532 			tcu::TextureFormat::ChannelOrder	channelOrder	= tcu::TextureFormat::CHANNELORDER_LAST;
1533 			tcu::TextureFormat::ChannelType		channelType		= tcu::TextureFormat::CHANNELTYPE_LAST;
1534 
1535 			if (subresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)
1536 			{
1537 				channelOrder	= tcu::TextureFormat::S;
1538 				channelType		= tcu::TextureFormat::UNSIGNED_INT8;
1539 			}
1540 			else
1541 			{
1542 				channelOrder = tcu::TextureFormat::D;
1543 
1544 				switch (m_texture->getTextureFormat().type)
1545 				{
1546 				case tcu::TextureFormat::UNSIGNED_INT_16_8_8:
1547 					channelType = tcu::TextureFormat::UNORM_INT16;
1548 					break;
1549 				case tcu::TextureFormat::UNSIGNED_INT_24_8:
1550 				case tcu::TextureFormat::UNSIGNED_INT_24_8_REV:
1551 					channelType = tcu::TextureFormat::UNORM_INT24;
1552 					break;
1553 				case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1554 					channelType = tcu::TextureFormat::FLOAT;
1555 					break;
1556 				default:
1557 					DE_FATAL("Unhandled texture format type in switch");
1558 				}
1559 			}
1560 
1561 			textureCopy	= m_texture->copy(tcu::TextureFormat(channelOrder, channelType));
1562 			texture		= textureCopy.get();
1563 		}
1564 		else
1565 		{
1566 			texture		= m_texture.get();
1567 		}
1568 
1569 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
1570 		{
1571 			// Read back result image
1572 			UniquePtr<tcu::TextureLevel>		result			(readColorAttachment(m_context.getDeviceInterface(),
1573 																					 m_context.getDevice(),
1574 																					 m_context.getUniversalQueue(),
1575 																					 m_context.getUniversalQueueFamilyIndex(),
1576 																					 m_context.getDefaultAllocator(),
1577 																					 **m_colorImages[imgNdx],
1578 																					 m_colorFormat,
1579 																					 m_renderSize));
1580 			const tcu::ConstPixelBufferAccess	resultAccess	= result->getAccess();
1581 			bool								compareOk		= validateResultImage(*texture,
1582 																					  m_imageViewType,
1583 																					  subresource,
1584 																					  sampler,
1585 																					  m_componentMapping,
1586 																					  coordAccess,
1587 																					  lodBounds,
1588 																					  lookupPrecision,
1589 																					  lookupScale,
1590 																					  lookupBias,
1591 																					  resultAccess,
1592 																					  errorAccess);
1593 			if (!compareOk)
1594 				m_context.getTestContext().getLog()
1595 				<< tcu::TestLog::Image("Result", "Result Image", resultAccess)
1596 				<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorAccess);
1597 
1598 			compareOkAll = compareOkAll && compareOk;
1599 		}
1600 	}
1601 
1602 	if (compareOkAll)
1603 		return tcu::TestStatus::pass("Result image matches reference");
1604 	else
1605 		return tcu::TestStatus::fail("Image mismatch");
1606 }
1607 
1608 } // pipeline
1609 } // vkt
1610