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