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