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