xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/image/vktImageMisalignedCubeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 The Android Open Source Project
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
22  * \brief Cube image with misaligned baseArrayLayer tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktImageMisalignedCubeTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageTexture.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 #include "vkBufferWithMemory.hpp"
43 
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46 #include "deMath.h"
47 
48 #include <string>
49 
50 using namespace vk;
51 
52 namespace vkt
53 {
54 namespace image
55 {
56 namespace
57 {
58 
makeImageCreateInfo(const tcu::IVec3 & size,const VkFormat format)59 inline VkImageCreateInfo makeImageCreateInfo(const tcu::IVec3 &size, const VkFormat format)
60 {
61     const VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
62                                     VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
63     const VkImageCreateInfo imageParams = {
64         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,  //  VkStructureType sType;
65         DE_NULL,                              //  const void* pNext;
66         VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,  //  VkImageCreateFlags flags;
67         VK_IMAGE_TYPE_2D,                     //  VkImageType imageType;
68         format,                               //  VkFormat format;
69         makeExtent3D(size.x(), size.y(), 1u), //  VkExtent3D extent;
70         1u,                                   //  uint32_t mipLevels;
71         (uint32_t)size.z(),                   //  uint32_t arrayLayers;
72         VK_SAMPLE_COUNT_1_BIT,                //  VkSampleCountFlagBits samples;
73         VK_IMAGE_TILING_OPTIMAL,              //  VkImageTiling tiling;
74         usage,                                //  VkImageUsageFlags usage;
75         VK_SHARING_MODE_EXCLUSIVE,            //  VkSharingMode sharingMode;
76         0u,                                   //  uint32_t queueFamilyIndexCount;
77         DE_NULL,                              //  const uint32_t* pQueueFamilyIndices;
78         VK_IMAGE_LAYOUT_UNDEFINED,            //  VkImageLayout initialLayout;
79     };
80 
81     return imageParams;
82 }
83 
fillBuffer(const DeviceInterface & vk,const VkDevice device,const Allocation & alloc,const VkDeviceSize offset,const VkDeviceSize size,const VkFormat format,const tcu::Vec4 & color)84 void fillBuffer(const DeviceInterface &vk, const VkDevice device, const Allocation &alloc, const VkDeviceSize offset,
85                 const VkDeviceSize size, const VkFormat format, const tcu::Vec4 &color)
86 {
87     const tcu::TextureFormat textureFormat = mapVkFormat(format);
88     const uint32_t colorPixelSize          = static_cast<uint32_t>(tcu::getPixelSize(textureFormat));
89     tcu::TextureLevel colorPixelBuffer(textureFormat, 1, 1);
90     tcu::PixelBufferAccess colorPixel(colorPixelBuffer);
91 
92     colorPixel.setPixel(color, 0, 0);
93 
94     const uint8_t *src = static_cast<uint8_t *>(colorPixel.getDataPtr());
95     uint8_t *dstBase   = static_cast<uint8_t *>(alloc.getHostPtr());
96     uint8_t *dst       = &dstBase[offset];
97 
98     for (uint32_t pixelPos = 0; pixelPos < size; pixelPos += colorPixelSize)
99         deMemcpy(&dst[pixelPos], src, colorPixelSize);
100 
101     flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset() + offset, size);
102 }
103 
makeBufferImageCopy(const vk::VkDeviceSize & bufferOffset,const vk::VkImageSubresourceLayers & imageSubresource,const vk::VkOffset3D & imageOffset,const vk::VkExtent3D & imageExtent)104 VkBufferImageCopy makeBufferImageCopy(const vk::VkDeviceSize &bufferOffset,
105                                       const vk::VkImageSubresourceLayers &imageSubresource,
106                                       const vk::VkOffset3D &imageOffset, const vk::VkExtent3D &imageExtent)
107 {
108     const VkBufferImageCopy copyParams = {
109         bufferOffset,     // VkDeviceSize bufferOffset;
110         0u,               // uint32_t bufferRowLength;
111         0u,               // uint32_t bufferImageHeight;
112         imageSubresource, // VkImageSubresourceLayers imageSubresource;
113         imageOffset,      // VkOffset3D imageOffset;
114         imageExtent,      // VkExtent3D imageExtent;
115     };
116     return copyParams;
117 }
118 
119 //! Interpret the memory as IVec4
readVec4(const void * const data,const uint32_t ndx)120 inline tcu::Vec4 readVec4(const void *const data, const uint32_t ndx)
121 {
122     const float *const p = reinterpret_cast<const float *>(data);
123     const uint32_t ofs   = 4 * ndx;
124 
125     return tcu::Vec4(p[ofs + 0], p[ofs + 1], p[ofs + 2], p[ofs + 3]);
126 }
127 
128 class MisalignedCubeTestInstance : public TestInstance
129 {
130 public:
131     MisalignedCubeTestInstance(Context &context, const tcu::IVec3 &size, const VkFormat format);
132     tcu::TestStatus iterate(void);
133 
134 private:
135     const tcu::IVec3 &m_size;
136     const VkFormat m_format;
137 };
138 
MisalignedCubeTestInstance(Context & context,const tcu::IVec3 & size,const VkFormat format)139 MisalignedCubeTestInstance::MisalignedCubeTestInstance(Context &context, const tcu::IVec3 &size, const VkFormat format)
140     : TestInstance(context)
141     , m_size(size)
142     , m_format(format)
143 {
144 }
145 
iterate(void)146 tcu::TestStatus MisalignedCubeTestInstance::iterate(void)
147 {
148     DE_ASSERT(de::inRange(m_size.z(), 6, 16));
149     DE_ASSERT(m_format == VK_FORMAT_R8G8B8A8_UNORM);
150 
151     const DeviceInterface &vk                = m_context.getDeviceInterface();
152     const VkDevice device                    = m_context.getDevice();
153     Allocator &allocator                     = m_context.getDefaultAllocator();
154     const VkQueue queue                      = m_context.getUniversalQueue();
155     const uint32_t queueFamilyIndex          = m_context.getUniversalQueueFamilyIndex();
156     const uint32_t numLayers                 = m_size.z();
157     const uint32_t cube0LayerStart           = 0;
158     const uint32_t cube1LayerStart           = numLayers - 6u;
159     const VkDeviceSize resultBufferSizeBytes = 2 * 6 * 4 * sizeof(float); // vec4[6] in shader
160     const VkExtent3D imageExtent             = makeExtent3D(m_size.x(), m_size.y(), 1u);
161     const uint32_t pixelSize                 = static_cast<uint32_t>(tcu::getPixelSize(mapVkFormat(m_format)));
162     const uint32_t layerSize                 = imageExtent.width * imageExtent.height * pixelSize;
163     const float eps                          = 1.0f / float(2 * 256);
164 
165     const VkBufferCreateInfo resultBufferCreateInfo =
166         makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
167     de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(
168         new BufferWithMemory(vk, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
169     const Allocation &resultBufferAlloc     = resultBuffer->getAllocation();
170     const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_size, m_format);
171     de::MovePtr<Image> image =
172         de::MovePtr<Image>(new Image(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
173     const VkImageSubresourceRange imageSubresourceRange0 =
174         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, cube0LayerStart, 6u);
175     Move<VkImageView> imageView0 =
176         makeImageView(vk, device, image->get(), VK_IMAGE_VIEW_TYPE_CUBE, m_format, imageSubresourceRange0);
177     const VkImageSubresourceRange imageSubresourceRange1 =
178         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, cube1LayerStart, 6u);
179     Move<VkImageView> imageView1 =
180         makeImageView(vk, device, image->get(), VK_IMAGE_VIEW_TYPE_CUBE, m_format, imageSubresourceRange1);
181 
182     Move<VkDescriptorSetLayout> descriptorSetLayout =
183         DescriptorSetLayoutBuilder()
184             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
185             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
186             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
187             .build(vk, device);
188     Move<VkDescriptorPool> descriptorPool =
189         DescriptorPoolBuilder()
190             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
191             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
192             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
193             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
194     Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
195     const VkDescriptorImageInfo descriptorImageInfo0 =
196         makeDescriptorImageInfo(DE_NULL, *imageView0, VK_IMAGE_LAYOUT_GENERAL);
197     const VkDescriptorImageInfo descriptorImageInfo1 =
198         makeDescriptorImageInfo(DE_NULL, *imageView1, VK_IMAGE_LAYOUT_GENERAL);
199     const VkDescriptorBufferInfo descriptorBufferInfo =
200         makeDescriptorBufferInfo(resultBuffer->get(), 0ull, resultBufferSizeBytes);
201 
202     const Move<VkShaderModule> shaderModule =
203         createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0);
204     const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, device, *descriptorSetLayout);
205     const Move<VkPipeline> pipeline             = makeComputePipeline(vk, device, *pipelineLayout, *shaderModule);
206     const Move<VkCommandPool> cmdPool =
207         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
208     const Move<VkCommandBuffer> cmdBuffer =
209         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
210 
211     const VkDeviceSize clearBufferSize = layerSize * numLayers;
212     const Move<VkBuffer> clearBuffer   = makeBuffer(vk, device, clearBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
213     const de::MovePtr<Allocation> clearBufferAlloc =
214         bindBuffer(vk, device, allocator, *clearBuffer, MemoryRequirement::HostVisible);
215     const VkImageSubresourceRange clearSubresRange =
216         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers);
217     const VkImageMemoryBarrier clearBarrier =
218         makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
219                                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image->get(), clearSubresRange);
220     const VkImageMemoryBarrier preShaderImageBarrier = makeImageMemoryBarrier(
221         VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
222         VK_IMAGE_LAYOUT_GENERAL, image->get(), clearSubresRange);
223     const VkBufferMemoryBarrier postShaderBarrier = makeBufferMemoryBarrier(
224         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, resultBuffer->get(), 0ull, VK_WHOLE_SIZE);
225     bool result = true;
226 
227     DescriptorSetUpdateBuilder()
228         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
229                      VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo0)
230         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
231                      VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo1)
232         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u),
233                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
234         .update(vk, device);
235 
236     beginCommandBuffer(vk, *cmdBuffer);
237 
238     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
239     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u,
240                              DE_NULL);
241 
242     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
243                           DE_NULL, 0u, DE_NULL, 1u, &clearBarrier);
244 
245     // Clear layers with predefined values
246     for (uint32_t layerNdx = 0; layerNdx < numLayers; ++layerNdx)
247     {
248         const float componentValue      = float(16 * layerNdx) / 255.0f;
249         const tcu::Vec4 clearColor      = tcu::Vec4(componentValue, componentValue, componentValue, 1.0f);
250         const VkDeviceSize bufferOffset = layerNdx * layerSize;
251         const VkImageSubresourceLayers imageSubresource =
252             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layerNdx, 1u);
253         const VkBufferImageCopy bufferImageCopyRegion =
254             makeBufferImageCopy(bufferOffset, imageSubresource, makeOffset3D(0u, 0u, 0u), imageExtent);
255 
256         fillBuffer(vk, device, *clearBufferAlloc, bufferOffset, layerSize, m_format, clearColor);
257 
258         vk.cmdCopyBufferToImage(*cmdBuffer, *clearBuffer, image->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
259                                 &bufferImageCopyRegion);
260     }
261 
262     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u,
263                           DE_NULL, 0u, DE_NULL, 1u, &preShaderImageBarrier);
264 
265     vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
266 
267     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, DE_NULL,
268                           1, &postShaderBarrier, 0, DE_NULL);
269 
270     endCommandBuffer(vk, *cmdBuffer);
271 
272     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
273 
274     invalidateAlloc(vk, device, resultBufferAlloc);
275 
276     // Check cube 0
277     for (uint32_t layerNdx = 0; layerNdx < 6; ++layerNdx)
278     {
279         const uint32_t layerUsed      = cube0LayerStart + layerNdx;
280         const float componentValue    = float(16 * layerUsed) / 255.0f;
281         const tcu::Vec4 expectedColor = tcu::Vec4(componentValue, componentValue, componentValue, 1.0f);
282         const tcu::Vec4 resultColor   = readVec4(resultBufferAlloc.getHostPtr(), layerNdx);
283         const tcu::Vec4 delta         = expectedColor - resultColor;
284 
285         if (deFloatAbs(delta.x()) > eps || deFloatAbs(delta.y()) > eps || deFloatAbs(delta.z()) > eps ||
286             deFloatAbs(delta.w()) > eps)
287             result = false;
288     }
289 
290     // Check cube 1
291     for (uint32_t layerNdx = 0; layerNdx < 6; ++layerNdx)
292     {
293         const uint32_t layerUsed      = cube1LayerStart + layerNdx;
294         const float componentValue    = float(16 * layerUsed) / 255.0f;
295         const tcu::Vec4 expectedColor = tcu::Vec4(componentValue, componentValue, componentValue, 1.0f);
296         const tcu::Vec4 resultColor   = readVec4(resultBufferAlloc.getHostPtr(), layerNdx + 6u);
297         const tcu::Vec4 delta         = expectedColor - resultColor;
298 
299         if (deFloatAbs(delta.x()) > eps || deFloatAbs(delta.y()) > eps || deFloatAbs(delta.z()) > eps ||
300             deFloatAbs(delta.w()) > eps)
301             result = false;
302     }
303 
304     if (result)
305         return tcu::TestStatus::pass("pass");
306     else
307         return tcu::TestStatus::fail("fail");
308 }
309 
310 class MisalignedCubeTest : public TestCase
311 {
312 public:
313     MisalignedCubeTest(tcu::TestContext &testCtx, const std::string &name, const tcu::IVec3 &size,
314                        const VkFormat format);
315 
316     void initPrograms(SourceCollections &programCollection) const;
317     TestInstance *createInstance(Context &context) const;
318 
319 private:
320     const tcu::IVec3 m_size;
321     const VkFormat m_format;
322 };
323 
MisalignedCubeTest(tcu::TestContext & testCtx,const std::string & name,const tcu::IVec3 & size,const VkFormat format)324 MisalignedCubeTest::MisalignedCubeTest(tcu::TestContext &testCtx, const std::string &name, const tcu::IVec3 &size,
325                                        const VkFormat format)
326     : TestCase(testCtx, name)
327     , m_size(size)
328     , m_format(format)
329 {
330 }
331 
initPrograms(SourceCollections & programCollection) const332 void MisalignedCubeTest::initPrograms(SourceCollections &programCollection) const
333 {
334     const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
335 
336     std::ostringstream src;
337     src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
338         << "\n"
339         << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
340         << "layout (binding = 0, " << formatQualifierStr << ") "
341         << "readonly uniform highp imageCube u_cubeImage0;\n"
342         << "layout (binding = 1, " << formatQualifierStr << ") "
343         << "readonly uniform highp imageCube u_cubeImage1;\n"
344         << "layout (binding = 2) writeonly buffer Output\n"
345         << "{\n"
346         << "    vec4 cube0_color0;\n"
347         << "    vec4 cube0_color1;\n"
348         << "    vec4 cube0_color2;\n"
349         << "    vec4 cube0_color3;\n"
350         << "    vec4 cube0_color4;\n"
351         << "    vec4 cube0_color5;\n"
352         << "    vec4 cube1_color0;\n"
353         << "    vec4 cube1_color1;\n"
354         << "    vec4 cube1_color2;\n"
355         << "    vec4 cube1_color3;\n"
356         << "    vec4 cube1_color4;\n"
357         << "    vec4 cube1_color5;\n"
358         << "} sb_out;\n"
359         << "\n"
360         << "void main (void)\n"
361         << "{\n"
362         << "    sb_out.cube0_color0 = imageLoad(u_cubeImage0, ivec3(1, 1, 0));\n"
363         << "    sb_out.cube0_color1 = imageLoad(u_cubeImage0, ivec3(1, 1, 1));\n"
364         << "    sb_out.cube0_color2 = imageLoad(u_cubeImage0, ivec3(1, 1, 2));\n"
365         << "    sb_out.cube0_color3 = imageLoad(u_cubeImage0, ivec3(1, 1, 3));\n"
366         << "    sb_out.cube0_color4 = imageLoad(u_cubeImage0, ivec3(1, 1, 4));\n"
367         << "    sb_out.cube0_color5 = imageLoad(u_cubeImage0, ivec3(1, 1, 5));\n"
368         << "    sb_out.cube1_color0 = imageLoad(u_cubeImage1, ivec3(1, 1, 0));\n"
369         << "    sb_out.cube1_color1 = imageLoad(u_cubeImage1, ivec3(1, 1, 1));\n"
370         << "    sb_out.cube1_color2 = imageLoad(u_cubeImage1, ivec3(1, 1, 2));\n"
371         << "    sb_out.cube1_color3 = imageLoad(u_cubeImage1, ivec3(1, 1, 3));\n"
372         << "    sb_out.cube1_color4 = imageLoad(u_cubeImage1, ivec3(1, 1, 4));\n"
373         << "    sb_out.cube1_color5 = imageLoad(u_cubeImage1, ivec3(1, 1, 5));\n"
374         << "}\n";
375 
376     programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
377 }
378 
createInstance(Context & context) const379 TestInstance *MisalignedCubeTest::createInstance(Context &context) const
380 {
381     return new MisalignedCubeTestInstance(context, m_size, m_format);
382 }
383 
384 //! Base sizes used to generate actual imager sizes in the test.
385 static const tcu::IVec3 s_baseImageSizes[] = {
386     tcu::IVec3(16, 16, 7), tcu::IVec3(16, 16, 8), tcu::IVec3(16, 16, 9), tcu::IVec3(16, 16, 10), tcu::IVec3(16, 16, 11),
387 };
388 
389 } // namespace
390 
createMisalignedCubeTests(tcu::TestContext & testCtx)391 tcu::TestCaseGroup *createMisalignedCubeTests(tcu::TestContext &testCtx)
392 {
393     // Cube image with misaligned baseArrayLayer test cases
394     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "misaligned_cube"));
395 
396     const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
397 
398     for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(s_baseImageSizes); ++imageSizeNdx)
399     {
400         const tcu::IVec3 size = s_baseImageSizes[imageSizeNdx];
401 
402         testGroup->addChild(new MisalignedCubeTest(testCtx, de::toString(size.z()), size, format));
403     }
404 
405     return testGroup.release();
406 }
407 
408 } // namespace image
409 } // namespace vkt
410