1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Google LLC.
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
25 *//*--------------------------------------------------------------------*/
26
27#include "vktPipelineImage2DViewOf3DTests.hpp"
28#include "vkPipelineConstructionUtil.hpp"
29#include "vktTestCase.hpp"
30#include "vkImageUtil.hpp"
31#include "vkPrograms.hpp"
32#include "vkTypeUtil.hpp"
33#include "vkObjUtil.hpp"
34#include "vkCmdUtil.hpp"
35#include "vkBuilderUtil.hpp"
36#include "vkImageWithMemory.hpp"
37#include "vkBufferWithMemory.hpp"
38#include "vkBarrierUtil.hpp"
39#include "tcuTexture.hpp"
40#include "tcuPlatform.hpp"
41#include "tcuImageCompare.hpp"
42#include "deMemory.h"
43
44#include <sstream>
45#include <vector>
46
47namespace vkt
48{
49namespace pipeline
50{
51
52using namespace vk;
53using de::MovePtr;
54
55namespace
56{
57enum ImageAccessType {
58	StorageImage = 0,
59	Sampler,
60	CombinedImageSampler
61};
62
63enum TestType {
64	Compute,
65	Fragment
66};
67
68struct TestParameters {
69	tcu::IVec3					imageSize;
70	uint32_t					mipLevel;
71	int32_t						layerNdx;
72	ImageAccessType				imageType;
73	TestType					testType;
74	VkFormat					imageFormat;
75	PipelineConstructionType	pipelineConstructionType;
76};
77
78inline int32_t computeMipLevelDimension (int32_t baseLevelDimension, uint32_t mipLevel)
79{
80	return de::max(baseLevelDimension >> mipLevel, 1);
81}
82
83tcu::IVec3 computeMipLevelSize (tcu::IVec3 baseLevelSize, uint32_t mipLevel)
84{
85	int32_t width = computeMipLevelDimension(baseLevelSize.x(), mipLevel);
86	int32_t height = computeMipLevelDimension(baseLevelSize.y(), mipLevel);
87	int32_t depth = computeMipLevelDimension(baseLevelSize.z(), mipLevel);
88	return tcu::IVec3(width, height, depth);
89}
90
91void copyImageLayerToBuffer (const DeviceInterface&		vk,
92							 VkCommandBuffer			cmdBuffer,
93							 VkImage					image,
94							 VkBuffer					buffer,
95							 tcu::IVec2					size,
96							 VkAccessFlags				srcAccessMask,
97							 VkImageLayout				oldLayout,
98							 deUint32					layerToCopy,
99							 uint32_t					mipLevel)
100{
101	const VkImageSubresourceRange	subresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, 0, 1u);
102	const VkImageMemoryBarrier		imageBarrier		=
103	{
104		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType
105		DE_NULL,									// const void*				pNext
106		srcAccessMask,								// VkAccessFlags			srcAccessMask
107		VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags			dstAccessMask
108		oldLayout,									// VkImageLayout			oldLayout
109		VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		// VkImageLayout			newLayout
110		VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex
111		VK_QUEUE_FAMILY_IGNORED,					// deUint32					destQueueFamilyIndex
112		image,										// VkImage					image
113		subresourceRange							// VkImageSubresourceRange	subresourceRange
114	};
115
116	vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
117						  0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
118
119	const VkImageSubresourceLayers	subresource			=
120	{
121		subresourceRange.aspectMask,	// VkImageAspectFlags	aspectMask
122		mipLevel,						// deUint32				mipLevel
123		0u,								// deUint32				baseArrayLayer
124		1u,								// deUint32				layerCount
125	};
126
127	const VkBufferImageCopy			region				=
128	{
129		0ull,										// VkDeviceSize					bufferOffset
130		0u,											// deUint32						bufferRowLength
131		0u,											// deUint32						bufferImageHeight
132		subresource,								// VkImageSubresourceLayers		imageSubresource
133		makeOffset3D(0, 0, (int)layerToCopy),		// VkOffset3D					imageOffset
134		makeExtent3D(size.x(), size.y(), 1u)		// VkExtent3D					imageExtent
135	};
136
137	vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, &region);
138
139	const VkBufferMemoryBarrier		bufferBarrier		=
140	{
141		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType
142		DE_NULL,									// const void*		pNext
143		VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags	srcAccessMask
144		VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags	dstAccessMask
145		VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex
146		VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex
147		buffer,										// VkBuffer			buffer
148		0ull,										// VkDeviceSize		offset
149		VK_WHOLE_SIZE								// VkDeviceSize		size
150	};
151
152	vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
153						  0u, DE_NULL, 1u, &bufferBarrier, 0u, DE_NULL);
154}
155
156// Draws a chess pattern to the given 'layer' (z-dimension) of the 'image'. Other layers will be cleared to white.
157void fillImage (const tcu::PixelBufferAccess& image, const int layer)
158{
159	const tcu::Vec4 clearColor = tcu::Vec4(1); // White clear color.
160	for (int z = 0; z < image.getSize().z(); ++z)
161	for (int y = 0; y < image.getSize().y(); ++y)
162	for (int x = 0; x < image.getSize().x(); ++x)
163	{
164		if (z == layer)
165		{
166			const float c = (float)((x + y) & 1);
167			const tcu::Vec4 color = tcu::Vec4(c, c, c, 1.0f);
168			image.setPixel(color, x, y, z);
169		}
170		else
171		{
172			image.setPixel(clearColor, x, y, z);
173		}
174	}
175}
176
177
178class Image2DView3DImageInstance : public vkt::TestInstance
179{
180public:
181								Image2DView3DImageInstance		(Context&				context,
182																 const TestParameters	testParameters)
183								: vkt::TestInstance(context),
184								  m_testParameters(testParameters)
185								{}
186
187	tcu::TestStatus				iterate							(void);
188private:
189	void						runComputePipeline				(const VkDescriptorSet&			descriptorSet,
190																 const VkDescriptorSetLayout	descriptorSetLayout,
191																 tcu::IVec3&					testMipLevelSize,
192																 VkCommandBuffer				cmdBuffer,
193																 VkImage						image,
194																 VkBuffer						outputBuffer);
195
196	void						runGraphicsPipeline				(const VkDescriptorSet&			descriptorSet,
197																 const VkDescriptorSetLayout	descriptorSetLayout,
198																 tcu::IVec3&					testMipLevelSize,
199																 VkCommandBuffer				cmdBuffer,
200																 VkImage						image,
201																 VkBuffer						outputBuffer);
202	const TestParameters		m_testParameters;
203};
204
205void Image2DView3DImageInstance::runComputePipeline (const VkDescriptorSet&			descriptorSet,
206													 const VkDescriptorSetLayout	descriptorSetLayout,
207													 tcu::IVec3&					testMipLevelSize,
208													 VkCommandBuffer				cmdBuffer,
209													 VkImage						image,
210													 VkBuffer						outputBuffer)
211{
212	const DeviceInterface&			vk					= m_context.getDeviceInterface();
213	const VkDevice					device				= m_context.getDevice();
214	const VkQueue					queue				= m_context.getUniversalQueue();
215	const bool						useSampler			= m_testParameters.imageType != StorageImage;
216
217	const Unique<VkShaderModule>	shaderModule		(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
218	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, descriptorSetLayout));
219	const Unique<VkPipeline>		pipeline			(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
220
221	vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
222	vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
223	vk.cmdDispatch(cmdBuffer, testMipLevelSize.x(), testMipLevelSize.y(), 1u);
224
225	// Copy the result image to a buffer.
226	copyImageLayerToBuffer(vk, cmdBuffer, image, outputBuffer, testMipLevelSize.xy(), VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, useSampler ? 0u : m_testParameters.layerNdx, useSampler ? 0u : m_testParameters.mipLevel);
227
228	endCommandBuffer(vk, cmdBuffer);
229
230	// Wait for completion.
231	submitCommandsAndWait(vk, device, queue, cmdBuffer);
232}
233
234void Image2DView3DImageInstance::runGraphicsPipeline (const VkDescriptorSet&		descriptorSet,
235													  const VkDescriptorSetLayout	descriptorSetLayout,
236													  tcu::IVec3&					testMipLevelSize,
237													  VkCommandBuffer				cmdBuffer,
238													  VkImage						image,
239													  VkBuffer						outputBuffer)
240{
241	const InstanceInterface&						vki								= m_context.getInstanceInterface();
242	const DeviceInterface&							vk								= m_context.getDeviceInterface();
243	const VkPhysicalDevice							physicalDevice					= m_context.getPhysicalDevice();
244	const VkDevice									device							= m_context.getDevice();
245	const VkQueue									queue							= m_context.getUniversalQueue();
246	const bool										useSampler						= m_testParameters.imageType != StorageImage;
247
248	const ShaderWrapper								vertShader						(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
249	const ShaderWrapper								fragShader						(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
250	const PipelineLayoutWrapper						pipelineLayout					(m_testParameters.pipelineConstructionType, vk, device, descriptorSetLayout);
251	RenderPassWrapper								renderPass						(m_testParameters.pipelineConstructionType, vk, device);
252	const std::vector<VkViewport>					viewport						= {makeViewport	(m_testParameters.imageSize.x(), m_testParameters.imageSize.y())};
253	const std::vector<VkRect2D>						scissor							= {makeRect2D	(m_testParameters.imageSize.x(), m_testParameters.imageSize.y())};
254
255	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyStateCreateInfo	=
256	{
257		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType							sType
258		DE_NULL,														// const void*								pNext
259		0u,																// VkPipelineInputAssemblyStateCreateFlags	flags
260		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,								// VkPrimitiveTopology						topology
261		VK_FALSE														// VkBool32									primitiveRestartEnable
262	};
263
264	const VkVertexInputBindingDescription			vertexInputBindingDescription		=
265		{
266			0u,								// deUint32				binding
267			sizeof(tcu::Vec4),				// deUint32				stride
268			VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate
269		};
270
271	const VkVertexInputAttributeDescription			vertexInputAttributeDescription		=
272		{
273			0u,								// deUint32		location
274			0u,								// deUint32		binding
275			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat		format
276			0u								// deUint32		offset
277		};
278
279	const VkPipelineVertexInputStateCreateInfo		vertexInputStateCreateInfoDefault	=
280		{
281			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType								sType
282			DE_NULL,													// const void*									pNext
283			(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags		flags
284			1u,															// deUint32										vertexBindingDescriptionCount
285			&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*		pVertexBindingDescriptions
286			1u,															// deUint32										vertexAttributeDescriptionCount
287			&vertexInputAttributeDescription							// const VkVertexInputAttributeDescription*		pVertexAttributeDescriptions
288		};
289
290	vk::GraphicsPipelineWrapper		graphicsPipeline	(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(), m_testParameters.pipelineConstructionType, 0u);
291	graphicsPipeline.setMonolithicPipelineLayout(pipelineLayout)
292			.setDefaultDepthStencilState()
293			.setDefaultRasterizationState()
294			.setDefaultMultisampleState()
295			.setupVertexInputState(&vertexInputStateCreateInfoDefault, &inputAssemblyStateCreateInfo)
296			.setupPreRasterizationShaderState(viewport,
297											  scissor,
298											  pipelineLayout,
299											  *renderPass,
300											  0u,
301											  vertShader)
302			.setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShader)
303			.setupFragmentOutputState(*renderPass, 0u)
304			.buildPipeline();
305
306	renderPass.createFramebuffer(vk, device, 0u, DE_NULL, DE_NULL, testMipLevelSize.x(), testMipLevelSize.y());
307
308	// Create vertex buffer and fill it with full screen quad.
309	const std::vector<tcu::Vec4> vertexData = {
310			{-1, -1, 1, 1},
311			{ 1, -1, 1, 1},
312			{ 1,  1, 1, 1},
313			{-1,  1, 1, 1},
314	};
315	size_t vertexBufferSize = sizeof(tcu::Vec4) * vertexData.size();
316	BufferWithMemory vertexBuffer(
317			vk,
318			device,
319			m_context.getDefaultAllocator(),
320			makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
321			MemoryRequirement::HostVisible);
322	deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertexData.data(), vertexBufferSize);
323	flushAlloc(vk, device, vertexBuffer.getAllocation());
324
325	VkDeviceSize vertexBufferOffset = 0;
326	vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &*vertexBuffer, &vertexBufferOffset);
327
328	graphicsPipeline.bind(cmdBuffer);
329	vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
330
331	renderPass.begin(vk, cmdBuffer, makeRect2D(testMipLevelSize.xy()));
332	vk.cmdDraw(cmdBuffer, 4, 1, 0, 0);
333	renderPass.end(vk, cmdBuffer);
334
335	// Copy the result image to a buffer.
336	copyImageLayerToBuffer(vk, cmdBuffer, image, outputBuffer, testMipLevelSize.xy(), VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, useSampler ? 0u : m_testParameters.layerNdx, useSampler ? 0u : m_testParameters.mipLevel);
337
338	endCommandBuffer(vk, cmdBuffer);
339
340	// Wait for completion.
341	submitCommandsAndWait(vk, device, queue, cmdBuffer);
342}
343
344tcu::TestStatus Image2DView3DImageInstance::iterate (void)
345{
346	const DeviceInterface&				vk					= m_context.getDeviceInterface();
347	const VkDevice						device				= m_context.getDevice();
348	const VkQueue						queue				= m_context.getUniversalQueue();
349	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
350	Allocator&							allocator			= m_context.getDefaultAllocator();
351	tcu::IVec3							imageSize			= m_testParameters.imageSize;
352	const bool							useSampler			= m_testParameters.imageType != StorageImage;
353	const tcu::TextureFormat			textureFormat		= mapVkFormat(m_testParameters.imageFormat);
354	const uint32_t						mipLevelCount		= 3;
355
356	tcu::IVec3							testMipLevelSize	= computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
357	uint32_t							bufferSize			= testMipLevelSize.x() * testMipLevelSize.y() * testMipLevelSize.z() * textureFormat.getPixelSize();
358	const BufferWithMemory				outputBuffer		(vk, device, allocator, makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
359
360	// Input image is used with sampler cases only.
361	de::MovePtr<BufferWithMemory>		inputImageBuffer;
362
363	// Upload the test image data for sampler cases.
364	if (useSampler)
365	{
366		// Initialize the input image's mip level and fill the target layer with a chess pattern, others will be white.
367		tcu::TextureLevel			inputImageMipLevel	(textureFormat, testMipLevelSize.x(), testMipLevelSize.y(), testMipLevelSize.z());
368		fillImage(inputImageMipLevel.getAccess(), m_testParameters.layerNdx);
369
370		// Create a buffer to upload the image.
371		const VkBufferCreateInfo	bufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
372		inputImageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
373
374		// Upload target mip level to the input buffer.
375		deMemcpy(inputImageBuffer->getAllocation().getHostPtr(), inputImageMipLevel.getAccess().getDataPtr(), bufferSize);
376		flushAlloc(vk, device, inputImageBuffer->getAllocation());
377	}
378
379	// Create the test image: sampled image or storage image, depending on the test type.
380	const VkImageUsageFlags				usage				= VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
381																VK_IMAGE_USAGE_TRANSFER_DST_BIT |
382																(useSampler ? VK_IMAGE_USAGE_SAMPLED_BIT : VK_IMAGE_USAGE_STORAGE_BIT);
383	const VkImageCreateInfo				imageCreateInfo		=
384	{
385		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,						// VkStructureType			sType
386		DE_NULL,													// const void*				pNext
387		VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT,					// VkImageCreateFlags		flags
388		VK_IMAGE_TYPE_3D,											// VkImageType				imageType
389		m_testParameters.imageFormat,								// VkFormat					format
390		makeExtent3D(imageSize.x(), imageSize.y(), imageSize.z()),	// VkExtent3D				extent
391		(uint32_t)mipLevelCount,									// uint32_t					mipLevels
392		1u,															// uint32_t					arrayLayers
393		VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits	samples
394		VK_IMAGE_TILING_OPTIMAL,									// VkImageTiling			tiling
395		usage,														// VkImageUsageFlags		usage
396		VK_SHARING_MODE_EXCLUSIVE,									// VkSharingMode			sharingMode
397		0u,															// uint32_t					queueFamilyIndexCount
398		DE_NULL,													// const uint32_t*			pQueueFamilyIndices
399		VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			initialLayout
400	};
401	ImageWithMemory						testImage			(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any);
402
403	// Make an image view covering one of the mip levels.
404	const VkImageSubresourceRange		subresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 1u, m_testParameters.layerNdx, 1u);
405	const Unique<VkImageView>			imageView			(makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat, subresourceRange));
406
407	// resultImage is used in sampler / combined image sampler tests to verify the sampled image.
408	MovePtr<ImageWithMemory>			resultImage;
409	Move<VkImageView>					resultImageView;
410	Move<VkSampler>						sampler;
411	if (useSampler)
412	{
413		const VkImageCreateInfo			resultImageCreateInfo		=
414		{
415			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,							// VkStructureType			sType
416			DE_NULL,														// const void*				pNext
417			0U,																// VkImageCreateFlags		flags
418			VK_IMAGE_TYPE_2D,												// VkImageType				imageType
419			m_testParameters.imageFormat,									// VkFormat					format
420			makeExtent3D(testMipLevelSize.x(), testMipLevelSize.y(), 1),	// VkExtent3D				extent
421			1u,																// deUint32					mipLevels
422			1u,																// deUint32					arrayLayers
423			VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits	samples
424			VK_IMAGE_TILING_OPTIMAL,										// VkImageTiling			tiling
425			VK_IMAGE_USAGE_STORAGE_BIT |
426				VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
427				VK_IMAGE_USAGE_TRANSFER_DST_BIT,							// VkImageUsageFlags		usage
428			VK_SHARING_MODE_EXCLUSIVE,										// VkSharingMode			sharingMode
429			0u,																// deUint32					queueFamilyIndexCount
430			DE_NULL,														// const deUint32*			pQueueFamilyIndices
431			VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout			initialLayout
432		};
433
434		resultImage = MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, resultImageCreateInfo, MemoryRequirement::Any));
435		const VkImageSubresourceRange	resultImgSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
436		resultImageView = makeImageView(vk, device, **resultImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat, resultImgSubresourceRange);
437
438		const VkSamplerCreateInfo		samplerCreateInfo			=
439		{
440			VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,		// VkStructureType			sType
441			DE_NULL,									// const void*				pNext
442			(VkSamplerCreateFlags)0,					// VkSamplerCreateFlags		flags
443			VK_FILTER_NEAREST,							// VkFilter					magFilter
444			VK_FILTER_NEAREST,							// VkFilter					minFilter
445			VK_SAMPLER_MIPMAP_MODE_NEAREST,				// VkSamplerMipmapMode		mipmapMode
446			VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// VkSamplerAddressMode		addressModeU
447			VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// VkSamplerAddressMode		addressModeV
448			VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,		// VkSamplerAddressMode		addressModeW
449			0.0f,										// float					mipLodBias
450			VK_FALSE,									// VkBool32					anisotropyEnable
451			1.0f,										// float					maxAnisotropy
452			VK_FALSE,									// VkBool32					compareEnable
453			VK_COMPARE_OP_ALWAYS,						// VkCompareOp				compareOp
454			0.0f,										// float					minLod
455			1.0f,										// float					maxLod
456			VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	// VkBorderColor			borderColor
457			VK_FALSE,									// VkBool32					unnormalizedCoordinates
458		};
459		sampler = createSampler(vk, device, &samplerCreateInfo);
460	}
461
462
463	// Create the descriptor set.
464	DescriptorSetLayoutBuilder			descriptorSetLayoutBuilder;
465	DescriptorPoolBuilder				descriptorPoolBuilder;
466
467	VkShaderStageFlags					shaderStage					= m_testParameters.testType == Compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
468	VkPipelineStageFlags				pipelineStage				= m_testParameters.testType == Compute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
469	switch (m_testParameters.imageType)
470	{
471	case StorageImage:
472		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
473		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
474		break;
475	case Sampler:
476		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, shaderStage);
477		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, shaderStage);
478		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
479		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
480		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER);
481		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
482		break;
483	case CombinedImageSampler:
484		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage);
485		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
486		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
487		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
488		break;
489	default:
490		TCU_THROW(InternalError, "Unimplemented testImage type.");
491	}
492
493	if (useSampler)
494	{
495		// Clear the result image.
496		clearColorImage(vk, device, queue, m_context.getUniversalQueueFamilyIndex(), **resultImage, tcu::Vec4(0,0,0,1), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, pipelineStage, 0u, 1u);
497	}
498	else
499	{
500		// Clear the test image.
501		clearColorImage(vk, device, queue, m_context.getUniversalQueueFamilyIndex(), testImage.get(), tcu::Vec4(0,0,0,1), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, pipelineStage, 0u, 1u, 0u, mipLevelCount);
502	}
503
504	// Prepare the command buffer.
505	const Unique<VkCommandPool>			cmdPool						(makeCommandPool(vk, device, queueFamilyIndex));
506	const Unique<VkCommandBuffer>		cmdBuffer					(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
507
508	// Start recording commands.
509	beginCommandBuffer(vk, *cmdBuffer);
510
511	if (useSampler)
512	{
513		// Copy the input image to the target mip level.
514		std::vector<VkBufferImageCopy> copies;
515		copies.push_back(makeBufferImageCopy(makeExtent3D(testMipLevelSize), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 0, 1)));
516		copyBufferToImage(vk, *cmdBuffer, **inputImageBuffer, bufferSize, copies, VK_IMAGE_ASPECT_COLOR_BIT, mipLevelCount, 1u, *testImage, VK_IMAGE_LAYOUT_GENERAL, pipelineStage);
517	}
518
519	const Move<VkDescriptorSetLayout>	descriptorSetLayout			(descriptorSetLayoutBuilder.build(vk, device));
520	const Move<VkDescriptorPool>		descriptorPool				(descriptorPoolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
521	const Unique<VkDescriptorSet>		descriptorSet				(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
522	const VkDescriptorImageInfo			testImageDescriptorInfo		= makeDescriptorImageInfo(*sampler, *imageView, VK_IMAGE_LAYOUT_GENERAL);
523
524	// Write descriptor update.
525	{
526		DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
527		uint32_t bindingIdx = 0;
528
529		switch (m_testParameters.imageType)
530		{
531		case StorageImage:
532			descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &testImageDescriptorInfo);
533			break;
534		case Sampler:
535			descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx++), VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &testImageDescriptorInfo);
536			descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx++), VK_DESCRIPTOR_TYPE_SAMPLER, &testImageDescriptorInfo);
537			break;
538		case CombinedImageSampler:
539			descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx++), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &testImageDescriptorInfo);
540			break;
541		}
542
543		if (useSampler)
544		{
545			const VkDescriptorImageInfo resultImageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *resultImageView, VK_IMAGE_LAYOUT_GENERAL);
546			descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageDescriptorInfo);
547		}
548
549		descriptorSetUpdateBuilder.update(vk, device);
550	}
551
552	if (m_testParameters.testType == Compute)
553		runComputePipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer, useSampler ? **resultImage : *testImage, *outputBuffer);
554	else
555		runGraphicsPipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer, useSampler ? **resultImage : *testImage, *outputBuffer);
556
557	// Validate the results.
558	{
559		// Create a reference image.
560		// The reference image has always a depth of 1, because it will be compared to the 2D result image (sampler cases) or to a single layer of a 3D image.
561		tcu::TextureLevel			referenceImage			(textureFormat, testMipLevelSize.x(), testMipLevelSize.y(), 1u);
562		fillImage(referenceImage.getAccess(), 0u);
563
564		const Allocation&			outputBufferAllocation	= outputBuffer.getAllocation();
565		invalidateAlloc(vk, device, outputBufferAllocation);
566
567		const deUint32*				bufferPtr				= static_cast<deUint32*>(outputBufferAllocation.getHostPtr());
568		tcu::ConstPixelBufferAccess	pixelBufferAccess		(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), testMipLevelSize.x(), testMipLevelSize.y(), 1u, bufferPtr);
569
570		if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Result", "Result comparison", referenceImage, pixelBufferAccess, tcu::Vec4(0.01f), tcu::COMPARE_LOG_ON_ERROR))
571			return tcu::TestStatus::fail("Pixel comparison failed.");
572
573	}
574
575	return tcu::TestStatus::pass("pass");
576}
577
578class ComputeImage2DView3DImageTest : public vkt::TestCase
579{
580public:
581								ComputeImage2DView3DImageTest	(tcu::TestContext&				testContext,
582																 const char*					name,
583																 const TestParameters&			testParameters)
584																 : vkt::TestCase (testContext, name),
585																 m_testParameters (testParameters) {}
586	virtual						~ComputeImage2DView3DImageTest			(void) {}
587
588	virtual void				initPrograms					(SourceCollections&				sourceCollections) const;
589	virtual void				checkSupport					(Context&						context) const;
590	virtual TestInstance*		createInstance					(Context&						context) const;
591private:
592	const TestParameters		m_testParameters;
593};
594
595
596void ComputeImage2DView3DImageTest::checkSupport (Context& context) const
597{
598	DE_ASSERT(m_testParameters.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
599
600	if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d"))
601		TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported.");
602
603	if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D)
604		TCU_THROW(NotSupportedError, "image2DViewOf3D not supported.");
605
606	if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D)
607		TCU_THROW(NotSupportedError, "sampler2DViewOf3D not supported.");
608}
609
610void ComputeImage2DView3DImageTest::initPrograms (SourceCollections& sourceCollections) const
611{
612	std::ostringstream src;
613	tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
614	if (m_testParameters.imageType == StorageImage)
615	{
616		src << "#version 450 core\n"
617			<< "layout (local_size_x = 1, local_size_y = 1) in;\n"
618			<< "layout (binding = 0, rgba8) writeonly uniform highp image2D storageImage;\n"
619			<< "void main (void) {\n"
620			<< "    ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
621			<< "    float c = float((uv.x + uv.y) & 1);\n"
622			<< "    vec4 color = vec4(c, c, c, 1.0);\n"
623			<< "    imageStore(storageImage, uv, color);\n"
624			<< "}\n";
625	}
626	else if (m_testParameters.imageType == Sampler)
627	{
628		src << "#version 450 core\n"
629			<< "layout (local_size_x = 1, local_size_y = 1) in;\n"
630			<< "layout (set=0, binding = 0) uniform texture2D image;\n"
631			<< "layout (set=0, binding = 1) uniform sampler samp;\n"
632			<< "layout (rgba8, set=0, binding = 2) writeonly uniform highp image2D verifyImage;\n"
633			<< "void main (void) {\n"
634			<< "    ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
635			<< "    vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() <<".0;\n"
636			<< "    vec4 color = texture(sampler2D(image, samp), texCoord);\n"
637			<< "    imageStore(verifyImage, uv, color);\n"
638			<< "}\n";
639	}
640	else if (m_testParameters.imageType == CombinedImageSampler)
641	{
642		src << "#version 450 core\n"
643			<< "layout (local_size_x = 1, local_size_y = 1) in;\n"
644			<< "layout (binding = 0) uniform sampler2D combinedSampler;\n"
645			<< "layout (rgba8, set=0, binding=1) writeonly uniform highp image2D verifyImage;\n"
646			<< "void main (void) {\n"
647			<< "    ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
648			<< "    vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() <<".0;\n"
649			<< "    vec4 color = texture(combinedSampler, texCoord);\n"
650			<< "    imageStore(verifyImage, uv, color);\n"
651			<< "}\n";
652	}
653
654	sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
655}
656
657TestInstance* ComputeImage2DView3DImageTest::createInstance (Context& context) const
658{
659	return new Image2DView3DImageInstance(context, m_testParameters);
660}
661
662class FragmentImage2DView3DImageTest : public vkt::TestCase
663{
664public:
665								FragmentImage2DView3DImageTest	(tcu::TestContext&				testContext,
666																 const char*					name,
667																 const TestParameters&			testParameters)
668																 : vkt::TestCase (testContext, name),
669																 m_testParameters (testParameters) {}
670	virtual						~FragmentImage2DView3DImageTest	(void) {}
671
672	virtual void				initPrograms					(SourceCollections&				sourceCollections) const;
673	virtual void				checkSupport					(Context&						context) const;
674	virtual TestInstance*		createInstance					(Context&						context) const;
675private:
676	const TestParameters		m_testParameters;
677};
678
679void FragmentImage2DView3DImageTest::initPrograms (SourceCollections& sourceCollections) const
680{
681	std::stringstream vertShader;
682	vertShader	<< "#version 450 core\n"
683				<< "layout(location = 0) in vec4 in_position;\n"
684				<< "out gl_PerVertex {\n"
685				<< "    vec4  gl_Position;\n"
686				<< "    float gl_PointSize;\n"
687				<< "};\n"
688				<< "void main() {\n"
689				<< "    gl_PointSize = 1.0;\n"
690				<< "    gl_Position  = in_position;\n"
691				<< "}\n";
692	sourceCollections.glslSources.add("vert") << glu::VertexSource(vertShader.str());
693
694	tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
695	std::stringstream fragShader;
696	if (m_testParameters.imageType == StorageImage)
697	{
698		fragShader	<< "#version 450 core\n"
699					<< "layout(rgba8, set = 0, binding = 0) uniform image2D storageImage;\n"
700					<< "void main()\n"
701					<< "{\n"
702					<< "    ivec2 uv = ivec2(gl_FragCoord.xy);\n"
703					<< "    float c = float((uv.x + uv.y) & 1);\n"
704					<< "    vec4 color = vec4(c, c, c, 1.0);\n"
705					<< "    imageStore(storageImage, uv, color);\n"
706					<< "}\n";
707	}
708
709	else if (m_testParameters.imageType == Sampler)
710	{
711		fragShader	<< "#version 450 core\n"
712					<< "layout (set = 0, binding = 0) uniform texture2D image;\n"
713					<< "layout (set = 0, binding = 1) uniform sampler samp;\n"
714					<< "layout (rgba8, set = 0, binding = 2) uniform image2D verifyImage;\n"
715					<< "void main (void) {\n"
716					<< "    ivec2 uv = ivec2(gl_FragCoord.xy);\n"
717					<< "    vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() <<".0;\n"
718					<< "    vec4 color = texture(sampler2D(image, samp), texCoord);\n"
719					<< "    imageStore(verifyImage, uv, color);\n"
720					<< "}\n";
721	}
722	else if (m_testParameters.imageType == CombinedImageSampler)
723	{
724		fragShader	<< "#version 450 core\n"
725					<< "layout (set = 0, binding = 0) uniform sampler2D combinedSampler;\n"
726					<< "layout (rgba8, set = 0, binding = 1) uniform image2D verifyImage;\n"
727					<< "void main (void) {\n"
728					<< "    ivec2 uv = ivec2(gl_FragCoord.xy);\n"
729					<< "    vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() <<".0;\n"
730					<< "    vec4 color = texture(combinedSampler, texCoord);\n"
731					<< "    imageStore(verifyImage, uv, color);\n"
732					<< "}\n";
733	}
734	sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragShader.str());
735}
736
737void FragmentImage2DView3DImageTest::checkSupport (Context& context) const
738{
739	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_testParameters.pipelineConstructionType);
740
741	if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d"))
742		TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported.");
743
744	if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D)
745		TCU_THROW(NotSupportedError, "image2DViewOf3D not supported.");
746
747	if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D)
748		TCU_THROW(NotSupportedError, "texture2DViewOf3D not supported.");
749
750	if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
751		TCU_THROW(NotSupportedError, "fragmentStoresAndAtomics not supported");
752}
753
754TestInstance* FragmentImage2DView3DImageTest::createInstance (Context& context) const
755{
756	return new Image2DView3DImageInstance(context, m_testParameters);
757}
758
759} // anonymous
760
761tcu::TestCaseGroup* createImage2DViewOf3DTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
762{
763	de::MovePtr<tcu::TestCaseGroup> imageTests			(new tcu::TestCaseGroup(testCtx, "image_2d_view_3d_image"));
764	de::MovePtr<tcu::TestCaseGroup>	computeGroup		(new tcu::TestCaseGroup(testCtx, "compute"));
765	de::MovePtr<tcu::TestCaseGroup>	fragmentGroup		(new tcu::TestCaseGroup(testCtx, "fragment"));
766
767	const struct {
768		const ImageAccessType	imageType;
769		const std::string		name;
770	} imageAccessTypes [] {
771		{ StorageImage,			"storage" },
772		{ Sampler,				"sampler" },
773		{ CombinedImageSampler,	"combined_image_sampler" }
774	};
775
776	const int32_t imageDimension = 64;
777	for (const auto& imageAccessType : imageAccessTypes)
778	{
779		de::MovePtr<tcu::TestCaseGroup>	computeSubGroup		(new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str()));
780		de::MovePtr<tcu::TestCaseGroup>	fragmentSubGroup	(new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str()));
781		for (uint32_t mipLevel = 0; mipLevel < 3; mipLevel += 2)
782		{
783			// Test the first and the last layer of the mip level.
784			std::vector<int32_t> layers = { 0, computeMipLevelDimension(imageDimension, mipLevel) -1 };
785			for (const auto& layer : layers)
786			{
787				TestParameters testParameters {
788						tcu::IVec3(imageDimension),	// IVec3						imageSize
789						mipLevel,					// uint32_t						mipLevel
790						layer,						// int32_t						layerNdx
791						imageAccessType.imageType,	// ImageAccessType				imageType
792						Fragment,					// TestType						testType
793						VK_FORMAT_R8G8B8A8_UNORM,	// VkFormat						imageFormat
794						pipelineConstructionType	// PipelineConstructionType		pipelineConstructionType
795					};
796				std::string testName = "mip" + std::to_string(mipLevel) +  "_layer" + std::to_string(layer);
797				fragmentSubGroup->addChild(new FragmentImage2DView3DImageTest(testCtx, testName.c_str(), testParameters));
798
799				if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
800				{
801					testParameters.testType = Compute;
802					computeSubGroup->addChild(new ComputeImage2DView3DImageTest(testCtx, testName.c_str(), testParameters));
803				}
804			}
805		}
806		computeGroup->addChild(computeSubGroup.release());
807		fragmentGroup->addChild(fragmentSubGroup.release());
808	}
809
810	imageTests->addChild(computeGroup.release());
811	imageTests->addChild(fragmentGroup.release());
812	return imageTests.release();
813}
814
815} // pipeline
816} // vkt
817