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