• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 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  vktImageSubresourceLayoutTests.cpp
22  * \brief Tests for vkGetImageSubresourceLayout
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTestCase.hpp"
26 
27 #include "vkDefs.hpp"
28 #include "vkImageUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkBarrierUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkStrUtil.hpp"
35 #include "vkBufferWithMemory.hpp"
36 #include "vkImageWithMemory.hpp"
37 
38 #include "tcuTestLog.hpp"
39 #include "vktTestCase.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuFloat.hpp"
42 #include "tcuCommandLine.hpp"
43 
44 #include "deRandom.hpp"
45 
46 #include <vector>
47 #include <sstream>
48 #include <limits>
49 #include <string>
50 
51 using namespace vk;
52 
53 namespace vkt
54 {
55 namespace image
56 {
57 namespace
58 {
59 
60 // Helper class to calculate buffer sizes and offsets for image mipmap levels.
61 class BufferLevels
62 {
63 public:
64 	struct Level
65 	{
66 		VkDeviceSize	offset;		// In bytes.
67 		VkDeviceSize	size;		// In bytes.
68 		VkExtent3D		dimensions;	// .depth will be the number of layers for 2D images and the depth for 3D images.
69 	};
70 
71 					BufferLevels	(VkImageType type, VkFormat format, VkExtent3D levelZero, deUint32 maxLevels, VkImageAspectFlags aspects = 0u);
72 	VkDeviceSize	totalSize		() const;
73 	VkDeviceSize	pixelSize		() const;
74 	deUint32		numLevels		() const;
75 	const Level&	getLevel		(deUint32 level) const;
76 
77 private:
78 	VkDeviceSize		m_pixelSize; // In bytes.
79 	std::vector<Level>	m_levels;
80 };
81 
BufferLevels(VkImageType type,VkFormat format,VkExtent3D levelZero,deUint32 maxLevels,VkImageAspectFlags aspects)82 BufferLevels::BufferLevels (VkImageType type, VkFormat format, VkExtent3D levelZero, deUint32 maxLevels, VkImageAspectFlags aspects)
83 {
84 	DE_ASSERT(type == VK_IMAGE_TYPE_2D || type == VK_IMAGE_TYPE_3D);
85 	DE_ASSERT(maxLevels >= 1u);
86 
87 	const auto		tcuFormat		= vk::mapVkFormat(format);
88 	const auto		maxLevelsSz		= static_cast<size_t>(maxLevels);
89 
90 	VkDeviceSize	currentOffset	= 0ull;
91 	VkExtent3D		nextExtent		= levelZero;
92 
93 	if (!aspects || (aspects & VK_IMAGE_ASPECT_COLOR_BIT))
94 	{
95 		m_pixelSize = static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat));
96 	}
97 	else if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
98 	{
99 		const auto copyFormat = getDepthCopyFormat(format);
100 		m_pixelSize = static_cast<VkDeviceSize>(tcu::getPixelSize(copyFormat));
101 	}
102 	else if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT)
103 	{
104 		const auto copyFormat = getStencilCopyFormat(format);
105 		m_pixelSize = static_cast<VkDeviceSize>(tcu::getPixelSize(copyFormat));
106 	}
107 	else
108 		DE_ASSERT(false);
109 
110 	while (m_levels.size() < maxLevelsSz)
111 	{
112 		Level level;
113 
114 		level.offset		= currentOffset;
115 		level.size			= m_pixelSize * nextExtent.width * nextExtent.height * nextExtent.depth;
116 		level.dimensions	= nextExtent;
117 
118 		m_levels.push_back(level);
119 
120 		// This was the last available level.
121 		if (nextExtent.width == 1u && nextExtent.height == 1u && (type == VK_IMAGE_TYPE_2D || nextExtent.depth == 1u))
122 			break;
123 
124 		nextExtent.width = std::max(1u, (nextExtent.width / 2u));
125 		nextExtent.height = std::max(1u, (nextExtent.height / 2u));
126 
127 		// 2D arrays all have the same array size.
128 		if (type == VK_IMAGE_TYPE_3D)
129 			nextExtent.depth = std::max(1u, (nextExtent.depth / 2u));
130 
131 		currentOffset += level.size;
132 	}
133 }
134 
totalSize() const135 VkDeviceSize BufferLevels::totalSize () const
136 {
137 	VkDeviceSize total = 0ull;
138 	std::for_each(begin(m_levels), end(m_levels), [&total] (const Level& l) { total += l.size; });
139 	return total;
140 }
141 
pixelSize() const142 VkDeviceSize BufferLevels::pixelSize () const
143 {
144 	return m_pixelSize;
145 }
146 
numLevels() const147 deUint32 BufferLevels::numLevels () const
148 {
149 	return static_cast<deUint32>(m_levels.size());
150 }
151 
getLevel(deUint32 level) const152 const BufferLevels::Level& BufferLevels::getLevel (deUint32 level) const
153 {
154 	return m_levels.at(level);
155 }
156 
157 // Default image dimensions. For 2D images, .depth indicates the number of layers.
getDefaultDimensions(VkImageType type,bool array)158 VkExtent3D getDefaultDimensions (VkImageType type, bool array)
159 {
160 	DE_ASSERT(type == VK_IMAGE_TYPE_2D || type == VK_IMAGE_TYPE_3D);
161 	DE_ASSERT(!array || type == VK_IMAGE_TYPE_2D);
162 
163 	constexpr VkExtent3D kDefault3D			= { 32u, 48u, 56u };
164 	constexpr VkExtent3D kDefault2DArray	= kDefault3D;
165 	constexpr VkExtent3D kDefault2D			= { 240u, 320u, 1u };
166 
167 	if (type == VK_IMAGE_TYPE_3D)
168 		return kDefault3D;
169 	if (array)
170 		return kDefault2DArray;
171 	return kDefault2D;
172 }
173 
174 struct TestParams
175 {
176 	VkImageType	imageType;
177 	VkFormat	imageFormat;
178 	VkExtent3D	dimensions;		// .depth will be the number of layers for 2D images and the depth for 3D images.
179 	deUint32	mipLevels;
180 	bool		imageOffset;	// Add an offset when a region of memory is bound to an image.
181 };
182 
183 class ImageSubresourceLayoutCase : public vkt::TestCase
184 {
185 public:
186 							ImageSubresourceLayoutCase		(tcu::TestContext& testCtx, const std::string& name, const TestParams& params);
~ImageSubresourceLayoutCase(void)187 	virtual					~ImageSubresourceLayoutCase		(void) {}
188 
initPrograms(vk::SourceCollections &) const189 	virtual void			initPrograms					(vk::SourceCollections&) const {}
190 	virtual TestInstance*	createInstance					(Context& context) const;
191 	virtual void			checkSupport					(Context& context) const;
192 
193 	static constexpr VkFormatFeatureFlags	kRequiredFeatures	= (VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
194 	static constexpr VkImageUsageFlags		kImageUsageFlags	= (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
195 	static constexpr VkImageTiling			kImageTiling		= VK_IMAGE_TILING_LINEAR;
196 protected:
197 	TestParams m_params;
198 };
199 
200 class ImageSubresourceLayoutInstance : public vkt::TestInstance
201 {
202 public:
203 								ImageSubresourceLayoutInstance	(Context& context, const TestParams& params);
~ImageSubresourceLayoutInstance(void)204 	virtual						~ImageSubresourceLayoutInstance	(void) {}
205 
206 	virtual tcu::TestStatus		iterate							(void);
207 	tcu::TestStatus				iterateAspect					(VkImageAspectFlagBits aspect);
208 private:
209 	TestParams m_params;
210 };
211 
ImageSubresourceLayoutCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)212 ImageSubresourceLayoutCase::ImageSubresourceLayoutCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
213 	: vkt::TestCase	(testCtx, name)
214 	, m_params		(params)
215 {
216 }
217 
createInstance(Context & context) const218 TestInstance* ImageSubresourceLayoutCase::createInstance (Context& context) const
219 {
220 	return new ImageSubresourceLayoutInstance (context, m_params);
221 }
222 
checkSupport(Context & context) const223 void ImageSubresourceLayoutCase::checkSupport (Context& context) const
224 {
225 	const auto&	vki				= context.getInstanceInterface();
226 	const auto	physicalDevice	= context.getPhysicalDevice();
227 
228 #ifndef CTS_USES_VULKANSC
229 	if (m_params.imageFormat == VK_FORMAT_A8_UNORM_KHR || m_params.imageFormat == VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR)
230 		context.requireDeviceFunctionality("VK_KHR_maintenance5");
231 #endif // CTS_USES_VULKANSC
232 
233 	const auto formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, m_params.imageFormat);
234 	if ((formatProperties.linearTilingFeatures & kRequiredFeatures) != kRequiredFeatures)
235 		TCU_THROW(NotSupportedError, "Required format features not supported");
236 
237 	VkImageFormatProperties imgFormatProperties;
238 	const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_params.imageFormat, m_params.imageType, kImageTiling, kImageUsageFlags, 0u, &imgFormatProperties);
239 	if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
240 		TCU_THROW(NotSupportedError, "Linear tiling not supported for format");
241 	VK_CHECK(result);
242 
243 	{
244 		BufferLevels levels (m_params.imageType, m_params.imageFormat, m_params.dimensions, m_params.mipLevels);
245 		if (imgFormatProperties.maxMipLevels < levels.numLevels())
246 			TCU_THROW(NotSupportedError, "Required number of mip levels not supported for format");
247 	}
248 
249 	if (m_params.imageType == VK_IMAGE_TYPE_2D && imgFormatProperties.maxArrayLayers < m_params.dimensions.depth)
250 		TCU_THROW(NotSupportedError, "Required number of layers not supported for format");
251 }
252 
ImageSubresourceLayoutInstance(Context & context,const TestParams & params)253 ImageSubresourceLayoutInstance::ImageSubresourceLayoutInstance (Context& context, const TestParams& params)
254 	: vkt::TestInstance	(context)
255 	, m_params			(params)
256 {
257 }
258 
259 // Fills length bytes starting at location with pseudorandom data.
fillWithRandomData(de::Random & rnd,void * location,VkDeviceSize length)260 void fillWithRandomData (de::Random& rnd, void* location, VkDeviceSize length)
261 {
262 	auto		bytePtr	= reinterpret_cast<unsigned char*>(location);
263 	const auto	endPtr	= bytePtr + length;
264 
265 	while (bytePtr != endPtr)
266 	{
267 		const auto remaining = (endPtr - bytePtr);
268 
269 		if (remaining >= 8)			{ const auto data = rnd.getUint64();	deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
270 		else if (remaining >= 4)	{ const auto data = rnd.getUint32();	deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
271 		else if (remaining >= 2)	{ const auto data = rnd.getUint16();	deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
272 		else						{ const auto data = rnd.getUint8();		deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
273 	}
274 }
275 
276 // Fills data in blocks of 32 bits, discarding the higher 8 bits of each block.
fillWithRandomData24In32(de::Random & rnd,void * location,VkDeviceSize length)277 void fillWithRandomData24In32 (de::Random& rnd, void* location, VkDeviceSize length)
278 {
279 	static const auto blockSize = sizeof(deUint32);
280 	DE_ASSERT(length % blockSize == 0);
281 
282 	auto		dataPtr		= reinterpret_cast<unsigned char*>(location);
283 	const auto	numBlocks	= length / blockSize;
284 
285 	for (VkDeviceSize i = 0; i < numBlocks; ++i)
286 	{
287 		auto data = rnd.getUint32();
288 		data &= 0xFFFFFFu; // Remove the higher 8 bits.
289 		deMemcpy(dataPtr, &data, blockSize);
290 		dataPtr += blockSize;
291 	}
292 }
293 
294 // Helpers to make fillWithRandomFloatingPoint a template. Returns normal numbers in the range [0, 1).
295 template <class T>
296 T getNormalFPValue (de::Random& rnd);
297 
298 template<>
getNormalFPValue(de::Random & rnd)299 float getNormalFPValue<float> (de::Random& rnd)
300 {
301 	float value;
302 	do {
303 		value = rnd.getFloat();
304 	} while (tcu::Float32(value).isDenorm());
305 	return value;
306 }
307 
308 template<>
getNormalFPValue(de::Random & rnd)309 double getNormalFPValue<double> (de::Random& rnd)
310 {
311 	double value;
312 	do {
313 		value = rnd.getDouble();
314 	} while (tcu::Float64(value).isDenorm());
315 	return value;
316 }
317 
318 template<>
getNormalFPValue(de::Random & rnd)319 tcu::Float16 getNormalFPValue<tcu::Float16> (de::Random& rnd)
320 {
321 	tcu::Float16 value;
322 	do {
323 		value = tcu::Float16(rnd.getFloat());
324 	} while (value.isDenorm());
325 	return value;
326 }
327 
328 template <class T>
fillWithRandomFloatingPoint(de::Random & rnd,void * location,VkDeviceSize length)329 void fillWithRandomFloatingPoint (de::Random& rnd, void* location, VkDeviceSize length)
330 {
331 	static const auto typeSize = sizeof(T);
332 
333 	DE_ASSERT(length % typeSize == 0);
334 
335 	const auto	numElements	= length / typeSize;
336 	auto		elemPtr		= reinterpret_cast<unsigned char*>(location);
337 	T			elem;
338 
339 	for (VkDeviceSize i = 0; i < numElements; ++i)
340 	{
341 		elem = getNormalFPValue<T>(rnd);
342 		deMemcpy(elemPtr, &elem, typeSize);
343 		elemPtr += typeSize;
344 	}
345 }
346 
iterate(void)347 tcu::TestStatus ImageSubresourceLayoutInstance::iterate (void)
348 {
349 	// Test every aspect supported by the image format.
350 	const auto tcuFormat	= mapVkFormat(m_params.imageFormat);
351 	const auto aspectFlags	= getImageAspectFlags(tcuFormat);
352 
353 	static const VkImageAspectFlagBits aspectBits[] =
354 	{
355 		VK_IMAGE_ASPECT_COLOR_BIT,
356 		VK_IMAGE_ASPECT_DEPTH_BIT,
357 		VK_IMAGE_ASPECT_STENCIL_BIT,
358 	};
359 
360 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(aspectBits); ++i)
361 	{
362 		const auto bit = aspectBits[i];
363 		if (aspectFlags & bit)
364 		{
365 			const auto aspectResult = iterateAspect(bit);
366 			if (aspectResult.getCode() != QP_TEST_RESULT_PASS)
367 				return aspectResult; // Early return for failures.
368 		}
369 	}
370 
371 	return tcu::TestStatus::pass("Pass");
372 }
373 
iterateAspect(VkImageAspectFlagBits imageAspect)374 tcu::TestStatus ImageSubresourceLayoutInstance::iterateAspect (VkImageAspectFlagBits imageAspect)
375 {
376 	// * Create linear image with several mipmaps
377 	// * Fill its levels with unique appropriate data (avoiding invalid sfloat values, for example).
378 	// * Ask for the subresource layout parameters.
379 	// * Verify they make sense.
380 	// * Check accessing data with the given parameters gives back the original data.
381 
382 	const auto&	vkd					= m_context.getDeviceInterface();
383 	const auto	device				= m_context.getDevice();
384 	auto&		alloc				= m_context.getDefaultAllocator();
385 	const auto	queue				= m_context.getUniversalQueue();
386 	const auto	queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
387 	auto&		log					= m_context.getTestContext().getLog();
388 
389 	log << tcu::TestLog::Message << "Testing aspect " << imageAspect << tcu::TestLog::EndMessage;
390 
391 	// Get an idea of the buffer size and parameters to prepare image data.
392 	const BufferLevels	bufferLevels	(m_params.imageType, m_params.imageFormat, m_params.dimensions, m_params.mipLevels, imageAspect);
393 	const auto			pixelSize		= bufferLevels.pixelSize();
394 	const auto			pixelSizeSz		= static_cast<size_t>(pixelSize);
395 	const auto			numLevels		= bufferLevels.numLevels();
396 
397 	// Create source buffer.
398 	const auto			bufferSize	= bufferLevels.totalSize();
399 	const auto			bufferInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
400 	BufferWithMemory	buffer		(vkd, device, alloc, bufferInfo, MemoryRequirement::HostVisible);
401 	auto&				bufferAlloc	= buffer.getAllocation();
402 	auto*				bufferPtr	= reinterpret_cast<unsigned char*>(bufferAlloc.getHostPtr());
403 
404 	// Fill buffer with random appropriate data.
405 	const deUint32	randomSeed	= 1594055758u + static_cast<deUint32>(m_params.imageFormat) + static_cast<deUint32>(imageAspect);
406 	de::Random		rnd			(randomSeed);
407 	const auto		tcuFormat	= mapVkFormat(m_params.imageFormat);
408 	// For some formats, the copy block is 32 bits wide but the 8 MSB need to be ignored, so we zero them out.
409 	const bool		use24LSB	= ((m_params.imageFormat == VK_FORMAT_X8_D24_UNORM_PACK32 || m_params.imageFormat == VK_FORMAT_D24_UNORM_S8_UINT) && imageAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
410 
411 	if (tcuFormat.type == tcu::TextureFormat::FLOAT || (m_params.imageFormat == VK_FORMAT_D32_SFLOAT_S8_UINT && imageAspect == VK_IMAGE_ASPECT_DEPTH_BIT))
412 		fillWithRandomFloatingPoint<float>(rnd, bufferPtr, bufferSize);
413 	else if (tcuFormat.type == tcu::TextureFormat::FLOAT64)
414 		fillWithRandomFloatingPoint<double>(rnd, bufferPtr, bufferSize);
415 	else if (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT)
416 		fillWithRandomFloatingPoint<tcu::Float16>(rnd, bufferPtr, bufferSize);
417 	else if (use24LSB)
418 		fillWithRandomData24In32(rnd, bufferPtr, bufferSize);
419 	else
420 		fillWithRandomData(rnd, bufferPtr, bufferSize);
421 
422 	flushAlloc(vkd, device, bufferAlloc);
423 
424 	// Reinterpret the depth dimension parameter as the number of layers if needed.
425 	const auto	numLayers	= ((m_params.imageType == VK_IMAGE_TYPE_3D) ? 1u : m_params.dimensions.depth);
426 	VkExtent3D	imageExtent	= m_params.dimensions;
427 	if (m_params.imageType == VK_IMAGE_TYPE_2D)
428 		imageExtent.depth = 1u;
429 
430 	// Create image.
431 	const VkImageCreateInfo imageInfo =
432 	{
433 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			//	VkStructureType			sType;
434 		nullptr,										//	const void*				pNext;
435 		0u,												//	VkImageCreateFlags		flags;
436 		m_params.imageType,								//	VkImageType				imageType;
437 		m_params.imageFormat,							//	VkFormat				format;
438 		imageExtent,									//	VkExtent3D				extent;
439 		numLevels,										//	deUint32				mipLevels;
440 		numLayers,										//	deUint32				arrayLayers;
441 		VK_SAMPLE_COUNT_1_BIT,							//	VkSampleCountFlagBits	samples;
442 		ImageSubresourceLayoutCase::kImageTiling,		//	VkImageTiling			tiling;
443 		ImageSubresourceLayoutCase::kImageUsageFlags,	//	VkImageUsageFlags		usage;
444 		VK_SHARING_MODE_EXCLUSIVE,						//	VkSharingMode			sharingMode;
445 		0u,												//	deUint32				queueFamilyIndexCount;
446 		nullptr,										//	const deUint32*			pQueueFamilyIndices;
447 		VK_IMAGE_LAYOUT_UNDEFINED,						//	VkImageLayout			initialLayout;
448 	};
449 
450 	Move<VkImage>				image = createImage(vkd, device, &imageInfo);
451 	VkMemoryRequirements		req = getImageMemoryRequirements(vkd, device, *image);
452 	if (m_params.imageOffset)
453 		req.size += req.alignment;
454 
455 	Allocator&									allocator				= m_context.getDefaultAllocator();
456 	de::MovePtr<Allocation>		imageAlloc	= allocator.allocate(req, MemoryRequirement::HostVisible);
457 
458 	VK_CHECK(vkd.bindImageMemory(device, *image, imageAlloc->getMemory(), m_params.imageOffset ? req.alignment : 0u));
459 	auto*			imagePtr	= reinterpret_cast<unsigned char*>(imageAlloc->getHostPtr());
460 
461 	// Copy regions.
462 	std::vector<VkBufferImageCopy> copyRegions;
463 	copyRegions.reserve(numLevels);
464 
465 	for (deUint32 levelNdx = 0u; levelNdx < numLevels; ++levelNdx)
466 	{
467 		const auto&	level		= bufferLevels.getLevel(levelNdx);
468 		auto		levelExtent	= level.dimensions;
469 
470 		if (m_params.imageType == VK_IMAGE_TYPE_2D)
471 			levelExtent.depth = 1u;	// For 2D images, .depth indicates the number of layers.
472 
473 		VkBufferImageCopy region;
474 		region.bufferOffset						= level.offset;
475 		region.bufferRowLength					= 0u;	// Tightly packed data.
476 		region.bufferImageHeight				= 0u;	// Ditto.
477 		region.imageSubresource.aspectMask		= imageAspect;
478 		region.imageSubresource.baseArrayLayer	= 0u;
479 		region.imageSubresource.layerCount		= numLayers;
480 		region.imageSubresource.mipLevel		= levelNdx;
481 		region.imageOffset						= { 0, 0, 0 };
482 		region.imageExtent						= levelExtent;
483 
484 		copyRegions.push_back(region);
485 	}
486 
487 	// Image layout transitions.
488 	const auto imageSubresourceRange	= makeImageSubresourceRange(imageAspect, 0u, numLevels, 0u, numLayers);
489 	const auto initialLayoutBarrier		= makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.get(), imageSubresourceRange);
490 	const auto finalLayoutBarrier		= makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, image.get(), imageSubresourceRange);
491 
492 	// Command buffer.
493 	const auto cmdPool		= makeCommandPool(vkd, device, queueFamilyIndex);
494 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
495 	const auto cmdBuffer	= cmdBufferPtr.get();
496 
497 	// Transition layout, copy, transition layout.
498 	beginCommandBuffer(vkd, cmdBuffer);
499 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &initialLayoutBarrier);
500 	vkd.cmdCopyBufferToImage(cmdBuffer, buffer.get(), image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(copyRegions.size()), copyRegions.data());
501 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &finalLayoutBarrier);
502 	endCommandBuffer(vkd, cmdBuffer);
503 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
504 
505 #ifdef CTS_USES_VULKANSC
506 	if (!m_context.getTestContext().getCommandLine().isSubProcess())
507 		return tcu::TestStatus::pass("Pass");
508 #endif
509 
510 	// Sync image memory for host access.
511 	invalidateAlloc(vkd, device, *imageAlloc);
512 
513 	VkSubresourceLayout levelSubresourceLayout;
514 	VkSubresourceLayout subresourceLayout;
515 	for (deUint32 levelNdx = 0u; levelNdx < numLevels; ++levelNdx)
516 	{
517 		// Get base level subresource.
518 		const auto levelSubresource = makeImageSubresource(imageAspect, levelNdx, 0u);
519 		vkd.getImageSubresourceLayout(device, image.get(), &levelSubresource, &levelSubresourceLayout);
520 
521 		const auto& level = bufferLevels.getLevel(levelNdx);
522 		for (deUint32 layerNdx = 0; layerNdx < numLayers; ++layerNdx)
523 		{
524 			const auto imageSubresource = makeImageSubresource(imageAspect, levelNdx, layerNdx);
525 			vkd.getImageSubresourceLayout(device, image.get(), &imageSubresource, &subresourceLayout);
526 
527 			// Verify returned values.
528 			const auto subresourceWidth		= level.dimensions.width;
529 			const auto subresourceHeight	= level.dimensions.height;
530 			const auto subresourceDepth		= ((m_params.imageType == VK_IMAGE_TYPE_2D) ? 1u : level.dimensions.depth);
531 			const auto numPixels			= subresourceWidth * subresourceHeight * subresourceDepth;
532 
533 			if (numLayers > 1u && levelSubresourceLayout.arrayPitch != subresourceLayout.arrayPitch)
534 			{
535 				// Inconsistent arrayPitch.
536 				std::ostringstream msg;
537 				msg << "Image level " << levelNdx
538 					<< " layer " << layerNdx
539 					<< " reports array pitch of " << subresourceLayout.arrayPitch << " bytes in size"
540 					<< " with base layer reporting array pitch of " << levelSubresourceLayout.arrayPitch << " bytes in size";
541 				return tcu::TestStatus::fail(msg.str());
542 			}
543 
544 			if ((subresourceLayout.offset - levelSubresourceLayout.offset) != (layerNdx * subresourceLayout.arrayPitch))
545 			{
546 				// Inconsistent offset.
547 				std::ostringstream msg;
548 				msg << "Image level " << levelNdx
549 					<< " layer " << layerNdx
550 					<< " has offset inconsistent with array pitch: base offset " << levelSubresourceLayout.offset
551 					<< ", layer offset " << subresourceLayout.offset
552 					<< ", array pitch " << subresourceLayout.arrayPitch;
553 				return tcu::TestStatus::fail(msg.str());
554 			}
555 
556 			if (subresourceLayout.size < pixelSize * numPixels)
557 			{
558 				// Subresource size too small.
559 				std::ostringstream msg;
560 				msg << "Image level " << levelNdx
561 					<< " layer " << layerNdx
562 					<< " reports " << subresourceLayout.size << " bytes in size"
563 					<< " with pixel size " << pixelSize
564 					<< " and dimensions " << subresourceWidth << "x" << subresourceHeight << "x" << subresourceDepth;
565 				return tcu::TestStatus::fail(msg.str());
566 			}
567 
568 			// Note: if subresourceHeight is <= 1u, rowPitch can be zero.
569 			if (subresourceHeight > 1u && subresourceLayout.rowPitch < pixelSize * subresourceWidth)
570 			{
571 				// Row pitch too small.
572 				std::ostringstream msg;
573 				msg << "Image level " << levelNdx
574 					<< " layer " << layerNdx
575 					<< " reports row pitch of " << subresourceLayout.rowPitch
576 					<< " bytes with " << pixelSize
577 					<< " bytes in pixel size and width " << subresourceWidth;
578 				return tcu::TestStatus::fail(msg.str());
579 			}
580 
581 			if (numLayers > 1u && subresourceLayout.arrayPitch < pixelSize * numPixels)
582 			{
583 				// Array pitch too small.
584 				std::ostringstream msg;
585 				msg << "Image level " << levelNdx
586 					<< " layer " << layerNdx
587 					<< " reports array pitch of " << subresourceLayout.arrayPitch
588 					<< " bytes with " << pixelSize
589 					<< " bytes in pixel size and layer dimensions " << subresourceWidth << "x" << subresourceHeight;
590 				return tcu::TestStatus::fail(msg.str());
591 			}
592 
593 			// If subresourceDepth is <= 1u, depthPitch can be zero.
594 			if (subresourceDepth > 1u && m_params.imageType == VK_IMAGE_TYPE_3D && subresourceLayout.depthPitch < pixelSize * subresourceWidth * subresourceHeight)
595 			{
596 				// Depth pitch too small.
597 				std::ostringstream msg;
598 				msg << "Image level " << levelNdx
599 					<< " layer " << layerNdx
600 					<< " reports depth pitch of " << subresourceLayout.depthPitch << " bytes"
601 					<< " with pixel size " << pixelSize
602 					<< " and dimensions " << subresourceWidth << "x" << subresourceHeight << "x" << subresourceDepth;
603 				return tcu::TestStatus::fail(msg.str());
604 			}
605 
606 			// Verify image data.
607 			const auto	layerBufferOffset	= level.offset + layerNdx * numPixels * pixelSize;
608 			const auto	layerImageOffset	= subresourceLayout.offset;
609 			const auto	layerBufferPtr		= bufferPtr + layerBufferOffset;
610 			const auto	layerImagePtr		= imagePtr + layerImageOffset + (m_params.imageOffset ? req.alignment : 0u);
611 			bool		pixelMatch;
612 
613 			// We could do this row by row to be faster, but in the use24LSB case we need to manipulate pixels independently.
614 			for (deUint32 x = 0u; x < subresourceWidth; ++x)
615 			for (deUint32 y = 0u; y < subresourceHeight; ++y)
616 			for (deUint32 z = 0u; z < subresourceDepth; ++z)
617 			{
618 				const auto bufferPixelOffset	= (z * subresourceWidth * subresourceHeight + y * subresourceWidth + x) * pixelSize;
619 				const auto imagePixelOffset		= z * subresourceLayout.depthPitch + y * subresourceLayout.rowPitch + x * pixelSize;
620 				const auto bufferPixelPtr		= layerBufferPtr + bufferPixelOffset;
621 				const auto imagePixelPtr		= layerImagePtr + imagePixelOffset;
622 
623 				if (use24LSB)
624 				{
625 					DE_ASSERT(pixelSize == sizeof(deUint32));
626 					deUint32 pixelValue;
627 					deMemcpy(&pixelValue, imagePixelPtr, pixelSizeSz);
628 					pixelValue &= 0xFFFFFFu; // Discard the 8 MSB.
629 					pixelMatch = (deMemCmp(bufferPixelPtr, &pixelValue, pixelSizeSz) == 0);
630 				}
631 				else
632 					pixelMatch = (deMemCmp(bufferPixelPtr, imagePixelPtr, pixelSizeSz) == 0);
633 
634 				if (!pixelMatch)
635 				{
636 					std::ostringstream msg;
637 					msg << "Found difference from image pixel to buffer pixel at coordinates"
638 						<< " level=" << levelNdx
639 						<< " layer=" << layerNdx
640 						<< " x=" << x
641 						<< " y=" << y
642 						<< " z=" << z
643 						;
644 					return tcu::TestStatus::fail(msg.str());
645 				}
646 			}
647 		}
648 	}
649 
650 	return tcu::TestStatus::pass("Pass");
651 }
652 
653 class ImageSubresourceLayoutInvarianceInstance: public vkt::TestInstance
654 {
655 public:
656 								ImageSubresourceLayoutInvarianceInstance	(Context& context, const TestParams& params);
657 	virtual						~ImageSubresourceLayoutInvarianceInstance	(void) = default;
658 
659 	virtual tcu::TestStatus		iterate										(void);
660 
661 private:
662 	TestParams m_params;
663 };
664 
ImageSubresourceLayoutInvarianceInstance(Context & context,const TestParams & params)665 ImageSubresourceLayoutInvarianceInstance::ImageSubresourceLayoutInvarianceInstance(Context& context, const TestParams& params)
666 	: vkt::TestInstance	(context)
667 	, m_params			(params)
668 {
669 }
670 
iterate(void)671 tcu::TestStatus ImageSubresourceLayoutInvarianceInstance::iterate(void)
672 {
673 #ifndef CTS_USES_VULKANSC
674 	const VkDevice			device	= m_context.getDevice();
675 	const DeviceInterface&	vk		= m_context.getDeviceInterface();
676 
677 	// Reinterpret the depth dimension parameter as the number of layers if needed
678 	const auto	numLayers = ((m_params.imageType == VK_IMAGE_TYPE_3D) ? 1u : m_params.dimensions.depth);
679 	VkExtent3D	imageExtent = m_params.dimensions;
680 	if (m_params.imageType == VK_IMAGE_TYPE_2D)
681 		imageExtent.depth = 1u;
682 
683 	// Create image
684 	const VkImageCreateInfo imageCreateInfo
685 	{
686 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			//	VkStructureType			sType;
687 		nullptr,										//	const void*				pNext;
688 		0u,												//	VkImageCreateFlags		flags;
689 		m_params.imageType,								//	VkImageType				imageType;
690 		m_params.imageFormat,							//	VkFormat				format;
691 		imageExtent,									//	VkExtent3D				extent;
692 		m_params.mipLevels,								//	deUint32				mipLevels;
693 		numLayers,										//	deUint32				arrayLayers;
694 		VK_SAMPLE_COUNT_1_BIT,							//	VkSampleCountFlagBits	samples;
695 		ImageSubresourceLayoutCase::kImageTiling,		//	VkImageTiling			tiling;
696 		ImageSubresourceLayoutCase::kImageUsageFlags,	//	VkImageUsageFlags		usage;
697 		VK_SHARING_MODE_EXCLUSIVE,						//	VkSharingMode			sharingMode;
698 		0u,												//	deUint32				queueFamilyIndexCount;
699 		nullptr,										//	const deUint32*			pQueueFamilyIndices;
700 		VK_IMAGE_LAYOUT_UNDEFINED,						//	VkImageLayout			initialLayout;
701 	};
702 
703 	Move<VkImage> image				= createImage(vk, device, &imageCreateInfo);
704 	const auto tcuFormat			= mapVkFormat(m_params.imageFormat);
705 	const auto supportedAspectFlags	= getImageAspectFlags(tcuFormat);
706 
707 	const std::vector<VkImageAspectFlagBits> testedAspectBits
708 	{
709 		VK_IMAGE_ASPECT_COLOR_BIT,
710 		VK_IMAGE_ASPECT_DEPTH_BIT,
711 		VK_IMAGE_ASPECT_STENCIL_BIT,
712 	};
713 	// test every aspect supported by the image format
714 	for (const auto aspectBit : testedAspectBits)
715 	{
716 		if ((supportedAspectFlags & aspectBit) == 0)
717 			continue;
718 
719 		// get base level subresource using image handle
720 		VkSubresourceLayout	subresourceLayout1	= {};
721 		VkImageSubresource	imageSubresource1	= makeImageSubresource(aspectBit, 0u, 0u);
722 		vk.getImageSubresourceLayout(device, *image, &imageSubresource1, &subresourceLayout1);
723 
724 		// get level subresource without using image handle
725 		VkImageSubresource2KHR				imageSubresource2		= initVulkanStructure();
726 		imageSubresource2.imageSubresource	= imageSubresource1;
727 		VkSubresourceLayout2KHR				subresourceLayout2      = initVulkanStructure();
728 		VkDeviceImageSubresourceInfoKHR		imageSubresourceInfo	= initVulkanStructure();
729 		imageSubresourceInfo.pCreateInfo	= &imageCreateInfo;
730 		imageSubresourceInfo.pSubresource	= &imageSubresource2;
731 		vk.getDeviceImageSubresourceLayoutKHR(device, &imageSubresourceInfo, &subresourceLayout2);
732 
733 		const auto size = sizeof(VkSubresourceLayout);
734 		if (deMemCmp(&subresourceLayout1, &(subresourceLayout2.subresourceLayout), size))
735 			return tcu::TestStatus::fail("Fail (vkGetDeviceImageSubresourceLayoutKHR)");
736 
737 		if (m_context.isDeviceFunctionalitySupported("VK_EXT_image_compression_control"))
738 		{
739 			VkSubresourceLayout2EXT subresourceLayout3 = initVulkanStructure();
740 			vk.getImageSubresourceLayout2KHR(device, *image, &imageSubresource2, &subresourceLayout3);
741 
742 			if (deMemCmp(&subresourceLayout1, &(subresourceLayout3.subresourceLayout), size))
743 				return tcu::TestStatus::fail("Fail (vkGetImageSubresourceLayout2KHR)");
744 		}
745 	}
746 #else
747 	DE_UNREF(m_params);
748 #endif // CTS_USES_VULKANSC
749 	return tcu::TestStatus::pass("Pass");
750 }
751 
752 class ImageSubresourceLayoutInvarianceCase: public ImageSubresourceLayoutCase
753 {
754 public:
755 							ImageSubresourceLayoutInvarianceCase	(tcu::TestContext& testCtx, const std::string& name, const TestParams& params);
756 	virtual					~ImageSubresourceLayoutInvarianceCase	(void) = default;
757 
758 	virtual TestInstance*	createInstance							(Context& context) const;
759 	virtual void			checkSupport							(Context& context) const;
760 };
761 
ImageSubresourceLayoutInvarianceCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)762 ImageSubresourceLayoutInvarianceCase::ImageSubresourceLayoutInvarianceCase(tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
763 	: ImageSubresourceLayoutCase(testCtx, name, params)
764 {
765 }
766 
createInstance(Context & context) const767 TestInstance* ImageSubresourceLayoutInvarianceCase::createInstance(Context& context) const
768 {
769 	return new ImageSubresourceLayoutInvarianceInstance(context, m_params);
770 }
771 
checkSupport(Context & context) const772 void ImageSubresourceLayoutInvarianceCase::checkSupport(Context& context) const
773 {
774 	ImageSubresourceLayoutCase::checkSupport(context);
775 	context.requireDeviceFunctionality("VK_KHR_maintenance5");
776 }
777 
778 } // anonymous namespace
779 
createImageSubresourceLayoutTests(tcu::TestContext & testCtx)780 tcu::TestCaseGroup* createImageSubresourceLayoutTests (tcu::TestContext& testCtx)
781 {
782 	de::MovePtr<tcu::TestCaseGroup> layoutTestGroup (new tcu::TestCaseGroup(testCtx, "subresource_layout"));
783 
784 	struct
785 	{
786 		VkImageType	type;
787 		bool		array;
788 		const char*	name;
789 	} imageClass[] =
790 	{
791 		// 2D images
792 		{ VK_IMAGE_TYPE_2D,	false,	"2d"},
793 		// 2D images with multiple layers
794 		{ VK_IMAGE_TYPE_2D,	true,	"2d_array"},
795 		// 3D images
796 		{ VK_IMAGE_TYPE_3D,	false,	"3d"},
797 	};
798 
799 	struct
800 	{
801 		deUint32	maxLevels;
802 		const char*	name;
803 	} mipLevels[] =
804 	{
805 		// Single mip level
806 		{ 1u,									"1_level"},
807 		// Two mip levels
808 		{ 2u,									"2_levels"},
809 		// Four mip levels
810 		{ 4u,									"4_levels"},
811 		// All possible levels
812 		{ std::numeric_limits<deUint32>::max(), "all_levels"},
813 	};
814 
815 	VkFormat testFormats[] =
816 	{
817 		VK_FORMAT_R4G4_UNORM_PACK8,
818 		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
819 		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
820 		VK_FORMAT_R5G6B5_UNORM_PACK16,
821 		VK_FORMAT_B5G6R5_UNORM_PACK16,
822 		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
823 		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
824 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
825 #ifndef CTS_USES_VULKANSC
826 		VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR,
827 #endif // CTS_USES_VULKANSC
828 		VK_FORMAT_R8_UNORM,
829 		VK_FORMAT_R8_SNORM,
830 		VK_FORMAT_R8_USCALED,
831 		VK_FORMAT_R8_SSCALED,
832 		VK_FORMAT_R8_UINT,
833 		VK_FORMAT_R8_SINT,
834 		VK_FORMAT_R8_SRGB,
835 #ifndef CTS_USES_VULKANSC
836 		VK_FORMAT_A8_UNORM_KHR,
837 #endif // CTS_USES_VULKANSC
838 		VK_FORMAT_R8G8_UNORM,
839 		VK_FORMAT_R8G8_SNORM,
840 		VK_FORMAT_R8G8_USCALED,
841 		VK_FORMAT_R8G8_SSCALED,
842 		VK_FORMAT_R8G8_UINT,
843 		VK_FORMAT_R8G8_SINT,
844 		VK_FORMAT_R8G8_SRGB,
845 		VK_FORMAT_R8G8B8_UNORM,
846 		VK_FORMAT_R8G8B8_SNORM,
847 		VK_FORMAT_R8G8B8_USCALED,
848 		VK_FORMAT_R8G8B8_SSCALED,
849 		VK_FORMAT_R8G8B8_UINT,
850 		VK_FORMAT_R8G8B8_SINT,
851 		VK_FORMAT_R8G8B8_SRGB,
852 		VK_FORMAT_B8G8R8_UNORM,
853 		VK_FORMAT_B8G8R8_SNORM,
854 		VK_FORMAT_B8G8R8_USCALED,
855 		VK_FORMAT_B8G8R8_SSCALED,
856 		VK_FORMAT_B8G8R8_UINT,
857 		VK_FORMAT_B8G8R8_SINT,
858 		VK_FORMAT_B8G8R8_SRGB,
859 		VK_FORMAT_R8G8B8A8_UNORM,
860 		VK_FORMAT_R8G8B8A8_SNORM,
861 		VK_FORMAT_R8G8B8A8_USCALED,
862 		VK_FORMAT_R8G8B8A8_SSCALED,
863 		VK_FORMAT_R8G8B8A8_UINT,
864 		VK_FORMAT_R8G8B8A8_SINT,
865 		VK_FORMAT_R8G8B8A8_SRGB,
866 		VK_FORMAT_B8G8R8A8_UNORM,
867 		VK_FORMAT_B8G8R8A8_SNORM,
868 		VK_FORMAT_B8G8R8A8_USCALED,
869 		VK_FORMAT_B8G8R8A8_SSCALED,
870 		VK_FORMAT_B8G8R8A8_UINT,
871 		VK_FORMAT_B8G8R8A8_SINT,
872 		VK_FORMAT_B8G8R8A8_SRGB,
873 		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
874 		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
875 		VK_FORMAT_A8B8G8R8_USCALED_PACK32,
876 		VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
877 		VK_FORMAT_A8B8G8R8_UINT_PACK32,
878 		VK_FORMAT_A8B8G8R8_SINT_PACK32,
879 		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
880 		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
881 		VK_FORMAT_A2R10G10B10_SNORM_PACK32,
882 		VK_FORMAT_A2R10G10B10_USCALED_PACK32,
883 		VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
884 		VK_FORMAT_A2R10G10B10_UINT_PACK32,
885 		VK_FORMAT_A2R10G10B10_SINT_PACK32,
886 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
887 		VK_FORMAT_A2B10G10R10_SNORM_PACK32,
888 		VK_FORMAT_A2B10G10R10_USCALED_PACK32,
889 		VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
890 		VK_FORMAT_A2B10G10R10_UINT_PACK32,
891 		VK_FORMAT_A2B10G10R10_SINT_PACK32,
892 		VK_FORMAT_R16_UNORM,
893 		VK_FORMAT_R16_SNORM,
894 		VK_FORMAT_R16_USCALED,
895 		VK_FORMAT_R16_SSCALED,
896 		VK_FORMAT_R16_UINT,
897 		VK_FORMAT_R16_SINT,
898 		VK_FORMAT_R16_SFLOAT,
899 		VK_FORMAT_R16G16_UNORM,
900 		VK_FORMAT_R16G16_SNORM,
901 		VK_FORMAT_R16G16_USCALED,
902 		VK_FORMAT_R16G16_SSCALED,
903 		VK_FORMAT_R16G16_UINT,
904 		VK_FORMAT_R16G16_SINT,
905 		VK_FORMAT_R16G16_SFLOAT,
906 		VK_FORMAT_R16G16B16_UNORM,
907 		VK_FORMAT_R16G16B16_SNORM,
908 		VK_FORMAT_R16G16B16_USCALED,
909 		VK_FORMAT_R16G16B16_SSCALED,
910 		VK_FORMAT_R16G16B16_UINT,
911 		VK_FORMAT_R16G16B16_SINT,
912 		VK_FORMAT_R16G16B16_SFLOAT,
913 		VK_FORMAT_R16G16B16A16_UNORM,
914 		VK_FORMAT_R16G16B16A16_SNORM,
915 		VK_FORMAT_R16G16B16A16_USCALED,
916 		VK_FORMAT_R16G16B16A16_SSCALED,
917 		VK_FORMAT_R16G16B16A16_UINT,
918 		VK_FORMAT_R16G16B16A16_SINT,
919 		VK_FORMAT_R16G16B16A16_SFLOAT,
920 		VK_FORMAT_R32_UINT,
921 		VK_FORMAT_R32_SINT,
922 		VK_FORMAT_R32_SFLOAT,
923 		VK_FORMAT_R32G32_UINT,
924 		VK_FORMAT_R32G32_SINT,
925 		VK_FORMAT_R32G32_SFLOAT,
926 		VK_FORMAT_R32G32B32_UINT,
927 		VK_FORMAT_R32G32B32_SINT,
928 		VK_FORMAT_R32G32B32_SFLOAT,
929 		VK_FORMAT_R32G32B32A32_UINT,
930 		VK_FORMAT_R32G32B32A32_SINT,
931 		VK_FORMAT_R32G32B32A32_SFLOAT,
932 		VK_FORMAT_R64_UINT,
933 		VK_FORMAT_R64_SINT,
934 		VK_FORMAT_R64_SFLOAT,
935 		VK_FORMAT_R64G64_UINT,
936 		VK_FORMAT_R64G64_SINT,
937 		VK_FORMAT_R64G64_SFLOAT,
938 		VK_FORMAT_R64G64B64_UINT,
939 		VK_FORMAT_R64G64B64_SINT,
940 		VK_FORMAT_R64G64B64_SFLOAT,
941 		VK_FORMAT_R64G64B64A64_UINT,
942 		VK_FORMAT_R64G64B64A64_SINT,
943 		VK_FORMAT_R64G64B64A64_SFLOAT,
944 		// Leaving out depth/stencil formats due to this part of the spec:
945 		//
946 		// "Depth/stencil formats are considered opaque and need not be stored in the exact number of bits per texel or component
947 		// ordering indicated by the format enum. However, implementations must not substitute a different depth or stencil
948 		// precision than that described in the format (e.g. D16 must not be implemented as D24 or D32)."
949 		//
950 		// Which means the size of the texel is not known for depth/stencil formats and we cannot iterate over them to check their
951 		// values.
952 #if 0
953 		VK_FORMAT_D16_UNORM,
954 		VK_FORMAT_X8_D24_UNORM_PACK32,
955 		VK_FORMAT_D32_SFLOAT,
956 		VK_FORMAT_S8_UINT,
957 		VK_FORMAT_D16_UNORM_S8_UINT,
958 		VK_FORMAT_D24_UNORM_S8_UINT,
959 		VK_FORMAT_D32_SFLOAT_S8_UINT,
960 #endif
961 	};
962 
963 	static const auto prefixLen = std::string("VK_FORMAT_").size();
964 	for (int classIdx = 0; classIdx < DE_LENGTH_OF_ARRAY(imageClass); ++classIdx)
965 	{
966 		const auto& imgClass = imageClass[classIdx];
967 		de::MovePtr<tcu::TestCaseGroup> classGroup (new tcu::TestCaseGroup(testCtx, imgClass.name));
968 
969 		for (int mipIdx = 0; mipIdx < DE_LENGTH_OF_ARRAY(mipLevels); ++mipIdx)
970 		{
971 			const auto &mipLevel = mipLevels[mipIdx];
972 			de::MovePtr<tcu::TestCaseGroup> mipGroup (new tcu::TestCaseGroup(testCtx, mipLevel.name));
973 
974 			for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(testFormats); ++formatIdx)
975 			{
976 				const auto			format		= testFormats[formatIdx];
977 				const auto			fmtName		= std::string(getFormatName(format));
978 				const auto			name		= de::toLower(fmtName.substr(prefixLen)); // Remove VK_FORMAT_ prefix.
979 
980 				TestParams params;
981 				params.imageFormat	= format;
982 				params.imageType	= imgClass.type;
983 				params.mipLevels	= mipLevel.maxLevels;
984 				params.dimensions	= getDefaultDimensions(imgClass.type, imgClass.array);
985 				params.imageOffset	= false;
986 
987 				mipGroup->addChild(new ImageSubresourceLayoutCase(testCtx, name, params));
988 
989 				params.imageOffset	= true;
990 
991 				mipGroup->addChild(new ImageSubresourceLayoutCase(testCtx, name+"_offset", params));
992 			}
993 
994 			classGroup->addChild(mipGroup.release());
995 		}
996 
997 		layoutTestGroup->addChild(classGroup.release());
998 	}
999 
1000 #ifndef CTS_USES_VULKANSC
1001 	// Tests for vkGetDeviceImageSubresourceLayoutKHR
1002 	de::MovePtr<tcu::TestCaseGroup> invarianceGroup(new tcu::TestCaseGroup(testCtx, "invariance"));
1003 
1004 	TestParams params;
1005 	params.imageOffset = false;
1006 	params.mipLevels = 1;
1007 
1008 	for (int formatIdx = 0 ; formatIdx < DE_LENGTH_OF_ARRAY(testFormats); ++formatIdx)
1009 	for (int classIdx = 0 ; classIdx < DE_LENGTH_OF_ARRAY(imageClass); ++classIdx)
1010 	{
1011 		const auto& imgClass = imageClass[classIdx];
1012 
1013 		params.imageFormat	= testFormats[formatIdx];
1014 		params.imageType	= imgClass.type;
1015 		params.dimensions	= getDefaultDimensions(imgClass.type, imgClass.array);
1016 		params.dimensions.width += formatIdx;
1017 
1018 		std::string name = getFormatName(params.imageFormat);
1019 		name = de::toLower(name.substr(prefixLen)) + "_" + imgClass.name;
1020 
1021 		invarianceGroup->addChild(new ImageSubresourceLayoutInvarianceCase(testCtx, name, params));
1022 	}
1023 	layoutTestGroup->addChild(invarianceGroup.release());
1024 #endif // CTS_USES_VULKANSC
1025 
1026 	return layoutTestGroup.release();
1027 }
1028 
1029 } // namespace image
1030 } // namespace vkt
1031