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