• 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 "tcuTextureUtil.hpp"
40 #include "tcuFloat.hpp"
41 
42 #include "deRandom.hpp"
43 
44 #include <vector>
45 #include <sstream>
46 #include <limits>
47 #include <string>
48 
49 using namespace vk;
50 
51 namespace vkt
52 {
53 namespace image
54 {
55 namespace
56 {
57 
58 // Helper class to calculate buffer sizes and offsets for image mipmap levels.
59 class BufferLevels
60 {
61 public:
62 	struct Level
63 	{
64 		VkDeviceSize	offset;		// In bytes.
65 		VkDeviceSize	size;		// In bytes.
66 		VkExtent3D		dimensions;	// .depth will be the number of layers for 2D images and the depth for 3D images.
67 	};
68 
69 					BufferLevels	(VkImageType type, VkFormat format, VkExtent3D levelZero, deUint32 maxLevels, VkImageAspectFlags aspects = 0u);
70 	VkDeviceSize	totalSize		() const;
71 	VkDeviceSize	pixelSize		() const;
72 	deUint32		numLevels		() const;
73 	const Level&	getLevel		(deUint32 level) const;
74 
75 private:
76 	VkDeviceSize		m_pixelSize; // In bytes.
77 	std::vector<Level>	m_levels;
78 };
79 
BufferLevels(VkImageType type,VkFormat format,VkExtent3D levelZero,deUint32 maxLevels,VkImageAspectFlags aspects)80 BufferLevels::BufferLevels (VkImageType type, VkFormat format, VkExtent3D levelZero, deUint32 maxLevels, VkImageAspectFlags aspects)
81 {
82 	DE_ASSERT(type == VK_IMAGE_TYPE_2D || type == VK_IMAGE_TYPE_3D);
83 	DE_ASSERT(maxLevels >= 1u);
84 
85 	const auto		tcuFormat		= vk::mapVkFormat(format);
86 	const auto		maxLevelsSz		= static_cast<size_t>(maxLevels);
87 
88 	VkDeviceSize	currentOffset	= 0ull;
89 	VkExtent3D		nextExtent		= levelZero;
90 	deUint32		levelCount		= 0;
91 
92 	if (!aspects || (aspects & VK_IMAGE_ASPECT_COLOR_BIT))
93 	{
94 		m_pixelSize = static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat));
95 	}
96 	else if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
97 	{
98 		const auto copyFormat = getDepthCopyFormat(format);
99 		m_pixelSize = static_cast<VkDeviceSize>(tcu::getPixelSize(copyFormat));
100 	}
101 	else if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT)
102 	{
103 		const auto copyFormat = getStencilCopyFormat(format);
104 		m_pixelSize = static_cast<VkDeviceSize>(tcu::getPixelSize(copyFormat));
105 	}
106 	else
107 		DE_ASSERT(false);
108 
109 	while (m_levels.size() < maxLevelsSz)
110 	{
111 		Level level;
112 
113 		level.offset		= currentOffset;
114 		level.size			= m_pixelSize * nextExtent.width * nextExtent.height * nextExtent.depth;
115 		level.dimensions	= nextExtent;
116 
117 		m_levels.push_back(level);
118 
119 		// This was the last available level.
120 		if (nextExtent.width == 1u && nextExtent.height == 1u && (type == VK_IMAGE_TYPE_2D || nextExtent.depth == 1u))
121 			break;
122 
123 		nextExtent.width = std::max(1u, (nextExtent.width / 2u));
124 		nextExtent.height = std::max(1u, (nextExtent.height / 2u));
125 
126 		// 2D arrays all have the same array size.
127 		if (type == VK_IMAGE_TYPE_3D)
128 			nextExtent.depth = std::max(1u, (nextExtent.depth / 2u));
129 
130 		currentOffset += level.size;
131 		++levelCount;
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 class ImageSubresourceLayoutCase : public vkt::TestCase
175 {
176 public:
177 	struct TestParams
178 	{
179 		VkImageType	imageType;
180 		VkFormat	imageFormat;
181 		VkExtent3D	dimensions;		// .depth will be the number of layers for 2D images and the depth for 3D images.
182 		deUint32	mipLevels;
183 	};
184 
185 							ImageSubresourceLayoutCase		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~ImageSubresourceLayoutCase(void)186 	virtual					~ImageSubresourceLayoutCase		(void) {}
187 
initPrograms(vk::SourceCollections &) const188 	virtual void			initPrograms					(vk::SourceCollections&) const {}
189 	virtual TestInstance*	createInstance					(Context& context) const;
190 	virtual void			checkSupport					(Context& context) const;
191 
192 	static constexpr VkFormatFeatureFlags	kRequiredFeatures	= (VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
193 	static constexpr VkImageUsageFlags		kImageUsageFlags	= (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
194 	static constexpr VkImageTiling			kImageTiling		= VK_IMAGE_TILING_LINEAR;
195 private:
196 	TestParams m_params;
197 };
198 
199 class ImageSubresourceLayoutInstance : public vkt::TestInstance
200 {
201 public:
202 								ImageSubresourceLayoutInstance	(Context& context, const ImageSubresourceLayoutCase::TestParams& params);
~ImageSubresourceLayoutInstance(void)203 	virtual						~ImageSubresourceLayoutInstance	(void) {}
204 
205 	virtual tcu::TestStatus		iterate							(void);
206 	tcu::TestStatus				iterateAspect					(VkImageAspectFlagBits aspect);
207 private:
208 	ImageSubresourceLayoutCase::TestParams m_params;
209 };
210 
ImageSubresourceLayoutCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)211 ImageSubresourceLayoutCase::ImageSubresourceLayoutCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
212 	: vkt::TestCase	(testCtx, name, description)
213 	, m_params		(params)
214 {
215 }
216 
createInstance(Context & context) const217 TestInstance* ImageSubresourceLayoutCase::createInstance (Context& context) const
218 {
219 	return new ImageSubresourceLayoutInstance (context, m_params);
220 }
221 
checkSupport(Context & context) const222 void ImageSubresourceLayoutCase::checkSupport (Context& context) const
223 {
224 	const auto&	vki				= context.getInstanceInterface();
225 	const auto	physicalDevice	= context.getPhysicalDevice();
226 
227 	const auto formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, m_params.imageFormat);
228 	if ((formatProperties.linearTilingFeatures & kRequiredFeatures) != kRequiredFeatures)
229 		TCU_THROW(NotSupportedError, "Required format features not supported");
230 
231 	VkImageFormatProperties imgFormatProperties;
232 	const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, m_params.imageFormat, m_params.imageType, kImageTiling, kImageUsageFlags, 0u, &imgFormatProperties);
233 	if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
234 		TCU_THROW(NotSupportedError, "Linear tiling not supported for format");
235 	VK_CHECK(result);
236 
237 	{
238 		BufferLevels levels (m_params.imageType, m_params.imageFormat, m_params.dimensions, m_params.mipLevels);
239 		if (imgFormatProperties.maxMipLevels < levels.numLevels())
240 			TCU_THROW(NotSupportedError, "Required number of mip levels not supported for format");
241 	}
242 
243 	if (m_params.imageType == VK_IMAGE_TYPE_2D && imgFormatProperties.maxArrayLayers < m_params.dimensions.depth)
244 		TCU_THROW(NotSupportedError, "Required number of layers not supported for format");
245 }
246 
ImageSubresourceLayoutInstance(Context & context,const ImageSubresourceLayoutCase::TestParams & params)247 ImageSubresourceLayoutInstance::ImageSubresourceLayoutInstance (Context& context, const ImageSubresourceLayoutCase::TestParams& params)
248 	: vkt::TestInstance	(context)
249 	, m_params			(params)
250 {
251 }
252 
253 // Fills length bytes starting at location with pseudorandom data.
fillWithRandomData(de::Random & rnd,void * location,VkDeviceSize length)254 void fillWithRandomData (de::Random& rnd, void* location, VkDeviceSize length)
255 {
256 	auto		bytePtr	= reinterpret_cast<unsigned char*>(location);
257 	const auto	endPtr	= bytePtr + length;
258 
259 	while (bytePtr != endPtr)
260 	{
261 		const auto remaining = (endPtr - bytePtr);
262 
263 		if (remaining >= 8)			{ const auto data = rnd.getUint64();	deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
264 		else if (remaining >= 4)	{ const auto data = rnd.getUint32();	deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
265 		else if (remaining >= 2)	{ const auto data = rnd.getUint16();	deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
266 		else						{ const auto data = rnd.getUint8();		deMemcpy(bytePtr, &data, sizeof(data)); bytePtr += sizeof(data); }
267 	}
268 }
269 
270 // Fills data in blocks of 32 bits, discarding the higher 8 bits of each block.
fillWithRandomData24In32(de::Random & rnd,void * location,VkDeviceSize length)271 void fillWithRandomData24In32 (de::Random& rnd, void* location, VkDeviceSize length)
272 {
273 	static const auto blockSize = sizeof(deUint32);
274 	DE_ASSERT(length % blockSize == 0);
275 
276 	auto		dataPtr		= reinterpret_cast<unsigned char*>(location);
277 	const auto	numBlocks	= length / blockSize;
278 
279 	for (VkDeviceSize i = 0; i < numBlocks; ++i)
280 	{
281 		auto data = rnd.getUint32();
282 		data &= 0xFFFFFFu; // Remove the higher 8 bits.
283 		deMemcpy(dataPtr, &data, blockSize);
284 		dataPtr += blockSize;
285 	}
286 }
287 
288 // Helpers to make fillWithRandomFloatingPoint a template. Returns normal numbers in the range [0, 1).
289 template <class T>
290 T getNormalFPValue (de::Random& rnd);
291 
292 template<>
getNormalFPValue(de::Random & rnd)293 float getNormalFPValue<float> (de::Random& rnd)
294 {
295 	float value;
296 	do {
297 		value = rnd.getFloat();
298 	} while (tcu::Float32(value).isDenorm());
299 	return value;
300 }
301 
302 template<>
getNormalFPValue(de::Random & rnd)303 double getNormalFPValue<double> (de::Random& rnd)
304 {
305 	double value;
306 	do {
307 		value = rnd.getDouble();
308 	} while (tcu::Float64(value).isDenorm());
309 	return value;
310 }
311 
312 template<>
getNormalFPValue(de::Random & rnd)313 tcu::Float16 getNormalFPValue<tcu::Float16> (de::Random& rnd)
314 {
315 	tcu::Float16 value;
316 	do {
317 		value = tcu::Float16(rnd.getFloat());
318 	} while (value.isDenorm());
319 	return value;
320 }
321 
322 template <class T>
fillWithRandomFloatingPoint(de::Random & rnd,void * location,VkDeviceSize length)323 void fillWithRandomFloatingPoint (de::Random& rnd, void* location, VkDeviceSize length)
324 {
325 	static const auto typeSize = sizeof(T);
326 
327 	DE_ASSERT(length % typeSize == 0);
328 
329 	const auto	numElements	= length / typeSize;
330 	auto		elemPtr		= reinterpret_cast<unsigned char*>(location);
331 	T			elem;
332 
333 	for (VkDeviceSize i = 0; i < numElements; ++i)
334 	{
335 		elem = getNormalFPValue<T>(rnd);
336 		deMemcpy(elemPtr, &elem, typeSize);
337 		elemPtr += typeSize;
338 	}
339 }
340 
iterate(void)341 tcu::TestStatus ImageSubresourceLayoutInstance::iterate (void)
342 {
343 	// Test every aspect supported by the image format.
344 	const auto tcuFormat	= mapVkFormat(m_params.imageFormat);
345 	const auto aspectFlags	= getImageAspectFlags(tcuFormat);
346 
347 	static const VkImageAspectFlagBits aspectBits[] =
348 	{
349 		VK_IMAGE_ASPECT_COLOR_BIT,
350 		VK_IMAGE_ASPECT_DEPTH_BIT,
351 		VK_IMAGE_ASPECT_STENCIL_BIT,
352 	};
353 
354 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(aspectBits); ++i)
355 	{
356 		const auto bit = aspectBits[i];
357 		if (aspectFlags & bit)
358 		{
359 			const auto aspectResult = iterateAspect(bit);
360 			if (aspectResult.getCode() != QP_TEST_RESULT_PASS)
361 				return aspectResult; // Early return for failures.
362 		}
363 	}
364 
365 	return tcu::TestStatus::pass("Pass");
366 }
367 
iterateAspect(VkImageAspectFlagBits imageAspect)368 tcu::TestStatus ImageSubresourceLayoutInstance::iterateAspect (VkImageAspectFlagBits imageAspect)
369 {
370 	// * Create linear image with several mipmaps
371 	// * Fill its levels with unique appropriate data (avoiding invalid sfloat values, for example).
372 	// * Ask for the subresource layout parameters.
373 	// * Verify they make sense.
374 	// * Check accessing data with the given parameters gives back the original data.
375 
376 	const auto&	vkd					= m_context.getDeviceInterface();
377 	const auto	device				= m_context.getDevice();
378 	auto&		alloc				= m_context.getDefaultAllocator();
379 	const auto	queue				= m_context.getUniversalQueue();
380 	const auto	queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
381 	auto&		log					= m_context.getTestContext().getLog();
382 
383 	log << tcu::TestLog::Message << "Testing aspect " << imageAspect << tcu::TestLog::EndMessage;
384 
385 	// Get an idea of the buffer size and parameters to prepare image data.
386 	const BufferLevels	bufferLevels	(m_params.imageType, m_params.imageFormat, m_params.dimensions, m_params.mipLevels, imageAspect);
387 	const auto			pixelSize		= bufferLevels.pixelSize();
388 	const auto			pixelSizeSz		= static_cast<size_t>(pixelSize);
389 	const auto			numLevels		= bufferLevels.numLevels();
390 
391 	// Create source buffer.
392 	const auto			bufferSize	= bufferLevels.totalSize();
393 	const auto			bufferInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
394 	BufferWithMemory	buffer		(vkd, device, alloc, bufferInfo, MemoryRequirement::HostVisible);
395 	auto&				bufferAlloc	= buffer.getAllocation();
396 	auto*				bufferPtr	= reinterpret_cast<unsigned char*>(bufferAlloc.getHostPtr());
397 
398 	// Fill buffer with random appropriate data.
399 	const deUint32	randomSeed	= 1594055758u + static_cast<deUint32>(m_params.imageFormat) + static_cast<deUint32>(imageAspect);
400 	de::Random		rnd			(randomSeed);
401 	const auto		tcuFormat	= mapVkFormat(m_params.imageFormat);
402 	// For some formats, the copy block is 32 bits wide but the 8 MSB need to be ignored, so we zero them out.
403 	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);
404 
405 	if (tcuFormat.type == tcu::TextureFormat::FLOAT || (m_params.imageFormat == VK_FORMAT_D32_SFLOAT_S8_UINT && imageAspect == VK_IMAGE_ASPECT_DEPTH_BIT))
406 		fillWithRandomFloatingPoint<float>(rnd, bufferPtr, bufferSize);
407 	else if (tcuFormat.type == tcu::TextureFormat::FLOAT64)
408 		fillWithRandomFloatingPoint<double>(rnd, bufferPtr, bufferSize);
409 	else if (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT)
410 		fillWithRandomFloatingPoint<tcu::Float16>(rnd, bufferPtr, bufferSize);
411 	else if (use24LSB)
412 		fillWithRandomData24In32(rnd, bufferPtr, bufferSize);
413 	else
414 		fillWithRandomData(rnd, bufferPtr, bufferSize);
415 
416 	flushAlloc(vkd, device, bufferAlloc);
417 
418 	// Reinterpret the depth dimension parameter as the number of layers if needed.
419 	const auto	numLayers	= ((m_params.imageType == VK_IMAGE_TYPE_3D) ? 1u : m_params.dimensions.depth);
420 	VkExtent3D	imageExtent	= m_params.dimensions;
421 	if (m_params.imageType == VK_IMAGE_TYPE_2D)
422 		imageExtent.depth = 1u;
423 
424 	// Create image.
425 	const VkImageCreateInfo imageInfo =
426 	{
427 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			//	VkStructureType			sType;
428 		nullptr,										//	const void*				pNext;
429 		0u,												//	VkImageCreateFlags		flags;
430 		m_params.imageType,								//	VkImageType				imageType;
431 		m_params.imageFormat,							//	VkFormat				format;
432 		imageExtent,									//	VkExtent3D				extent;
433 		numLevels,										//	deUint32				mipLevels;
434 		numLayers,										//	deUint32				arrayLayers;
435 		VK_SAMPLE_COUNT_1_BIT,							//	VkSampleCountFlagBits	samples;
436 		ImageSubresourceLayoutCase::kImageTiling,		//	VkImageTiling			tiling;
437 		ImageSubresourceLayoutCase::kImageUsageFlags,	//	VkImageUsageFlags		usage;
438 		VK_SHARING_MODE_EXCLUSIVE,						//	VkSharingMode			sharingMode;
439 		0u,												//	deUint32				queueFamilyIndexCount;
440 		nullptr,										//	const deUint32*			pQueueFamilyIndices;
441 		VK_IMAGE_LAYOUT_UNDEFINED,						//	VkImageLayout			initialLayout;
442 	};
443 	ImageWithMemory image		(vkd, device, alloc, imageInfo, MemoryRequirement::HostVisible);
444 	auto&			imageAlloc	= image.getAllocation();
445 	auto*			imagePtr	= reinterpret_cast<unsigned char*>(imageAlloc.getHostPtr());
446 
447 	// Copy regions.
448 	std::vector<VkBufferImageCopy> copyRegions;
449 	copyRegions.reserve(numLevels);
450 
451 	for (deUint32 levelNdx = 0u; levelNdx < numLevels; ++levelNdx)
452 	{
453 		const auto&	level		= bufferLevels.getLevel(levelNdx);
454 		auto		levelExtent	= level.dimensions;
455 
456 		if (m_params.imageType == VK_IMAGE_TYPE_2D)
457 			levelExtent.depth = 1u;	// For 2D images, .depth indicates the number of layers.
458 
459 		VkBufferImageCopy region;
460 		region.bufferOffset						= level.offset;
461 		region.bufferRowLength					= 0u;	// Tightly packed data.
462 		region.bufferImageHeight				= 0u;	// Ditto.
463 		region.imageSubresource.aspectMask		= imageAspect;
464 		region.imageSubresource.baseArrayLayer	= 0u;
465 		region.imageSubresource.layerCount		= numLayers;
466 		region.imageSubresource.mipLevel		= levelNdx;
467 		region.imageOffset						= { 0, 0, 0 };
468 		region.imageExtent						= levelExtent;
469 
470 		copyRegions.push_back(region);
471 	}
472 
473 	// Image layout transitions.
474 	const auto imageSubresourceRange	= makeImageSubresourceRange(imageAspect, 0u, numLevels, 0u, numLayers);
475 	const auto initialLayoutBarrier		= makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.get(), imageSubresourceRange);
476 	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);
477 
478 	// Command buffer.
479 	const auto cmdPool		= makeCommandPool(vkd, device, queueFamilyIndex);
480 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
481 	const auto cmdBuffer	= cmdBufferPtr.get();
482 
483 	// Transition layout, copy, transition layout.
484 	beginCommandBuffer(vkd, cmdBuffer);
485 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &initialLayoutBarrier);
486 	vkd.cmdCopyBufferToImage(cmdBuffer, buffer.get(), image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<deUint32>(copyRegions.size()), copyRegions.data());
487 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &finalLayoutBarrier);
488 	endCommandBuffer(vkd, cmdBuffer);
489 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
490 
491 	// Sync image memory for host access.
492 	invalidateAlloc(vkd, device, imageAlloc);
493 
494 	VkSubresourceLayout levelSubresourceLayout;
495 	VkSubresourceLayout subresourceLayout;
496 	for (deUint32 levelNdx = 0u; levelNdx < numLevels; ++levelNdx)
497 	{
498 		// Get base level subresource.
499 		const auto levelSubresource = makeImageSubresource(imageAspect, levelNdx, 0u);
500 		vkd.getImageSubresourceLayout(device, image.get(), &levelSubresource, &levelSubresourceLayout);
501 
502 		const auto& level = bufferLevels.getLevel(levelNdx);
503 		for (deUint32 layerNdx = 0; layerNdx < numLayers; ++layerNdx)
504 		{
505 			const auto imageSubresource = makeImageSubresource(imageAspect, levelNdx, layerNdx);
506 			vkd.getImageSubresourceLayout(device, image.get(), &imageSubresource, &subresourceLayout);
507 
508 			// Verify returned values.
509 			const auto subresourceWidth		= level.dimensions.width;
510 			const auto subresourceHeight	= level.dimensions.height;
511 			const auto subresourceDepth		= ((m_params.imageType == VK_IMAGE_TYPE_2D) ? 1u : level.dimensions.depth);
512 			const auto numPixels			= subresourceWidth * subresourceHeight * subresourceDepth;
513 
514 			if (numLayers > 1u && levelSubresourceLayout.arrayPitch != subresourceLayout.arrayPitch)
515 			{
516 				// Inconsistent arrayPitch.
517 				std::ostringstream msg;
518 				msg << "Image level " << levelNdx
519 					<< " layer " << layerNdx
520 					<< " reports array pitch of " << subresourceLayout.arrayPitch << " bytes in size"
521 					<< " with base layer reporting array pitch of " << levelSubresourceLayout.arrayPitch << " bytes in size";
522 				return tcu::TestStatus::fail(msg.str());
523 			}
524 
525 			if ((subresourceLayout.offset - levelSubresourceLayout.offset) != (layerNdx * subresourceLayout.arrayPitch))
526 			{
527 				// Inconsistent offset.
528 				std::ostringstream msg;
529 				msg << "Image level " << levelNdx
530 					<< " layer " << layerNdx
531 					<< " has offset inconsistent with array pitch: base offset " << levelSubresourceLayout.offset
532 					<< ", layer offset " << subresourceLayout.offset
533 					<< ", array pitch " << subresourceLayout.arrayPitch;
534 				return tcu::TestStatus::fail(msg.str());
535 			}
536 
537 			if (subresourceLayout.size < pixelSize * numPixels)
538 			{
539 				// Subresource size too small.
540 				std::ostringstream msg;
541 				msg << "Image level " << levelNdx
542 					<< " layer " << layerNdx
543 					<< " reports " << subresourceLayout.size << " bytes in size"
544 					<< " with pixel size " << pixelSize
545 					<< " and dimensions " << subresourceWidth << "x" << subresourceHeight << "x" << subresourceDepth;
546 				return tcu::TestStatus::fail(msg.str());
547 			}
548 
549 			// Note: if subresourceHeight is <= 1u, rowPitch can be zero.
550 			if (subresourceHeight > 1u && subresourceLayout.rowPitch < pixelSize * subresourceWidth)
551 			{
552 				// Row pitch too small.
553 				std::ostringstream msg;
554 				msg << "Image level " << levelNdx
555 					<< " layer " << layerNdx
556 					<< " reports row pitch of " << subresourceLayout.rowPitch
557 					<< " bytes with " << pixelSize
558 					<< " bytes in pixel size and width " << subresourceWidth;
559 				return tcu::TestStatus::fail(msg.str());
560 			}
561 
562 			if (numLayers > 1u && subresourceLayout.arrayPitch < pixelSize * numPixels)
563 			{
564 				// Array pitch too small.
565 				std::ostringstream msg;
566 				msg << "Image level " << levelNdx
567 					<< " layer " << layerNdx
568 					<< " reports array pitch of " << subresourceLayout.arrayPitch
569 					<< " bytes with " << pixelSize
570 					<< " bytes in pixel size and layer dimensions " << subresourceWidth << "x" << subresourceHeight;
571 				return tcu::TestStatus::fail(msg.str());
572 			}
573 
574 			// If subresourceDepth is <= 1u, depthPitch can be zero.
575 			if (subresourceDepth > 1u && m_params.imageType == VK_IMAGE_TYPE_3D && subresourceLayout.depthPitch < pixelSize * subresourceWidth * subresourceHeight)
576 			{
577 				// Depth pitch too small.
578 				std::ostringstream msg;
579 				msg << "Image level " << levelNdx
580 					<< " layer " << layerNdx
581 					<< " reports depth pitch of " << subresourceLayout.depthPitch << " bytes"
582 					<< " with pixel size " << pixelSize
583 					<< " and dimensions " << subresourceWidth << "x" << subresourceHeight << "x" << subresourceDepth;
584 				return tcu::TestStatus::fail(msg.str());
585 			}
586 
587 			// Verify image data.
588 			const auto	layerBufferOffset	= level.offset + layerNdx * numPixels * pixelSize;
589 			const auto	layerImageOffset	= subresourceLayout.offset;
590 			const auto	layerBufferPtr		= bufferPtr + layerBufferOffset;
591 			const auto	layerImagePtr		= imagePtr + layerImageOffset;
592 			bool		pixelMatch;
593 
594 			// We could do this row by row to be faster, but in the use24LSB case we need to manipulate pixels independently.
595 			for (deUint32 x = 0u; x < subresourceWidth; ++x)
596 			for (deUint32 y = 0u; y < subresourceHeight; ++y)
597 			for (deUint32 z = 0u; z < subresourceDepth; ++z)
598 			{
599 				const auto bufferPixelOffset	= (z * subresourceWidth * subresourceHeight + y * subresourceWidth + x) * pixelSize;
600 				const auto imagePixelOffset		= z * subresourceLayout.depthPitch + y * subresourceLayout.rowPitch + x * pixelSize;
601 				const auto bufferPixelPtr		= layerBufferPtr + bufferPixelOffset;
602 				const auto imagePixelPtr		= layerImagePtr + imagePixelOffset;
603 
604 				if (use24LSB)
605 				{
606 					DE_ASSERT(pixelSize == sizeof(deUint32));
607 					deUint32 pixelValue;
608 					deMemcpy(&pixelValue, imagePixelPtr, pixelSizeSz);
609 					pixelValue &= 0xFFFFFFu; // Discard the 8 MSB.
610 					pixelMatch = (deMemCmp(bufferPixelPtr, &pixelValue, pixelSizeSz) == 0);
611 				}
612 				else
613 					pixelMatch = (deMemCmp(bufferPixelPtr, imagePixelPtr, pixelSizeSz) == 0);
614 
615 				if (!pixelMatch)
616 				{
617 					std::ostringstream msg;
618 					msg << "Found difference from image pixel to buffer pixel at coordinates"
619 						<< " level=" << levelNdx
620 						<< " layer=" << layerNdx
621 						<< " x=" << x
622 						<< " y=" << y
623 						<< " z=" << z
624 						;
625 					return tcu::TestStatus::fail(msg.str());
626 				}
627 			}
628 		}
629 	}
630 
631 	return tcu::TestStatus::pass("Pass");
632 }
633 
634 } // anonymous namespace
635 
createImageSubresourceLayoutTests(tcu::TestContext & testCtx)636 tcu::TestCaseGroup* createImageSubresourceLayoutTests (tcu::TestContext& testCtx)
637 {
638 	de::MovePtr<tcu::TestCaseGroup> layoutTestGroup (new tcu::TestCaseGroup(testCtx, "subresource_layout", "Tests for vkGetImageSubresourceLayout"));
639 
640 	struct
641 	{
642 		VkImageType	type;
643 		bool		array;
644 		const char*	name;
645 		const char*	desc;
646 	} imageClass[] =
647 	{
648 		{ VK_IMAGE_TYPE_2D,	false,	"2d",		"2D images"							},
649 		{ VK_IMAGE_TYPE_2D,	true,	"2d_array",	"2D images with multiple layers"	},
650 		{ VK_IMAGE_TYPE_3D,	false,	"3d",		"3D images"							},
651 	};
652 
653 	struct
654 	{
655 		deUint32	maxLevels;
656 		const char*	name;
657 		const char*	desc;
658 	} mipLevels[] =
659 	{
660 		{ 1u,									"1_level",		"Single mip level"		},
661 		{ 2u,									"2_levels",		"Two mip levels"		},
662 		{ 4u,									"4_levels",		"Four mip levels"		},
663 		{ std::numeric_limits<deUint32>::max(),	"all_levels",	"All possible levels"	},
664 	};
665 
666 	VkFormat testFormats[] =
667 	{
668 		VK_FORMAT_R4G4_UNORM_PACK8,
669 		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
670 		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
671 		VK_FORMAT_R5G6B5_UNORM_PACK16,
672 		VK_FORMAT_B5G6R5_UNORM_PACK16,
673 		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
674 		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
675 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
676 		VK_FORMAT_R8_UNORM,
677 		VK_FORMAT_R8_SNORM,
678 		VK_FORMAT_R8_USCALED,
679 		VK_FORMAT_R8_SSCALED,
680 		VK_FORMAT_R8_UINT,
681 		VK_FORMAT_R8_SINT,
682 		VK_FORMAT_R8_SRGB,
683 		VK_FORMAT_R8G8_UNORM,
684 		VK_FORMAT_R8G8_SNORM,
685 		VK_FORMAT_R8G8_USCALED,
686 		VK_FORMAT_R8G8_SSCALED,
687 		VK_FORMAT_R8G8_UINT,
688 		VK_FORMAT_R8G8_SINT,
689 		VK_FORMAT_R8G8_SRGB,
690 		VK_FORMAT_R8G8B8_UNORM,
691 		VK_FORMAT_R8G8B8_SNORM,
692 		VK_FORMAT_R8G8B8_USCALED,
693 		VK_FORMAT_R8G8B8_SSCALED,
694 		VK_FORMAT_R8G8B8_UINT,
695 		VK_FORMAT_R8G8B8_SINT,
696 		VK_FORMAT_R8G8B8_SRGB,
697 		VK_FORMAT_B8G8R8_UNORM,
698 		VK_FORMAT_B8G8R8_SNORM,
699 		VK_FORMAT_B8G8R8_USCALED,
700 		VK_FORMAT_B8G8R8_SSCALED,
701 		VK_FORMAT_B8G8R8_UINT,
702 		VK_FORMAT_B8G8R8_SINT,
703 		VK_FORMAT_B8G8R8_SRGB,
704 		VK_FORMAT_R8G8B8A8_UNORM,
705 		VK_FORMAT_R8G8B8A8_SNORM,
706 		VK_FORMAT_R8G8B8A8_USCALED,
707 		VK_FORMAT_R8G8B8A8_SSCALED,
708 		VK_FORMAT_R8G8B8A8_UINT,
709 		VK_FORMAT_R8G8B8A8_SINT,
710 		VK_FORMAT_R8G8B8A8_SRGB,
711 		VK_FORMAT_B8G8R8A8_UNORM,
712 		VK_FORMAT_B8G8R8A8_SNORM,
713 		VK_FORMAT_B8G8R8A8_USCALED,
714 		VK_FORMAT_B8G8R8A8_SSCALED,
715 		VK_FORMAT_B8G8R8A8_UINT,
716 		VK_FORMAT_B8G8R8A8_SINT,
717 		VK_FORMAT_B8G8R8A8_SRGB,
718 		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
719 		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
720 		VK_FORMAT_A8B8G8R8_USCALED_PACK32,
721 		VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
722 		VK_FORMAT_A8B8G8R8_UINT_PACK32,
723 		VK_FORMAT_A8B8G8R8_SINT_PACK32,
724 		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
725 		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
726 		VK_FORMAT_A2R10G10B10_SNORM_PACK32,
727 		VK_FORMAT_A2R10G10B10_USCALED_PACK32,
728 		VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
729 		VK_FORMAT_A2R10G10B10_UINT_PACK32,
730 		VK_FORMAT_A2R10G10B10_SINT_PACK32,
731 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
732 		VK_FORMAT_A2B10G10R10_SNORM_PACK32,
733 		VK_FORMAT_A2B10G10R10_USCALED_PACK32,
734 		VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
735 		VK_FORMAT_A2B10G10R10_UINT_PACK32,
736 		VK_FORMAT_A2B10G10R10_SINT_PACK32,
737 		VK_FORMAT_R16_UNORM,
738 		VK_FORMAT_R16_SNORM,
739 		VK_FORMAT_R16_USCALED,
740 		VK_FORMAT_R16_SSCALED,
741 		VK_FORMAT_R16_UINT,
742 		VK_FORMAT_R16_SINT,
743 		VK_FORMAT_R16_SFLOAT,
744 		VK_FORMAT_R16G16_UNORM,
745 		VK_FORMAT_R16G16_SNORM,
746 		VK_FORMAT_R16G16_USCALED,
747 		VK_FORMAT_R16G16_SSCALED,
748 		VK_FORMAT_R16G16_UINT,
749 		VK_FORMAT_R16G16_SINT,
750 		VK_FORMAT_R16G16_SFLOAT,
751 		VK_FORMAT_R16G16B16_UNORM,
752 		VK_FORMAT_R16G16B16_SNORM,
753 		VK_FORMAT_R16G16B16_USCALED,
754 		VK_FORMAT_R16G16B16_SSCALED,
755 		VK_FORMAT_R16G16B16_UINT,
756 		VK_FORMAT_R16G16B16_SINT,
757 		VK_FORMAT_R16G16B16_SFLOAT,
758 		VK_FORMAT_R16G16B16A16_UNORM,
759 		VK_FORMAT_R16G16B16A16_SNORM,
760 		VK_FORMAT_R16G16B16A16_USCALED,
761 		VK_FORMAT_R16G16B16A16_SSCALED,
762 		VK_FORMAT_R16G16B16A16_UINT,
763 		VK_FORMAT_R16G16B16A16_SINT,
764 		VK_FORMAT_R16G16B16A16_SFLOAT,
765 		VK_FORMAT_R32_UINT,
766 		VK_FORMAT_R32_SINT,
767 		VK_FORMAT_R32_SFLOAT,
768 		VK_FORMAT_R32G32_UINT,
769 		VK_FORMAT_R32G32_SINT,
770 		VK_FORMAT_R32G32_SFLOAT,
771 		VK_FORMAT_R32G32B32_UINT,
772 		VK_FORMAT_R32G32B32_SINT,
773 		VK_FORMAT_R32G32B32_SFLOAT,
774 		VK_FORMAT_R32G32B32A32_UINT,
775 		VK_FORMAT_R32G32B32A32_SINT,
776 		VK_FORMAT_R32G32B32A32_SFLOAT,
777 		VK_FORMAT_R64_UINT,
778 		VK_FORMAT_R64_SINT,
779 		VK_FORMAT_R64_SFLOAT,
780 		VK_FORMAT_R64G64_UINT,
781 		VK_FORMAT_R64G64_SINT,
782 		VK_FORMAT_R64G64_SFLOAT,
783 		VK_FORMAT_R64G64B64_UINT,
784 		VK_FORMAT_R64G64B64_SINT,
785 		VK_FORMAT_R64G64B64_SFLOAT,
786 		VK_FORMAT_R64G64B64A64_UINT,
787 		VK_FORMAT_R64G64B64A64_SINT,
788 		VK_FORMAT_R64G64B64A64_SFLOAT,
789 		// Leaving out depth/stencil formats due to this part of the spec:
790 		//
791 		// "Depth/stencil formats are considered opaque and need not be stored in the exact number of bits per texel or component
792 		// ordering indicated by the format enum. However, implementations must not substitute a different depth or stencil
793 		// precision than that described in the format (e.g. D16 must not be implemented as D24 or D32)."
794 		//
795 		// Which means the size of the texel is not known for depth/stencil formats and we cannot iterate over them to check their
796 		// values.
797 #if 0
798 		VK_FORMAT_D16_UNORM,
799 		VK_FORMAT_X8_D24_UNORM_PACK32,
800 		VK_FORMAT_D32_SFLOAT,
801 		VK_FORMAT_S8_UINT,
802 		VK_FORMAT_D16_UNORM_S8_UINT,
803 		VK_FORMAT_D24_UNORM_S8_UINT,
804 		VK_FORMAT_D32_SFLOAT_S8_UINT,
805 #endif
806 	};
807 
808 	for (int classIdx = 0; classIdx < DE_LENGTH_OF_ARRAY(imageClass); ++classIdx)
809 	{
810 		const auto& imgClass = imageClass[classIdx];
811 		de::MovePtr<tcu::TestCaseGroup> classGroup (new tcu::TestCaseGroup(testCtx, imgClass.name, imgClass.desc));
812 
813 		for (int mipIdx = 0; mipIdx < DE_LENGTH_OF_ARRAY(mipLevels); ++mipIdx)
814 		{
815 			const auto &mipLevel = mipLevels[mipIdx];
816 			de::MovePtr<tcu::TestCaseGroup> mipGroup (new tcu::TestCaseGroup(testCtx, mipLevel.name, mipLevel.desc));
817 
818 			for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(testFormats); ++formatIdx)
819 			{
820 				static const auto	prefixLen	= std::string("VK_FORMAT_").size();
821 				const auto			format		= testFormats[formatIdx];
822 				const auto			fmtName		= std::string(getFormatName(format));
823 				const auto			name		= de::toLower(fmtName.substr(prefixLen)); // Remove VK_FORMAT_ prefix.
824 				const auto			desc		= "Using format " + fmtName;
825 
826 				ImageSubresourceLayoutCase::TestParams params;
827 				params.imageFormat	= format;
828 				params.imageType	= imgClass.type;
829 				params.mipLevels	= mipLevel.maxLevels;
830 				params.dimensions	= getDefaultDimensions(imgClass.type, imgClass.array);
831 
832 				mipGroup->addChild(new ImageSubresourceLayoutCase(testCtx, name, desc, params));
833 			}
834 
835 			classGroup->addChild(mipGroup.release());
836 		}
837 
838 		layoutTestGroup->addChild(classGroup.release());
839 	}
840 
841 	return layoutTestGroup.release();
842 }
843 
844 } // namespace image
845 } // namespace vkt
846