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