• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "tcuTexLookupVerifier.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "deSTLUtil.hpp"
36 
37 namespace vkt
38 {
39 namespace pipeline
40 {
41 
42 using namespace vk;
43 using de::MovePtr;
44 using de::UniquePtr;
45 
46 namespace
47 {
48 
getCompatibleImageType(VkImageViewType viewType)49 static VkImageType getCompatibleImageType (VkImageViewType viewType)
50 {
51 	switch (viewType)
52 	{
53 		case VK_IMAGE_VIEW_TYPE_1D:				return VK_IMAGE_TYPE_1D;
54 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:		return VK_IMAGE_TYPE_1D;
55 		case VK_IMAGE_VIEW_TYPE_2D:				return VK_IMAGE_TYPE_2D;
56 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:		return VK_IMAGE_TYPE_2D;
57 		case VK_IMAGE_VIEW_TYPE_3D:				return VK_IMAGE_TYPE_3D;
58 		case VK_IMAGE_VIEW_TYPE_CUBE:			return VK_IMAGE_TYPE_2D;
59 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:		return VK_IMAGE_TYPE_2D;
60 		default:
61 			break;
62 	}
63 
64 	DE_ASSERT(false);
65 	return VK_IMAGE_TYPE_1D;
66 }
67 
68 template<typename TcuFormatType>
createTestTexture(const TcuFormatType format,VkImageViewType viewType,const tcu::IVec3 & size,int layerCount)69 static MovePtr<TestTexture> createTestTexture (const TcuFormatType format, VkImageViewType viewType, const tcu::IVec3& size, int layerCount)
70 {
71 	MovePtr<TestTexture>	texture;
72 	const VkImageType		imageType = getCompatibleImageType(viewType);
73 
74 	switch (imageType)
75 	{
76 		case VK_IMAGE_TYPE_1D:
77 			if (layerCount == 1)
78 				texture = MovePtr<TestTexture>(new TestTexture1D(format, size.x()));
79 			else
80 				texture = MovePtr<TestTexture>(new TestTexture1DArray(format, size.x(), layerCount));
81 
82 			break;
83 
84 		case VK_IMAGE_TYPE_2D:
85 			if (layerCount == 1)
86 			{
87 				texture = MovePtr<TestTexture>(new TestTexture2D(format, size.x(), size.y()));
88 			}
89 			else
90 			{
91 				if (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
92 				{
93 					if (layerCount == tcu::CUBEFACE_LAST && viewType == VK_IMAGE_VIEW_TYPE_CUBE)
94 					{
95 						texture = MovePtr<TestTexture>(new TestTextureCube(format, size.x()));
96 					}
97 					else
98 					{
99 						DE_ASSERT(layerCount % tcu::CUBEFACE_LAST == 0);
100 
101 						texture = MovePtr<TestTexture>(new TestTextureCubeArray(format, size.x(), layerCount));
102 					}
103 				}
104 				else
105 				{
106 					texture = MovePtr<TestTexture>(new TestTexture2DArray(format, size.x(), size.y(), layerCount));
107 				}
108 			}
109 
110 			break;
111 
112 		case VK_IMAGE_TYPE_3D:
113 			texture = MovePtr<TestTexture>(new TestTexture3D(format, size.x(), size.y(), size.z()));
114 			break;
115 
116 		default:
117 			DE_ASSERT(false);
118 	}
119 
120 	return texture;
121 }
122 
123 } // anonymous
124 
ImageSamplingInstance(Context & context,const tcu::UVec2 & renderSize,VkImageViewType imageViewType,VkFormat imageFormat,const tcu::IVec3 & imageSize,int layerCount,const VkComponentMapping & componentMapping,const VkImageSubresourceRange & subresourceRange,const VkSamplerCreateInfo & samplerParams,float samplerLod,const std::vector<Vertex4Tex4> & vertices,VkDescriptorType samplingType,int imageCount)125 ImageSamplingInstance::ImageSamplingInstance (Context&							context,
126 											  const tcu::UVec2&					renderSize,
127 											  VkImageViewType					imageViewType,
128 											  VkFormat							imageFormat,
129 											  const tcu::IVec3&					imageSize,
130 											  int								layerCount,
131 											  const VkComponentMapping&			componentMapping,
132 											  const VkImageSubresourceRange&	subresourceRange,
133 											  const VkSamplerCreateInfo&		samplerParams,
134 											  float								samplerLod,
135 											  const std::vector<Vertex4Tex4>&	vertices,
136 											  VkDescriptorType					samplingType,
137 											  int								imageCount)
138 	: vkt::TestInstance		(context)
139 	, m_samplingType		(samplingType)
140 	, m_imageViewType		(imageViewType)
141 	, m_imageFormat			(imageFormat)
142 	, m_imageSize			(imageSize)
143 	, m_layerCount			(layerCount)
144 	, m_imageCount			(imageCount)
145 	, m_componentMapping	(componentMapping)
146 	, m_subresourceRange	(subresourceRange)
147 	, m_samplerParams		(samplerParams)
148 	, m_samplerLod			(samplerLod)
149 	, m_renderSize			(renderSize)
150 	, m_colorFormat			(VK_FORMAT_R8G8B8A8_UNORM)
151 	, m_vertices			(vertices)
152 {
153 	const DeviceInterface&		vk						= context.getDeviceInterface();
154 	const VkDevice				vkDevice				= context.getDevice();
155 	const VkQueue				queue					= context.getUniversalQueue();
156 	const deUint32				queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
157 	SimpleAllocator				memAlloc				(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
158 	const VkComponentMapping	componentMappingRGBA	= { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
159 
160 	if (!isSupportedSamplableFormat(context.getInstanceInterface(), context.getPhysicalDevice(), imageFormat))
161 		throw tcu::NotSupportedError(std::string("Unsupported format for sampling: ") + getFormatName(imageFormat));
162 
163 	if ((deUint32)imageCount > context.getDeviceProperties().limits.maxColorAttachments)
164 		throw tcu::NotSupportedError(std::string("Unsupported render target count: ") + de::toString(imageCount));
165 
166 	if ((samplerParams.minFilter == VK_FILTER_LINEAR ||
167 		 samplerParams.magFilter == VK_FILTER_LINEAR ||
168 		 samplerParams.mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR) &&
169 		!isLinearFilteringSupported(context.getInstanceInterface(), context.getPhysicalDevice(), imageFormat, VK_IMAGE_TILING_OPTIMAL))
170 		throw tcu::NotSupportedError(std::string("Unsupported format for linear filtering: ") + getFormatName(imageFormat));
171 
172 	if ((samplerParams.addressModeU == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
173 		 samplerParams.addressModeV == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
174 		 samplerParams.addressModeW == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE) &&
175 		!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_sampler_mirror_clamp_to_edge"))
176 		TCU_THROW(NotSupportedError, "VK_KHR_sampler_mirror_clamp_to_edge not supported");
177 
178 	if (isCompressedFormat(imageFormat) && imageViewType == VK_IMAGE_VIEW_TYPE_3D)
179 	{
180 		// \todo [2016-01-22 pyry] Mandate VK_ERROR_FORMAT_NOT_SUPPORTED
181 		try
182 		{
183 			const VkImageFormatProperties	formatProperties	= getPhysicalDeviceImageFormatProperties(context.getInstanceInterface(),
184 																										 context.getPhysicalDevice(),
185 																										 imageFormat,
186 																										 VK_IMAGE_TYPE_3D,
187 																										 VK_IMAGE_TILING_OPTIMAL,
188 																										 VK_IMAGE_USAGE_SAMPLED_BIT,
189 																										 (VkImageCreateFlags)0);
190 
191 			if (formatProperties.maxExtent.width == 0 &&
192 				formatProperties.maxExtent.height == 0 &&
193 				formatProperties.maxExtent.depth == 0)
194 				TCU_THROW(NotSupportedError, "3D compressed format not supported");
195 		}
196 		catch (const Error&)
197 		{
198 			TCU_THROW(NotSupportedError, "3D compressed format not supported");
199 		}
200 	}
201 
202 	if (imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && !context.getDeviceFeatures().imageCubeArray)
203 		TCU_THROW(NotSupportedError, "imageCubeArray feature is not supported");
204 
205 	// Create texture images, views and samplers
206 	{
207 		VkImageCreateFlags			imageFlags			= 0u;
208 
209 		if (m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE || m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
210 			imageFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
211 
212 		// Initialize texture data
213 		if (isCompressedFormat(imageFormat))
214 			m_texture = createTestTexture(mapVkCompressedFormat(imageFormat), imageViewType, imageSize, layerCount);
215 		else
216 			m_texture = createTestTexture(mapVkFormat(imageFormat), imageViewType, imageSize, layerCount);
217 
218 		const VkImageCreateInfo	imageParams =
219 		{
220 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,							// VkStructureType			sType;
221 			DE_NULL,														// const void*				pNext;
222 			imageFlags,														// VkImageCreateFlags		flags;
223 			getCompatibleImageType(m_imageViewType),						// VkImageType				imageType;
224 			imageFormat,													// VkFormat					format;
225 			{																// VkExtent3D				extent;
226 				(deUint32)m_imageSize.x(),
227 				(deUint32)m_imageSize.y(),
228 				(deUint32)m_imageSize.z()
229 			},
230 			(deUint32)m_texture->getNumLevels(),							// deUint32					mipLevels;
231 			(deUint32)m_layerCount,											// deUint32					arrayLayers;
232 			VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits	samples;
233 			VK_IMAGE_TILING_OPTIMAL,										// VkImageTiling			tiling;
234 			VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,	// VkImageUsageFlags		usage;
235 			VK_SHARING_MODE_EXCLUSIVE,										// VkSharingMode			sharingMode;
236 			1u,																// deUint32					queueFamilyIndexCount;
237 			&queueFamilyIndex,												// const deUint32*			pQueueFamilyIndices;
238 			VK_IMAGE_LAYOUT_UNDEFINED										// VkImageLayout			initialLayout;
239 		};
240 
241 		m_images.resize(m_imageCount);
242 		m_imageAllocs.resize(m_imageCount);
243 		m_imageViews.resize(m_imageCount);
244 
245 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
246 		{
247 			m_images[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &imageParams)));
248 			m_imageAllocs[imgNdx] = SharedAllocPtr(new UniqueAlloc(memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, **m_images[imgNdx]), MemoryRequirement::Any)));
249 			VK_CHECK(vk.bindImageMemory(vkDevice, **m_images[imgNdx], (*m_imageAllocs[imgNdx])->getMemory(), (*m_imageAllocs[imgNdx])->getOffset()));
250 
251 			// Upload texture data
252 			uploadTestTexture(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_texture, **m_images[imgNdx]);
253 
254 			// Create image view and sampler
255 			const VkImageViewCreateInfo imageViewParams =
256 			{
257 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType			sType;
258 				DE_NULL,									// const void*				pNext;
259 				0u,											// VkImageViewCreateFlags	flags;
260 				**m_images[imgNdx],							// VkImage					image;
261 				m_imageViewType,							// VkImageViewType			viewType;
262 				imageFormat,								// VkFormat					format;
263 				m_componentMapping,							// VkComponentMapping		components;
264 				m_subresourceRange,							// VkImageSubresourceRange	subresourceRange;
265 			};
266 
267 			m_imageViews[imgNdx] = SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &imageViewParams)));
268 		}
269 
270 		m_sampler	= createSampler(vk, vkDevice, &m_samplerParams);
271 	}
272 
273 	// Create descriptor set for image and sampler
274 	{
275 		DescriptorPoolBuilder descriptorPoolBuilder;
276 		if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
277 			descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER, 1u);
278 		descriptorPoolBuilder.addType(m_samplingType, m_imageCount);
279 		m_descriptorPool = descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
280 			m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? m_imageCount + 1u : m_imageCount);
281 
282 		DescriptorSetLayoutBuilder setLayoutBuilder;
283 		if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
284 			setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
285 		setLayoutBuilder.addArrayBinding(m_samplingType, m_imageCount, VK_SHADER_STAGE_FRAGMENT_BIT);
286 		m_descriptorSetLayout = setLayoutBuilder.build(vk, vkDevice);
287 
288 		const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
289 		{
290 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
291 			DE_NULL,											// const void*					pNext;
292 			*m_descriptorPool,									// VkDescriptorPool				descriptorPool;
293 			1u,													// deUint32						setLayoutCount;
294 			&m_descriptorSetLayout.get()						// const VkDescriptorSetLayout*	pSetLayouts;
295 		};
296 
297 		m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocateInfo);
298 
299 		const VkSampler sampler = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? DE_NULL : *m_sampler;
300 		std::vector<VkDescriptorImageInfo> descriptorImageInfo(m_imageCount);
301 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
302 		{
303 			descriptorImageInfo[imgNdx].sampler		= sampler;									// VkSampler		sampler;
304 			descriptorImageInfo[imgNdx].imageView	= **m_imageViews[imgNdx];					// VkImageView		imageView;
305 			descriptorImageInfo[imgNdx].imageLayout	= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;	// VkImageLayout	imageLayout;
306 		}
307 
308 		DescriptorSetUpdateBuilder setUpdateBuilder;
309 		if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
310 		{
311 			const VkDescriptorImageInfo descriptorSamplerInfo =
312 			{
313 				*m_sampler,									// VkSampler		sampler;
314 				DE_NULL,									// VkImageView		imageView;
315 				VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL	// VkImageLayout	imageLayout;
316 			};
317 			setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_SAMPLER, &descriptorSamplerInfo);
318 		}
319 
320 		const deUint32 binding = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? 1u : 0u;
321 		setUpdateBuilder.writeArray(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(binding), m_samplingType, m_imageCount, descriptorImageInfo.data());
322 		setUpdateBuilder.update(vk, vkDevice);
323 	}
324 
325 	// Create color images and views
326 	{
327 		const VkImageCreateInfo colorImageParams =
328 		{
329 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
330 			DE_NULL,																	// const void*				pNext;
331 			0u,																			// VkImageCreateFlags		flags;
332 			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
333 			m_colorFormat,																// VkFormat					format;
334 			{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y(), 1u },				// VkExtent3D				extent;
335 			1u,																			// deUint32					mipLevels;
336 			1u,																			// deUint32					arrayLayers;
337 			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
338 			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
339 			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,		// VkImageUsageFlags		usage;
340 			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
341 			1u,																			// deUint32					queueFamilyIndexCount;
342 			&queueFamilyIndex,															// const deUint32*			pQueueFamilyIndices;
343 			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout			initialLayout;
344 		};
345 
346 		m_colorImages.resize(m_imageCount);
347 		m_colorImageAllocs.resize(m_imageCount);
348 		m_colorAttachmentViews.resize(m_imageCount);
349 
350 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
351 		{
352 			m_colorImages[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &colorImageParams)));
353 			m_colorImageAllocs[imgNdx] = SharedAllocPtr(new UniqueAlloc(memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, **m_colorImages[imgNdx]), MemoryRequirement::Any)));
354 			VK_CHECK(vk.bindImageMemory(vkDevice, **m_colorImages[imgNdx], (*m_colorImageAllocs[imgNdx])->getMemory(), (*m_colorImageAllocs[imgNdx])->getOffset()));
355 
356 			const VkImageViewCreateInfo colorAttachmentViewParams =
357 			{
358 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType			sType;
359 				DE_NULL,											// const void*				pNext;
360 				0u,													// VkImageViewCreateFlags	flags;
361 				**m_colorImages[imgNdx],							// VkImage					image;
362 				VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType			viewType;
363 				m_colorFormat,										// VkFormat					format;
364 				componentMappingRGBA,								// VkComponentMapping		components;
365 				{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }		// VkImageSubresourceRange	subresourceRange;
366 			};
367 
368 			m_colorAttachmentViews[imgNdx] = SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &colorAttachmentViewParams)));
369 		}
370 	}
371 
372 	// Create render pass
373 	{
374 		std::vector<VkAttachmentDescription>	colorAttachmentDescriptions(m_imageCount);
375 		std::vector<VkAttachmentReference>		colorAttachmentReferences(m_imageCount);
376 
377 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
378 		{
379 			colorAttachmentDescriptions[imgNdx].flags			= 0u;										// VkAttachmentDescriptionFlags		flags;
380 			colorAttachmentDescriptions[imgNdx].format			= m_colorFormat;							// VkFormat							format;
381 			colorAttachmentDescriptions[imgNdx].samples			= VK_SAMPLE_COUNT_1_BIT;					// VkSampleCountFlagBits			samples;
382 			colorAttachmentDescriptions[imgNdx].loadOp			= VK_ATTACHMENT_LOAD_OP_CLEAR;				// VkAttachmentLoadOp				loadOp;
383 			colorAttachmentDescriptions[imgNdx].storeOp			= VK_ATTACHMENT_STORE_OP_STORE;				// VkAttachmentStoreOp				storeOp;
384 			colorAttachmentDescriptions[imgNdx].stencilLoadOp	= VK_ATTACHMENT_LOAD_OP_DONT_CARE;			// VkAttachmentLoadOp				stencilLoadOp;
385 			colorAttachmentDescriptions[imgNdx].stencilStoreOp	= VK_ATTACHMENT_STORE_OP_DONT_CARE;			// VkAttachmentStoreOp				stencilStoreOp;
386 			colorAttachmentDescriptions[imgNdx].initialLayout	= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout					initialLayout;
387 			colorAttachmentDescriptions[imgNdx].finalLayout		= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout					finalLayout;
388 
389 			colorAttachmentReferences[imgNdx].attachment		= (deUint32)imgNdx;							// deUint32							attachment;
390 			colorAttachmentReferences[imgNdx].layout			= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout					layout;
391 		}
392 
393 		const VkSubpassDescription subpassDescription =
394 		{
395 			0u,													// VkSubpassDescriptionFlags	flags;
396 			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint			pipelineBindPoint;
397 			0u,													// deUint32						inputAttachmentCount;
398 			DE_NULL,											// const VkAttachmentReference*	pInputAttachments;
399 			(deUint32)m_imageCount,								// deUint32						colorAttachmentCount;
400 			&colorAttachmentReferences[0],						// const VkAttachmentReference*	pColorAttachments;
401 			DE_NULL,											// const VkAttachmentReference*	pResolveAttachments;
402 			DE_NULL,											// const VkAttachmentReference*	pDepthStencilAttachment;
403 			0u,													// deUint32						preserveAttachmentCount;
404 			DE_NULL												// const VkAttachmentReference*	pPreserveAttachments;
405 		};
406 
407 		const VkRenderPassCreateInfo renderPassParams =
408 		{
409 			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
410 			DE_NULL,											// const void*						pNext;
411 			0u,													// VkRenderPassCreateFlags			flags;
412 			(deUint32)m_imageCount,								// deUint32							attachmentCount;
413 			&colorAttachmentDescriptions[0],					// const VkAttachmentDescription*	pAttachments;
414 			1u,													// deUint32							subpassCount;
415 			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
416 			0u,													// deUint32							dependencyCount;
417 			DE_NULL												// const VkSubpassDependency*		pDependencies;
418 		};
419 
420 		m_renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
421 	}
422 
423 	// Create framebuffer
424 	{
425 		std::vector<VkImageView> pAttachments(m_imageCount);
426 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
427 			pAttachments[imgNdx] = m_colorAttachmentViews[imgNdx]->get();
428 
429 		const VkFramebufferCreateInfo framebufferParams =
430 		{
431 			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType			sType;
432 			DE_NULL,											// const void*				pNext;
433 			0u,													// VkFramebufferCreateFlags	flags;
434 			*m_renderPass,										// VkRenderPass				renderPass;
435 			(deUint32)m_imageCount,								// deUint32					attachmentCount;
436 			&pAttachments[0],									// const VkImageView*		pAttachments;
437 			(deUint32)m_renderSize.x(),							// deUint32					width;
438 			(deUint32)m_renderSize.y(),							// deUint32					height;
439 			1u													// deUint32					layers;
440 		};
441 
442 		m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
443 	}
444 
445 	// Create pipeline layout
446 	{
447 		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
448 		{
449 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
450 			DE_NULL,											// const void*					pNext;
451 			0u,													// VkPipelineLayoutCreateFlags	flags;
452 			1u,													// deUint32						setLayoutCount;
453 			&m_descriptorSetLayout.get(),						// const VkDescriptorSetLayout*	pSetLayouts;
454 			0u,													// deUint32						pushConstantRangeCount;
455 			DE_NULL												// const VkPushConstantRange*	pPushConstantRanges;
456 		};
457 
458 		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
459 	}
460 
461 	m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tex_vert"), 0);
462 	m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tex_frag"), 0);
463 
464 	// Create pipeline
465 	{
466 		const VkPipelineShaderStageCreateInfo shaderStages[2] =
467 		{
468 			{
469 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
470 				DE_NULL,													// const void*							pNext;
471 				0u,															// VkPipelineShaderStageCreateFlags		flags;
472 				VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
473 				*m_vertexShaderModule,										// VkShaderModule						module;
474 				"main",														// const char*							pName;
475 				DE_NULL														// const VkSpecializationInfo*			pSpecializationInfo;
476 			},
477 			{
478 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
479 				DE_NULL,													// const void*							pNext;
480 				0u,															// VkPipelineShaderStageCreateFlags		flags;
481 				VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
482 				*m_fragmentShaderModule,									// VkShaderModule						module;
483 				"main",														// const char*							pName;
484 				DE_NULL														// const VkSpecializationInfo*			pSpecializationInfo;
485 			}
486 		};
487 
488 		const VkVertexInputBindingDescription vertexInputBindingDescription =
489 		{
490 			0u,									// deUint32					binding;
491 			sizeof(Vertex4Tex4),				// deUint32					strideInBytes;
492 			VK_VERTEX_INPUT_RATE_VERTEX			// VkVertexInputStepRate	inputRate;
493 		};
494 
495 		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
496 		{
497 			{
498 				0u,										// deUint32	location;
499 				0u,										// deUint32	binding;
500 				VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
501 				0u										// deUint32	offset;
502 			},
503 			{
504 				1u,										// deUint32	location;
505 				0u,										// deUint32	binding;
506 				VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat	format;
507 				DE_OFFSET_OF(Vertex4Tex4, texCoord),	// deUint32	offset;
508 			}
509 		};
510 
511 		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
512 		{
513 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
514 			DE_NULL,														// const void*								pNext;
515 			0u,																// VkPipelineVertexInputStateCreateFlags	flags;
516 			1u,																// deUint32									vertexBindingDescriptionCount;
517 			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
518 			2u,																// deUint32									vertexAttributeDescriptionCount;
519 			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
520 		};
521 
522 		const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
523 		{
524 			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType							sType;
525 			DE_NULL,														// const void*								pNext;
526 			0u,																// VkPipelineInputAssemblyStateCreateFlags	flags;
527 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,							// VkPrimitiveTopology						topology;
528 			false															// VkBool32									primitiveRestartEnable;
529 		};
530 
531 		const VkViewport viewport =
532 		{
533 			0.0f,						// float	x;
534 			0.0f,						// float	y;
535 			(float)m_renderSize.x(),	// float	width;
536 			(float)m_renderSize.y(),	// float	height;
537 			0.0f,						// float	minDepth;
538 			1.0f						// float	maxDepth;
539 		};
540 
541 		const VkRect2D scissor = { { 0, 0 }, { (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() } };
542 
543 		const VkPipelineViewportStateCreateInfo viewportStateParams =
544 		{
545 			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType						sType;
546 			DE_NULL,														// const void*							pNext;
547 			0u,																// VkPipelineViewportStateCreateFlags	flags;
548 			1u,																// deUint32								viewportCount;
549 			&viewport,														// const VkViewport*					pViewports;
550 			1u,																// deUint32								scissorCount;
551 			&scissor														// const VkRect2D*						pScissors;
552 		};
553 
554 		const VkPipelineRasterizationStateCreateInfo rasterStateParams =
555 		{
556 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType							sType;
557 			DE_NULL,														// const void*								pNext;
558 			0u,																// VkPipelineRasterizationStateCreateFlags	flags;
559 			false,															// VkBool32									depthClampEnable;
560 			false,															// VkBool32									rasterizerDiscardEnable;
561 			VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
562 			VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
563 			VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
564 			false,															// VkBool32									depthBiasEnable;
565 			0.0f,															// float									depthBiasConstantFactor;
566 			0.0f,															// float									depthBiasClamp;
567 			0.0f,															// float									depthBiasSlopeFactor;
568 			1.0f															// float									lineWidth;
569 		};
570 
571 		std::vector<VkPipelineColorBlendAttachmentState>	colorBlendAttachmentStates(m_imageCount);
572 
573 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
574 		{
575 			colorBlendAttachmentStates[imgNdx].blendEnable			= false;												// VkBool32					blendEnable;
576 			colorBlendAttachmentStates[imgNdx].srcColorBlendFactor	= VK_BLEND_FACTOR_ONE;									// VkBlendFactor			srcColorBlendFactor;
577 			colorBlendAttachmentStates[imgNdx].dstColorBlendFactor	= VK_BLEND_FACTOR_ZERO;									// VkBlendFactor			dstColorBlendFactor;
578 			colorBlendAttachmentStates[imgNdx].colorBlendOp			= VK_BLEND_OP_ADD;										// VkBlendOp				colorBlendOp;
579 			colorBlendAttachmentStates[imgNdx].srcAlphaBlendFactor	= VK_BLEND_FACTOR_ONE;									// VkBlendFactor			srcAlphaBlendFactor;
580 			colorBlendAttachmentStates[imgNdx].dstAlphaBlendFactor	= VK_BLEND_FACTOR_ZERO;									// VkBlendFactor			dstAlphaBlendFactor;
581 			colorBlendAttachmentStates[imgNdx].alphaBlendOp			= VK_BLEND_OP_ADD;										// VkBlendOp				alphaBlendOp;
582 			colorBlendAttachmentStates[imgNdx].colorWriteMask		= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |	// VkColorComponentFlags	colorWriteMask;
583 																		VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
584 		}
585 
586 		const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
587 		{
588 			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
589 			DE_NULL,													// const void*									pNext;
590 			0u,															// VkPipelineColorBlendStateCreateFlags			flags;
591 			false,														// VkBool32										logicOpEnable;
592 			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
593 			(deUint32)m_imageCount,										// deUint32										attachmentCount;
594 			&colorBlendAttachmentStates[0],								// const VkPipelineColorBlendAttachmentState*	pAttachments;
595 			{ 0.0f, 0.0f, 0.0f, 0.0f }									// float										blendConstants[4];
596 		};
597 
598 		const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
599 		{
600 			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
601 			DE_NULL,													// const void*								pNext;
602 			0u,															// VkPipelineMultisampleStateCreateFlags	flags;
603 			VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits					rasterizationSamples;
604 			false,														// VkBool32									sampleShadingEnable;
605 			0.0f,														// float									minSampleShading;
606 			DE_NULL,													// const VkSampleMask*						pSampleMask;
607 			false,														// VkBool32									alphaToCoverageEnable;
608 			false														// VkBool32									alphaToOneEnable;
609 		};
610 
611 		VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
612 		{
613 			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
614 			DE_NULL,													// const void*								pNext;
615 			0u,															// VkPipelineDepthStencilStateCreateFlags	flags;
616 			false,														// VkBool32									depthTestEnable;
617 			false,														// VkBool32									depthWriteEnable;
618 			VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
619 			false,														// VkBool32									depthBoundsTestEnable;
620 			false,														// VkBool32									stencilTestEnable;
621 			{															// VkStencilOpState							front;
622 				VK_STENCIL_OP_ZERO,		// VkStencilOp	failOp;
623 				VK_STENCIL_OP_ZERO,		// VkStencilOp	passOp;
624 				VK_STENCIL_OP_ZERO,		// VkStencilOp	depthFailOp;
625 				VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
626 				0u,						// deUint32		compareMask;
627 				0u,						// deUint32		writeMask;
628 				0u						// deUint32		reference;
629 			},
630 			{															// VkStencilOpState	back;
631 				VK_STENCIL_OP_ZERO,		// VkStencilOp	failOp;
632 				VK_STENCIL_OP_ZERO,		// VkStencilOp	passOp;
633 				VK_STENCIL_OP_ZERO,		// VkStencilOp	depthFailOp;
634 				VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
635 				0u,						// deUint32		compareMask;
636 				0u,						// deUint32		writeMask;
637 				0u						// deUint32		reference;
638 			},
639 			0.0f,														// float			minDepthBounds;
640 			1.0f														// float			maxDepthBounds;
641 		};
642 
643 		const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
644 		{
645 			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
646 			DE_NULL,											// const void*										pNext;
647 			0u,													// VkPipelineCreateFlags							flags;
648 			2u,													// deUint32											stageCount;
649 			shaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
650 			&vertexInputStateParams,							// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
651 			&inputAssemblyStateParams,							// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
652 			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
653 			&viewportStateParams,								// const VkPipelineViewportStateCreateInfo*			pViewportState;
654 			&rasterStateParams,									// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
655 			&multisampleStateParams,							// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
656 			&depthStencilStateParams,							// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
657 			&colorBlendStateParams,								// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
658 			(const VkPipelineDynamicStateCreateInfo*)DE_NULL,	// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
659 			*m_pipelineLayout,									// VkPipelineLayout									layout;
660 			*m_renderPass,										// VkRenderPass										renderPass;
661 			0u,													// deUint32											subpass;
662 			0u,													// VkPipeline										basePipelineHandle;
663 			0u													// deInt32											basePipelineIndex;
664 		};
665 
666 		m_graphicsPipeline	= createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
667 	}
668 
669 	// Create vertex buffer
670 	{
671 		const VkDeviceSize			vertexBufferSize	= (VkDeviceSize)(m_vertices.size() * sizeof(Vertex4Tex4));
672 		const VkBufferCreateInfo	vertexBufferParams	=
673 		{
674 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
675 			DE_NULL,									// const void*			pNext;
676 			0u,											// VkBufferCreateFlags	flags;
677 			vertexBufferSize,							// VkDeviceSize			size;
678 			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
679 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
680 			1u,											// deUint32				queueFamilyIndexCount;
681 			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
682 		};
683 
684 		DE_ASSERT(vertexBufferSize > 0);
685 
686 		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
687 		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
688 
689 		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
690 
691 		// Load vertices into vertex buffer
692 		deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], (size_t)vertexBufferSize);
693 		flushMappedMemoryRange(vk, vkDevice, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), vertexBufferParams.size);
694 	}
695 
696 	// Create command pool
697 	{
698 		const VkCommandPoolCreateInfo cmdPoolParams =
699 		{
700 			VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,		// VkStructureType				sType;
701 			DE_NULL,										// const void*					pNext;
702 			VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,			// VkCommandPoolCreateFlags	flags;
703 			queueFamilyIndex								// deUint32					queueFamilyIndex;
704 		};
705 
706 		m_cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
707 	}
708 
709 	// Create command buffer
710 	{
711 		const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
712 		{
713 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
714 			DE_NULL,										// const void*				pNext;
715 			*m_cmdPool,										// VkCommandPool			commandPool;
716 			VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
717 			1u,												// deUint32					bufferCount;
718 		};
719 
720 		const VkCommandBufferBeginInfo cmdBufferBeginInfo =
721 		{
722 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType					sType;
723 			DE_NULL,										// const void*						pNext;
724 			0u,												// VkCommandBufferUsageFlags		flags;
725 			(const VkCommandBufferInheritanceInfo*)DE_NULL,
726 		};
727 
728 		const std::vector<VkClearValue> attachmentClearValues (m_imageCount, defaultClearValue(m_colorFormat));
729 
730 		const VkRenderPassBeginInfo renderPassBeginInfo =
731 		{
732 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,				// VkStructureType		sType;
733 			DE_NULL,												// const void*			pNext;
734 			*m_renderPass,											// VkRenderPass			renderPass;
735 			*m_framebuffer,											// VkFramebuffer		framebuffer;
736 			{
737 				{ 0, 0 },
738 				{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
739 			},														// VkRect2D				renderArea;
740 			static_cast<deUint32>(attachmentClearValues.size()),	// deUint32				clearValueCount;
741 			&attachmentClearValues[0]								// const VkClearValue*	pClearValues;
742 		};
743 
744 		std::vector<VkImageMemoryBarrier> preAttachmentBarriers(m_imageCount);
745 
746 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
747 		{
748 			preAttachmentBarriers[imgNdx].sType								= VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;	// VkStructureType			sType;
749 			preAttachmentBarriers[imgNdx].pNext								= DE_NULL;									// const void*				pNext;
750 			preAttachmentBarriers[imgNdx].srcAccessMask						= 0u;										// VkAccessFlags			srcAccessMask;
751 			preAttachmentBarriers[imgNdx].dstAccessMask						= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;		// VkAccessFlags			dstAccessMask;
752 			preAttachmentBarriers[imgNdx].oldLayout							= VK_IMAGE_LAYOUT_UNDEFINED;				// VkImageLayout			oldLayout;
753 			preAttachmentBarriers[imgNdx].newLayout							= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;	// VkImageLayout			newLayout;
754 			preAttachmentBarriers[imgNdx].srcQueueFamilyIndex				= VK_QUEUE_FAMILY_IGNORED;					// deUint32					srcQueueFamilyIndex;
755 			preAttachmentBarriers[imgNdx].dstQueueFamilyIndex				= VK_QUEUE_FAMILY_IGNORED;					// deUint32					dstQueueFamilyIndex;
756 			preAttachmentBarriers[imgNdx].image								= **m_colorImages[imgNdx];					// VkImage					image;
757 			preAttachmentBarriers[imgNdx].subresourceRange.aspectMask		= VK_IMAGE_ASPECT_COLOR_BIT;				// VkImageSubresourceRange	subresourceRange;
758 			preAttachmentBarriers[imgNdx].subresourceRange.baseMipLevel		= 0u;
759 			preAttachmentBarriers[imgNdx].subresourceRange.levelCount		= 1u;
760 			preAttachmentBarriers[imgNdx].subresourceRange.baseArrayLayer	= 0u;
761 			preAttachmentBarriers[imgNdx].subresourceRange.layerCount		= 1u;
762 		}
763 
764 		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferAllocateInfo);
765 
766 		VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo));
767 
768 		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (VkDependencyFlags)0,
769 			0u, DE_NULL, 0u, DE_NULL, (deUint32)m_imageCount, &preAttachmentBarriers[0]);
770 
771 		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
772 
773 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline);
774 
775 		vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
776 
777 		const VkDeviceSize vertexBufferOffset = 0;
778 		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
779 		vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
780 
781 		vk.cmdEndRenderPass(*m_cmdBuffer);
782 		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
783 	}
784 
785 	// Create fence
786 	{
787 		const VkFenceCreateInfo fenceParams =
788 		{
789 			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
790 			DE_NULL,								// const void*			pNext;
791 			0u										// VkFenceCreateFlags	flags;
792 		};
793 
794 		m_fence = createFence(vk, vkDevice, &fenceParams);
795 	}
796 }
797 
~ImageSamplingInstance(void)798 ImageSamplingInstance::~ImageSamplingInstance (void)
799 {
800 }
801 
iterate(void)802 tcu::TestStatus ImageSamplingInstance::iterate (void)
803 {
804 	const DeviceInterface&		vk			= m_context.getDeviceInterface();
805 	const VkDevice				vkDevice	= m_context.getDevice();
806 	const VkQueue				queue		= m_context.getUniversalQueue();
807 	const VkSubmitInfo			submitInfo	=
808 	{
809 		VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
810 		DE_NULL,						// const void*				pNext;
811 		0u,								// deUint32					waitSemaphoreCount;
812 		DE_NULL,						// const VkSemaphore*		pWaitSemaphores;
813 		DE_NULL,
814 		1u,								// deUint32					commandBufferCount;
815 		&m_cmdBuffer.get(),				// const VkCommandBuffer*	pCommandBuffers;
816 		0u,								// deUint32					signalSemaphoreCount;
817 		DE_NULL							// const VkSemaphore*		pSignalSemaphores;
818 	};
819 
820 	VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get()));
821 	VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence));
822 	VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
823 
824 	return verifyImage();
825 }
826 
827 namespace
828 {
829 
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)830 bool isLookupResultValid (const tcu::Texture1DView&		texture,
831 						  const tcu::Sampler&			sampler,
832 						  const tcu::LookupPrecision&	precision,
833 						  const tcu::Vec4&				coords,
834 						  const tcu::Vec2&				lodBounds,
835 						  const tcu::Vec4&				result)
836 {
837 	return tcu::isLookupResultValid(texture, sampler, precision, coords.x(), lodBounds, result);
838 }
839 
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)840 bool isLookupResultValid (const tcu::Texture1DArrayView&	texture,
841 						  const tcu::Sampler&				sampler,
842 						  const tcu::LookupPrecision&		precision,
843 						  const tcu::Vec4&					coords,
844 						  const tcu::Vec2&					lodBounds,
845 						  const tcu::Vec4&					result)
846 {
847 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1), lodBounds, result);
848 }
849 
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)850 bool isLookupResultValid (const tcu::Texture2DView&		texture,
851 						  const tcu::Sampler&			sampler,
852 						  const tcu::LookupPrecision&	precision,
853 						  const tcu::Vec4&				coords,
854 						  const tcu::Vec2&				lodBounds,
855 						  const tcu::Vec4&				result)
856 {
857 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1), lodBounds, result);
858 }
859 
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)860 bool isLookupResultValid (const tcu::Texture2DArrayView&	texture,
861 						  const tcu::Sampler&				sampler,
862 						  const tcu::LookupPrecision&		precision,
863 						  const tcu::Vec4&					coords,
864 						  const tcu::Vec2&					lodBounds,
865 						  const tcu::Vec4&					result)
866 {
867 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
868 }
869 
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)870 bool isLookupResultValid (const tcu::TextureCubeView&	texture,
871 						  const tcu::Sampler&			sampler,
872 						  const tcu::LookupPrecision&	precision,
873 						  const tcu::Vec4&				coords,
874 						  const tcu::Vec2&				lodBounds,
875 						  const tcu::Vec4&				result)
876 {
877 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
878 }
879 
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)880 bool isLookupResultValid (const tcu::TextureCubeArrayView&	texture,
881 						  const tcu::Sampler&				sampler,
882 						  const tcu::LookupPrecision&		precision,
883 						  const tcu::Vec4&					coords,
884 						  const tcu::Vec2&					lodBounds,
885 						  const tcu::Vec4&					result)
886 {
887 	return tcu::isLookupResultValid(texture, sampler, precision, tcu::IVec4(precision.coordBits.x()), coords, lodBounds, result);
888 }
889 
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)890 bool isLookupResultValid(const tcu::Texture3DView&		texture,
891 						 const tcu::Sampler&			sampler,
892 						 const tcu::LookupPrecision&	precision,
893 						 const tcu::Vec4&				coords,
894 						 const tcu::Vec2&				lodBounds,
895 						 const tcu::Vec4&				result)
896 {
897 	return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0,1,2), lodBounds, result);
898 }
899 
900 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)901 bool validateResultImage (const TextureViewType&				texture,
902 						  const tcu::Sampler&					sampler,
903 						  const tcu::ConstPixelBufferAccess&	texCoords,
904 						  const tcu::Vec2&						lodBounds,
905 						  const tcu::LookupPrecision&			lookupPrecision,
906 						  const tcu::Vec4&						lookupScale,
907 						  const tcu::Vec4&						lookupBias,
908 						  const tcu::ConstPixelBufferAccess&	result,
909 						  const tcu::PixelBufferAccess&			errorMask)
910 {
911 	const int	w		= result.getWidth();
912 	const int	h		= result.getHeight();
913 	bool		allOk	= true;
914 
915 	for (int y = 0; y < h; ++y)
916 	{
917 		for (int x = 0; x < w; ++x)
918 		{
919 			const tcu::Vec4		resultPixel	= result.getPixel(x, y);
920 			const tcu::Vec4		resultColor	= (resultPixel - lookupBias) / lookupScale;
921 			const tcu::Vec4		texCoord	= texCoords.getPixel(x, y);
922 			const bool			pixelOk		= isLookupResultValid(texture, sampler, lookupPrecision, texCoord, lodBounds, resultColor);
923 
924 			errorMask.setPixel(tcu::Vec4(pixelOk?0.0f:1.0f, pixelOk?1.0f:0.0f, 0.0f, 1.0f), x, y);
925 
926 			if (!pixelOk)
927 				allOk = false;
928 		}
929 	}
930 
931 	return allOk;
932 }
933 
934 template<typename ScalarType>
getSwizzledComp(const tcu::Vector<ScalarType,4> & vec,vk::VkComponentSwizzle comp,int identityNdx)935 ScalarType getSwizzledComp (const tcu::Vector<ScalarType, 4>& vec, vk::VkComponentSwizzle comp, int identityNdx)
936 {
937 	if (comp == vk::VK_COMPONENT_SWIZZLE_IDENTITY)
938 		return vec[identityNdx];
939 	else if (comp == vk::VK_COMPONENT_SWIZZLE_ZERO)
940 		return ScalarType(0);
941 	else if (comp == vk::VK_COMPONENT_SWIZZLE_ONE)
942 		return ScalarType(1);
943 	else
944 		return vec[comp - vk::VK_COMPONENT_SWIZZLE_R];
945 }
946 
947 template<typename ScalarType>
swizzle(const tcu::Vector<ScalarType,4> & vec,const vk::VkComponentMapping & swz)948 tcu::Vector<ScalarType, 4> swizzle (const tcu::Vector<ScalarType, 4>& vec, const vk::VkComponentMapping& swz)
949 {
950 	return tcu::Vector<ScalarType, 4>(getSwizzledComp(vec, swz.r, 0),
951 									  getSwizzledComp(vec, swz.g, 1),
952 									  getSwizzledComp(vec, swz.b, 2),
953 									  getSwizzledComp(vec, swz.a, 3));
954 }
955 
swizzleScaleBias(const tcu::Vec4 & vec,const vk::VkComponentMapping & swz)956 tcu::Vec4 swizzleScaleBias (const tcu::Vec4& vec, const vk::VkComponentMapping& swz)
957 {
958 	const float channelValues[] =
959 	{
960 		1.0f, // -1
961 		1.0f, // 0
962 		1.0f,
963 		vec.x(),
964 		vec.y(),
965 		vec.z(),
966 		vec.w()
967 	};
968 
969 	return tcu::Vec4(channelValues[swz.r], channelValues[swz.g], channelValues[swz.b], channelValues[swz.a]);
970 }
971 
972 template<typename ScalarType>
swizzleT(const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & dst,const vk::VkComponentMapping & swz)973 void swizzleT (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
974 {
975 	for (int z = 0; z < dst.getDepth(); ++z)
976 	for (int y = 0; y < dst.getHeight(); ++y)
977 	for (int x = 0; x < dst.getWidth(); ++x)
978 		dst.setPixel(swizzle(src.getPixelT<ScalarType>(x, y, z), swz), x, y, z);
979 }
980 
swizzleFromSRGB(const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & dst,const vk::VkComponentMapping & swz)981 void swizzleFromSRGB (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
982 {
983 	for (int z = 0; z < dst.getDepth(); ++z)
984 	for (int y = 0; y < dst.getHeight(); ++y)
985 	for (int x = 0; x < dst.getWidth(); ++x)
986 		dst.setPixel(swizzle(tcu::sRGBToLinear(src.getPixelT<float>(x, y, z)), swz), x, y, z);
987 }
988 
swizzle(const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & dst,const vk::VkComponentMapping & swz)989 void swizzle (const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& dst, const vk::VkComponentMapping& swz)
990 {
991 	const tcu::TextureChannelClass	chnClass	= tcu::getTextureChannelClass(dst.getFormat().type);
992 
993 	DE_ASSERT(src.getWidth() == dst.getWidth() &&
994 			  src.getHeight() == dst.getHeight() &&
995 			  src.getDepth() == dst.getDepth());
996 
997 	if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
998 		swizzleT<deInt32>(src, dst, swz);
999 	else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1000 		swizzleT<deUint32>(src, dst, swz);
1001 	else if (tcu::isSRGB(src.getFormat()) && !tcu::isSRGB(dst.getFormat()))
1002 		swizzleFromSRGB(src, dst, swz);
1003 	else
1004 		swizzleT<float>(src, dst, swz);
1005 }
1006 
isIdentitySwizzle(const vk::VkComponentMapping & swz)1007 bool isIdentitySwizzle (const vk::VkComponentMapping& swz)
1008 {
1009 	return (swz.r == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.r == vk::VK_COMPONENT_SWIZZLE_R) &&
1010 		   (swz.g == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.g == vk::VK_COMPONENT_SWIZZLE_G) &&
1011 		   (swz.b == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.b == vk::VK_COMPONENT_SWIZZLE_B) &&
1012 		   (swz.a == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.a == vk::VK_COMPONENT_SWIZZLE_A);
1013 }
1014 
1015 template<typename TextureViewType> struct TexViewTraits;
1016 
1017 template<> struct TexViewTraits<tcu::Texture1DView>			{ typedef tcu::Texture1D		TextureType; };
1018 template<> struct TexViewTraits<tcu::Texture1DArrayView>	{ typedef tcu::Texture1DArray	TextureType; };
1019 template<> struct TexViewTraits<tcu::Texture2DView>			{ typedef tcu::Texture2D		TextureType; };
1020 template<> struct TexViewTraits<tcu::Texture2DArrayView>	{ typedef tcu::Texture2DArray	TextureType; };
1021 template<> struct TexViewTraits<tcu::TextureCubeView>		{ typedef tcu::TextureCube		TextureType; };
1022 template<> struct TexViewTraits<tcu::TextureCubeArrayView>	{ typedef tcu::TextureCubeArray	TextureType; };
1023 template<> struct TexViewTraits<tcu::Texture3DView>			{ typedef tcu::Texture3D		TextureType; };
1024 
1025 template<typename TextureViewType>
1026 typename TexViewTraits<TextureViewType>::TextureType* createSkeletonClone (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0);
1027 
getSwizzleTargetFormat(tcu::TextureFormat format)1028 tcu::TextureFormat getSwizzleTargetFormat (tcu::TextureFormat format)
1029 {
1030 	// Swizzled texture needs to hold all four channels
1031 	// \todo [2016-09-21 pyry] We could save some memory by using smaller formats
1032 	//						   when possible (for example U8).
1033 
1034 	const tcu::TextureChannelClass	chnClass	= tcu::getTextureChannelClass(format.type);
1035 
1036 	if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
1037 		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
1038 	else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1039 		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
1040 	else
1041 		return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1042 }
1043 
1044 template<>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1045 tcu::Texture1D* createSkeletonClone<tcu::Texture1DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1046 {
1047 	return new tcu::Texture1D(format, level0.getWidth());
1048 }
1049 
1050 template<>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1051 tcu::Texture1DArray* createSkeletonClone<tcu::Texture1DArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1052 {
1053 	return new tcu::Texture1DArray(format, level0.getWidth(), level0.getHeight());
1054 }
1055 
1056 template<>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1057 tcu::Texture2D* createSkeletonClone<tcu::Texture2DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1058 {
1059 	return new tcu::Texture2D(format, level0.getWidth(), level0.getHeight());
1060 }
1061 
1062 template<>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1063 tcu::Texture2DArray* createSkeletonClone<tcu::Texture2DArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1064 {
1065 	return new tcu::Texture2DArray(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
1066 }
1067 
1068 template<>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1069 tcu::Texture3D* createSkeletonClone<tcu::Texture3DView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1070 {
1071 	return new tcu::Texture3D(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
1072 }
1073 
1074 template<>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1075 tcu::TextureCubeArray* createSkeletonClone<tcu::TextureCubeArrayView> (tcu::TextureFormat format, const tcu::ConstPixelBufferAccess& level0)
1076 {
1077 	return new tcu::TextureCubeArray(format, level0.getWidth(), level0.getDepth());
1078 }
1079 
1080 template<typename TextureViewType>
createSwizzledCopy(const TextureViewType & texture,const vk::VkComponentMapping & swz)1081 MovePtr<typename TexViewTraits<TextureViewType>::TextureType> createSwizzledCopy (const TextureViewType& texture, const vk::VkComponentMapping& swz)
1082 {
1083 	MovePtr<typename TexViewTraits<TextureViewType>::TextureType>	copy	(createSkeletonClone<TextureViewType>(getSwizzleTargetFormat(texture.getLevel(0).getFormat()), texture.getLevel(0)));
1084 
1085 	for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
1086 	{
1087 		copy->allocLevel(levelNdx);
1088 		swizzle(texture.getLevel(levelNdx), copy->getLevel(levelNdx), swz);
1089 	}
1090 
1091 	return copy;
1092 }
1093 
1094 template<>
createSwizzledCopy(const tcu::TextureCubeView & texture,const vk::VkComponentMapping & swz)1095 MovePtr<tcu::TextureCube> createSwizzledCopy (const tcu::TextureCubeView& texture, const vk::VkComponentMapping& swz)
1096 {
1097 	MovePtr<tcu::TextureCube>	copy	(new tcu::TextureCube(getSwizzleTargetFormat(texture.getLevelFace(0, tcu::CUBEFACE_NEGATIVE_X).getFormat()), texture.getSize()));
1098 
1099 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1100 	{
1101 		for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
1102 		{
1103 			copy->allocLevel((tcu::CubeFace)faceNdx, levelNdx);
1104 			swizzle(texture.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), copy->getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), swz);
1105 		}
1106 	}
1107 
1108 	return copy;
1109 }
1110 
1111 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)1112 bool validateResultImage (const TextureViewType&				texture,
1113 						  const tcu::Sampler&					sampler,
1114 						  const vk::VkComponentMapping&			swz,
1115 						  const tcu::ConstPixelBufferAccess&	texCoords,
1116 						  const tcu::Vec2&						lodBounds,
1117 						  const tcu::LookupPrecision&			lookupPrecision,
1118 						  const tcu::Vec4&						lookupScale,
1119 						  const tcu::Vec4&						lookupBias,
1120 						  const tcu::ConstPixelBufferAccess&	result,
1121 						  const tcu::PixelBufferAccess&			errorMask)
1122 {
1123 	if (isIdentitySwizzle(swz))
1124 		return validateResultImage(texture, sampler, texCoords, lodBounds, lookupPrecision, lookupScale, lookupBias, result, errorMask);
1125 	else
1126 	{
1127 		// There is (currently) no way to handle swizzling inside validation loop
1128 		// and thus we need to pre-swizzle the texture.
1129 		UniquePtr<typename TexViewTraits<TextureViewType>::TextureType>	swizzledTex	(createSwizzledCopy(texture, swz));
1130 
1131 		return validateResultImage(*swizzledTex, sampler, texCoords, lodBounds, lookupPrecision, swizzleScaleBias(lookupScale, swz), swizzleScaleBias(lookupBias, swz), result, errorMask);
1132 	}
1133 }
1134 
resolveSubresourceRange(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource)1135 vk::VkImageSubresourceRange resolveSubresourceRange (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource)
1136 {
1137 	vk::VkImageSubresourceRange	resolved					= subresource;
1138 
1139 	if (subresource.levelCount == VK_REMAINING_MIP_LEVELS)
1140 		resolved.levelCount = testTexture.getNumLevels()-subresource.baseMipLevel;
1141 
1142 	if (subresource.layerCount == VK_REMAINING_ARRAY_LAYERS)
1143 		resolved.layerCount = testTexture.getArraySize()-subresource.baseArrayLayer;
1144 
1145 	return resolved;
1146 }
1147 
getTexture1DView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1148 MovePtr<tcu::Texture1DView> getTexture1DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1149 {
1150 	DE_ASSERT(subresource.layerCount == 1);
1151 
1152 	levels.resize(subresource.levelCount);
1153 
1154 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1155 	{
1156 		const tcu::ConstPixelBufferAccess& srcLevel = testTexture.getLevel((int)subresource.baseMipLevel+levelNdx, subresource.baseArrayLayer);
1157 
1158 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, 0, srcLevel.getWidth(), 1, 1);
1159 	}
1160 
1161 	return MovePtr<tcu::Texture1DView>(new tcu::Texture1DView((int)levels.size(), &levels[0]));
1162 }
1163 
getTexture1DArrayView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1164 MovePtr<tcu::Texture1DArrayView> getTexture1DArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1165 {
1166 	const TestTexture1D*		tex1D		= dynamic_cast<const TestTexture1D*>(&testTexture);
1167 	const TestTexture1DArray*	tex1DArray	= dynamic_cast<const TestTexture1DArray*>(&testTexture);
1168 
1169 	DE_ASSERT(!!tex1D != !!tex1DArray);
1170 	DE_ASSERT(tex1DArray || subresource.baseArrayLayer == 0);
1171 
1172 	levels.resize(subresource.levelCount);
1173 
1174 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1175 	{
1176 		const tcu::ConstPixelBufferAccess& srcLevel = tex1D ? tex1D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1177 															: tex1DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1178 
1179 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, (int)subresource.baseArrayLayer, 0, srcLevel.getWidth(), (int)subresource.layerCount, 1);
1180 	}
1181 
1182 	return MovePtr<tcu::Texture1DArrayView>(new tcu::Texture1DArrayView((int)levels.size(), &levels[0]));
1183 }
1184 
getTexture2DView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1185 MovePtr<tcu::Texture2DView> getTexture2DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1186 {
1187 	const TestTexture2D*		tex2D		= dynamic_cast<const TestTexture2D*>(&testTexture);
1188 	const TestTexture2DArray*	tex2DArray	= dynamic_cast<const TestTexture2DArray*>(&testTexture);
1189 
1190 	DE_ASSERT(subresource.layerCount == 1);
1191 	DE_ASSERT(!!tex2D != !!tex2DArray);
1192 	DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
1193 
1194 	levels.resize(subresource.levelCount);
1195 
1196 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1197 	{
1198 		const tcu::ConstPixelBufferAccess& srcLevel = tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1199 															: tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1200 
1201 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), 1);
1202 	}
1203 
1204 	return MovePtr<tcu::Texture2DView>(new tcu::Texture2DView((int)levels.size(), &levels[0]));
1205 }
1206 
getTexture2DArrayView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1207 MovePtr<tcu::Texture2DArrayView> getTexture2DArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1208 {
1209 	const TestTexture2D*		tex2D		= dynamic_cast<const TestTexture2D*>(&testTexture);
1210 	const TestTexture2DArray*	tex2DArray	= dynamic_cast<const TestTexture2DArray*>(&testTexture);
1211 
1212 	DE_ASSERT(!!tex2D != !!tex2DArray);
1213 	DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
1214 
1215 	levels.resize(subresource.levelCount);
1216 
1217 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1218 	{
1219 		const tcu::ConstPixelBufferAccess& srcLevel = tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1220 															: tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1221 
1222 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), (int)subresource.layerCount);
1223 	}
1224 
1225 	return MovePtr<tcu::Texture2DArrayView>(new tcu::Texture2DArrayView((int)levels.size(), &levels[0]));
1226 }
1227 
getTextureCubeView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1228 MovePtr<tcu::TextureCubeView> getTextureCubeView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1229 {
1230 	const static tcu::CubeFace s_faceMap[tcu::CUBEFACE_LAST] =
1231 	{
1232 		tcu::CUBEFACE_POSITIVE_X,
1233 		tcu::CUBEFACE_NEGATIVE_X,
1234 		tcu::CUBEFACE_POSITIVE_Y,
1235 		tcu::CUBEFACE_NEGATIVE_Y,
1236 		tcu::CUBEFACE_POSITIVE_Z,
1237 		tcu::CUBEFACE_NEGATIVE_Z
1238 	};
1239 
1240 	const TestTextureCube*		texCube			= dynamic_cast<const TestTextureCube*>(&testTexture);
1241 	const TestTextureCubeArray*	texCubeArray	= dynamic_cast<const TestTextureCubeArray*>(&testTexture);
1242 
1243 	DE_ASSERT(!!texCube != !!texCubeArray);
1244 	DE_ASSERT(subresource.layerCount == 6);
1245 	DE_ASSERT(texCubeArray || subresource.baseArrayLayer == 0);
1246 
1247 	levels.resize(subresource.levelCount*tcu::CUBEFACE_LAST);
1248 
1249 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1250 	{
1251 		for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
1252 		{
1253 			const tcu::ConstPixelBufferAccess& srcLevel = texCubeArray ? texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx)
1254 																	   : texCube->getTexture().getLevelFace(levelNdx, s_faceMap[faceNdx]);
1255 
1256 			levels[faceNdx*subresource.levelCount + levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer + (texCubeArray ? faceNdx : 0), srcLevel.getWidth(), srcLevel.getHeight(), 1);
1257 		}
1258 	}
1259 
1260 	{
1261 		const tcu::ConstPixelBufferAccess*	reordered[tcu::CUBEFACE_LAST];
1262 
1263 		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1264 			reordered[s_faceMap[faceNdx]] = &levels[faceNdx*subresource.levelCount];
1265 
1266 		return MovePtr<tcu::TextureCubeView>(new tcu::TextureCubeView((int)subresource.levelCount, reordered));
1267 	}
1268 }
1269 
getTextureCubeArrayView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1270 MovePtr<tcu::TextureCubeArrayView> getTextureCubeArrayView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1271 {
1272 	const TestTextureCubeArray*	texCubeArray	= dynamic_cast<const TestTextureCubeArray*>(&testTexture);
1273 
1274 	DE_ASSERT(texCubeArray);
1275 	DE_ASSERT(subresource.layerCount%6 == 0);
1276 
1277 	levels.resize(subresource.levelCount);
1278 
1279 	for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
1280 	{
1281 		const tcu::ConstPixelBufferAccess& srcLevel = texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel+levelNdx);
1282 
1283 		levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(), srcLevel.getHeight(), (int)subresource.layerCount);
1284 	}
1285 
1286 	return MovePtr<tcu::TextureCubeArrayView>(new tcu::TextureCubeArrayView((int)levels.size(), &levels[0]));
1287 }
1288 
getTexture3DView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1289 MovePtr<tcu::Texture3DView> getTexture3DView (const TestTexture& testTexture, const vk::VkImageSubresourceRange& subresource, std::vector<tcu::ConstPixelBufferAccess>& levels)
1290 {
1291 	DE_ASSERT(subresource.baseArrayLayer == 0 && subresource.layerCount == 1);
1292 
1293 	levels.resize(subresource.levelCount);
1294 
1295 	for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1296 		levels[levelNdx] = testTexture.getLevel((int)subresource.baseMipLevel+levelNdx, subresource.baseArrayLayer);
1297 
1298 	return MovePtr<tcu::Texture3DView>(new tcu::Texture3DView((int)levels.size(), &levels[0]));
1299 }
1300 
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)1301 bool validateResultImage (const TestTexture&					texture,
1302 						  const VkImageViewType					imageViewType,
1303 						  const VkImageSubresourceRange&		subresource,
1304 						  const tcu::Sampler&					sampler,
1305 						  const vk::VkComponentMapping&			componentMapping,
1306 						  const tcu::ConstPixelBufferAccess&	coordAccess,
1307 						  const tcu::Vec2&						lodBounds,
1308 						  const tcu::LookupPrecision&			lookupPrecision,
1309 						  const tcu::Vec4&						lookupScale,
1310 						  const tcu::Vec4&						lookupBias,
1311 						  const tcu::ConstPixelBufferAccess&	resultAccess,
1312 						  const tcu::PixelBufferAccess&			errorAccess)
1313 {
1314 	std::vector<tcu::ConstPixelBufferAccess>	levels;
1315 
1316 	switch (imageViewType)
1317 	{
1318 		case VK_IMAGE_VIEW_TYPE_1D:
1319 		{
1320 			UniquePtr<tcu::Texture1DView>			texView(getTexture1DView(texture, subresource, levels));
1321 
1322 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1323 		}
1324 
1325 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
1326 		{
1327 			UniquePtr<tcu::Texture1DArrayView>		texView(getTexture1DArrayView(texture, subresource, levels));
1328 
1329 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1330 		}
1331 
1332 		case VK_IMAGE_VIEW_TYPE_2D:
1333 		{
1334 			UniquePtr<tcu::Texture2DView>			texView(getTexture2DView(texture, subresource, levels));
1335 
1336 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1337 		}
1338 
1339 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
1340 		{
1341 			UniquePtr<tcu::Texture2DArrayView>		texView(getTexture2DArrayView(texture, subresource, levels));
1342 
1343 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1344 		}
1345 
1346 		case VK_IMAGE_VIEW_TYPE_CUBE:
1347 		{
1348 			UniquePtr<tcu::TextureCubeView>			texView(getTextureCubeView(texture, subresource, levels));
1349 
1350 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1351 		}
1352 
1353 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
1354 		{
1355 			UniquePtr<tcu::TextureCubeArrayView>	texView(getTextureCubeArrayView(texture, subresource, levels));
1356 
1357 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1358 			break;
1359 		}
1360 
1361 		case VK_IMAGE_VIEW_TYPE_3D:
1362 		{
1363 			UniquePtr<tcu::Texture3DView>			texView(getTexture3DView(texture, subresource, levels));
1364 
1365 			return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1366 		}
1367 
1368 		default:
1369 			DE_ASSERT(false);
1370 			return false;
1371 	}
1372 }
1373 
1374 } // anonymous
1375 
verifyImage(void)1376 tcu::TestStatus ImageSamplingInstance::verifyImage (void)
1377 {
1378 	const VkPhysicalDeviceLimits&		limits					= m_context.getDeviceProperties().limits;
1379 	// \note Color buffer is used to capture coordinates - not sampled texture values
1380 	const tcu::TextureFormat			colorFormat				(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1381 	const tcu::TextureFormat			depthStencilFormat;		// Undefined depth/stencil format.
1382 	const CoordinateCaptureProgram		coordCaptureProgram;
1383 	const rr::Program					rrProgram				= coordCaptureProgram.getReferenceProgram();
1384 	ReferenceRenderer					refRenderer				(m_renderSize.x(), m_renderSize.y(), 1, colorFormat, depthStencilFormat, &rrProgram);
1385 
1386 	bool								compareOkAll			= true;
1387 	bool								anyWarnings				= false;
1388 
1389 	tcu::Vec4							lookupScale				(1.0f);
1390 	tcu::Vec4							lookupBias				(0.0f);
1391 
1392 	getLookupScaleBias(m_imageFormat, lookupScale, lookupBias);
1393 
1394 	// Render out coordinates
1395 	{
1396 		const rr::RenderState renderState(refRenderer.getViewportState());
1397 		refRenderer.draw(renderState, rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
1398 	}
1399 
1400 	// Verify results
1401 	{
1402 		const tcu::Sampler					sampler			= mapVkSampler(m_samplerParams);
1403 		const float							referenceLod	= de::clamp(m_samplerParams.mipLodBias + m_samplerLod, m_samplerParams.minLod, m_samplerParams.maxLod);
1404 		const float							lodError		= 1.0f / static_cast<float>((1u << limits.mipmapPrecisionBits) - 1u);
1405 		const tcu::Vec2						lodBounds		(referenceLod - lodError, referenceLod + lodError);
1406 		const vk::VkImageSubresourceRange	subresource		= resolveSubresourceRange(*m_texture, m_subresourceRange);
1407 
1408 		const tcu::ConstPixelBufferAccess	coordAccess		= refRenderer.getAccess();
1409 		tcu::TextureLevel					errorMask		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), (int)m_renderSize.x(), (int)m_renderSize.y());
1410 		const tcu::PixelBufferAccess		errorAccess		= errorMask.getAccess();
1411 
1412 		const bool							allowSnorm8Bug	= m_texture->getTextureFormat().type == tcu::TextureFormat::SNORM_INT8 &&
1413 															  (m_samplerParams.minFilter == VK_FILTER_LINEAR || m_samplerParams.magFilter == VK_FILTER_LINEAR);
1414 
1415 		tcu::LookupPrecision				lookupPrecision;
1416 
1417 		// Set precision requirements - very low for these tests as
1418 		// the point of the test is not to validate accuracy.
1419 		lookupPrecision.coordBits		= tcu::IVec3(17, 17, 17);
1420 		lookupPrecision.uvwBits			= tcu::IVec3(5, 5, 5);
1421 		lookupPrecision.colorMask		= tcu::BVec4(true);
1422 		lookupPrecision.colorThreshold	= tcu::computeFixedPointThreshold(tcu::IVec4(8, 8, 8, 8)) / swizzleScaleBias(lookupScale, m_componentMapping);
1423 
1424 		if (tcu::isSRGB(m_texture->getTextureFormat()))
1425 			lookupPrecision.colorThreshold += tcu::Vec4(4.f / 255.f);
1426 
1427 		for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
1428 		{
1429 			// Read back result image
1430 			UniquePtr<tcu::TextureLevel>		result			(readColorAttachment(m_context.getDeviceInterface(),
1431 																					 m_context.getDevice(),
1432 																					 m_context.getUniversalQueue(),
1433 																					 m_context.getUniversalQueueFamilyIndex(),
1434 																					 m_context.getDefaultAllocator(),
1435 																					 **m_colorImages[imgNdx],
1436 																					 m_colorFormat,
1437 																					 m_renderSize));
1438 			const tcu::ConstPixelBufferAccess	resultAccess	= result->getAccess();
1439 			bool								compareOk		= validateResultImage(*m_texture,
1440 																					  m_imageViewType,
1441 																					  subresource,
1442 																					  sampler,
1443 																					  m_componentMapping,
1444 																					  coordAccess,
1445 																					  lodBounds,
1446 																					  lookupPrecision,
1447 																					  lookupScale,
1448 																					  lookupBias,
1449 																					  resultAccess,
1450 																					  errorAccess);
1451 
1452 			if (!compareOk && allowSnorm8Bug)
1453 			{
1454 				// HW waiver (VK-GL-CTS issue: 229)
1455 				//
1456 				// Due to an error in bit replication of the fixed point SNORM values, linear filtered
1457 				// negative SNORM values will differ slightly from ideal precision in the last bit, moving
1458 				// the values towards 0.
1459 				//
1460 				// This occurs on all members of the PowerVR Rogue family of GPUs
1461 				tcu::LookupPrecision	relaxedPrecision;
1462 
1463 				relaxedPrecision.colorThreshold += tcu::Vec4(4.f / 255.f);
1464 
1465 				m_context.getTestContext().getLog()
1466 					<< tcu::TestLog::Message
1467 					<< "Warning: Strict validation failed, re-trying with lower precision for SNORM8 format"
1468 					<< tcu::TestLog::EndMessage;
1469 				anyWarnings = true;
1470 
1471 				compareOk = validateResultImage(*m_texture,
1472 												m_imageViewType,
1473 												subresource,
1474 												sampler,
1475 												m_componentMapping,
1476 												coordAccess,
1477 												lodBounds,
1478 												relaxedPrecision,
1479 												lookupScale,
1480 												lookupBias,
1481 												resultAccess,
1482 												errorAccess);
1483 			}
1484 
1485 			if (!compareOk)
1486 				m_context.getTestContext().getLog()
1487 				<< tcu::TestLog::Image("Result", "Result Image", resultAccess)
1488 				<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorAccess);
1489 
1490 			compareOkAll = compareOkAll && compareOk;
1491 		}
1492 	}
1493 
1494 	if (compareOkAll)
1495 	{
1496 		if (anyWarnings)
1497 			return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Inaccurate filtering results");
1498 		else
1499 			return tcu::TestStatus::pass("Result image matches reference");
1500 	}
1501 	else
1502 		return tcu::TestStatus::fail("Image mismatch");
1503 }
1504 
1505 } // pipeline
1506 } // vkt
1507