• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
51 namespace vkt
52 {
53 namespace pipeline
54 {
55 
56 using namespace vk;
57 
58 namespace
59 {
60 
61 constexpr uint32_t	kWidth			= 8u;
62 constexpr uint32_t	kHeight			= 8u;
63 constexpr VkFormat	kFormat			= VK_FORMAT_R8G8B8A8_UINT;
64 constexpr uint32_t	kVertexCount	= 3u;
65 constexpr auto		kUsageLayout	= VK_IMAGE_LAYOUT_GENERAL;
66 
67 enum class TestType
68 {
69 	LOAD = 0,
70 	STORE,
71 };
72 
73 struct 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 
82 private:
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 
87 public:
88 	tcu::Maybe<uint32_t>	mipLevel;
89 	bool					sampleImg;
90 
TestParamsvkt::pipeline::__anonb13940c10111::TestParams91 	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 
getSelectedLevelvkt::pipeline::__anonb13940c10111::TestParams127 	uint32_t getSelectedLevel (void) const
128 	{
129 		return (useMipMaps() ? mipLevel.get() : 0u);
130 	}
131 
getFullImageLevelsvkt::pipeline::__anonb13940c10111::TestParams132 	uint32_t getFullImageLevels (void) const
133 	{
134 		return (useMipMaps() ? getMaxMipLevelCount() : 1u);
135 	}
136 
getActualRangevkt::pipeline::__anonb13940c10111::TestParams137 	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 
getSlicedViewRangevkt::pipeline::__anonb13940c10111::TestParams145 	uint32_t getSlicedViewRange (void) const
146 	{
147 		return range;
148 	}
149 
getSliceExtentvkt::pipeline::__anonb13940c10111::TestParams150 	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 
getFullLevelExtentvkt::pipeline::__anonb13940c10111::TestParams163 	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 
getMaxMipLevelCountForSizevkt::pipeline::__anonb13940c10111::TestParams176 	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 
182 private:
getMaxMipLevelCountvkt::pipeline::__anonb13940c10111::TestParams183 	uint32_t getMaxMipLevelCount (void) const
184 	{
185 		return getMaxMipLevelCountForSize(depth);
186 	}
187 
useMipMapsvkt::pipeline::__anonb13940c10111::TestParams188 	bool useMipMaps (void) const
189 	{
190 		return static_cast<bool>(mipLevel);
191 	}
192 
useRemainingSlicesvkt::pipeline::__anonb13940c10111::TestParams193 	bool useRemainingSlices (void) const
194 	{
195 		return (range == VK_REMAINING_3D_SLICES_EXT);
196 	}
197 };
198 
199 class SlicedViewTestCase : public vkt::TestCase
200 {
201 public:
SlicedViewTestCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)202 						SlicedViewTestCase		(tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
203 							: vkt::TestCase(testCtx, name), m_params(params) {}
~SlicedViewTestCase(void)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 
210 protected:
211 	const TestParams	m_params;
212 };
213 
214 class SlicedViewTestInstance : public vkt::TestInstance
215 {
216 public:
SlicedViewTestInstance(Context & context,const TestParams & params)217 						SlicedViewTestInstance	(Context& context, const TestParams& params)
218 							: vkt::TestInstance(context), m_params (params)
219 							{}
~SlicedViewTestInstance(void)220 	virtual				~SlicedViewTestInstance	(void) {}
221 
222 protected:
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 
242 class SlicedViewLoadTestInstance : public SlicedViewTestInstance
243 {
244 public:
SlicedViewLoadTestInstance(Context & context,const TestParams & params)245 					SlicedViewLoadTestInstance	(Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {}
~SlicedViewLoadTestInstance(void)246 	virtual			~SlicedViewLoadTestInstance	(void) {}
247 
248 	tcu::TestStatus	iterate						(void);
249 };
250 
251 class SlicedViewStoreTestInstance : public SlicedViewTestInstance
252 {
253 public:
SlicedViewStoreTestInstance(Context & context,const TestParams & params)254 					SlicedViewStoreTestInstance		(Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {}
~SlicedViewStoreTestInstance(void)255 	virtual			~SlicedViewStoreTestInstance	(void) {}
256 
257 	tcu::TestStatus	iterate							(void);
258 };
259 
checkSupport(Context & context) const260 void 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 
initPrograms(vk::SourceCollections & programCollection) const268 void 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 
createInstance(Context & context) const384 TestInstance* 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 
makeIVec3(uint32_t width,uint32_t height,uint32_t depth)395 tcu::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 
makePixelBufferAccess(const BufferWithMemory & buffer,const tcu::IVec3 & size,const tcu::TextureFormat & format)400 de::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 
makeTransferBuffer(const VkExtent3D & extent,const tcu::TextureFormat & format,const DeviceInterface & vkd,const VkDevice device,Allocator & alloc)406 de::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 
makeAndFillTransferBuffer(const VkExtent3D & extent,const tcu::TextureFormat & format,const DeviceInterface & vkd,const VkDevice device,Allocator & alloc)423 de::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 
make3DImage(const DeviceInterface & vkd,const VkDevice device,Allocator & alloc,const VkFormat format,const VkExtent3D & extent,uint32_t mipLevels,const bool sampling)449 de::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 
makeCommonImageSubresourceRange(uint32_t baseLevel,uint32_t levelCount)477 VkImageSubresourceRange makeCommonImageSubresourceRange (uint32_t baseLevel, uint32_t levelCount)
478 {
479 	return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, baseLevel, levelCount, 0u, 1u);
480 }
481 
makeCommonImageSubresourceLayers(uint32_t mipLevel)482 VkImageSubresourceLayers makeCommonImageSubresourceLayers (uint32_t mipLevel)
483 {
484 	return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0u, 1u);
485 }
486 
make3DImageView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format,const tcu::Maybe<tcu::UVec2> & slices,uint32_t mipLevel,uint32_t levelCount)487 Move<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 
makePipelineStage(VkShaderStageFlagBits shaderStage)515 VkPipelineStageFlagBits 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 
runPipeline(const DeviceInterface & vkd,const VkDevice device,const VkCommandBuffer cmdBuffer,const VkImageView slicedImage,const VkImageView auxiliarImage)526 void 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 
runGraphicsPipeline(const DeviceInterface & vkd,const VkDevice device,const VkCommandBuffer cmdBuffer)558 void 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 
runComputePipeline(const DeviceInterface & vkd,const VkDevice device,const VkCommandBuffer cmdBuffer)587 void 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 
runSamplingPipeline(const VkImage fullImage,const VkImageView slicedView,const VkExtent3D & levelExtent)599 bool 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 
iterate(void)722 tcu::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 
iterate(void)831 tcu::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 
932 using TestCaseGroupPtr = de::MovePtr<tcu::TestCaseGroup>;
933 
934 } // anonymous
935 
createImageSlicedViewOf3DTests(tcu::TestContext & testCtx)936 tcu::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