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 ¶ms);
~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 ¶ms);
~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 ¶ms)
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 ¶ms)
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 ¶ms);
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 ¶ms)
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 ¶ms);
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 ¶ms)
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