1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  * Copyright (c) 2023 LunarG, Inc.
7  * Copyright (c) 2023 Nintendo
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file vktPipelineRenderToImageTests.cpp
23  * \brief Render to image tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineRenderToImageTests.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktPipelineVertexUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vkObjUtil.hpp"
33 
34 #include "vkMemUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 
43 #include "tcuTextureUtil.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuTestLog.hpp"
46 #include "tcuPlatform.hpp"
47 #include "vkPlatform.hpp"
48 
49 #include "deUniquePtr.hpp"
50 #include "deSharedPtr.hpp"
51 
52 #include <string>
53 #include <vector>
54 #include <set>
55 #include <algorithm>
56 
57 namespace vkt
58 {
59 namespace pipeline
60 {
61 namespace
62 {
63 using namespace vk;
64 using de::MovePtr;
65 using de::SharedPtr;
66 using de::UniquePtr;
67 using std::vector;
68 using tcu::BVec4;
69 using tcu::IVec2;
70 using tcu::IVec3;
71 using tcu::IVec4;
72 using tcu::UVec4;
73 using tcu::Vec4;
74 
75 typedef SharedPtr<Unique<VkImageView>> SharedPtrVkImageView;
76 
77 enum Constants
78 {
79     NUM_CUBE_FACES                = 6,
80     REFERENCE_COLOR_VALUE         = 125,
81     REFERENCE_STENCIL_VALUE       = 42,
82     MAX_SIZE                      = -1, //!< Should be queried at runtime and replaced with max possible value
83     MAX_VERIFICATION_REGION_SIZE  = 32, //!<  Limit the checked area to a small size, especially for huge images
84     MAX_VERIFICATION_REGION_DEPTH = 8,
85 
86     MASK_W         = (1 | 0 | 0 | 0),
87     MASK_W_LAYERS  = (1 | 0 | 0 | 8),
88     MASK_WH        = (1 | 2 | 0 | 0),
89     MASK_WH_LAYERS = (1 | 2 | 0 | 8),
90     MASK_WHD       = (1 | 2 | 4 | 0),
91 };
92 
93 enum AllocationKind
94 {
95     ALLOCATION_KIND_SUBALLOCATED = 0,
96     ALLOCATION_KIND_DEDICATED,
97 };
98 
99 static const float REFERENCE_DEPTH_VALUE = 1.0f;
100 static const Vec4 COLOR_TABLE[]          = {
101     Vec4(0.9f, 0.0f, 0.0f, 1.0f), Vec4(0.6f, 1.0f, 0.0f, 1.0f), Vec4(0.3f, 0.0f, 1.0f, 1.0f),
102     Vec4(0.1f, 1.0f, 1.0f, 1.0f), Vec4(0.8f, 1.0f, 0.0f, 1.0f), Vec4(0.5f, 0.0f, 1.0f, 1.0f),
103     Vec4(0.2f, 0.0f, 0.0f, 1.0f), Vec4(1.0f, 1.0f, 0.0f, 1.0f),
104 };
105 
106 struct CaseDef
107 {
108     PipelineConstructionType pipelineConstructionType;
109     VkImageViewType viewType;
110     IVec4 imageSizeHint; //!< (w, h, d, layers), a component may have a symbolic value MAX_SIZE
111     VkFormat colorFormat;
112     VkFormat depthStencilFormat; //! A depth/stencil format, or UNDEFINED if not used
113     AllocationKind allocationKind;
114 };
115 
116 template <typename T>
makeSharedPtr(Move<T> move)117 inline SharedPtr<Unique<T>> makeSharedPtr(Move<T> move)
118 {
119     return SharedPtr<Unique<T>>(new Unique<T>(move));
120 }
121 
122 template <typename T>
sizeInBytes(const vector<T> & vec)123 inline VkDeviceSize sizeInBytes(const vector<T> &vec)
124 {
125     return vec.size() * sizeof(vec[0]);
126 }
127 
isCube(const VkImageViewType viewType)128 inline bool isCube(const VkImageViewType viewType)
129 {
130     return (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
131 }
132 
product(const IVec4 & v)133 inline VkDeviceSize product(const IVec4 &v)
134 {
135     return ((static_cast<VkDeviceSize>(v.x()) * v.y()) * v.z()) * v.w();
136 }
137 
138 template <typename T>
sum(const vector<T> & v)139 inline T sum(const vector<T> &v)
140 {
141     T total = static_cast<T>(0);
142     for (typename vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
143         total += *it;
144     return total;
145 }
146 
147 template <typename T, int Size>
findIndexOfMaxComponent(const tcu::Vector<T,Size> & vec)148 int findIndexOfMaxComponent(const tcu::Vector<T, Size> &vec)
149 {
150     int index = 0;
151     T value   = vec[0];
152 
153     for (int i = 1; i < Size; ++i)
154     {
155         if (vec[i] > value)
156         {
157             index = i;
158             value = vec[i];
159         }
160     }
161 
162     return index;
163 }
164 
maxLayersOrDepth(const IVec4 & size)165 inline int maxLayersOrDepth(const IVec4 &size)
166 {
167     // This is safe because 3D images must have layers (w) = 1
168     return deMax32(size.z(), size.w());
169 }
170 
bindBuffer(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkBuffer & buffer,const MemoryRequirement requirement,Allocator & allocator,AllocationKind allocationKind)171 de::MovePtr<Allocation> bindBuffer(const InstanceInterface &vki, const DeviceInterface &vkd,
172                                    const VkPhysicalDevice &physDevice, const VkDevice device, const VkBuffer &buffer,
173                                    const MemoryRequirement requirement, Allocator &allocator,
174                                    AllocationKind allocationKind)
175 {
176     switch (allocationKind)
177     {
178     case ALLOCATION_KIND_SUBALLOCATED:
179     {
180         return vk::bindBuffer(vkd, device, allocator, buffer, requirement);
181     }
182 
183     case ALLOCATION_KIND_DEDICATED:
184     {
185         return bindBufferDedicated(vki, vkd, physDevice, device, buffer, requirement);
186     }
187 
188     default:
189     {
190         TCU_THROW(InternalError, "Invalid allocation kind");
191     }
192     }
193 }
194 
bindImage(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkImage & image,const MemoryRequirement requirement,Allocator & allocator,AllocationKind allocationKind)195 de::MovePtr<Allocation> bindImage(const InstanceInterface &vki, const DeviceInterface &vkd,
196                                   const VkPhysicalDevice &physDevice, const VkDevice device, const VkImage &image,
197                                   const MemoryRequirement requirement, Allocator &allocator,
198                                   AllocationKind allocationKind)
199 {
200     switch (allocationKind)
201     {
202     case ALLOCATION_KIND_SUBALLOCATED:
203     {
204         return vk::bindImage(vkd, device, allocator, image, requirement);
205     }
206 
207     case ALLOCATION_KIND_DEDICATED:
208     {
209         return bindImageDedicated(vki, vkd, physDevice, device, image, requirement);
210     }
211 
212     default:
213     {
214         TCU_THROW(InternalError, "Invalid allocation kind");
215     }
216     }
217 }
218 
219 // This is very test specific, so be careful if you want to reuse this code.
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,const VkPipeline basePipeline,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const IVec2 & renderSize,const VkPrimitiveTopology topology,const uint32_t subpass,const bool useDepth,const bool useStencil)220 void preparePipelineWrapper(GraphicsPipelineWrapper &gpw,
221                             const VkPipeline basePipeline, // for derivatives
222                             const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass,
223                             const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule,
224                             const IVec2 &renderSize, const VkPrimitiveTopology topology, const uint32_t subpass,
225                             const bool useDepth, const bool useStencil)
226 {
227     const VkVertexInputBindingDescription vertexInputBindingDescription = {
228         0u,                          // uint32_t binding;
229         sizeof(Vertex4RGBA),         // uint32_t stride;
230         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
231     };
232 
233     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
234         {
235             0u,                            // uint32_t location;
236             0u,                            // uint32_t binding;
237             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
238             0u,                            // uint32_t offset;
239         },
240         {
241             1u,                            // uint32_t location;
242             0u,                            // uint32_t binding;
243             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
244             sizeof(Vec4),                  // uint32_t offset;
245         }};
246 
247     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
248         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
249         DE_NULL,                                                   // const void* pNext;
250         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags flags;
251         1u,                                                        // uint32_t vertexBindingDescriptionCount;
252         &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
253         DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount;
254         vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
255     };
256 
257     const std::vector<VkViewport> viewport{makeViewport(renderSize)};
258     const std::vector<VkRect2D> scissor{makeRect2D(renderSize)};
259 
260     const VkStencilOpState stencilOpState =
261         makeStencilOpState(VK_STENCIL_OP_KEEP,                              // stencil fail
262                            VK_STENCIL_OP_KEEP,                              // depth & stencil pass
263                            VK_STENCIL_OP_KEEP,                              // depth only fail
264                            VK_COMPARE_OP_EQUAL,                             // compare op
265                            ~0u,                                             // compare mask
266                            ~0u,                                             // write mask
267                            static_cast<uint32_t>(REFERENCE_STENCIL_VALUE)); // reference
268 
269     VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = {
270         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
271         DE_NULL,                                                    // const void* pNext;
272         (VkPipelineDepthStencilStateCreateFlags)0,                  // VkPipelineDepthStencilStateCreateFlags flags;
273         useDepth,                                                   // VkBool32 depthTestEnable;
274         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
275         VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
276         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
277         useStencil,                                                 // VkBool32 stencilTestEnable;
278         stencilOpState,                                             // VkStencilOpState front;
279         stencilOpState,                                             // VkStencilOpState back;
280         0.0f,                                                       // float minDepthBounds;
281         1.0f,                                                       // float maxDepthBounds;
282     };
283 
284     const VkColorComponentFlags colorComponentsAll =
285         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
286     // Number of blend attachments must equal the number of color attachments during any subpass.
287     const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {
288         VK_FALSE,             // VkBool32 blendEnable;
289         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcColorBlendFactor;
290         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
291         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
292         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcAlphaBlendFactor;
293         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
294         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
295         colorComponentsAll,   // VkColorComponentFlags colorWriteMask;
296     };
297 
298     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = {
299         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
300         DE_NULL,                                                  // const void* pNext;
301         (VkPipelineColorBlendStateCreateFlags)0,                  // VkPipelineColorBlendStateCreateFlags flags;
302         VK_FALSE,                                                 // VkBool32 logicOpEnable;
303         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
304         1u,                                                       // uint32_t attachmentCount;
305         &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
306         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
307     };
308 
309     gpw.setDefaultTopology(topology)
310         .setDefaultRasterizationState()
311         .setDefaultMultisampleState()
312         .setupVertexInputState(&vertexInputStateInfo)
313         .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, renderPass, subpass, vertexModule)
314         .setupFragmentShaderState(pipelineLayout, renderPass, subpass, fragmentModule, &pipelineDepthStencilStateInfo)
315         .setupFragmentOutputState(renderPass, subpass, &pipelineColorBlendStateInfo)
316         .setMonolithicPipelineLayout(pipelineLayout)
317         .buildPipeline(DE_NULL, basePipeline, -1);
318 }
319 
320 //! Make a render pass with one subpass per color attachment and depth/stencil attachment (if used).
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const VkFormat colorFormat,const VkFormat depthStencilFormat,const uint32_t numLayers,const VkImageLayout initialColorImageLayout=VK_IMAGE_LAYOUT_UNDEFINED,const VkImageLayout initialDepthStencilImageLayout=VK_IMAGE_LAYOUT_UNDEFINED)321 RenderPassWrapper makeRenderPass(const DeviceInterface &vk, const VkDevice device,
322                                  const PipelineConstructionType pipelineConstructionType, const VkFormat colorFormat,
323                                  const VkFormat depthStencilFormat, const uint32_t numLayers,
324                                  const VkImageLayout initialColorImageLayout        = VK_IMAGE_LAYOUT_UNDEFINED,
325                                  const VkImageLayout initialDepthStencilImageLayout = VK_IMAGE_LAYOUT_UNDEFINED)
326 {
327     const VkAttachmentDescription colorAttachmentDescription = {
328         (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags flags;
329         colorFormat,                              // VkFormat format;
330         VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
331         VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
332         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
333         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
334         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
335         initialColorImageLayout,                  // VkImageLayout initialLayout;
336         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
337     };
338     vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
339 
340     const VkAttachmentDescription depthStencilAttachmentDescription = {
341         (VkAttachmentDescriptionFlags)0,                  // VkAttachmentDescriptionFlags flags;
342         depthStencilFormat,                               // VkFormat format;
343         VK_SAMPLE_COUNT_1_BIT,                            // VkSampleCountFlagBits samples;
344         VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp loadOp;
345         VK_ATTACHMENT_STORE_OP_DONT_CARE,                 // VkAttachmentStoreOp storeOp;
346         VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp stencilLoadOp;
347         VK_ATTACHMENT_STORE_OP_DONT_CARE,                 // VkAttachmentStoreOp stencilStoreOp;
348         initialDepthStencilImageLayout,                   // VkImageLayout initialLayout;
349         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
350     };
351 
352     if (depthStencilFormat != VK_FORMAT_UNDEFINED)
353         attachmentDescriptions.insert(attachmentDescriptions.end(), numLayers, depthStencilAttachmentDescription);
354 
355     // Create a subpass for each attachment (each attachement is a layer of an arrayed image).
356     vector<VkAttachmentReference> colorAttachmentReferences(numLayers);
357     vector<VkAttachmentReference> depthStencilAttachmentReferences(numLayers);
358     vector<VkSubpassDescription> subpasses;
359 
360     // Ordering here must match the framebuffer attachments
361     for (uint32_t i = 0; i < numLayers; ++i)
362     {
363         const VkAttachmentReference attachmentRef = {
364             i,                                       // uint32_t attachment;
365             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
366         };
367         const VkAttachmentReference depthStencilAttachmentRef = {
368             i + numLayers,                                   // uint32_t attachment;
369             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout;
370         };
371 
372         colorAttachmentReferences[i]        = attachmentRef;
373         depthStencilAttachmentReferences[i] = depthStencilAttachmentRef;
374 
375         const VkAttachmentReference *pDepthStencilAttachment =
376             (depthStencilFormat != VK_FORMAT_UNDEFINED ? &depthStencilAttachmentReferences[i] : DE_NULL);
377         const VkSubpassDescription subpassDescription = {
378             (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags flags;
379             VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
380             0u,                              // uint32_t inputAttachmentCount;
381             DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
382             1u,                              // uint32_t colorAttachmentCount;
383             &colorAttachmentReferences[i],   // const VkAttachmentReference* pColorAttachments;
384             DE_NULL,                         // const VkAttachmentReference* pResolveAttachments;
385             pDepthStencilAttachment,         // const VkAttachmentReference* pDepthStencilAttachment;
386             0u,                              // uint32_t preserveAttachmentCount;
387             DE_NULL                          // const uint32_t* pPreserveAttachments;
388         };
389         subpasses.push_back(subpassDescription);
390     }
391 
392     const VkRenderPassCreateInfo renderPassInfo = {
393         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,            // VkStructureType sType;
394         DE_NULL,                                              // const void* pNext;
395         (VkRenderPassCreateFlags)0,                           // VkRenderPassCreateFlags flags;
396         static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount;
397         &attachmentDescriptions[0],                           // const VkAttachmentDescription* pAttachments;
398         static_cast<uint32_t>(subpasses.size()),              // uint32_t subpassCount;
399         &subpasses[0],                                        // const VkSubpassDescription* pSubpasses;
400         0u,                                                   // uint32_t dependencyCount;
401         DE_NULL                                               // const VkSubpassDependency* pDependencies;
402     };
403 
404     return RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
405 }
406 
makeImage(const DeviceInterface & vk,const VkDevice device,VkImageCreateFlags flags,VkImageType imageType,const VkFormat format,const IVec3 & size,const uint32_t numMipLevels,const uint32_t numLayers,const VkImageUsageFlags usage)407 Move<VkImage> makeImage(const DeviceInterface &vk, const VkDevice device, VkImageCreateFlags flags,
408                         VkImageType imageType, const VkFormat format, const IVec3 &size, const uint32_t numMipLevels,
409                         const uint32_t numLayers, const VkImageUsageFlags usage)
410 {
411     const VkImageCreateInfo imageParams = {
412         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
413         DE_NULL,                             // const void* pNext;
414         flags,                               // VkImageCreateFlags flags;
415         imageType,                           // VkImageType imageType;
416         format,                              // VkFormat format;
417         makeExtent3D(size),                  // VkExtent3D extent;
418         numMipLevels,                        // uint32_t mipLevels;
419         numLayers,                           // uint32_t arrayLayers;
420         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
421         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
422         usage,                               // VkImageUsageFlags usage;
423         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
424         0u,                                  // uint32_t queueFamilyIndexCount;
425         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
426         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
427     };
428     return createImage(vk, device, &imageParams);
429 }
430 
makeColorSubresourceRange(const int baseArrayLayer,const int layerCount)431 inline VkImageSubresourceRange makeColorSubresourceRange(const int baseArrayLayer, const int layerCount)
432 {
433     return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<uint32_t>(baseArrayLayer),
434                                      static_cast<uint32_t>(layerCount));
435 }
436 
437 //! Get a reference clear value based on color format.
getClearValue(const VkFormat format)438 VkClearValue getClearValue(const VkFormat format)
439 {
440     if (isUintFormat(format) || isIntFormat(format))
441         return makeClearValueColorU32(REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE,
442                                       REFERENCE_COLOR_VALUE);
443     else
444         return makeClearValueColorF32(1.0f, 1.0f, 1.0f, 1.0f);
445 }
446 
getColorFormatStr(const int numComponents,const bool isUint,const bool isSint)447 std::string getColorFormatStr(const int numComponents, const bool isUint, const bool isSint)
448 {
449     std::ostringstream str;
450     if (numComponents == 1)
451         str << (isUint ? "uint" : isSint ? "int" : "float");
452     else
453         str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
454 
455     return str.str();
456 }
457 
458 //! A half-viewport quad. Use with TRIANGLE_STRIP topology.
genFullQuadVertices(const int subpassCount)459 vector<Vertex4RGBA> genFullQuadVertices(const int subpassCount)
460 {
461     vector<Vertex4RGBA> vectorData;
462     for (int subpassNdx = 0; subpassNdx < subpassCount; ++subpassNdx)
463     {
464         Vertex4RGBA data = {
465             Vec4(0.0f, -1.0f, 0.0f, 1.0f),
466             COLOR_TABLE[subpassNdx % DE_LENGTH_OF_ARRAY(COLOR_TABLE)],
467         };
468         vectorData.push_back(data);
469         data.position = Vec4(0.0f, 1.0f, 0.0f, 1.0f);
470         vectorData.push_back(data);
471         data.position = Vec4(1.0f, -1.0f, 0.0f, 1.0f);
472         vectorData.push_back(data);
473         data.position = Vec4(1.0f, 1.0f, 0.0f, 1.0f);
474         vectorData.push_back(data);
475     }
476     return vectorData;
477 }
478 
getImageType(const VkImageViewType viewType)479 VkImageType getImageType(const VkImageViewType viewType)
480 {
481     switch (viewType)
482     {
483     case VK_IMAGE_VIEW_TYPE_1D:
484     case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
485         return VK_IMAGE_TYPE_1D;
486 
487     case VK_IMAGE_VIEW_TYPE_2D:
488     case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
489     case VK_IMAGE_VIEW_TYPE_CUBE:
490     case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
491         return VK_IMAGE_TYPE_2D;
492 
493     case VK_IMAGE_VIEW_TYPE_3D:
494         return VK_IMAGE_TYPE_3D;
495 
496     default:
497         DE_ASSERT(0);
498         return VK_IMAGE_TYPE_LAST;
499     }
500 }
501 
502 //! ImageViewType for accessing a single layer/slice of an image
getImageViewSliceType(const VkImageViewType viewType)503 VkImageViewType getImageViewSliceType(const VkImageViewType viewType)
504 {
505     switch (viewType)
506     {
507     case VK_IMAGE_VIEW_TYPE_1D:
508     case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
509         return VK_IMAGE_VIEW_TYPE_1D;
510 
511     case VK_IMAGE_VIEW_TYPE_2D:
512     case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
513     case VK_IMAGE_VIEW_TYPE_CUBE:
514     case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
515     case VK_IMAGE_VIEW_TYPE_3D:
516         return VK_IMAGE_VIEW_TYPE_2D;
517 
518     default:
519         DE_ASSERT(0);
520         return VK_IMAGE_VIEW_TYPE_LAST;
521     }
522 }
523 
getImageCreateFlags(const VkImageViewType viewType)524 VkImageCreateFlags getImageCreateFlags(const VkImageViewType viewType)
525 {
526     VkImageCreateFlags flags = (VkImageCreateFlags)0;
527 
528     if (viewType == VK_IMAGE_VIEW_TYPE_3D)
529         flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
530     if (isCube(viewType))
531         flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
532 
533     return flags;
534 }
535 
generateExpectedImage(const tcu::PixelBufferAccess & outputImage,const IVec2 & renderSize,const int colorDepthOffset)536 void generateExpectedImage(const tcu::PixelBufferAccess &outputImage, const IVec2 &renderSize,
537                            const int colorDepthOffset)
538 {
539     const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(outputImage.getFormat().type);
540     const bool isInt                            = (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ||
541                         channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
542     const VkClearValue clearValue               = getClearValue(mapTextureFormat(outputImage.getFormat()));
543 
544     if (isInt)
545         tcu::clear(outputImage, IVec4(clearValue.color.int32));
546     else
547         tcu::clear(outputImage, Vec4(clearValue.color.float32));
548 
549     for (int z = 0; z < outputImage.getDepth(); ++z)
550     {
551         const Vec4 &setColor    = COLOR_TABLE[(z + colorDepthOffset) % DE_LENGTH_OF_ARRAY(COLOR_TABLE)];
552         const IVec4 setColorInt = (static_cast<float>(REFERENCE_COLOR_VALUE) * setColor).cast<int32_t>();
553 
554         for (int y = 0; y < renderSize.y(); ++y)
555             for (int x = renderSize.x() / 2; x < renderSize.x(); ++x)
556             {
557                 if (isInt)
558                     outputImage.setPixel(setColorInt, x, y, z);
559                 else
560                     outputImage.setPixel(setColor, x, y, z);
561             }
562     }
563 }
564 
getMaxImageSize(const VkImageViewType viewType,const IVec4 & sizeHint)565 IVec4 getMaxImageSize(const VkImageViewType viewType, const IVec4 &sizeHint)
566 {
567     //Limits have been taken from the vulkan specification
568     IVec4 size = IVec4(sizeHint.x() != MAX_SIZE ? sizeHint.x() : 4096, sizeHint.y() != MAX_SIZE ? sizeHint.y() : 4096,
569                        sizeHint.z() != MAX_SIZE ? sizeHint.z() : 256, sizeHint.w() != MAX_SIZE ? sizeHint.w() : 256);
570 
571     switch (viewType)
572     {
573     case VK_IMAGE_VIEW_TYPE_1D:
574     case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
575         size.x() = deMin32(4096, size.x());
576         break;
577 
578     case VK_IMAGE_VIEW_TYPE_2D:
579     case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
580         size.x() = deMin32(4096, size.x());
581         size.y() = deMin32(4096, size.y());
582         break;
583 
584     case VK_IMAGE_VIEW_TYPE_3D:
585         size.x() = deMin32(256, size.x());
586         size.y() = deMin32(256, size.y());
587         break;
588 
589     case VK_IMAGE_VIEW_TYPE_CUBE:
590     case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
591         size.x() = deMin32(4096, size.x());
592         size.y() = deMin32(4096, size.y());
593         size.w() = deMin32(252, size.w());
594         size.w() = NUM_CUBE_FACES * (size.w() / NUM_CUBE_FACES); // round down to 6 faces
595         break;
596 
597     default:
598         DE_ASSERT(0);
599         return IVec4();
600     }
601 
602     return size;
603 }
604 
605 //! Get a smaller image size. Returns a vector of zeroes, if it can't reduce more.
getReducedImageSize(const CaseDef & caseDef,IVec4 size)606 IVec4 getReducedImageSize(const CaseDef &caseDef, IVec4 size)
607 {
608     const int maxIndex    = findIndexOfMaxComponent(size);
609     const int reducedSize = size[maxIndex] >> 1;
610 
611     switch (caseDef.viewType)
612     {
613     case VK_IMAGE_VIEW_TYPE_CUBE:
614     case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
615         if (maxIndex < 2)
616             size.x() = size.y() = reducedSize;
617         else if (maxIndex == 3 && reducedSize >= NUM_CUBE_FACES)
618             size.w() = NUM_CUBE_FACES * (reducedSize / NUM_CUBE_FACES); // round down to a multiple of 6
619         else
620             size = IVec4(0);
621         break;
622 
623     default:
624         size[maxIndex] = reducedSize;
625         break;
626     }
627 
628     if (reducedSize == 0)
629         size = IVec4(0);
630 
631     return size;
632 }
633 
634 //! Get the image memory requirements for the image size under test, expecting potential image
635 //! creation failure if the required size is larger than the device's maxResourceSize, returning
636 //! false if creation failed.
getSupportedImageMemoryRequirements(Context & context,const CaseDef & caseDef,const VkFormat format,const IVec4 size,const VkImageUsageFlags usage,VkMemoryRequirements & imageMemoryRequiements)637 bool getSupportedImageMemoryRequirements(Context &context, const CaseDef &caseDef, const VkFormat format,
638                                          const IVec4 size, const VkImageUsageFlags usage,
639                                          VkMemoryRequirements &imageMemoryRequiements)
640 {
641     const DeviceInterface &vk  = context.getDeviceInterface();
642     const VkDevice device      = context.getDevice();
643     bool imageCreationPossible = true;
644 
645     try
646     {
647         Move<VkImage> image =
648             makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), format,
649                       size.swizzle(0, 1, 2), 1u, size.w(), usage);
650 
651         vk.getImageMemoryRequirements(device, *image, &imageMemoryRequiements);
652     }
653     // vkCreateImage is allowed to return VK_ERROR_OUT_OF_HOST_MEMORY if the image's
654     // memory requirements will exceed maxResourceSize.
655     catch (const vk::OutOfMemoryError &)
656     {
657         imageCreationPossible = false;
658     }
659 
660     return imageCreationPossible;
661 }
662 
isDepthStencilFormatSupported(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkFormat format)663 bool isDepthStencilFormatSupported(const InstanceInterface &vki, const VkPhysicalDevice physDevice,
664                                    const VkFormat format)
665 {
666     const VkFormatProperties properties = getPhysicalDeviceFormatProperties(vki, physDevice, format);
667     return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
668 }
669 
getFormatAspectFlags(const VkFormat format)670 VkImageAspectFlags getFormatAspectFlags(const VkFormat format)
671 {
672     if (format == VK_FORMAT_UNDEFINED)
673         return 0;
674 
675     const tcu::TextureFormat::ChannelOrder order = mapVkFormat(format).order;
676 
677     switch (order)
678     {
679     case tcu::TextureFormat::DS:
680         return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
681     case tcu::TextureFormat::D:
682         return VK_IMAGE_ASPECT_DEPTH_BIT;
683     case tcu::TextureFormat::S:
684         return VK_IMAGE_ASPECT_STENCIL_BIT;
685     default:
686         return VK_IMAGE_ASPECT_COLOR_BIT;
687     }
688 }
689 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)690 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
691 {
692     const int numComponents = getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
693     const bool isUint       = isUintFormat(caseDef.colorFormat);
694     const bool isSint       = isIntFormat(caseDef.colorFormat);
695 
696     // Vertex shader
697     {
698         std::ostringstream src;
699         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
700             << "\n"
701             << "layout(location = 0) in  vec4 in_position;\n"
702             << "layout(location = 1) in  vec4 in_color;\n"
703             << "layout(location = 0) out vec4 out_color;\n"
704             << "\n"
705             << "out gl_PerVertex {\n"
706             << "    vec4 gl_Position;\n"
707             << "};\n"
708             << "\n"
709             << "void main(void)\n"
710             << "{\n"
711             << "    gl_Position = in_position;\n"
712             << "    out_color = in_color;\n"
713             << "}\n";
714 
715         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
716     }
717 
718     // Fragment shader
719     {
720         std::ostringstream colorValue;
721         colorValue << REFERENCE_COLOR_VALUE;
722         const std::string colorFormat  = getColorFormatStr(numComponents, isUint, isSint);
723         const std::string colorInteger = (isUint || isSint ? " * " + colorFormat + "(" + colorValue.str() + ")" : "");
724 
725         std::ostringstream src;
726         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
727             << "\n"
728             << "layout(location = 0) in  vec4 in_color;\n"
729             << "layout(location = 0) out " << colorFormat << " o_color;\n"
730             << "\n"
731             << "void main(void)\n"
732             << "{\n"
733             << "    o_color = " << colorFormat << "("
734             << (numComponents == 1 ? "in_color.r" :
735                 numComponents == 2 ? "in_color.rg" :
736                 numComponents == 3 ? "in_color.rgb" :
737                                      "in_color")
738             << colorInteger << ");\n"
739             << "}\n";
740 
741         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
742     }
743 }
744 
745 //! See testAttachmentSize() description
testWithSizeReduction(Context & context,const CaseDef & caseDef)746 tcu::TestStatus testWithSizeReduction(Context &context, const CaseDef &caseDef)
747 {
748     const DeviceInterface &vk         = context.getDeviceInterface();
749     const InstanceInterface &vki      = context.getInstanceInterface();
750     const VkDevice device             = context.getDevice();
751     const VkPhysicalDevice physDevice = context.getPhysicalDevice();
752     const VkQueue queue               = context.getUniversalQueue();
753     const uint32_t queueFamilyIndex   = context.getUniversalQueueFamilyIndex();
754     Allocator &allocator              = context.getDefaultAllocator();
755 
756     IVec4 imageSize = getMaxImageSize(caseDef.viewType, caseDef.imageSizeHint);
757 
758     const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
759     const VkImageUsageFlags depthStencilImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
760     const bool useDepthStencil                     = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
761 
762     {
763         VkImageFormatProperties colorImageFormatProperties;
764         const auto result = vki.getPhysicalDeviceImageFormatProperties(
765             physDevice, caseDef.colorFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL, colorImageUsage,
766             getImageCreateFlags(caseDef.viewType), &colorImageFormatProperties);
767 
768         VK_CHECK(result);
769 
770         imageSize.x() = std::min(static_cast<uint32_t>(imageSize.x()), colorImageFormatProperties.maxExtent.width);
771         imageSize.y() = std::min(static_cast<uint32_t>(imageSize.y()), colorImageFormatProperties.maxExtent.height);
772         imageSize.z() = std::min(static_cast<uint32_t>(imageSize.z()), colorImageFormatProperties.maxExtent.depth);
773         imageSize.w() = std::min(static_cast<uint32_t>(imageSize.w()), colorImageFormatProperties.maxArrayLayers);
774     }
775 
776     if (useDepthStencil)
777     {
778         VkImageFormatProperties depthStencilImageFormatProperties;
779         const auto result = vki.getPhysicalDeviceImageFormatProperties(
780             physDevice, caseDef.depthStencilFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL,
781             depthStencilImageUsage, getImageCreateFlags(caseDef.viewType), &depthStencilImageFormatProperties);
782 
783         VK_CHECK(result);
784 
785         imageSize.x() =
786             std::min(static_cast<uint32_t>(imageSize.x()), depthStencilImageFormatProperties.maxExtent.width);
787         imageSize.y() =
788             std::min(static_cast<uint32_t>(imageSize.y()), depthStencilImageFormatProperties.maxExtent.height);
789         imageSize.z() =
790             std::min(static_cast<uint32_t>(imageSize.z()), depthStencilImageFormatProperties.maxExtent.depth);
791         imageSize.w() =
792             std::min(static_cast<uint32_t>(imageSize.w()), depthStencilImageFormatProperties.maxArrayLayers);
793     }
794 
795     bool allocationPossible = false;
796     while (!allocationPossible)
797     {
798         // Get the image memory requirements
799         VkMemoryRequirements colorImageMemReqs;
800         VkDeviceSize neededMemory = 0;
801         uint32_t memoryTypeNdx    = 0;
802 
803         if (!getSupportedImageMemoryRequirements(context, caseDef, caseDef.colorFormat, imageSize, colorImageUsage,
804                                                  colorImageMemReqs))
805         {
806             // Try again with reduced image size
807             imageSize = getReducedImageSize(caseDef, imageSize);
808             if (imageSize == IVec4())
809                 return tcu::TestStatus::fail("Couldn't create an image with required size");
810             else
811                 continue;
812         }
813 
814         neededMemory = colorImageMemReqs.size;
815 
816         if (useDepthStencil)
817         {
818             VkMemoryRequirements depthStencilImageMemReqs;
819 
820             if (!getSupportedImageMemoryRequirements(context, caseDef, caseDef.depthStencilFormat, imageSize,
821                                                      depthStencilImageUsage, depthStencilImageMemReqs))
822             {
823                 // Try again with reduced image size
824                 imageSize = getReducedImageSize(caseDef, imageSize);
825                 if (imageSize == IVec4())
826                     return tcu::TestStatus::fail("Couldn't create an image with required size");
827                 else
828                     continue;
829             }
830 
831             neededMemory += depthStencilImageMemReqs.size;
832         }
833 
834         // Reserve an additional 15% device memory, plus the 512KB for checking results
835         {
836             const VkDeviceSize reserveForChecking = 500ull * 1024ull;
837             const float additionalMemory          = 1.15f;
838             neededMemory =
839                 static_cast<VkDeviceSize>(static_cast<float>(neededMemory) * additionalMemory) + reserveForChecking;
840         }
841 
842         // Query the available memory in the corresponding memory heap
843         {
844             const VkPhysicalDeviceMemoryProperties memoryProperties =
845                 getPhysicalDeviceMemoryProperties(vki, physDevice);
846             // Use the color image memory requirements, assume depth stencil uses the same memory type
847             memoryTypeNdx =
848                 selectMatchingMemoryType(memoryProperties, colorImageMemReqs.memoryTypeBits, MemoryRequirement::Any);
849             tcu::PlatformMemoryLimits memoryLimits;
850             context.getTestContext().getPlatform().getMemoryLimits(memoryLimits);
851             VkDeviceSize maxMemory =
852                 std::min(memoryProperties.memoryHeaps[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].size,
853                          VkDeviceSize(memoryLimits.totalSystemMemory));
854 
855             if (neededMemory > maxMemory)
856             {
857                 // Try again with reduced image size
858                 imageSize = getReducedImageSize(caseDef, imageSize);
859                 if (imageSize == IVec4())
860                     return tcu::TestStatus::fail("Couldn't create an image with required size");
861                 else
862                     continue;
863             }
864         }
865 
866         // Attempt a memory allocation
867         {
868             VkDeviceMemory object                   = 0;
869             const VkMemoryAllocateInfo allocateInfo = {
870                 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, //VkStructureType sType;
871                 DE_NULL,                                //const void* pNext;
872                 neededMemory,                           //VkDeviceSize allocationSize;
873                 memoryTypeNdx                           //uint32_t memoryTypeIndex;
874             };
875 
876             const VkResult result = vk.allocateMemory(device, &allocateInfo, DE_NULL, &object);
877 
878             if (VK_ERROR_OUT_OF_DEVICE_MEMORY == result || VK_ERROR_OUT_OF_HOST_MEMORY == result)
879             {
880                 // Try again with reduced image size
881                 imageSize = getReducedImageSize(caseDef, imageSize);
882                 if (imageSize == IVec4())
883                     return tcu::TestStatus::fail("Couldn't create an image with required size");
884             }
885             else if (VK_SUCCESS != result)
886             {
887                 return tcu::TestStatus::fail("Couldn't allocate memory");
888             }
889             else
890             {
891                 //free memory using Move pointer
892                 Move<VkDeviceMemory> memoryAllocated(check<VkDeviceMemory>(object),
893                                                      Deleter<VkDeviceMemory>(vk, device, DE_NULL));
894                 allocationPossible = true;
895             }
896         }
897     }
898 
899     context.getTestContext().getLog() << tcu::TestLog::Message
900                                       << "Using an image with size (width, height, depth, layers) = " << imageSize
901                                       << tcu::TestLog::EndMessage;
902 
903     // "Slices" is either the depth of a 3D image, or the number of layers of an arrayed image
904     const int32_t numSlices = maxLayersOrDepth(imageSize);
905 
906     // Determine the verification bounds. The checked region will be in the center of the rendered image
907     const IVec4 checkSize   = tcu::min(imageSize, IVec4(MAX_VERIFICATION_REGION_SIZE, MAX_VERIFICATION_REGION_SIZE,
908                                                         MAX_VERIFICATION_REGION_DEPTH, MAX_VERIFICATION_REGION_DEPTH));
909     const IVec4 checkOffset = (imageSize - checkSize) / 2;
910 
911     // Only make enough space for the check region
912     const VkDeviceSize colorBufferSize = product(checkSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
913     const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
914     const UniquePtr<Allocation> colorBufferAlloc(bindBuffer(
915         vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
916 
917     {
918         deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
919         flushAlloc(vk, device, *colorBufferAlloc);
920     }
921 
922     const ShaderWrapper vertexModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
923     const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
924     RenderPassWrapper renderPass(makeRenderPass(vk, device, caseDef.pipelineConstructionType, caseDef.colorFormat,
925                                                 caseDef.depthStencilFormat, static_cast<uint32_t>(numSlices),
926                                                 (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D) ?
927                                                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL :
928                                                     VK_IMAGE_LAYOUT_UNDEFINED));
929     const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device);
930     vector<GraphicsPipelineWrapper> pipelines;
931 
932     Move<VkImage> colorImage;
933     MovePtr<Allocation> colorImageAlloc;
934     vector<SharedPtrVkImageView> colorAttachments;
935     Move<VkImage> depthStencilImage;
936     MovePtr<Allocation> depthStencilImageAlloc;
937     vector<SharedPtrVkImageView> depthStencilAttachments;
938     vector<VkImage> images;
939     vector<VkImageView> attachmentHandles; // all attachments (color and d/s)
940     Move<VkBuffer> vertexBuffer;
941     MovePtr<Allocation> vertexBufferAlloc;
942 
943     // Create a color image
944     {
945         colorImage      = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType),
946                                     caseDef.colorFormat, imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), colorImageUsage);
947         colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator,
948                                     caseDef.allocationKind);
949     }
950 
951     // Create a depth/stencil image (always a 2D image, optionally layered)
952     if (useDepthStencil)
953     {
954         depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
955                                       IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, depthStencilImageUsage);
956         depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any,
957                                            allocator, caseDef.allocationKind);
958     }
959 
960     // Create a vertex buffer
961     {
962         const vector<Vertex4RGBA> vertices  = genFullQuadVertices(numSlices);
963         const VkDeviceSize vertexBufferSize = sizeInBytes(vertices);
964 
965         vertexBuffer      = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
966         vertexBufferAlloc = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible,
967                                        allocator, caseDef.allocationKind);
968 
969         deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
970         flushAlloc(vk, device, *vertexBufferAlloc);
971     }
972 
973     // Prepare color image upfront for rendering to individual slices.  3D slices aren't separate subresources, so they shouldn't be transitioned
974     // during each subpass like array layers.
975     if (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D)
976     {
977         const Unique<VkCommandPool> cmdPool(
978             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
979         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
980 
981         beginCommandBuffer(vk, *cmdBuffer);
982 
983         const VkImageMemoryBarrier imageBarrier = {
984             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType            sType;
985             DE_NULL,                                  // const void*                pNext;
986             (VkAccessFlags)0,                         // VkAccessFlags              srcAccessMask;
987             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // VkAccessFlags              dstAccessMask;
988             VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout              oldLayout;
989             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout              newLayout;
990             VK_QUEUE_FAMILY_IGNORED,                  // uint32_t                   srcQueueFamilyIndex;
991             VK_QUEUE_FAMILY_IGNORED,                  // uint32_t                   dstQueueFamilyIndex;
992             *colorImage,                              // VkImage                    image;
993             {
994                 // VkImageSubresourceRange    subresourceRange;
995                 VK_IMAGE_ASPECT_COLOR_BIT,            // VkImageAspectFlags    aspectMask;
996                 0u,                                   // uint32_t              baseMipLevel;
997                 1u,                                   // uint32_t              levelCount;
998                 0u,                                   // uint32_t              baseArrayLayer;
999                 static_cast<uint32_t>(imageSize.w()), // uint32_t              layerCount;
1000             }};
1001 
1002         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1003                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
1004                               &imageBarrier);
1005 
1006         endCommandBuffer(vk, *cmdBuffer);
1007         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1008     }
1009 
1010     // For each image layer or slice (3D), create an attachment and a pipeline
1011     {
1012         const VkImageAspectFlags depthStencilAspect = getFormatAspectFlags(caseDef.depthStencilFormat);
1013         const bool useDepth                         = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
1014         const bool useStencil                       = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1015         VkPipeline basePipeline                     = DE_NULL;
1016 
1017         // Color attachments are first in the framebuffer
1018         pipelines.reserve(numSlices);
1019         for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1020         {
1021             colorAttachments.push_back(
1022                 makeSharedPtr(makeImageView(vk, device, *colorImage, getImageViewSliceType(caseDef.viewType),
1023                                             caseDef.colorFormat, makeColorSubresourceRange(subpassNdx, 1))));
1024             images.push_back(*colorImage);
1025             attachmentHandles.push_back(**colorAttachments.back());
1026 
1027 #ifndef CTS_USES_VULKANSC // Pipeline derivatives are forbidden in Vulkan SC
1028             // We also have to create pipelines for each subpass
1029             pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1030                                    caseDef.pipelineConstructionType,
1031                                    (basePipeline == DE_NULL ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT :
1032                                                               VK_PIPELINE_CREATE_DERIVATIVE_BIT));
1033 #else
1034             pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1035                                    caseDef.pipelineConstructionType, 0u);
1036 #endif // CTS_USES_VULKANSC
1037             preparePipelineWrapper(pipelines.back(), basePipeline, pipelineLayout, *renderPass, vertexModule,
1038                                    fragmentModule, imageSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1039                                    static_cast<uint32_t>(subpassNdx), useDepth, useStencil);
1040 
1041             if (pipelines.front().wasBuild())
1042                 basePipeline = pipelines.front().getPipeline();
1043         }
1044 
1045         // Then D/S attachments, if any
1046         if (useDepthStencil)
1047             for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1048             {
1049                 depthStencilAttachments.push_back(makeSharedPtr(
1050                     makeImageView(vk, device, *depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat,
1051                                   makeImageSubresourceRange(depthStencilAspect, 0u, 1u, subpassNdx, 1u))));
1052                 images.push_back(*depthStencilImage);
1053                 attachmentHandles.push_back(**depthStencilAttachments.back());
1054             }
1055     }
1056 
1057     renderPass.createFramebuffer(vk, device, static_cast<uint32_t>(attachmentHandles.size()), &images[0],
1058                                  &attachmentHandles[0], static_cast<uint32_t>(imageSize.x()),
1059                                  static_cast<uint32_t>(imageSize.y()));
1060 
1061     {
1062         const Unique<VkCommandPool> cmdPool(
1063             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1064         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1065 
1066         beginCommandBuffer(vk, *cmdBuffer);
1067         {
1068             vector<VkClearValue> clearValues(numSlices, getClearValue(caseDef.colorFormat));
1069 
1070             if (useDepthStencil)
1071                 clearValues.insert(clearValues.end(), numSlices,
1072                                    makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
1073 
1074             const VkDeviceSize vertexBufferOffset = 0ull;
1075 
1076             renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, imageSize.x(), imageSize.y()),
1077                              (uint32_t)clearValues.size(), &clearValues[0]);
1078             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1079         }
1080 
1081         // Draw
1082         for (uint32_t subpassNdx = 0; subpassNdx < static_cast<uint32_t>(numSlices); ++subpassNdx)
1083         {
1084             if (subpassNdx != 0)
1085                 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1086 
1087             pipelines[subpassNdx].bind(*cmdBuffer);
1088             vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx * 4u, 0u);
1089         }
1090 
1091         renderPass.end(vk, *cmdBuffer);
1092 
1093         // Copy colorImage -> host visible colorBuffer
1094         {
1095             const VkImageMemoryBarrier imageBarriers[] = {{
1096                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,     // VkStructureType sType;
1097                 DE_NULL,                                    // const void* pNext;
1098                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,       // VkAccessFlags outputMask;
1099                 VK_ACCESS_TRANSFER_READ_BIT,                // VkAccessFlags inputMask;
1100                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   // VkImageLayout oldLayout;
1101                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,       // VkImageLayout newLayout;
1102                 VK_QUEUE_FAMILY_IGNORED,                    // uint32_t srcQueueFamilyIndex;
1103                 VK_QUEUE_FAMILY_IGNORED,                    // uint32_t destQueueFamilyIndex;
1104                 *colorImage,                                // VkImage image;
1105                 makeColorSubresourceRange(0, imageSize.w()) // VkImageSubresourceRange subresourceRange;
1106             }};
1107 
1108             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1109                                   VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
1110                                   DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
1111 
1112             // Copy the checked region rather than the whole image
1113             const VkImageSubresourceLayers subresource = {
1114                 VK_IMAGE_ASPECT_COLOR_BIT,              // VkImageAspectFlags    aspectMask;
1115                 0u,                                     // uint32_t              mipLevel;
1116                 static_cast<uint32_t>(checkOffset.w()), // uint32_t              baseArrayLayer;
1117                 static_cast<uint32_t>(checkSize.w()),   // uint32_t              layerCount;
1118             };
1119 
1120             const VkBufferImageCopy region = {
1121                 0ull,        // VkDeviceSize                bufferOffset;
1122                 0u,          // uint32_t                    bufferRowLength;
1123                 0u,          // uint32_t                    bufferImageHeight;
1124                 subresource, // VkImageSubresourceLayers    imageSubresource;
1125                 makeOffset3D(checkOffset.x(), checkOffset.y(),
1126                              checkOffset.z()),            // VkOffset3D                  imageOffset;
1127                 makeExtent3D(checkSize.swizzle(0, 1, 2)), // VkExtent3D                  imageExtent;
1128             };
1129 
1130             vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u,
1131                                     &region);
1132 
1133             const VkBufferMemoryBarrier bufferBarriers[] = {
1134                 {
1135                     VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType    sType;
1136                     DE_NULL,                                 // const void*        pNext;
1137                     VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags      srcAccessMask;
1138                     VK_ACCESS_HOST_READ_BIT,                 // VkAccessFlags      dstAccessMask;
1139                     VK_QUEUE_FAMILY_IGNORED,                 // uint32_t           srcQueueFamilyIndex;
1140                     VK_QUEUE_FAMILY_IGNORED,                 // uint32_t           dstQueueFamilyIndex;
1141                     *colorBuffer,                            // VkBuffer           buffer;
1142                     0ull,                                    // VkDeviceSize       offset;
1143                     VK_WHOLE_SIZE,                           // VkDeviceSize       size;
1144                 },
1145             };
1146 
1147             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
1148                                   DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1149         }
1150 
1151         endCommandBuffer(vk, *cmdBuffer);
1152         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1153     }
1154 
1155     // Verify results
1156     {
1157         invalidateAlloc(vk, device, *colorBufferAlloc);
1158 
1159         const tcu::TextureFormat format = mapVkFormat(caseDef.colorFormat);
1160         const int checkDepth            = maxLayersOrDepth(checkSize);
1161         const int depthOffset           = maxLayersOrDepth(checkOffset);
1162         const tcu::ConstPixelBufferAccess resultImage(format, checkSize.x(), checkSize.y(), checkDepth,
1163                                                       colorBufferAlloc->getHostPtr());
1164         tcu::TextureLevel textureLevel(format, checkSize.x(), checkSize.y(), checkDepth);
1165         const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
1166         bool ok                                    = false;
1167 
1168         generateExpectedImage(expectedImage, checkSize.swizzle(0, 1), depthOffset);
1169 
1170         if (isFloatFormat(caseDef.colorFormat))
1171             ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage,
1172                                             resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1173         else
1174             ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage,
1175                                           resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT);
1176 
1177         return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1178     }
1179 }
1180 
checkImageViewTypeRequirements(Context & context,const VkImageViewType viewType)1181 void checkImageViewTypeRequirements(Context &context, const VkImageViewType viewType)
1182 {
1183 #ifndef CTS_USES_VULKANSC
1184     if (viewType == VK_IMAGE_VIEW_TYPE_3D)
1185     {
1186         if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
1187             !context.getPortabilitySubsetFeatures().imageView2DOn3DImage)
1188         {
1189             TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support 2D or 2D array "
1190                                          "image view to be created on a 3D VkImage");
1191         }
1192 
1193         context.requireDeviceFunctionality("VK_KHR_maintenance1");
1194     }
1195 #endif // CTS_USES_VULKANSC
1196 
1197     if (viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
1198         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
1199 }
1200 
checkSupportAttachmentSize(Context & context,const CaseDef caseDef)1201 void checkSupportAttachmentSize(Context &context, const CaseDef caseDef)
1202 {
1203     const InstanceInterface &vki      = context.getInstanceInterface();
1204     const VkPhysicalDevice physDevice = context.getPhysicalDevice();
1205 
1206     checkImageViewTypeRequirements(context, caseDef.viewType);
1207 
1208     if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
1209         context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
1210 
1211     {
1212         VkImageFormatProperties colorImageFormatProperties;
1213         const auto result = vki.getPhysicalDeviceImageFormatProperties(
1214             physDevice, caseDef.colorFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL,
1215             (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
1216             getImageCreateFlags(caseDef.viewType), &colorImageFormatProperties);
1217 
1218         if (result != VK_SUCCESS)
1219         {
1220             TCU_THROW(NotSupportedError, "Unsupported color attachment format");
1221         }
1222     }
1223 
1224     if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED)
1225     {
1226 
1227         VkImageFormatProperties depthStencilImageFormatProperties;
1228         const auto result = vki.getPhysicalDeviceImageFormatProperties(
1229             physDevice, caseDef.depthStencilFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL,
1230             VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, getImageCreateFlags(caseDef.viewType),
1231             &depthStencilImageFormatProperties);
1232 
1233         if (result != VK_SUCCESS)
1234         {
1235             TCU_THROW(NotSupportedError, "Unsupported depth/stencil attachment format");
1236         }
1237     }
1238 
1239     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1240                                           caseDef.pipelineConstructionType);
1241 }
1242 
1243 //! A test that can exercise very big color and depth/stencil attachment sizes.
1244 //! If the total memory consumed by images is too large, or if the implementation returns OUT_OF_MEMORY error somewhere,
1245 //! the test can be retried with a next increment of size reduction index, making the attachments smaller.
testAttachmentSize(Context & context,const CaseDef caseDef)1246 tcu::TestStatus testAttachmentSize(Context &context, const CaseDef caseDef)
1247 {
1248     return testWithSizeReduction(context, caseDef);
1249     // Never reached
1250 }
1251 
getMipLevelSizes(IVec4 baseSize)1252 vector<IVec4> getMipLevelSizes(IVec4 baseSize)
1253 {
1254     vector<IVec4> levels;
1255     levels.push_back(baseSize);
1256 
1257     while (baseSize.x() != 1 || baseSize.y() != 1 || baseSize.z() != 1)
1258     {
1259         baseSize.x() = deMax32(baseSize.x() >> 1, 1);
1260         baseSize.y() = deMax32(baseSize.y() >> 1, 1);
1261         baseSize.z() = deMax32(baseSize.z() >> 1, 1);
1262         levels.push_back(baseSize);
1263     }
1264 
1265     return levels;
1266 }
1267 
1268 //! Compute memory consumed by each mip level, including all layers. Sizes include a padding for alignment.
getPerMipLevelStorageSize(const vector<IVec4> & mipLevelSizes,const VkDeviceSize pixelSize)1269 vector<VkDeviceSize> getPerMipLevelStorageSize(const vector<IVec4> &mipLevelSizes, const VkDeviceSize pixelSize)
1270 {
1271     const int64_t levelAlignment = 16;
1272     vector<VkDeviceSize> storageSizes;
1273 
1274     for (vector<IVec4>::const_iterator it = mipLevelSizes.begin(); it != mipLevelSizes.end(); ++it)
1275         storageSizes.push_back(deAlign64(pixelSize * product(*it), levelAlignment));
1276 
1277     return storageSizes;
1278 }
1279 
drawToMipLevel(const Context & context,const CaseDef & caseDef,const int mipLevel,const IVec4 & mipSize,const int numSlices,const VkImage colorImage,const VkImage depthStencilImage,const VkBuffer vertexBuffer,const PipelineLayoutWrapper & pipelineLayout,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule)1280 void drawToMipLevel(const Context &context, const CaseDef &caseDef, const int mipLevel, const IVec4 &mipSize,
1281                     const int numSlices, const VkImage colorImage, const VkImage depthStencilImage,
1282                     const VkBuffer vertexBuffer, const PipelineLayoutWrapper &pipelineLayout,
1283                     const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule)
1284 {
1285     const InstanceInterface &vki                = context.getInstanceInterface();
1286     const DeviceInterface &vk                   = context.getDeviceInterface();
1287     const VkPhysicalDevice physDevice           = context.getPhysicalDevice();
1288     const VkDevice device                       = context.getDevice();
1289     const VkQueue queue                         = context.getUniversalQueue();
1290     const uint32_t queueFamilyIndex             = context.getUniversalQueueFamilyIndex();
1291     const VkImageAspectFlags depthStencilAspect = getFormatAspectFlags(caseDef.depthStencilFormat);
1292     const bool useDepth                         = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
1293     const bool useStencil                       = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1294     RenderPassWrapper renderPass(makeRenderPass(vk, device, caseDef.pipelineConstructionType, caseDef.colorFormat,
1295                                                 caseDef.depthStencilFormat, static_cast<uint32_t>(numSlices),
1296                                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1297                                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
1298     vector<GraphicsPipelineWrapper> pipelines;
1299     vector<SharedPtrVkImageView> colorAttachments;
1300     vector<SharedPtrVkImageView> depthStencilAttachments;
1301     vector<VkImage> images;
1302     vector<VkImageView> attachmentHandles; // all attachments (color and d/s)
1303 
1304     // For each image layer or slice (3D), create an attachment and a pipeline
1305     {
1306         VkPipeline basePipeline = DE_NULL;
1307 
1308         // Color attachments are first in the framebuffer
1309         pipelines.reserve(numSlices);
1310         for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1311         {
1312             colorAttachments.push_back(makeSharedPtr(
1313                 makeImageView(vk, device, colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat,
1314                               makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, subpassNdx, 1u))));
1315             images.push_back(colorImage);
1316             attachmentHandles.push_back(**colorAttachments.back());
1317 
1318             // We also have to create pipelines for each subpass
1319 #ifndef CTS_USES_VULKANSC // Pipeline derivatives are forbidden in Vulkan SC
1320             pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1321                                    caseDef.pipelineConstructionType,
1322                                    (basePipeline == DE_NULL ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT :
1323                                                               VK_PIPELINE_CREATE_DERIVATIVE_BIT));
1324 #else
1325             pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1326                                    caseDef.pipelineConstructionType, 0u);
1327 #endif // CTS_USES_VULKANSC
1328             preparePipelineWrapper(pipelines.back(), basePipeline, pipelineLayout, *renderPass, vertexModule,
1329                                    fragmentModule, mipSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1330                                    static_cast<uint32_t>(subpassNdx), useDepth, useStencil);
1331 
1332             if (pipelines.front().wasBuild())
1333                 basePipeline = pipelines.front().getPipeline();
1334         }
1335 
1336         // Then D/S attachments, if any
1337         if (useDepth || useStencil)
1338             for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1339             {
1340                 depthStencilAttachments.push_back(makeSharedPtr(
1341                     makeImageView(vk, device, depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat,
1342                                   makeImageSubresourceRange(depthStencilAspect, mipLevel, 1u, subpassNdx, 1u))));
1343                 images.push_back(depthStencilImage);
1344                 attachmentHandles.push_back(**depthStencilAttachments.back());
1345             }
1346     }
1347 
1348     renderPass.createFramebuffer(vk, device, static_cast<uint32_t>(attachmentHandles.size()), &images[0],
1349                                  &attachmentHandles[0], static_cast<uint32_t>(mipSize.x()),
1350                                  static_cast<uint32_t>(mipSize.y()));
1351 
1352     {
1353         const Unique<VkCommandPool> cmdPool(
1354             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1355         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1356 
1357         beginCommandBuffer(vk, *cmdBuffer);
1358         {
1359             vector<VkClearValue> clearValues(numSlices, getClearValue(caseDef.colorFormat));
1360 
1361             if (useDepth || useStencil)
1362                 clearValues.insert(clearValues.end(), numSlices,
1363                                    makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
1364 
1365             const VkDeviceSize vertexBufferOffset = 0ull;
1366 
1367             renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, mipSize.x(), mipSize.y()), (uint32_t)clearValues.size(),
1368                              &clearValues[0]);
1369             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
1370         }
1371 
1372         // Draw
1373         for (uint32_t subpassNdx = 0; subpassNdx < static_cast<uint32_t>(numSlices); ++subpassNdx)
1374         {
1375             if (subpassNdx != 0)
1376                 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1377 
1378             pipelines[subpassNdx].bind(*cmdBuffer);
1379             vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx * 4u, 0u);
1380         }
1381 
1382         renderPass.end(vk, *cmdBuffer);
1383 
1384         endCommandBuffer(vk, *cmdBuffer);
1385         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1386     }
1387 }
1388 
checkSupportRenderToMipMaps(Context & context,const CaseDef caseDef)1389 void checkSupportRenderToMipMaps(Context &context, const CaseDef caseDef)
1390 {
1391     checkImageViewTypeRequirements(context, caseDef.viewType);
1392 
1393     if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
1394         context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
1395 
1396     if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED &&
1397         !isDepthStencilFormatSupported(context.getInstanceInterface(), context.getPhysicalDevice(),
1398                                        caseDef.depthStencilFormat))
1399         TCU_THROW(NotSupportedError, "Unsupported depth/stencil format");
1400 
1401     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1402                                           caseDef.pipelineConstructionType);
1403 }
1404 
1405 //! Use image mip levels as attachments
testRenderToMipMaps(Context & context,const CaseDef caseDef)1406 tcu::TestStatus testRenderToMipMaps(Context &context, const CaseDef caseDef)
1407 {
1408     const DeviceInterface &vk         = context.getDeviceInterface();
1409     const InstanceInterface &vki      = context.getInstanceInterface();
1410     const VkDevice device             = context.getDevice();
1411     const VkPhysicalDevice physDevice = context.getPhysicalDevice();
1412     const VkQueue queue               = context.getUniversalQueue();
1413     const uint32_t queueFamilyIndex   = context.getUniversalQueueFamilyIndex();
1414     Allocator &allocator              = context.getDefaultAllocator();
1415 
1416     const IVec4 imageSize             = caseDef.imageSizeHint; // MAX_SIZE is not used in this test
1417     const int32_t numSlices           = maxLayersOrDepth(imageSize);
1418     const vector<IVec4> mipLevelSizes = getMipLevelSizes(imageSize);
1419     const vector<VkDeviceSize> mipLevelStorageSizes =
1420         getPerMipLevelStorageSize(mipLevelSizes, tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)));
1421     const int numMipLevels     = static_cast<int>(mipLevelSizes.size());
1422     const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
1423 
1424     // Create a color buffer big enough to hold all layers and mip levels
1425     const VkDeviceSize colorBufferSize = sum(mipLevelStorageSizes);
1426     const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1427     const UniquePtr<Allocation> colorBufferAlloc(bindBuffer(
1428         vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
1429 
1430     {
1431         deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
1432         flushAlloc(vk, device, *colorBufferAlloc);
1433     }
1434 
1435     const ShaderWrapper vertexModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
1436     const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
1437     const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device);
1438 
1439     Move<VkImage> colorImage;
1440     MovePtr<Allocation> colorImageAlloc;
1441     Move<VkImage> depthStencilImage;
1442     MovePtr<Allocation> depthStencilImageAlloc;
1443     Move<VkBuffer> vertexBuffer;
1444     MovePtr<Allocation> vertexBufferAlloc;
1445 
1446     // Create a color image
1447     {
1448         const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1449 
1450         colorImage =
1451             makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType),
1452                       caseDef.colorFormat, imageSize.swizzle(0, 1, 2), numMipLevels, imageSize.w(), imageUsage);
1453         colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator,
1454                                     caseDef.allocationKind);
1455     }
1456 
1457     // Create a depth/stencil image (always a 2D image, optionally layered)
1458     if (useDepthStencil)
1459     {
1460         const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1461 
1462         depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
1463                                       IVec3(imageSize.x(), imageSize.y(), 1), numMipLevels, numSlices, imageUsage);
1464         depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any,
1465                                            allocator, caseDef.allocationKind);
1466     }
1467 
1468     // Create a vertex buffer
1469     {
1470         const vector<Vertex4RGBA> vertices  = genFullQuadVertices(numSlices);
1471         const VkDeviceSize vertexBufferSize = sizeInBytes(vertices);
1472 
1473         vertexBuffer      = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1474         vertexBufferAlloc = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible,
1475                                        allocator, caseDef.allocationKind);
1476 
1477         deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
1478         flushAlloc(vk, device, *vertexBufferAlloc);
1479     }
1480 
1481     // Prepare images
1482     {
1483         const Unique<VkCommandPool> cmdPool(
1484             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1485         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1486 
1487         beginCommandBuffer(vk, *cmdBuffer);
1488 
1489         const VkImageMemoryBarrier imageBarriers[] = {
1490             {
1491                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType            sType;
1492                 DE_NULL,                                  // const void*                pNext;
1493                 (VkAccessFlags)0,                         // VkAccessFlags              srcAccessMask;
1494                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // VkAccessFlags              dstAccessMask;
1495                 VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout              oldLayout;
1496                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout              newLayout;
1497                 VK_QUEUE_FAMILY_IGNORED,                  // uint32_t                   srcQueueFamilyIndex;
1498                 VK_QUEUE_FAMILY_IGNORED,                  // uint32_t                   dstQueueFamilyIndex;
1499                 *colorImage,                              // VkImage                    image;
1500                 {
1501                     // VkImageSubresourceRange    subresourceRange;
1502                     VK_IMAGE_ASPECT_COLOR_BIT,            // VkImageAspectFlags    aspectMask;
1503                     0u,                                   // uint32_t              baseMipLevel;
1504                     static_cast<uint32_t>(numMipLevels),  // uint32_t              levelCount;
1505                     0u,                                   // uint32_t              baseArrayLayer;
1506                     static_cast<uint32_t>(imageSize.w()), // uint32_t              layerCount;
1507                 },
1508             },
1509             {
1510                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,           // VkStructureType            sType;
1511                 DE_NULL,                                          // const void*                pNext;
1512                 (VkAccessFlags)0,                                 // VkAccessFlags              srcAccessMask;
1513                 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,     // VkAccessFlags              dstAccessMask;
1514                 VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout              oldLayout;
1515                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout              newLayout;
1516                 VK_QUEUE_FAMILY_IGNORED,                          // uint32_t                   srcQueueFamilyIndex;
1517                 VK_QUEUE_FAMILY_IGNORED,                          // uint32_t                   dstQueueFamilyIndex;
1518                 *depthStencilImage,                               // VkImage                    image;
1519                 {
1520                     // VkImageSubresourceRange    subresourceRange;
1521                     getFormatAspectFlags(caseDef.depthStencilFormat), // VkImageAspectFlags    aspectMask;
1522                     0u,                                               // uint32_t              baseMipLevel;
1523                     static_cast<uint32_t>(numMipLevels),              // uint32_t              levelCount;
1524                     0u,                                               // uint32_t              baseArrayLayer;
1525                     static_cast<uint32_t>(numSlices),                 // uint32_t              layerCount;
1526                 },
1527             }};
1528 
1529         const uint32_t numImageBarriers =
1530             static_cast<uint32_t>(DE_LENGTH_OF_ARRAY(imageBarriers) - (useDepthStencil ? 0 : 1));
1531 
1532         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1533                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
1534                                   VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
1535                               0u, 0u, DE_NULL, 0u, DE_NULL, numImageBarriers, imageBarriers);
1536 
1537         endCommandBuffer(vk, *cmdBuffer);
1538         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1539     }
1540 
1541     // Draw
1542     for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1543     {
1544         const IVec4 &mipSize  = mipLevelSizes[mipLevel];
1545         const int levelSlices = maxLayersOrDepth(mipSize);
1546 
1547         drawToMipLevel(context, caseDef, mipLevel, mipSize, levelSlices, *colorImage, *depthStencilImage, *vertexBuffer,
1548                        pipelineLayout, vertexModule, fragmentModule);
1549     }
1550 
1551     // Copy results: colorImage -> host visible colorBuffer
1552     {
1553         const Unique<VkCommandPool> cmdPool(
1554             createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1555         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1556 
1557         beginCommandBuffer(vk, *cmdBuffer);
1558 
1559         {
1560             const VkImageMemoryBarrier imageBarriers[] = {{
1561                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType            sType;
1562                 DE_NULL,                                  // const void*                pNext;
1563                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // VkAccessFlags              srcAccessMask;
1564                 VK_ACCESS_TRANSFER_READ_BIT,              // VkAccessFlags              dstAccessMask;
1565                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout              oldLayout;
1566                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,     // VkImageLayout              newLayout;
1567                 VK_QUEUE_FAMILY_IGNORED,                  // uint32_t                   srcQueueFamilyIndex;
1568                 VK_QUEUE_FAMILY_IGNORED,                  // uint32_t                   dstQueueFamilyIndex;
1569                 *colorImage,                              // VkImage                    image;
1570                 {
1571                     // VkImageSubresourceRange    subresourceRange;
1572                     VK_IMAGE_ASPECT_COLOR_BIT,            // VkImageAspectFlags    aspectMask;
1573                     0u,                                   // uint32_t              baseMipLevel;
1574                     static_cast<uint32_t>(numMipLevels),  // uint32_t              levelCount;
1575                     0u,                                   // uint32_t              baseArrayLayer;
1576                     static_cast<uint32_t>(imageSize.w()), // uint32_t              layerCount;
1577                 },
1578             }};
1579 
1580             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1581                                   VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
1582                                   DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
1583         }
1584         {
1585             vector<VkBufferImageCopy> regions;
1586             VkDeviceSize levelOffset     = 0ull;
1587             VkBufferImageCopy workRegion = {
1588                 0ull, // VkDeviceSize                bufferOffset;
1589                 0u,   // uint32_t                    bufferRowLength;
1590                 0u,   // uint32_t                    bufferImageHeight;
1591                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
1592                                            imageSize.w()), // VkImageSubresourceLayers    imageSubresource;
1593                 makeOffset3D(0, 0, 0),                     // VkOffset3D                  imageOffset;
1594                 makeExtent3D(0, 0, 0),                     // VkExtent3D                  imageExtent;
1595             };
1596 
1597             for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1598             {
1599                 workRegion.bufferOffset              = levelOffset;
1600                 workRegion.imageSubresource.mipLevel = static_cast<uint32_t>(mipLevel);
1601                 workRegion.imageExtent               = makeExtent3D(mipLevelSizes[mipLevel].swizzle(0, 1, 2));
1602 
1603                 regions.push_back(workRegion);
1604 
1605                 levelOffset += mipLevelStorageSizes[mipLevel];
1606             }
1607 
1608             vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer,
1609                                     static_cast<uint32_t>(regions.size()), &regions[0]);
1610         }
1611         {
1612             const VkBufferMemoryBarrier bufferBarriers[] = {
1613                 {
1614                     VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType    sType;
1615                     DE_NULL,                                 // const void*        pNext;
1616                     VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags      srcAccessMask;
1617                     VK_ACCESS_HOST_READ_BIT,                 // VkAccessFlags      dstAccessMask;
1618                     VK_QUEUE_FAMILY_IGNORED,                 // uint32_t           srcQueueFamilyIndex;
1619                     VK_QUEUE_FAMILY_IGNORED,                 // uint32_t           dstQueueFamilyIndex;
1620                     *colorBuffer,                            // VkBuffer           buffer;
1621                     0ull,                                    // VkDeviceSize       offset;
1622                     VK_WHOLE_SIZE,                           // VkDeviceSize       size;
1623                 },
1624             };
1625 
1626             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
1627                                   DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1628         }
1629 
1630         endCommandBuffer(vk, *cmdBuffer);
1631         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1632     }
1633 
1634     // Verify results (per mip level)
1635     {
1636         invalidateAlloc(vk, device, *colorBufferAlloc);
1637 
1638         const tcu::TextureFormat format = mapVkFormat(caseDef.colorFormat);
1639 
1640         VkDeviceSize levelOffset = 0ull;
1641         bool allOk               = true;
1642 
1643         for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1644         {
1645             const IVec4 &mipSize         = mipLevelSizes[mipLevel];
1646             const void *const pLevelData = static_cast<const uint8_t *>(colorBufferAlloc->getHostPtr()) + levelOffset;
1647             const int levelDepth         = maxLayersOrDepth(mipSize);
1648             const tcu::ConstPixelBufferAccess resultImage(format, mipSize.x(), mipSize.y(), levelDepth, pLevelData);
1649             tcu::TextureLevel textureLevel(format, mipSize.x(), mipSize.y(), levelDepth);
1650             const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
1651             const std::string comparisonName           = "Mip level " + de::toString(mipLevel);
1652             bool ok                                    = false;
1653 
1654             generateExpectedImage(expectedImage, mipSize.swizzle(0, 1), 0);
1655 
1656             if (isFloatFormat(caseDef.colorFormat))
1657                 ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison",
1658                                                 comparisonName.c_str(), expectedImage, resultImage, tcu::Vec4(0.01f),
1659                                                 tcu::COMPARE_LOG_RESULT);
1660             else
1661                 ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison",
1662                                               comparisonName.c_str(), expectedImage, resultImage, tcu::UVec4(2),
1663                                               tcu::COMPARE_LOG_RESULT);
1664 
1665             allOk = allOk && ok; // keep testing all levels, even if we know it's a fail overall
1666             levelOffset += mipLevelStorageSizes[mipLevel];
1667         }
1668 
1669         return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1670     }
1671 }
1672 
getSizeDescription(const IVec4 & size)1673 std::string getSizeDescription(const IVec4 &size)
1674 {
1675     std::ostringstream str;
1676 
1677     const char *const description[4] = {"width", "height", "depth", "layers"};
1678 
1679     int numMaxComponents = 0;
1680 
1681     for (int i = 0; i < 4; ++i)
1682     {
1683         if (size[i] == MAX_SIZE)
1684         {
1685             if (numMaxComponents > 0)
1686                 str << "_";
1687 
1688             str << description[i];
1689             ++numMaxComponents;
1690         }
1691     }
1692 
1693     if (numMaxComponents == 0)
1694         str << "small";
1695 
1696     return str.str();
1697 }
1698 
getFormatString(const VkFormat format)1699 inline std::string getFormatString(const VkFormat format)
1700 {
1701     std::string name(getFormatName(format));
1702     return de::toLower(name.substr(10));
1703 }
1704 
getFormatString(const VkFormat colorFormat,const VkFormat depthStencilFormat)1705 std::string getFormatString(const VkFormat colorFormat, const VkFormat depthStencilFormat)
1706 {
1707     std::ostringstream str;
1708     str << getFormatString(colorFormat);
1709     if (depthStencilFormat != VK_FORMAT_UNDEFINED)
1710         str << "_" << getFormatString(depthStencilFormat);
1711     return str.str();
1712 }
1713 
getShortImageViewTypeName(const VkImageViewType imageViewType)1714 std::string getShortImageViewTypeName(const VkImageViewType imageViewType)
1715 {
1716     std::string s(getImageViewTypeName(imageViewType));
1717     return de::toLower(s.substr(19));
1718 }
1719 
bvecFromMask(uint32_t mask)1720 inline BVec4 bvecFromMask(uint32_t mask)
1721 {
1722     return BVec4((mask >> 0) & 1, (mask >> 1) & 1, (mask >> 2) & 1, (mask >> 3) & 1);
1723 }
1724 
genSizeCombinations(const IVec4 & baselineSize,const uint32_t sizeMask,const VkImageViewType imageViewType)1725 vector<IVec4> genSizeCombinations(const IVec4 &baselineSize, const uint32_t sizeMask,
1726                                   const VkImageViewType imageViewType)
1727 {
1728     vector<IVec4> sizes;
1729     std::set<uint32_t> masks;
1730 
1731     for (uint32_t i = 0; i < (1u << 4); ++i)
1732     {
1733         // Cube images have square faces
1734         if (isCube(imageViewType) && ((i & MASK_WH) != 0))
1735             i |= MASK_WH;
1736 
1737         masks.insert(i & sizeMask);
1738     }
1739 
1740     for (std::set<uint32_t>::const_iterator it = masks.begin(); it != masks.end(); ++it)
1741         sizes.push_back(tcu::select(IVec4(MAX_SIZE), baselineSize, bvecFromMask(*it)));
1742 
1743     return sizes;
1744 }
1745 
addTestCasesWithFunctions(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType,AllocationKind allocationKind)1746 void addTestCasesWithFunctions(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType,
1747                                AllocationKind allocationKind)
1748 {
1749     const struct
1750     {
1751         VkImageViewType viewType;
1752         IVec4 baselineSize; //!< image size: (dimX, dimY, dimZ, arraySize)
1753         uint32_t sizeMask;  //!< if a dimension is masked, generate a huge size case for it
1754     } testCase[] = {
1755         {VK_IMAGE_VIEW_TYPE_1D, IVec4(54, 1, 1, 1), MASK_W},
1756         {VK_IMAGE_VIEW_TYPE_1D_ARRAY, IVec4(54, 1, 1, 4), MASK_W_LAYERS},
1757         {VK_IMAGE_VIEW_TYPE_2D, IVec4(44, 23, 1, 1), MASK_WH},
1758         {VK_IMAGE_VIEW_TYPE_2D_ARRAY, IVec4(44, 23, 1, 4), MASK_WH_LAYERS},
1759         {VK_IMAGE_VIEW_TYPE_3D, IVec4(22, 31, 7, 1), MASK_WHD},
1760         {VK_IMAGE_VIEW_TYPE_CUBE, IVec4(35, 35, 1, 6), MASK_WH},
1761         {VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, IVec4(35, 35, 1, 2 * 6), MASK_WH_LAYERS},
1762     };
1763 
1764     const VkFormat format[] = {VK_FORMAT_R8G8B8A8_UNORM,
1765                                VK_FORMAT_R32_UINT,
1766                                VK_FORMAT_R16G16_SINT,
1767                                VK_FORMAT_R32G32B32A32_SFLOAT,
1768                                VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1769                                VK_FORMAT_R5G6B5_UNORM_PACK16,
1770                                VK_FORMAT_A2B10G10R10_UINT_PACK32,
1771                                VK_FORMAT_A2B10G10R10_UNORM_PACK32};
1772 
1773     const VkFormat depthStencilFormat[] = {
1774         VK_FORMAT_UNDEFINED, // don't use a depth/stencil attachment
1775         VK_FORMAT_D16_UNORM,          VK_FORMAT_S8_UINT,
1776         VK_FORMAT_D24_UNORM_S8_UINT, // one of the following mixed formats must be supported
1777         VK_FORMAT_D32_SFLOAT_S8_UINT,
1778     };
1779 
1780     for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCase); ++caseNdx)
1781     {
1782         MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(
1783             group->getTestContext(), getShortImageViewTypeName(testCase[caseNdx].viewType).c_str()));
1784 
1785         // Generate attachment size cases
1786         {
1787             vector<IVec4> sizes = genSizeCombinations(testCase[caseNdx].baselineSize, testCase[caseNdx].sizeMask,
1788                                                       testCase[caseNdx].viewType);
1789 
1790 #ifdef CTS_USES_VULKANSC
1791             // filter out sizes in which width and height is equal to maximimum values
1792             sizes.erase(std::remove_if(begin(sizes), end(sizes),
1793                                        [&](const IVec4 &v) { return v.x() == MAX_SIZE && v.y() == MAX_SIZE; }),
1794                         end(sizes));
1795 #endif // CTS_USES_VULKANSC
1796 
1797             MovePtr<tcu::TestCaseGroup> smallGroup(new tcu::TestCaseGroup(group->getTestContext(), "small"));
1798             MovePtr<tcu::TestCaseGroup> hugeGroup(new tcu::TestCaseGroup(group->getTestContext(), "huge"));
1799 
1800             imageGroup->addChild(smallGroup.get());
1801             imageGroup->addChild(hugeGroup.get());
1802 
1803             for (vector<IVec4>::const_iterator sizeIter = sizes.begin(); sizeIter != sizes.end(); ++sizeIter)
1804             {
1805                 // The first size is the baseline size, put it in a dedicated group
1806                 if (sizeIter == sizes.begin())
1807                 {
1808                     for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1809                         for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
1810                         {
1811                             const CaseDef caseDef{
1812                                 pipelineConstructionType,        // PipelineConstructionType pipelineConstructionType;
1813                                 testCase[caseNdx].viewType,      // VkImageViewType imageType;
1814                                 *sizeIter,                       // IVec4 imageSizeHint;
1815                                 format[formatNdx],               // VkFormat colorFormat;
1816                                 depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat;
1817                                 allocationKind                   // AllocationKind allocationKind;
1818                             };
1819                             addFunctionCaseWithPrograms(
1820                                 smallGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]),
1821                                 checkSupportAttachmentSize, initPrograms, testAttachmentSize, caseDef);
1822                         }
1823                 }
1824                 else // All huge cases go into a separate group
1825                 {
1826                     if (allocationKind != ALLOCATION_KIND_DEDICATED)
1827                     {
1828                         MovePtr<tcu::TestCaseGroup> sizeGroup(
1829                             new tcu::TestCaseGroup(group->getTestContext(), getSizeDescription(*sizeIter).c_str()));
1830                         const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
1831 
1832                         // Use the same color format for all cases, to reduce the number of permutations
1833                         for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1834                         {
1835                             const CaseDef caseDef{
1836                                 pipelineConstructionType,        // PipelineConstructionType pipelineConstructionType;
1837                                 testCase[caseNdx].viewType,      // VkImageViewType viewType;
1838                                 *sizeIter,                       // IVec4 imageSizeHint;
1839                                 colorFormat,                     // VkFormat colorFormat;
1840                                 depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat;
1841                                 allocationKind                   // AllocationKind allocationKind;
1842                             };
1843                             addFunctionCaseWithPrograms(
1844                                 sizeGroup.get(), getFormatString(colorFormat, depthStencilFormat[dsFormatNdx]),
1845                                 checkSupportAttachmentSize, initPrograms, testAttachmentSize, caseDef);
1846                         }
1847                         hugeGroup->addChild(sizeGroup.release());
1848                     }
1849                 }
1850             }
1851             smallGroup.release();
1852             hugeGroup.release();
1853         }
1854 
1855         // Generate mip map cases
1856         {
1857             MovePtr<tcu::TestCaseGroup> mipmapGroup(new tcu::TestCaseGroup(group->getTestContext(), "mipmap"));
1858 
1859             for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1860                 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
1861                 {
1862                     const CaseDef caseDef{
1863                         pipelineConstructionType,        // PipelineConstructionType pipelineConstructionType;
1864                         testCase[caseNdx].viewType,      // VkImageViewType imageType;
1865                         testCase[caseNdx].baselineSize,  // IVec4 imageSizeHint;
1866                         format[formatNdx],               // VkFormat colorFormat;
1867                         depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat;
1868                         allocationKind                   // AllocationKind allocationKind;
1869                     };
1870                     addFunctionCaseWithPrograms(
1871                         mipmapGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]),
1872                         checkSupportRenderToMipMaps, initPrograms, testRenderToMipMaps, caseDef);
1873                 }
1874             imageGroup->addChild(mipmapGroup.release());
1875         }
1876 
1877         group->addChild(imageGroup.release());
1878     }
1879 }
1880 
addCoreRenderToImageTests(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)1881 void addCoreRenderToImageTests(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType)
1882 {
1883     addTestCasesWithFunctions(group, pipelineConstructionType, ALLOCATION_KIND_SUBALLOCATED);
1884 }
1885 
addDedicatedAllocationRenderToImageTests(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)1886 void addDedicatedAllocationRenderToImageTests(tcu::TestCaseGroup *group,
1887                                               PipelineConstructionType pipelineConstructionType)
1888 {
1889     addTestCasesWithFunctions(group, pipelineConstructionType, ALLOCATION_KIND_DEDICATED);
1890 }
1891 
1892 } // namespace
1893 
createRenderToImageTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1894 tcu::TestCaseGroup *createRenderToImageTests(tcu::TestContext &testCtx,
1895                                              PipelineConstructionType pipelineConstructionType)
1896 {
1897     de::MovePtr<tcu::TestCaseGroup> renderToImageTests(new tcu::TestCaseGroup(testCtx, "render_to_image"));
1898 
1899     // Core render to image tests
1900     renderToImageTests->addChild(createTestGroup(testCtx, "core", addCoreRenderToImageTests, pipelineConstructionType));
1901     // Render to image tests for dedicated memory allocation
1902     renderToImageTests->addChild(createTestGroup(testCtx, "dedicated_allocation",
1903                                                  addDedicatedAllocationRenderToImageTests, pipelineConstructionType));
1904 
1905     return renderToImageTests.release();
1906 }
1907 
1908 } // namespace pipeline
1909 } // namespace vkt
1910