1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Valve Corporation.
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
23 *//*--------------------------------------------------------------------*/
24
25#include "vktPipelineImageSlicedViewOf3DTests.hpp"
26#include "vktTestCase.hpp"
27
28#include "vkImageUtil.hpp"
29#include "vkTypeUtil.hpp"
30#include "vkObjUtil.hpp"
31#include "vkCmdUtil.hpp"
32#include "vkBuilderUtil.hpp"
33#include "vkImageWithMemory.hpp"
34#include "vkBufferWithMemory.hpp"
35#include "vkBarrierUtil.hpp"
36
37#include "tcuTexture.hpp"
38#include "tcuImageCompare.hpp"
39#include "tcuTextureUtil.hpp"
40
41#include "deRandom.hpp"
42
43#include <sstream>
44#include <vector>
45#include <tuple>
46#include <set>
47#include <limits>
48#include <string>
49#include <algorithm>
50
51namespace vkt
52{
53namespace pipeline
54{
55
56using namespace vk;
57
58namespace
59{
60
61constexpr uint32_t	kWidth			= 8u;
62constexpr uint32_t	kHeight			= 8u;
63constexpr VkFormat	kFormat			= VK_FORMAT_R8G8B8A8_UINT;
64constexpr uint32_t	kVertexCount	= 3u;
65constexpr auto		kUsageLayout	= VK_IMAGE_LAYOUT_GENERAL;
66
67enum class TestType
68{
69	LOAD = 0,
70	STORE,
71};
72
73struct TestParams
74{
75	TestType				testType;
76	VkShaderStageFlagBits	stage;
77	uint32_t				width;
78	uint32_t				height;
79	uint32_t				depth;
80	uint32_t				offset;
81
82private:
83	// We want to test both normal ranges and VK_REMAINING_3D_SLICES_EXT, but in the latter case we cannot blindly use the range
84	// value for some operations. See getActualRange() and getSlicedViewRange().
85	uint32_t				range;
86
87public:
88	tcu::Maybe<uint32_t>	mipLevel;
89	bool					sampleImg;
90
91	TestParams (TestType testType_, VkShaderStageFlagBits stage_, uint32_t width_, uint32_t height_, uint32_t depth_, uint32_t offset_, uint32_t range_,
92				const tcu::Maybe<uint32_t>& mipLevel_, bool sampleImg_)
93		: testType	(testType_)
94		, stage		(stage_)
95		, width		(width_)
96		, height	(height_)
97		, depth		(depth_)
98		, offset	(offset_)
99		, range		(range_)
100		, mipLevel	(mipLevel_)
101		, sampleImg	(sampleImg_)
102	{
103		DE_ASSERT(stage == VK_SHADER_STAGE_COMPUTE_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT);
104		DE_ASSERT(range > 0u);
105
106		const auto selectedLevel = getSelectedLevel();
107
108		if (useMipMaps())
109		{
110			// To simplify things.
111			DE_ASSERT(width == height && width == depth);
112
113			const auto maxMipLevelCount	= getMaxMipLevelCount();
114			DE_ASSERT(selectedLevel < maxMipLevelCount);
115			DE_UNREF(maxMipLevelCount); // For release builds.
116		}
117
118		const uint32_t selectedLevelDepth = (depth >> selectedLevel);
119		DE_UNREF(selectedLevelDepth); // For release builds.
120
121		if (!useRemainingSlices())
122			DE_ASSERT(offset + range <= selectedLevelDepth);
123		else
124			DE_ASSERT(offset < selectedLevelDepth);
125	}
126
127	uint32_t getSelectedLevel (void) const
128	{
129		return (useMipMaps() ? mipLevel.get() : 0u);
130	}
131
132	uint32_t getFullImageLevels (void) const
133	{
134		return (useMipMaps() ? getMaxMipLevelCount() : 1u);
135	}
136
137	uint32_t getActualRange (void) const
138	{
139		const auto levelDepth = (depth >> getSelectedLevel());
140		DE_ASSERT(levelDepth > 0u);
141
142		return (useRemainingSlices() ? (levelDepth - offset) : range);
143	}
144
145	uint32_t getSlicedViewRange (void) const
146	{
147		return range;
148	}
149
150	VkExtent3D getSliceExtent (void) const
151	{
152		const auto selectedLevel	= getSelectedLevel();
153		const auto extent			= makeExtent3D((width >> selectedLevel),
154												   (height >> selectedLevel),
155												   getActualRange());
156
157		DE_ASSERT(extent.width > 0u);
158		DE_ASSERT(extent.height > 0u);
159		DE_ASSERT(extent.depth > 0u);
160		return extent;
161	}
162
163	VkExtent3D getFullLevelExtent (void) const
164	{
165		const auto selectedLevel	= getSelectedLevel();
166		const auto extent			= makeExtent3D((width >> selectedLevel),
167												   (height >> selectedLevel),
168												   (depth >> selectedLevel));
169
170		DE_ASSERT(extent.width > 0u);
171		DE_ASSERT(extent.height > 0u);
172		DE_ASSERT(extent.depth > 0u);
173		return extent;
174	}
175
176	static uint32_t getMaxMipLevelCountForSize (uint32_t size)
177	{
178		DE_ASSERT(size <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
179		return static_cast<uint32_t>(deLog2Floor32(static_cast<int32_t>(size)) + 1);
180	}
181
182private:
183	uint32_t getMaxMipLevelCount (void) const
184	{
185		return getMaxMipLevelCountForSize(depth);
186	}
187
188	bool useMipMaps (void) const
189	{
190		return static_cast<bool>(mipLevel);
191	}
192
193	bool useRemainingSlices (void) const
194	{
195		return (range == VK_REMAINING_3D_SLICES_EXT);
196	}
197};
198
199class SlicedViewTestCase : public vkt::TestCase
200{
201public:
202						SlicedViewTestCase		(tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
203							: vkt::TestCase(testCtx, name), m_params(params) {}
204	virtual				~SlicedViewTestCase		(void) {}
205
206	void				initPrograms			(vk::SourceCollections& programCollection) const override;
207	TestInstance*		createInstance			(Context& context) const override;
208	void				checkSupport			(Context& context) const override;
209
210protected:
211	const TestParams	m_params;
212};
213
214class SlicedViewTestInstance : public vkt::TestInstance
215{
216public:
217						SlicedViewTestInstance	(Context& context, const TestParams& params)
218							: vkt::TestInstance(context), m_params (params)
219							{}
220	virtual				~SlicedViewTestInstance	(void) {}
221
222protected:
223	virtual void		runPipeline				(const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer, const VkImageView slicedImage, const VkImageView auxiliarImage);
224	virtual void		runGraphicsPipeline		(const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer);
225	virtual void		runComputePipeline		(const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer);
226	bool				runSamplingPipeline		(const VkImage fullImage, const VkImageView slicedView, const VkExtent3D& levelExtent);
227
228	const TestParams	m_params;
229
230	Move<VkDescriptorSetLayout>	m_setLayout;
231	Move<VkDescriptorPool>		m_descriptorPool;
232	Move<VkDescriptorSet>		m_descriptorSet;
233	Move<VkPipelineLayout>		m_pipelineLayout;
234
235	// Only for graphics pipelines.
236	Move<VkRenderPass>			m_renderPass;
237	Move<VkFramebuffer>			m_framebuffer;
238
239	Move<VkPipeline>			m_pipeline;
240};
241
242class SlicedViewLoadTestInstance : public SlicedViewTestInstance
243{
244public:
245					SlicedViewLoadTestInstance	(Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {}
246	virtual			~SlicedViewLoadTestInstance	(void) {}
247
248	tcu::TestStatus	iterate						(void);
249};
250
251class SlicedViewStoreTestInstance : public SlicedViewTestInstance
252{
253public:
254					SlicedViewStoreTestInstance		(Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {}
255	virtual			~SlicedViewStoreTestInstance	(void) {}
256
257	tcu::TestStatus	iterate							(void);
258};
259
260void SlicedViewTestCase::checkSupport (Context &context) const
261{
262	context.requireDeviceFunctionality(VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME);
263
264	if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
265		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
266}
267
268void SlicedViewTestCase::initPrograms(vk::SourceCollections &programCollection) const
269{
270	const std::string bindings =
271		"layout (rgba8ui, set=0, binding=0) uniform uimage3D slicedImage;\n"
272		"layout (rgba8ui, set=0, binding=1) uniform uimage3D auxiliarImage;\n"
273		;
274
275	std::string loadFrom;
276	std::string storeTo;
277
278	// We may need to load stuff from the sliced image into an auxiliary image if we're testing load, or we may need to store stuff
279	// to the sliced image, read from the auxiliary image if we're testing stores.
280	if (m_params.testType == TestType::LOAD)
281	{
282		loadFrom	= "slicedImage";
283		storeTo		= "auxiliarImage";
284	}
285	else if (m_params.testType == TestType::STORE)
286	{
287		loadFrom	= "auxiliarImage";
288		storeTo		= "slicedImage";
289	}
290	else
291		DE_ASSERT(false);
292
293	std::ostringstream mainOperation;
294
295	// Note: "coords" will vary depending on the shader stage.
296	mainOperation
297		<< "    const ivec3 size = imageSize(slicedImage);\n"
298		<< "    const uvec4 badColor = uvec4(0, 0, 0, 0);\n"
299		<< "    const uvec4 goodColor = imageLoad(" << loadFrom << ", coords);\n"
300		<< "    const uvec4 storedColor = ((size.z == " << m_params.getActualRange() << ") ? goodColor : badColor);\n"
301		<< "    imageStore(" << storeTo << ", coords, storedColor);\n"
302		;
303
304	if (m_params.stage == VK_SHADER_STAGE_COMPUTE_BIT)
305	{
306		// For compute, we'll launch as many workgroups as slices, and each invocation will handle one pixel.
307		const auto sliceExtent = m_params.getSliceExtent();
308		std::ostringstream comp;
309		comp
310			<< "#version 460\n"
311			<< "layout (local_size_x=" << sliceExtent.width << ", local_size_y=" << sliceExtent.height << ", local_size_z=1) in;\n"
312			<< bindings
313			<< "void main (void) {\n"
314			<< "    const ivec3 coords = ivec3(ivec2(gl_LocalInvocationID.xy), int(gl_WorkGroupID.x));\n"
315			<< mainOperation.str()
316			<< "}\n"
317			;
318		programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
319	}
320	else if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
321	{
322		// For fragment, we'll draw as many instances as slices, and each draw will use a full-screen triangle to generate as many
323		// fragment shader invocations as pixels in the image (the framebuffer needs to have the same size as the storage images).
324		std::ostringstream frag;
325		frag
326			<< "#version 460\n"
327			<< "layout (location=0) in flat int zCoord;\n"
328			<< bindings
329			<< "void main (void) {\n"
330			<< "    const ivec3 coords = ivec3(ivec2(gl_FragCoord.xy), zCoord);\n"
331			<< mainOperation.str()
332			<< "}\n"
333			;
334
335		std::ostringstream vert;
336		vert
337			<< "#version 460\n"
338			<< "layout (location=0) out flat int zCoord;\n"
339			<< "vec2 positions[3] = vec2[](\n"
340			<< "    vec2(-1.0, -1.0),\n"
341			<< "    vec2( 3.0, -1.0),\n"
342			<< "    vec2(-1.0,  3.0)\n"
343			<< ");\n"
344			<< "void main() {\n"
345			<< "    gl_Position = vec4(positions[gl_VertexIndex % 3], 0.0, 1.0);\n"
346			<< "    zCoord = int(gl_InstanceIndex);\n"
347			<< "}\n"
348			;
349
350		programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
351		programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
352	}
353	else
354	{
355		DE_ASSERT(false);
356	}
357
358	if (m_params.sampleImg)
359	{
360		// Prepare a compute shader that will sample the whole level to verify it's available.
361		const auto levelExtent = m_params.getFullLevelExtent();
362
363		std::ostringstream comp;
364		comp
365			<< "#version 460\n"
366			<< "layout (local_size_x=" << levelExtent.width << ", local_size_y=" << levelExtent.height << ", local_size_z=" << levelExtent.depth << ") in;\n"
367			<< "layout (set=0, binding=0) uniform usampler3D combinedSampler;\n"		// The image being tested.
368			<< "layout (set=0, binding=1, rgba8ui) uniform uimage3D auxiliarImage;\n"	// Verification storage image.
369			<< "void main() {\n"
370			<< "    const vec3 levelExtent = vec3(" << levelExtent.width << ", " << levelExtent.height << ", " << levelExtent.depth << ");\n"
371			<< "    const vec3 sampleCoords = vec3(\n"
372			<< "        (float(gl_LocalInvocationID.x) + 0.5) / levelExtent.x,\n"
373			<< "        (float(gl_LocalInvocationID.y) + 0.5) / levelExtent.y,\n"
374			<< "        (float(gl_LocalInvocationID.z) + 0.5) / levelExtent.z);\n"
375			<< "    const ivec3 storeCoords = ivec3(int(gl_LocalInvocationID.x), int(gl_LocalInvocationID.y), int(gl_LocalInvocationID.z));\n"
376			<< "    const uvec4 sampledColor = texture(combinedSampler, sampleCoords);\n"
377			<< "    imageStore(auxiliarImage, storeCoords, sampledColor);\n"
378			<< "}\n"
379			;
380		programCollection.glslSources.add("compSample") << glu::ComputeSource(comp.str());
381	}
382}
383
384TestInstance* SlicedViewTestCase::createInstance (Context& context) const
385{
386	if (m_params.testType == TestType::LOAD)
387		return new SlicedViewLoadTestInstance(context, m_params);
388	if (m_params.testType == TestType::STORE)
389		return new SlicedViewStoreTestInstance(context, m_params);
390
391	DE_ASSERT(false);
392	return nullptr;
393}
394
395tcu::IVec3 makeIVec3 (uint32_t width, uint32_t height, uint32_t depth)
396{
397	return tcu::IVec3(static_cast<int>(width), static_cast<int>(height), static_cast<int>(depth));
398}
399
400de::MovePtr<tcu::PixelBufferAccess> makePixelBufferAccess (const BufferWithMemory& buffer, const tcu::IVec3& size, const tcu::TextureFormat& format)
401{
402	de::MovePtr<tcu::PixelBufferAccess> bufferImage (new tcu::PixelBufferAccess(format, size, buffer.getAllocation().getHostPtr()));
403	return bufferImage;
404}
405
406de::MovePtr<BufferWithMemory> makeTransferBuffer (const VkExtent3D& extent, const tcu::TextureFormat& format,
407												  const DeviceInterface& vkd, const VkDevice device, Allocator& alloc)
408{
409	DE_ASSERT(extent.width > 0u);
410	DE_ASSERT(extent.height > 0u);
411	DE_ASSERT(extent.depth > 0u);
412
413	const auto pixelSizeBytes	= tcu::getPixelSize(format);
414	const auto pixelCount		= extent.width * extent.height * extent.depth;
415	const auto bufferSize		= static_cast<VkDeviceSize>(pixelCount) * static_cast<VkDeviceSize>(pixelSizeBytes);
416	const auto bufferUsage		= (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
417	const auto bufferCreateInfo	= makeBufferCreateInfo(bufferSize, bufferUsage);
418
419	de::MovePtr<BufferWithMemory> buffer (new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
420	return buffer;
421}
422
423de::MovePtr<BufferWithMemory> makeAndFillTransferBuffer (const VkExtent3D& extent, const tcu::TextureFormat& format,
424														 const DeviceInterface& vkd, const VkDevice device, Allocator& alloc)
425{
426	DE_ASSERT(tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
427
428	auto		buffer		= makeTransferBuffer(extent, format, vkd, device, alloc);
429	const auto	size		= makeIVec3(extent.width, extent.height, extent.depth);
430	auto		bufferImg	= makePixelBufferAccess(*buffer, size, format);
431
432	// Fill image with predefined pattern.
433	for (int z = 0; z < size.z(); ++z)
434		for (int y = 0; y < size.y(); ++y)
435			for (int x = 0; x < size.x(); ++x)
436			{
437				const tcu::UVec4 color (
438					static_cast<uint32_t>(0x80 | x),
439					static_cast<uint32_t>(0x80 | y),
440					static_cast<uint32_t>(0x80 | z),
441					1u
442				);
443				bufferImg->setPixel(color, x, y, z);
444			}
445
446	return buffer;
447}
448
449de::MovePtr<ImageWithMemory> make3DImage (const DeviceInterface &vkd, const VkDevice device, Allocator& alloc, const VkFormat format, const VkExtent3D& extent, uint32_t mipLevels, const bool sampling)
450{
451	const VkImageUsageFlags imageUsage	= (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
452										| (sampling ? VK_IMAGE_USAGE_SAMPLED_BIT : static_cast<VkImageUsageFlagBits>(0)));
453
454	const VkImageCreateInfo imageCreateInfo =
455	{
456		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
457		nullptr,								//	const void*				pNext;
458		0u,										//	VkImageCreateFlags		flags;
459		VK_IMAGE_TYPE_3D,						//	VkImageType				imageType;
460		format,									//	VkFormat				format;
461		extent,									//	VkExtent3D				extent;
462		mipLevels,								//	uint32_t				mipLevels;
463		1u,										//	uint32_t				arrayLayers;
464		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
465		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
466		imageUsage,								//	VkImageUsageFlags		usage;
467		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
468		0u,										//	uint32_t				queueFamilyIndexCount;
469		nullptr,								//	const uint32_t*			pQueueFamilyIndices;
470		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
471	};
472
473	de::MovePtr<ImageWithMemory> image (new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
474	return image;
475}
476
477VkImageSubresourceRange makeCommonImageSubresourceRange (uint32_t baseLevel, uint32_t levelCount)
478{
479	return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, baseLevel, levelCount, 0u, 1u);
480}
481
482VkImageSubresourceLayers makeCommonImageSubresourceLayers (uint32_t mipLevel)
483{
484	return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0u, 1u);
485}
486
487Move<VkImageView> make3DImageView (const DeviceInterface &vkd, const VkDevice device, const VkImage image, const VkFormat format,
488								   const tcu::Maybe<tcu::UVec2>& slices/*x=offset, y=range)*/, uint32_t mipLevel, uint32_t levelCount)
489{
490	const bool subSlice = static_cast<bool>(slices);
491
492	VkImageViewSlicedCreateInfoEXT sliceCreateInfo = initVulkanStructure();
493
494	if (subSlice)
495	{
496		sliceCreateInfo.sliceOffset	= slices->x();
497		sliceCreateInfo.sliceCount	= slices->y();
498	}
499
500	const VkImageViewCreateInfo viewCreateInfo =
501	{
502		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,				//	VkStructureType			sType;
503		(subSlice ? &sliceCreateInfo : nullptr),				//	const void*				pNext;
504		0u,														//	VkImageViewCreateFlags	flags;
505		image,													//	VkImage					image;
506		VK_IMAGE_VIEW_TYPE_3D,									//	VkImageViewType			viewType;
507		format,													//	VkFormat				format;
508		makeComponentMappingRGBA(),								//	VkComponentMapping		components;
509		makeCommonImageSubresourceRange(mipLevel, levelCount),	//	VkImageSubresourceRange	subresourceRange;
510	};
511
512	return createImageView(vkd, device, &viewCreateInfo);
513}
514
515VkPipelineStageFlagBits makePipelineStage (VkShaderStageFlagBits shaderStage)
516{
517	if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
518		return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
519	if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
520		return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
521
522	DE_ASSERT(false);
523	return VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM;
524}
525
526void SlicedViewTestInstance::runPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer, const VkImageView slicedImage, const VkImageView auxiliarImage)
527{
528	// The layouts created and used here must match the shaders.
529	const auto descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
530
531	DescriptorSetLayoutBuilder layoutBuilder;
532	layoutBuilder.addSingleBinding(descriptorType, m_params.stage);
533	layoutBuilder.addSingleBinding(descriptorType, m_params.stage);
534	m_setLayout = layoutBuilder.build(vkd, device);
535
536	DescriptorPoolBuilder poolBuilder;
537	poolBuilder.addType(descriptorType, 2u);
538	m_descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
539
540	m_descriptorSet		= makeDescriptorSet(vkd, device, m_descriptorPool.get(), m_setLayout.get());
541	m_pipelineLayout	= makePipelineLayout(vkd, device, m_setLayout.get());
542
543	DescriptorSetUpdateBuilder updateBuilder;
544	const auto slicedImageDescInfo		= makeDescriptorImageInfo(DE_NULL, slicedImage, kUsageLayout);
545	const auto auxiliarImageDescInfo	= makeDescriptorImageInfo(DE_NULL, auxiliarImage, kUsageLayout);
546	updateBuilder.writeSingle(m_descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &slicedImageDescInfo);
547	updateBuilder.writeSingle(m_descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &auxiliarImageDescInfo);
548	updateBuilder.update(vkd, device);
549
550	if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
551		runGraphicsPipeline(vkd, device, cmdBuffer);
552	else if (m_params.stage == VK_SHADER_STAGE_COMPUTE_BIT)
553		runComputePipeline(vkd, device, cmdBuffer);
554	else
555		DE_ASSERT(false);
556}
557
558void SlicedViewTestInstance::runGraphicsPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer)
559{
560	const auto	sliceExtent	= m_params.getSliceExtent();
561	const auto&	binaries	= m_context.getBinaryCollection();
562	const auto	vertShader	= createShaderModule(vkd, device, binaries.get("vert"));
563	const auto	fragShader	= createShaderModule(vkd, device, binaries.get("frag"));
564	const auto	extent		= makeExtent3D(sliceExtent.width, sliceExtent.height, 1u);
565	const auto	bindPoint	= VK_PIPELINE_BIND_POINT_GRAPHICS;
566
567	m_renderPass	= makeRenderPass(vkd, device);
568	m_framebuffer	= makeFramebuffer(vkd, device, m_renderPass.get(), 0u, nullptr, sliceExtent.width, sliceExtent.height);
569
570	const std::vector<VkViewport>	viewports	(1u, makeViewport(extent));
571	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(extent));
572
573	const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
574
575	m_pipeline = makeGraphicsPipeline(vkd, device, m_pipelineLayout.get(),
576									  vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(),
577									  m_renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
578									  &vertexInputStateCreateInfo);
579
580	beginRenderPass(vkd, cmdBuffer, m_renderPass.get(), m_framebuffer.get(), scissors.at(0u));
581	vkd.cmdBindPipeline(cmdBuffer, bindPoint, m_pipeline.get());
582	vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
583	vkd.cmdDraw(cmdBuffer, kVertexCount, sliceExtent.depth, 0u, 0u);
584	endRenderPass(vkd, cmdBuffer);
585}
586
587void SlicedViewTestInstance::runComputePipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer)
588{
589	const auto bindPoint	= VK_PIPELINE_BIND_POINT_COMPUTE;
590	const auto compShader	= createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"));
591
592	m_pipeline = makeComputePipeline(vkd, device, m_pipelineLayout.get(), compShader.get());
593
594	vkd.cmdBindPipeline(cmdBuffer, bindPoint, m_pipeline.get());
595	vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
596	vkd.cmdDispatch(cmdBuffer, m_params.getActualRange(), 1u, 1u);
597}
598
599bool SlicedViewTestInstance::runSamplingPipeline (const VkImage fullImage, const VkImageView slicedView, const VkExtent3D& levelExtent)
600{
601	const auto&		vkd			= m_context.getDeviceInterface();
602	const auto		device		= m_context.getDevice();
603	const auto		qfIndex		= m_context.getUniversalQueueFamilyIndex();
604	const auto		queue		= m_context.getUniversalQueue();
605	auto&			alloc		= m_context.getDefaultAllocator();
606
607	const auto bindPoint		= VK_PIPELINE_BIND_POINT_COMPUTE;
608	const auto shaderStage		= VK_SHADER_STAGE_COMPUTE_BIT;
609	const auto pipelineStage	= makePipelineStage(shaderStage);
610
611	// Command pool and buffer.
612	const auto cmdPool		= makeCommandPool(vkd, device, qfIndex);
613	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
614	const auto cmdBuffer	= cmdBufferPtr.get();
615
616	// Descriptor set layout and pipeline layout.
617	DescriptorSetLayoutBuilder setLayoutBuilder;
618	setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage);
619	setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
620	const auto setLayout		= setLayoutBuilder.build(vkd, device);
621	const auto pipelineLayout	= makePipelineLayout(vkd, device, setLayout.get());
622
623	// Pipeline.
624	const auto compShader	= createShaderModule(vkd, device, m_context.getBinaryCollection().get("compSample"));
625	const auto pipeline		= makeComputePipeline(vkd, device, pipelineLayout.get(), compShader.get());
626
627	// Descriptor pool and set.
628	DescriptorPoolBuilder poolBuilder;
629	poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
630	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
631	const auto descriptorPool	= poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
632	const auto descriptorSet	= makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
633
634	// Update descriptor set.
635	const VkSamplerCreateInfo samplerCreateInfo =
636	{
637		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,		//	VkStructureType			sType;
638		nullptr,									//	const void*				pNext;
639		0u,											//	VkSamplerCreateFlags	flags;
640		VK_FILTER_NEAREST,							//	VkFilter				magFilter;
641		VK_FILTER_NEAREST,							//	VkFilter				minFilter;
642		VK_SAMPLER_MIPMAP_MODE_NEAREST,				//	VkSamplerMipmapMode		mipmapMode;
643		VK_SAMPLER_ADDRESS_MODE_REPEAT,				//	VkSamplerAddressMode	addressModeU;
644		VK_SAMPLER_ADDRESS_MODE_REPEAT,				//	VkSamplerAddressMode	addressModeV;
645		VK_SAMPLER_ADDRESS_MODE_REPEAT,				//	VkSamplerAddressMode	addressModeW;
646		0.0f,										//	float					mipLodBias;
647		VK_FALSE,									//	VkBool32				anisotropyEnable;
648		1.0f,										//	float					maxAnisotropy;
649		VK_FALSE,									//	VkBool32				compareEnable;
650		VK_COMPARE_OP_NEVER,						//	VkCompareOp				compareOp;
651		0.0f,										//	float					minLod;
652		0.0f,										//	float					maxLod;
653		VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,		//	VkBorderColor			borderColor;
654		VK_FALSE,									//	VkBool32				unnormalizedCoordinates;
655	};
656	const auto sampler = createSampler(vkd, device, &samplerCreateInfo);
657
658	// This will be used as a storage image to verify the sampling results.
659	// It has the same size as the full level extent, but only a single level and not sliced.
660	const auto auxiliarImage	= make3DImage(vkd, device, alloc, kFormat, levelExtent, 1u, false/*sampling*/);
661	const auto auxiliarView		= make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u);
662
663	DescriptorSetUpdateBuilder updateBuilder;
664	const auto sampledImageInfo = makeDescriptorImageInfo(sampler.get(), slicedView, kUsageLayout);
665	const auto storageImageInfo = makeDescriptorImageInfo(DE_NULL, auxiliarView.get(), kUsageLayout);
666	updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &sampledImageInfo);
667	updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImageInfo);
668	updateBuilder.update(vkd, device);
669
670	const auto tcuFormat	= mapVkFormat(kFormat);
671	const auto verifBuffer	= makeTransferBuffer(levelExtent, tcuFormat, vkd, device, alloc);
672	const auto refBuffer	= makeTransferBuffer(levelExtent, tcuFormat, vkd, device, alloc);
673
674	beginCommandBuffer(vkd, cmdBuffer);
675
676	// Move auxiliar image to the proper layout.
677	const auto shaderAccess			= (VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
678	const auto colorSRR				= makeCommonImageSubresourceRange(0u, 1u);
679	const auto preDispatchBarrier	= makeImageMemoryBarrier(0u, shaderAccess, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, auxiliarImage->get(), colorSRR);
680	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, pipelineStage, &preDispatchBarrier);
681
682	vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
683	vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
684	vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
685
686	// Sync shader writes before copying to verification buffer.
687	const auto preCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
688	cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier);
689
690	// Copy storage image to verification buffer.
691	const auto colorSRL		= makeCommonImageSubresourceLayers(0u);
692	const auto copyRegion	= makeBufferImageCopy(levelExtent, colorSRL);
693	vkd.cmdCopyImageToBuffer(cmdBuffer, auxiliarImage->get(), kUsageLayout, verifBuffer->get(), 1u, &copyRegion);
694
695	// Copy full level from the original full image to the reference buffer to compare them.
696	const auto refSRL		= makeCommonImageSubresourceLayers(m_params.getSelectedLevel());
697	const auto refCopy		= makeBufferImageCopy(levelExtent, refSRL);
698	vkd.cmdCopyImageToBuffer(cmdBuffer, fullImage, kUsageLayout, refBuffer->get(), 1u, &refCopy);
699
700	// Sync copies to host.
701	const auto postCopyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
702	cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyBarrier);
703
704	endCommandBuffer(vkd, cmdBuffer);
705	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
706
707	// Compare both buffers.
708	auto& verifBufferAlloc	= verifBuffer->getAllocation();
709	auto& refBufferAlloc	= refBuffer->getAllocation();
710	invalidateAlloc(vkd, device, verifBufferAlloc);
711	invalidateAlloc(vkd, device, refBufferAlloc);
712
713	const auto iExtent = makeIVec3(levelExtent.width, levelExtent.height, levelExtent.depth);
714	const tcu::ConstPixelBufferAccess verifAcces	(tcuFormat, iExtent, verifBufferAlloc.getHostPtr());
715	const tcu::ConstPixelBufferAccess refAccess		(tcuFormat, iExtent, refBufferAlloc.getHostPtr());
716
717	auto&				log			= m_context.getTestContext().getLog();
718	const tcu::UVec4	threshold	(0u, 0u, 0u, 0u);
719	return tcu::intThresholdCompare(log, "SamplingResult", "", refAccess, verifAcces, threshold, tcu::COMPARE_LOG_ON_ERROR);
720}
721
722tcu::TestStatus SlicedViewLoadTestInstance::iterate (void)
723{
724	const auto&			vkd			= m_context.getDeviceInterface();
725	const auto			device		= m_context.getDevice();
726	auto&				alloc		= m_context.getDefaultAllocator();
727	const auto			qfIndex		= m_context.getUniversalQueueFamilyIndex();
728	const auto			queue		= m_context.getUniversalQueue();
729
730	const auto mipLevel			= m_params.getSelectedLevel();
731	const auto fullExtent		= makeExtent3D(m_params.width, m_params.height, m_params.depth);
732	const auto sliceExtent		= m_params.getSliceExtent();
733	const auto tcuFormat		= mapVkFormat(kFormat);
734	const auto auxiliarBuffer	= makeAndFillTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
735	const auto verifBuffer		= makeTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
736	const auto fullImage		= make3DImage(vkd, device, alloc, kFormat, fullExtent, m_params.getFullImageLevels(), m_params.sampleImg);
737	const auto fullSRR			= makeCommonImageSubresourceRange(0u, VK_REMAINING_MIP_LEVELS);
738	const auto singleSRR		= makeCommonImageSubresourceRange(0u, 1u);
739	const auto targetLevelSRL	= makeCommonImageSubresourceLayers(mipLevel);
740	const auto baseLevelSRL		= makeCommonImageSubresourceLayers(0u);
741	const auto clearColor		= makeClearValueColorU32(0u, 0u, 0u, 0u);
742	const auto pipelineStage	= makePipelineStage(m_params.stage);
743
744	const auto cmdPool			= makeCommandPool(vkd, device, qfIndex);
745	const auto cmdBufferPtr		= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
746	const auto cmdBuffer		= cmdBufferPtr.get();
747
748	beginCommandBuffer(vkd, cmdBuffer);
749
750	// Zero-out full image.
751	const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
752														VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
753														fullImage->get(), fullSRR);
754	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
755	vkd.cmdClearColorImage(cmdBuffer, fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &fullSRR);
756
757	// Copy reference buffer to full image at the right offset.
758	const auto preCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
759													   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
760													   fullImage->get(), fullSRR);
761	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier);
762
763	const VkBufferImageCopy sliceCopy =
764	{
765		0ull,														//	VkDeviceSize				bufferOffset;
766		0u,															//	deUint32					bufferRowLength;
767		0u,															//	deUint32					bufferImageHeight;
768		targetLevelSRL,												//	VkImageSubresourceLayers	imageSubresource;
769		makeOffset3D(0, 0, static_cast<int32_t>(m_params.offset)),	//	VkOffset3D					imageOffset;
770		sliceExtent,												//	VkExtent3D					imageExtent;
771	};
772	vkd.cmdCopyBufferToImage(cmdBuffer, auxiliarBuffer->get(), fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &sliceCopy);
773
774	// Move full image to the general layout to be able to read from or write to it from the shader.
775	// Note: read-only optimal is not a valid layout for this.
776	const auto postCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
777														VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout,
778														fullImage->get(), fullSRR);
779	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &postCopyBarrier);
780
781	// Create sliced view of the full image.
782	const auto slicedView = make3DImageView(vkd, device, fullImage->get(), kFormat, tcu::just(tcu::UVec2(m_params.offset, m_params.getSlicedViewRange())), mipLevel, 1u);
783
784	// Create storage image and view with reduced size (this will be the destination image in the shader).
785	const auto auxiliarImage	= make3DImage(vkd, device, alloc, kFormat, sliceExtent, 1u, false/*sampling*/);
786	const auto auxiliarView		= make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u);
787
788	// Move the auxiliar image to the general layout for writing.
789	const auto preWriteBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, kUsageLayout, auxiliarImage->get(), singleSRR);
790	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, pipelineStage, &preWriteBarrier);
791
792	// Run load operation.
793	runPipeline(vkd, device, cmdBuffer, slicedView.get(), auxiliarView.get());
794
795	// Copy auxiliar image (result) to verification buffer.
796	const auto preVerifCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
797	cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preVerifCopyBarrier);
798	const auto verifCopyRegion = makeBufferImageCopy(sliceExtent, baseLevelSRL);
799	vkd.cmdCopyImageToBuffer(cmdBuffer, auxiliarImage->get(), kUsageLayout, verifBuffer->get(), 1u, &verifCopyRegion);
800
801	// Sync verification buffer with host reads.
802	const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
803	cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
804
805	endCommandBuffer(vkd, cmdBuffer);
806	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
807
808	const auto	sliceExtentIV3		= makeIVec3(sliceExtent.width, sliceExtent.height, sliceExtent.depth);
809	auto&		auxiliarBufferAlloc	= auxiliarBuffer->getAllocation();
810	auto&		verifBufferAlloc	= verifBuffer->getAllocation();
811
812	// Invalidate verification buffer allocation.
813	invalidateAlloc(vkd, device, verifBufferAlloc);
814
815	// Compare auxiliar buffer and verification buffer.
816	const tcu::ConstPixelBufferAccess initialImage (tcuFormat, sliceExtentIV3, auxiliarBufferAlloc.getHostPtr());
817	const tcu::ConstPixelBufferAccess finalImage (tcuFormat, sliceExtentIV3, verifBufferAlloc.getHostPtr());
818
819	auto& log = m_context.getTestContext().getLog();
820	const tcu::UVec4 threshold(0u, 0u, 0u, 0u);
821
822	if (!tcu::intThresholdCompare(log, "Comparison", "Comparison of reference and result", initialImage, finalImage, threshold, tcu::COMPARE_LOG_ON_ERROR))
823		return tcu::TestStatus::fail("Image comparison failed; check log for details");
824
825	if (m_params.sampleImg && !runSamplingPipeline(fullImage->get(), slicedView.get(), m_params.getFullLevelExtent()))
826		return tcu::TestStatus::fail("Sampling full level failed; check log for details");
827
828	return tcu::TestStatus::pass("Pass");
829}
830
831tcu::TestStatus SlicedViewStoreTestInstance::iterate (void)
832{
833	const auto&			vkd			= m_context.getDeviceInterface();
834	const auto			device		= m_context.getDevice();
835	auto&				alloc		= m_context.getDefaultAllocator();
836	const auto			qfIndex		= m_context.getUniversalQueueFamilyIndex();
837	const auto			queue		= m_context.getUniversalQueue();
838
839	const auto mipLevel			= m_params.getSelectedLevel();
840	const auto fullExtent		= makeExtent3D(m_params.width, m_params.height, m_params.depth);
841	const auto sliceExtent		= m_params.getSliceExtent();
842	const auto tcuFormat		= mapVkFormat(kFormat);
843	const auto auxiliarBuffer	= makeAndFillTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
844	const auto verifBuffer		= makeTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
845	const auto fullImage		= make3DImage(vkd, device, alloc, kFormat, fullExtent, m_params.getFullImageLevels(), m_params.sampleImg);
846	const auto fullSRR			= makeCommonImageSubresourceRange(0u, VK_REMAINING_MIP_LEVELS);
847	const auto singleSRR		= makeCommonImageSubresourceRange(0u, 1u);
848	const auto targetLevelSRL	= makeCommonImageSubresourceLayers(mipLevel);
849	const auto baseLevelSRL		= makeCommonImageSubresourceLayers(0u);
850	const auto clearColor		= makeClearValueColorU32(0u, 0u, 0u, 0u);
851	const auto pipelineStage	= makePipelineStage(m_params.stage);
852
853	const auto cmdPool			= makeCommandPool(vkd, device, qfIndex);
854	const auto cmdBufferPtr		= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
855	const auto cmdBuffer		= cmdBufferPtr.get();
856
857	beginCommandBuffer(vkd, cmdBuffer);
858
859	// Zero-out full image.
860	const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, fullImage->get(), fullSRR);
861	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
862	vkd.cmdClearColorImage(cmdBuffer, fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &fullSRR);
863
864	// Create sliced view of the full image.
865	const auto slicedView = make3DImageView(vkd, device, fullImage->get(), kFormat, tcu::just(tcu::UVec2(m_params.offset, m_params.getSlicedViewRange())), mipLevel, 1u);
866
867	// Create storage image and view with reduced size (this will be the source image in the shader).
868	const auto auxiliarImage	= make3DImage(vkd, device, alloc, kFormat, sliceExtent, 1u, false/*sampling*/);
869	const auto auxiliarView		= make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u);
870
871	// Copy reference buffer into auxiliar image.
872	const auto preCopyBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, auxiliarImage->get(), singleSRR);
873	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier);
874	const auto sliceCopy = makeBufferImageCopy(sliceExtent, baseLevelSRL);
875	vkd.cmdCopyBufferToImage(cmdBuffer, auxiliarBuffer->get(), auxiliarImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &sliceCopy);
876
877	// Move both images to the general layout for reading and writing.
878	// Note: read-only optimal is not a valid layout for the read image.
879	const auto preShaderBarrierAux	= makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, auxiliarImage->get(), singleSRR);
880	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &preShaderBarrierAux);
881	const auto preShaderBarrierFull	= makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, fullImage->get(), fullSRR);
882	cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &preShaderBarrierFull);
883
884	// Run store operation.
885	runPipeline(vkd, device, cmdBuffer, slicedView.get(), auxiliarView.get());
886
887	// Copy the right section of the full image (result) to verification buffer.
888	const auto preVerifCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
889	cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preVerifCopyBarrier);
890
891	const VkBufferImageCopy verifCopy =
892	{
893		0ull,														//	VkDeviceSize				bufferOffset;
894		0u,															//	deUint32					bufferRowLength;
895		0u,															//	deUint32					bufferImageHeight;
896		targetLevelSRL,												//	VkImageSubresourceLayers	imageSubresource;
897		makeOffset3D(0, 0, static_cast<int32_t>(m_params.offset)),	//	VkOffset3D					imageOffset;
898		sliceExtent,												//	VkExtent3D					imageExtent;
899	};
900	vkd.cmdCopyImageToBuffer(cmdBuffer, fullImage->get(), kUsageLayout, verifBuffer->get(), 1u, &verifCopy);
901
902	// Sync verification buffer with host reads.
903	const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
904	cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
905
906	endCommandBuffer(vkd, cmdBuffer);
907	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
908
909	const auto	sliceExtentIV3		= makeIVec3(sliceExtent.width, sliceExtent.height, sliceExtent.depth);
910	auto&		auxiliarBufferAlloc	= auxiliarBuffer->getAllocation();
911	auto&		verifBufferAlloc	= verifBuffer->getAllocation();
912
913	// Invalidate verification buffer allocation.
914	invalidateAlloc(vkd, device, verifBufferAlloc);
915
916	// Compare auxiliar buffer and verification buffer.
917	const tcu::ConstPixelBufferAccess initialImage (tcuFormat, sliceExtentIV3, auxiliarBufferAlloc.getHostPtr());
918	const tcu::ConstPixelBufferAccess finalImage (tcuFormat, sliceExtentIV3, verifBufferAlloc.getHostPtr());
919
920	auto& log = m_context.getTestContext().getLog();
921	const tcu::UVec4 threshold(0u, 0u, 0u, 0u);
922
923	if (!tcu::intThresholdCompare(log, "Comparison", "Comparison of reference and result", initialImage, finalImage, threshold, tcu::COMPARE_LOG_ON_ERROR))
924		return tcu::TestStatus::fail("Image comparison failed; check log for details");
925
926	if (m_params.sampleImg && !runSamplingPipeline(fullImage->get(), slicedView.get(), m_params.getFullLevelExtent()))
927		return tcu::TestStatus::fail("Sampling full level failed; check log for details");
928
929	return tcu::TestStatus::pass("Pass");
930}
931
932using TestCaseGroupPtr = de::MovePtr<tcu::TestCaseGroup>;
933
934} // anonymous
935
936tcu::TestCaseGroup* createImageSlicedViewOf3DTests (tcu::TestContext& testCtx)
937{
938	TestCaseGroupPtr imageTests (new tcu::TestCaseGroup(testCtx, "sliced_view_of_3d_image"));
939
940	const struct
941	{
942		VkShaderStageFlagBits	stage;
943		const char*				name;
944	} stageCases[] =
945	{
946		{ VK_SHADER_STAGE_COMPUTE_BIT,	"comp"	},
947		{ VK_SHADER_STAGE_FRAGMENT_BIT,	"frag"	},
948	};
949
950	const struct
951	{
952		TestType			testType;
953		const char*			name;
954	} testTypeCases[] =
955	{
956		{ TestType::LOAD,		"load"	},
957		{ TestType::STORE,		"store"	},
958	};
959
960	const struct
961	{
962		bool				sampleImg;
963		const char*			suffix;
964	} samplingCases[] =
965	{
966		{ false,			""					},
967		{ true,				"_with_sampling"	},
968	};
969
970	const uint32_t	seed	= 1667817299u;
971	de::Random		rnd		(seed);
972
973	// Basic tests with 2 slices and a view of the first or second slice.
974	{
975		const uint32_t basicDepth = 2u;
976		const uint32_t basicRange = 1u;
977
978		TestCaseGroupPtr basicTests (new tcu::TestCaseGroup(testCtx, "basic"));
979
980		for (const auto& testTypeCase : testTypeCases)
981		{
982			TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
983
984			for (const auto& stageCase : stageCases)
985			{
986				TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name));
987
988				for (uint32_t offset = 0u; offset < basicDepth; ++offset)
989				{
990					for (const auto& samplingCase : samplingCases)
991					{
992						const auto	testName	= "offset_" + std::to_string(offset) + samplingCase.suffix;
993						TestParams	params		(testTypeCase.testType, stageCase.stage, kWidth, kHeight, basicDepth, offset, basicRange, tcu::Nothing, samplingCase.sampleImg);
994
995						stageGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
996					}
997				}
998
999				testTypeGroup->addChild(stageGroup.release());
1000			}
1001
1002			basicTests->addChild(testTypeGroup.release());
1003		}
1004
1005		imageTests->addChild(basicTests.release());
1006	}
1007
1008	// Full slice tests.
1009	{
1010		const uint32_t fullDepth = 4u;
1011
1012		TestCaseGroupPtr fullSliceTests (new tcu::TestCaseGroup(testCtx, "full_slice"));
1013
1014		for (const auto& testTypeCase : testTypeCases)
1015		{
1016			TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
1017
1018			for (const auto& stageCase : stageCases)
1019			{
1020				for (const auto& samplingCase : samplingCases)
1021				{
1022					const auto testName = std::string(stageCase.name) + samplingCase.suffix;
1023					TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, fullDepth, 0u, fullDepth, tcu::Nothing, samplingCase.sampleImg);
1024					testTypeGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
1025				}
1026			}
1027
1028			fullSliceTests->addChild(testTypeGroup.release());
1029		}
1030
1031		imageTests->addChild(fullSliceTests.release());
1032	}
1033
1034	// Pseudorandom test cases.
1035	{
1036		using CaseId	= std::tuple<uint32_t, uint32_t, uint32_t>; // depth, offset, range
1037		using CaseIdSet	= std::set<CaseId>;
1038
1039		const uint32_t	depthCases	= 5u;
1040		const uint32_t	rangeCases	= 5u;
1041		const int		minDepth	= 10u;
1042		const int		maxDepth	= 32u;
1043
1044		TestCaseGroupPtr randomTests (new tcu::TestCaseGroup(testCtx, "random"));
1045
1046		for (const auto& testTypeCase : testTypeCases)
1047		{
1048			TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
1049
1050			for (const auto& stageCase : stageCases)
1051			{
1052				TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name));
1053
1054				CaseIdSet generatedCases;
1055
1056				for (uint32_t i = 0u; i < depthCases; ++i)
1057				{
1058					const uint32_t depth = static_cast<uint32_t>(rnd.getInt(minDepth, maxDepth));
1059
1060					for (uint32_t j = 0u; j < rangeCases; ++j)
1061					{
1062						uint32_t offset	= 0u;
1063						uint32_t range	= 0u;
1064
1065						for (;;)
1066						{
1067							DE_ASSERT(depth > 0u);
1068							offset = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(depth - 1u)));
1069
1070							DE_ASSERT(offset < depth);
1071							range = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(depth - offset)));
1072
1073							// 0 is interpreted as VK_REMAINING_3D_SLICES_EXT.
1074							if (range == 0u)
1075								range = VK_REMAINING_3D_SLICES_EXT;
1076
1077							// The current seed may generate duplicate cases with non-unique names, so we filter those out.
1078							const CaseId currentCase (depth, offset, range);
1079							if (de::contains(begin(generatedCases), end(generatedCases), currentCase))
1080								continue;
1081
1082							generatedCases.insert(currentCase);
1083							break;
1084						}
1085
1086						const auto	rangeStr	= ((range == VK_REMAINING_3D_SLICES_EXT) ? "remaining_3d_slices" : std::to_string(range));
1087						const auto	testName	= "depth_" + std::to_string(depth) + "_offset_" + std::to_string(offset) + "_range_" + rangeStr;
1088						TestParams	params		(testTypeCase.testType, stageCase.stage, kWidth, kHeight, depth, offset, range, tcu::Nothing, false);
1089
1090						stageGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
1091					}
1092				}
1093
1094				testTypeGroup->addChild(stageGroup.release());
1095			}
1096
1097			randomTests->addChild(testTypeGroup.release());
1098		}
1099
1100		imageTests->addChild(randomTests.release());
1101	}
1102
1103	// Mip level test cases.
1104	{
1105		using CaseId	= std::tuple<uint32_t, uint32_t>; // depth, offset, range
1106		using CaseIdSet	= std::set<CaseId>;
1107
1108		const uint32_t	casesPerLevel	= 2u;
1109		const uint32_t	width			= kWidth;
1110		const uint32_t	height			= kWidth;
1111		const uint32_t	depth			= kWidth;
1112		const uint32_t	maxLevels		= TestParams::getMaxMipLevelCountForSize(kWidth);
1113
1114		TestCaseGroupPtr mipLevelTests (new tcu::TestCaseGroup(testCtx, "mip_level"));
1115
1116		for (const auto& testTypeCase : testTypeCases)
1117		{
1118			TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
1119
1120			for (const auto& stageCase : stageCases)
1121			{
1122				TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name));
1123
1124				for (uint32_t level = 0u; level < maxLevels; ++level)
1125				{
1126					const auto	levelSize		= (depth >> level);
1127					const auto	groupName		= "level_" + std::to_string(level);
1128					CaseIdSet	generatedCases;
1129
1130					DE_ASSERT(levelSize > 0u);
1131
1132					TestCaseGroupPtr levelGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str()));
1133
1134					// Generate a few pseudorandom cases per mip level.
1135					for (uint32_t i = 0u; i < casesPerLevel; ++i)
1136					{
1137						uint32_t offset = 0u;
1138						uint32_t range = 0u;
1139
1140						for (;;)
1141						{
1142							offset = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(levelSize - 1u)));
1143							DE_ASSERT(offset < levelSize);
1144
1145							range = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(levelSize - offset)));
1146
1147							// 0 is interpreted as VK_REMAINING_3D_SLICES_EXT.
1148							if (range == 0u)
1149								range = VK_REMAINING_3D_SLICES_EXT;
1150
1151							const CaseId currentCase (offset, range);
1152							if (de::contains(begin(generatedCases), end(generatedCases), currentCase))
1153								continue;
1154
1155							generatedCases.insert(currentCase);
1156							break;
1157						}
1158
1159						const auto rangeStr	= ((range == VK_REMAINING_3D_SLICES_EXT) ? "remaining_3d_slices" : std::to_string(range));
1160						const auto testName	= "offset_" + std::to_string(offset) + "_range_" + rangeStr;
1161						TestParams params	(testTypeCase.testType, stageCase.stage, width, height, depth, offset, range, tcu::just(level), false);
1162
1163						levelGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
1164					}
1165
1166					stageGroup->addChild(levelGroup.release());
1167				}
1168
1169				testTypeGroup->addChild(stageGroup.release());
1170			}
1171
1172			mipLevelTests->addChild(testTypeGroup.release());
1173		}
1174
1175		imageTests->addChild(mipLevelTests.release());
1176	}
1177
1178	return imageTests.release();
1179}
1180
1181} // pipeline
1182} // vkt
1183