Merge "Touch watchdog before freeing objs in max_concurrent" into oc-dev am: 47e683efe5
[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                                                                                                                                                                  (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
922                                                                                                                                                                                                                                                          : VK_IMAGE_LAYOUT_UNDEFINED));
923         const Unique<VkPipelineLayout>  pipelineLayout  (makePipelineLayout                     (vk, device));
924         vector<SharedPtrVkPipeline>             pipelines;
925
926         Move<VkImage>                                   colorImage;
927         MovePtr<Allocation>                             colorImageAlloc;
928         vector<SharedPtrVkImageView>    colorAttachments;
929         Move<VkImage>                                   depthStencilImage;
930         MovePtr<Allocation>                             depthStencilImageAlloc;
931         vector<SharedPtrVkImageView>    depthStencilAttachments;
932         vector<VkImageView>                             attachmentHandles;                      // all attachments (color and d/s)
933         Move<VkBuffer>                                  vertexBuffer;
934         MovePtr<Allocation>                             vertexBufferAlloc;
935         Move<VkFramebuffer>                             framebuffer;
936
937         // Create a color image
938         {
939                 const VkImageUsageFlags imageUsage      = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
940
941                 colorImage              = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat,
942                                                                         imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), imageUsage);
943                 colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
944         }
945
946         // Create a depth/stencil image (always a 2D image, optionally layered)
947         if (useDepthStencil)
948         {
949                 const VkImageUsageFlags imageUsage      = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
950
951                 depthStencilImage               = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
952                                                                                         IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, imageUsage);
953                 depthStencilImageAlloc  = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
954         }
955
956         // Create a vertex buffer
957         {
958                 const vector<Vertex4RGBA>       vertices                        = genFullQuadVertices(numSlices);
959                 const VkDeviceSize                      vertexBufferSize        = sizeInBytes(vertices);
960
961                 vertexBuffer            = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
962                 vertexBufferAlloc       = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind);
963
964                 deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
965                 flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
966         }
967
968         // Prepare color image upfront for rendering to individual slices.  3D slices aren't separate subresources, so they shouldn't be transitioned
969         // during each subpass like array layers.
970         if (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D)
971         {
972                 const Unique<VkCommandPool>             cmdPool         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
973                 const Unique<VkCommandBuffer>   cmdBuffer       (makeCommandBuffer(vk, device, *cmdPool));
974
975                 beginCommandBuffer(vk, *cmdBuffer);
976
977                 const VkImageMemoryBarrier      imageBarrier    =
978                 {
979                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                         // VkStructureType            sType;
980                         DE_NULL,                                                                                        // const void*                pNext;
981                         (VkAccessFlags)0,                                                                       // VkAccessFlags              srcAccessMask;
982                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,                           // VkAccessFlags              dstAccessMask;
983                         VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout              oldLayout;
984                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout              newLayout;
985                         VK_QUEUE_FAMILY_IGNORED,                                                        // uint32_t                   srcQueueFamilyIndex;
986                         VK_QUEUE_FAMILY_IGNORED,                                                        // uint32_t                   dstQueueFamilyIndex;
987                         *colorImage,                                                                            // VkImage                    image;
988                         {                                                                                                       // VkImageSubresourceRange    subresourceRange;
989                                 VK_IMAGE_ASPECT_COLOR_BIT,                                                      // VkImageAspectFlags    aspectMask;
990                                 0u,                                                                                                     // uint32_t              baseMipLevel;
991                                 1u,                                                                                                     // uint32_t              levelCount;
992                                 0u,                                                                                                     // uint32_t              baseArrayLayer;
993                                 static_cast<deUint32>(imageSize.w()),                           // uint32_t              layerCount;
994                         }
995                 };
996
997                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
998                                                                 0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
999
1000                 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1001                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1002         }
1003
1004         // For each image layer or slice (3D), create an attachment and a pipeline
1005         {
1006                 const VkImageAspectFlags        depthStencilAspect              = getFormatAspectFlags(caseDef.depthStencilFormat);
1007                 const bool                                      useDepth                                = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT)   != 0;
1008                 const bool                                      useStencil                              = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1009                 VkPipeline                                      basePipeline                    = DE_NULL;
1010
1011                 // Color attachments are first in the framebuffer
1012                 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1013                 {
1014                         colorAttachments.push_back(makeSharedPtr(
1015                                 makeImageView(vk, device, *colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat, makeColorSubresourceRange(subpassNdx, 1))));
1016                         attachmentHandles.push_back(**colorAttachments.back());
1017
1018                         // We also have to create pipelines for each subpass
1019                         pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(
1020                                 vk, device, basePipeline, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, imageSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1021                                 static_cast<deUint32>(subpassNdx), useDepth, useStencil)));
1022
1023                         basePipeline = **pipelines.front();
1024                 }
1025
1026                 // Then D/S attachments, if any
1027                 if (useDepthStencil)
1028                 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1029                 {
1030                         depthStencilAttachments.push_back(makeSharedPtr(
1031                                 makeImageView(vk, device, *depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat, makeImageSubresourceRange(depthStencilAspect, 0u, 1u, subpassNdx, 1u))));
1032                         attachmentHandles.push_back(**depthStencilAttachments.back());
1033                 }
1034         }
1035
1036         framebuffer = makeFramebuffer(vk, device, *renderPass, static_cast<deUint32>(attachmentHandles.size()), &attachmentHandles[0], static_cast<deUint32>(imageSize.x()), static_cast<deUint32>(imageSize.y()));
1037
1038         {
1039                 const Unique<VkCommandPool>             cmdPool         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1040                 const Unique<VkCommandBuffer>   cmdBuffer       (makeCommandBuffer(vk, device, *cmdPool));
1041
1042                 beginCommandBuffer(vk, *cmdBuffer);
1043                 {
1044                         vector<VkClearValue>    clearValues     (numSlices, getClearValue(caseDef.colorFormat));
1045
1046                         if (useDepthStencil)
1047                                 clearValues.insert(clearValues.end(), numSlices, makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
1048
1049                         const VkRect2D                  renderArea      =
1050                         {
1051                                 makeOffset2D(0, 0),
1052                                 makeExtent2D(imageSize.x(), imageSize.y()),
1053                         };
1054                         const VkRenderPassBeginInfo     renderPassBeginInfo     =
1055                         {
1056                                 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,       // VkStructureType         sType;
1057                                 DE_NULL,                                                                        // const void*             pNext;
1058                                 *renderPass,                                                            // VkRenderPass            renderPass;
1059                                 *framebuffer,                                                           // VkFramebuffer           framebuffer;
1060                                 renderArea,                                                                     // VkRect2D                renderArea;
1061                                 static_cast<deUint32>(clearValues.size()),      // uint32_t                clearValueCount;
1062                                 &clearValues[0],                                                        // const VkClearValue*     pClearValues;
1063                         };
1064                         const VkDeviceSize              vertexBufferOffset      = 0ull;
1065
1066                         vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1067                         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1068                 }
1069
1070                 // Draw
1071                 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(numSlices); ++subpassNdx)
1072                 {
1073                         if (subpassNdx != 0)
1074                                 vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1075
1076                         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]);
1077                         vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx*4u, 0u);
1078                 }
1079
1080                 vk.cmdEndRenderPass(*cmdBuffer);
1081
1082                 // Copy colorImage -> host visible colorBuffer
1083                 {
1084                         const VkImageMemoryBarrier      imageBarriers[] =
1085                         {
1086                                 {
1087                                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                 // VkStructureType                      sType;
1088                                         DE_NULL,                                                                                // const void*                          pNext;
1089                                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,                   // VkAccessFlags                        outputMask;
1090                                         VK_ACCESS_TRANSFER_READ_BIT,                                    // VkAccessFlags                        inputMask;
1091                                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               // VkImageLayout                        oldLayout;
1092                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                   // VkImageLayout                        newLayout;
1093                                         VK_QUEUE_FAMILY_IGNORED,                                                // deUint32                                     srcQueueFamilyIndex;
1094                                         VK_QUEUE_FAMILY_IGNORED,                                                // deUint32                                     destQueueFamilyIndex;
1095                                         *colorImage,                                                                    // VkImage                                      image;
1096                                         makeColorSubresourceRange(0, imageSize.w())             // VkImageSubresourceRange      subresourceRange;
1097                                 }
1098                         };
1099
1100                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1101                                                                   0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
1102
1103                         // Copy the checked region rather than the whole image
1104                         const VkImageSubresourceLayers  subresource     =
1105                         {
1106                                 VK_IMAGE_ASPECT_COLOR_BIT,                                                      // VkImageAspectFlags    aspectMask;
1107                                 0u,                                                                                                     // uint32_t              mipLevel;
1108                                 static_cast<deUint32>(checkOffset.w()),                         // uint32_t              baseArrayLayer;
1109                                 static_cast<deUint32>(checkSize.w()),                           // uint32_t              layerCount;
1110                         };
1111
1112                         const VkBufferImageCopy                 region          =
1113                         {
1114                                 0ull,                                                                                                                           // VkDeviceSize                bufferOffset;
1115                                 0u,                                                                                                                                     // uint32_t                    bufferRowLength;
1116                                 0u,                                                                                                                                     // uint32_t                    bufferImageHeight;
1117                                 subresource,                                                                                                            // VkImageSubresourceLayers    imageSubresource;
1118                                 makeOffset3D(checkOffset.x(), checkOffset.y(), checkOffset.z()),        // VkOffset3D                  imageOffset;
1119                                 makeExtent3D(checkSize.swizzle(0, 1, 2)),                                                       // VkExtent3D                  imageExtent;
1120                         };
1121
1122                         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &region);
1123
1124                         const VkBufferMemoryBarrier     bufferBarriers[] =
1125                         {
1126                                 {
1127                                         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,        // VkStructureType    sType;
1128                                         DE_NULL,                                                                        // const void*        pNext;
1129                                         VK_ACCESS_TRANSFER_WRITE_BIT,                           // VkAccessFlags      srcAccessMask;
1130                                         VK_ACCESS_HOST_READ_BIT,                                        // VkAccessFlags      dstAccessMask;
1131                                         VK_QUEUE_FAMILY_IGNORED,                                        // uint32_t           srcQueueFamilyIndex;
1132                                         VK_QUEUE_FAMILY_IGNORED,                                        // uint32_t           dstQueueFamilyIndex;
1133                                         *colorBuffer,                                                           // VkBuffer           buffer;
1134                                         0ull,                                                                           // VkDeviceSize       offset;
1135                                         VK_WHOLE_SIZE,                                                          // VkDeviceSize       size;
1136                                 },
1137                         };
1138
1139                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1140                                                                   0u, DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1141                 }
1142
1143                 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1144                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1145         }
1146
1147         // Verify results
1148         {
1149                 invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1150
1151                 const tcu::TextureFormat                        format                  = mapVkFormat(caseDef.colorFormat);
1152                 const int                                                       checkDepth              = maxLayersOrDepth(checkSize);
1153                 const int                                                       depthOffset             = maxLayersOrDepth(checkOffset);
1154                 const tcu::ConstPixelBufferAccess       resultImage             (format, checkSize.x(), checkSize.y(), checkDepth, colorBufferAlloc->getHostPtr());
1155                 tcu::TextureLevel                                       textureLevel    (format, checkSize.x(), checkSize.y(), checkDepth);
1156                 const tcu::PixelBufferAccess            expectedImage   = textureLevel.getAccess();
1157                 bool                                                            ok                              = false;
1158
1159                 generateExpectedImage(expectedImage, checkSize.swizzle(0, 1), depthOffset);
1160
1161                 if (isFloatFormat(caseDef.colorFormat))
1162                         ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1163                 else
1164                         ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT);
1165
1166                 return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1167         }
1168 }
1169
1170 void checkImageViewTypeRequirements (Context& context, const VkImageViewType viewType)
1171 {
1172         if (viewType == VK_IMAGE_VIEW_TYPE_3D &&
1173                 !de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_maintenance1"))
1174                 TCU_THROW(NotSupportedError, "Extension VK_KHR_maintenance1 not supported");
1175
1176         if (viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && !context.getDeviceFeatures().imageCubeArray)
1177                 TCU_THROW(NotSupportedError, "Missing feature: imageCubeArray");
1178 }
1179
1180 //! A test that can exercise very big color and depth/stencil attachment sizes.
1181 //! If the total memory consumed by images is too large, or if the implementation returns OUT_OF_MEMORY error somewhere,
1182 //! the test can be retried with a next increment of size reduction index, making the attachments smaller.
1183 tcu::TestStatus testAttachmentSize (Context& context, const CaseDef caseDef)
1184 {
1185         checkImageViewTypeRequirements(context, caseDef.viewType);
1186
1187         int sizeReductionIndex = 0;
1188
1189         if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
1190         {
1191                 const std::string extensionName("VK_KHR_dedicated_allocation");
1192
1193                 if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName))
1194                         TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str());
1195         }
1196
1197         for (;;)
1198         {
1199                 try
1200                 {
1201                         return testWithSizeReduction(context, caseDef, sizeReductionIndex);
1202                 }
1203                 catch (OutOfMemoryError& ex)
1204                 {
1205                         context.getTestContext().getLog()
1206                                 << tcu::TestLog::Message << "-- OutOfMemoryError: " << ex.getMessage() << tcu::TestLog::EndMessage;
1207
1208                         ++sizeReductionIndex;
1209                 }
1210         }
1211         // Never reached
1212 }
1213
1214 vector<IVec4> getMipLevelSizes (IVec4 baseSize)
1215 {
1216         vector<IVec4> levels;
1217         levels.push_back(baseSize);
1218
1219         while (baseSize.x() != 1 || baseSize.y() != 1 || baseSize.z() != 1)
1220         {
1221                 baseSize.x() = deMax32(baseSize.x() >> 1, 1);
1222                 baseSize.y() = deMax32(baseSize.y() >> 1, 1);
1223                 baseSize.z() = deMax32(baseSize.z() >> 1, 1);
1224                 levels.push_back(baseSize);
1225         }
1226
1227         return levels;
1228 }
1229
1230 //! Compute memory consumed by each mip level, including all layers. Sizes include a padding for alignment.
1231 vector<VkDeviceSize> getPerMipLevelStorageSize (const vector<IVec4>& mipLevelSizes, const VkDeviceSize pixelSize)
1232 {
1233         const deInt64                   levelAlignment  = 16;
1234         vector<VkDeviceSize>    storageSizes;
1235
1236         for (vector<IVec4>::const_iterator it = mipLevelSizes.begin(); it != mipLevelSizes.end(); ++it)
1237                 storageSizes.push_back(deAlign64(pixelSize * product(*it), levelAlignment));
1238
1239         return storageSizes;
1240 }
1241
1242 void drawToMipLevel (const Context&                             context,
1243                                          const CaseDef&                         caseDef,
1244                                          const int                                      mipLevel,
1245                                          const IVec4&                           mipSize,
1246                                          const int                                      numSlices,
1247                                          const VkImage                          colorImage,
1248                                          const VkImage                          depthStencilImage,
1249                                          const VkBuffer                         vertexBuffer,
1250                                          const VkPipelineLayout         pipelineLayout,
1251                                          const VkShaderModule           vertexModule,
1252                                          const VkShaderModule           fragmentModule)
1253 {
1254         const DeviceInterface&                  vk                                      = context.getDeviceInterface();
1255         const VkDevice                                  device                          = context.getDevice();
1256         const VkQueue                                   queue                           = context.getUniversalQueue();
1257         const deUint32                                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
1258         const VkImageAspectFlags                depthStencilAspect      = getFormatAspectFlags(caseDef.depthStencilFormat);
1259         const bool                                              useDepth                        = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT)   != 0;
1260         const bool                                              useStencil                      = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1261         const Unique<VkRenderPass>              renderPass                      (makeRenderPass(vk, device, caseDef.colorFormat, caseDef.depthStencilFormat, static_cast<deUint32>(numSlices),
1262                                                                                                                                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1263                                                                                                                                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
1264         vector<SharedPtrVkPipeline>             pipelines;
1265         vector<SharedPtrVkImageView>    colorAttachments;
1266         vector<SharedPtrVkImageView>    depthStencilAttachments;
1267         vector<VkImageView>                             attachmentHandles;                      // all attachments (color and d/s)
1268
1269         // For each image layer or slice (3D), create an attachment and a pipeline
1270         {
1271                 VkPipeline                                      basePipeline                    = DE_NULL;
1272
1273                 // Color attachments are first in the framebuffer
1274                 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1275                 {
1276                         colorAttachments.push_back(makeSharedPtr(makeImageView(
1277                                 vk, device, colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat,
1278                                 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, subpassNdx, 1u))));
1279                         attachmentHandles.push_back(**colorAttachments.back());
1280
1281                         // We also have to create pipelines for each subpass
1282                         pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(
1283                                 vk, device, basePipeline, pipelineLayout, *renderPass, vertexModule, fragmentModule, mipSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1284                                 static_cast<deUint32>(subpassNdx), useDepth, useStencil)));
1285
1286                         basePipeline = **pipelines.front();
1287                 }
1288
1289                 // Then D/S attachments, if any
1290                 if (useDepth || useStencil)
1291                 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1292                 {
1293                         depthStencilAttachments.push_back(makeSharedPtr(makeImageView(
1294                                 vk, device, depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat,
1295                                 makeImageSubresourceRange(depthStencilAspect, mipLevel, 1u, subpassNdx, 1u))));
1296                         attachmentHandles.push_back(**depthStencilAttachments.back());
1297                 }
1298         }
1299
1300         const Unique<VkFramebuffer>                     framebuffer (makeFramebuffer(vk, device, *renderPass, static_cast<deUint32>(attachmentHandles.size()), &attachmentHandles[0],
1301                                                                                                                                          static_cast<deUint32>(mipSize.x()), static_cast<deUint32>(mipSize.y())));
1302
1303         {
1304                 const Unique<VkCommandPool>             cmdPool         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1305                 const Unique<VkCommandBuffer>   cmdBuffer       (makeCommandBuffer(vk, device, *cmdPool));
1306
1307                 beginCommandBuffer(vk, *cmdBuffer);
1308                 {
1309                         vector<VkClearValue>    clearValues     (numSlices, getClearValue(caseDef.colorFormat));
1310
1311                         if (useDepth || useStencil)
1312                                 clearValues.insert(clearValues.end(), numSlices, makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
1313
1314                         const VkRect2D                  renderArea      =
1315                         {
1316                                 makeOffset2D(0, 0),
1317                                 makeExtent2D(mipSize.x(), mipSize.y()),
1318                         };
1319                         const VkRenderPassBeginInfo     renderPassBeginInfo     =
1320                         {
1321                                 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,       // VkStructureType         sType;
1322                                 DE_NULL,                                                                        // const void*             pNext;
1323                                 *renderPass,                                                            // VkRenderPass            renderPass;
1324                                 *framebuffer,                                                           // VkFramebuffer           framebuffer;
1325                                 renderArea,                                                                     // VkRect2D                renderArea;
1326                                 static_cast<deUint32>(clearValues.size()),      // uint32_t                clearValueCount;
1327                                 &clearValues[0],                                                        // const VkClearValue*     pClearValues;
1328                         };
1329                         const VkDeviceSize              vertexBufferOffset      = 0ull;
1330
1331                         vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1332                         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
1333                 }
1334
1335                 // Draw
1336                 for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(numSlices); ++subpassNdx)
1337                 {
1338                         if (subpassNdx != 0)
1339                                 vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1340
1341                         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]);
1342                         vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx*4u, 0u);
1343                 }
1344
1345                 vk.cmdEndRenderPass(*cmdBuffer);
1346
1347                 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1348                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1349         }
1350 }
1351
1352 //! Use image mip levels as attachments
1353 tcu::TestStatus testRenderToMipMaps (Context& context, const CaseDef caseDef)
1354 {
1355         checkImageViewTypeRequirements(context, caseDef.viewType);
1356
1357         const DeviceInterface&                  vk                                      = context.getDeviceInterface();
1358         const InstanceInterface&                vki                                     = context.getInstanceInterface();
1359         const VkDevice                                  device                          = context.getDevice();
1360         const VkPhysicalDevice                  physDevice                      = context.getPhysicalDevice();
1361         const VkQueue                                   queue                           = context.getUniversalQueue();
1362         const deUint32                                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
1363         Allocator&                                              allocator                       = context.getDefaultAllocator();
1364
1365         const IVec4                                             imageSize                               = caseDef.imageSizeHint;        // MAX_SIZE is not used in this test
1366         const deInt32                                   numSlices                               = maxLayersOrDepth(imageSize);
1367         const vector<IVec4>                             mipLevelSizes                   = getMipLevelSizes(imageSize);
1368         const vector<VkDeviceSize>              mipLevelStorageSizes    = getPerMipLevelStorageSize(mipLevelSizes, tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)));
1369         const int                                               numMipLevels                    = static_cast<int>(mipLevelSizes.size());
1370         const bool                                              useDepthStencil                 = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
1371
1372         if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
1373         {
1374                 const std::string extensionName("VK_KHR_dedicated_allocation");
1375
1376                 if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName))
1377                         TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str());
1378         }
1379
1380         if (useDepthStencil && !isDepthStencilFormatSupported(vki, physDevice, caseDef.depthStencilFormat))
1381                 TCU_THROW(NotSupportedError, "Unsupported depth/stencil format");
1382
1383         // Create a color buffer big enough to hold all layers and mip levels
1384         const VkDeviceSize                              colorBufferSize         = sum(mipLevelStorageSizes);
1385         const Unique<VkBuffer>                  colorBuffer                     (makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1386         const UniquePtr<Allocation>             colorBufferAlloc        (bindBuffer(vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
1387
1388         {
1389                 deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
1390                 flushMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1391         }
1392
1393         const Unique<VkShaderModule>    vertexModule            (createShaderModule     (vk, device, context.getBinaryCollection().get("vert"), 0u));
1394         const Unique<VkShaderModule>    fragmentModule          (createShaderModule     (vk, device, context.getBinaryCollection().get("frag"), 0u));
1395         const Unique<VkPipelineLayout>  pipelineLayout          (makePipelineLayout     (vk, device));
1396
1397         Move<VkImage>                                   colorImage;
1398         MovePtr<Allocation>                             colorImageAlloc;
1399         Move<VkImage>                                   depthStencilImage;
1400         MovePtr<Allocation>                             depthStencilImageAlloc;
1401         Move<VkBuffer>                                  vertexBuffer;
1402         MovePtr<Allocation>                             vertexBufferAlloc;
1403
1404         // Create a color image
1405         {
1406                 const VkImageUsageFlags imageUsage      = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1407
1408                 colorImage              = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat,
1409                                                                         imageSize.swizzle(0, 1, 2), numMipLevels, imageSize.w(), imageUsage);
1410                 colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
1411         }
1412
1413         // Create a depth/stencil image (always a 2D image, optionally layered)
1414         if (useDepthStencil)
1415         {
1416                 const VkImageUsageFlags imageUsage      = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1417
1418                 depthStencilImage               = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
1419                                                                                         IVec3(imageSize.x(), imageSize.y(), 1), numMipLevels, numSlices, imageUsage);
1420                 depthStencilImageAlloc  = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
1421         }
1422
1423         // Create a vertex buffer
1424         {
1425                 const vector<Vertex4RGBA>       vertices                        = genFullQuadVertices(numSlices);
1426                 const VkDeviceSize                      vertexBufferSize        = sizeInBytes(vertices);
1427
1428                 vertexBuffer            = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1429                 vertexBufferAlloc       = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind);
1430
1431                 deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
1432                 flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
1433         }
1434
1435         // Prepare images
1436         {
1437                 const Unique<VkCommandPool>             cmdPool         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1438                 const Unique<VkCommandBuffer>   cmdBuffer       (makeCommandBuffer(vk, device, *cmdPool));
1439
1440                 beginCommandBuffer(vk, *cmdBuffer);
1441
1442                 const VkImageMemoryBarrier      imageBarriers[] =
1443                 {
1444                         {
1445                                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                         // VkStructureType            sType;
1446                                 DE_NULL,                                                                                        // const void*                pNext;
1447                                 (VkAccessFlags)0,                                                                       // VkAccessFlags              srcAccessMask;
1448                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,                           // VkAccessFlags              dstAccessMask;
1449                                 VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout              oldLayout;
1450                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout              newLayout;
1451                                 VK_QUEUE_FAMILY_IGNORED,                                                        // uint32_t                   srcQueueFamilyIndex;
1452                                 VK_QUEUE_FAMILY_IGNORED,                                                        // uint32_t                   dstQueueFamilyIndex;
1453                                 *colorImage,                                                                            // VkImage                    image;
1454                                 {                                                                                                       // VkImageSubresourceRange    subresourceRange;
1455                                         VK_IMAGE_ASPECT_COLOR_BIT,                                                      // VkImageAspectFlags    aspectMask;
1456                                         0u,                                                                                                     // uint32_t              baseMipLevel;
1457                                         static_cast<deUint32>(numMipLevels),                            // uint32_t              levelCount;
1458                                         0u,                                                                                                     // uint32_t              baseArrayLayer;
1459                                         static_cast<deUint32>(imageSize.w()),                           // uint32_t              layerCount;
1460                                 },
1461                         },
1462                         {
1463                                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                         // VkStructureType            sType;
1464                                 DE_NULL,                                                                                        // const void*                pNext;
1465                                 (VkAccessFlags)0,                                                                       // VkAccessFlags              srcAccessMask;
1466                                 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,           // VkAccessFlags              dstAccessMask;
1467                                 VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout              oldLayout;
1468                                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,       // VkImageLayout              newLayout;
1469                                 VK_QUEUE_FAMILY_IGNORED,                                                        // uint32_t                   srcQueueFamilyIndex;
1470                                 VK_QUEUE_FAMILY_IGNORED,                                                        // uint32_t                   dstQueueFamilyIndex;
1471                                 *depthStencilImage,                                                                     // VkImage                    image;
1472                                 {                                                                                                       // VkImageSubresourceRange    subresourceRange;
1473                                         getFormatAspectFlags(caseDef.depthStencilFormat),       // VkImageAspectFlags    aspectMask;
1474                                         0u,                                                                                                     // uint32_t              baseMipLevel;
1475                                         static_cast<deUint32>(numMipLevels),                            // uint32_t              levelCount;
1476                                         0u,                                                                                                     // uint32_t              baseArrayLayer;
1477                                         static_cast<deUint32>(numSlices),                                       // uint32_t              layerCount;
1478                                 },
1479                         }
1480                 };
1481
1482                 const deUint32  numImageBarriers = static_cast<deUint32>(DE_LENGTH_OF_ARRAY(imageBarriers) - (useDepthStencil ? 0 : 1));
1483
1484                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
1485                                                                 0u, DE_NULL, 0u, DE_NULL, numImageBarriers, imageBarriers);
1486
1487                 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1488                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1489         }
1490
1491         // Draw
1492         for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1493         {
1494                 const IVec4&    mipSize         = mipLevelSizes[mipLevel];
1495                 const int               levelSlices     = maxLayersOrDepth(mipSize);
1496
1497                 drawToMipLevel (context, caseDef, mipLevel, mipSize, levelSlices, *colorImage, *depthStencilImage, *vertexBuffer, *pipelineLayout,
1498                                                 *vertexModule, *fragmentModule);
1499         }
1500
1501         // Copy results: colorImage -> host visible colorBuffer
1502         {
1503                 const Unique<VkCommandPool>             cmdPool         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1504                 const Unique<VkCommandBuffer>   cmdBuffer       (makeCommandBuffer(vk, device, *cmdPool));
1505
1506                 beginCommandBuffer(vk, *cmdBuffer);
1507
1508                 {
1509                         const VkImageMemoryBarrier      imageBarriers[] =
1510                         {
1511                                 {
1512                                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                 // VkStructureType            sType;
1513                                         DE_NULL,                                                                                // const void*                pNext;
1514                                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,                   // VkAccessFlags              srcAccessMask;
1515                                         VK_ACCESS_TRANSFER_READ_BIT,                                    // VkAccessFlags              dstAccessMask;
1516                                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,               // VkImageLayout              oldLayout;
1517                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                   // VkImageLayout              newLayout;
1518                                         VK_QUEUE_FAMILY_IGNORED,                                                // uint32_t                   srcQueueFamilyIndex;
1519                                         VK_QUEUE_FAMILY_IGNORED,                                                // uint32_t                   dstQueueFamilyIndex;
1520                                         *colorImage,                                                                    // VkImage                    image;
1521                                         {                                                                                               // VkImageSubresourceRange    subresourceRange;
1522                                                 VK_IMAGE_ASPECT_COLOR_BIT,                                                      // VkImageAspectFlags    aspectMask;
1523                                                 0u,                                                                                                     // uint32_t              baseMipLevel;
1524                                                 static_cast<deUint32>(numMipLevels),                            // uint32_t              levelCount;
1525                                                 0u,                                                                                                     // uint32_t              baseArrayLayer;
1526                                                 static_cast<deUint32>(imageSize.w()),                           // uint32_t              layerCount;
1527                                         },
1528                                 }
1529                         };
1530
1531                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1532                                                                         0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
1533                 }
1534                 {
1535                         vector<VkBufferImageCopy>       regions;
1536                         VkDeviceSize                            levelOffset = 0ull;
1537                         VkBufferImageCopy                       workRegion      =
1538                         {
1539                                 0ull,                                                                                                                                                           // VkDeviceSize                bufferOffset;
1540                                 0u,                                                                                                                                                                     // uint32_t                    bufferRowLength;
1541                                 0u,                                                                                                                                                                     // uint32_t                    bufferImageHeight;
1542                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageSize.w()),           // VkImageSubresourceLayers    imageSubresource;
1543                                 makeOffset3D(0, 0, 0),                                                                                                                          // VkOffset3D                  imageOffset;
1544                                 makeExtent3D(0, 0, 0),                                                                                                                          // VkExtent3D                  imageExtent;
1545                         };
1546
1547                         for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1548                         {
1549                                 workRegion.bufferOffset                                 = levelOffset;
1550                                 workRegion.imageSubresource.mipLevel    = static_cast<deUint32>(mipLevel);
1551                                 workRegion.imageExtent                                  = makeExtent3D(mipLevelSizes[mipLevel].swizzle(0, 1, 2));
1552
1553                                 regions.push_back(workRegion);
1554
1555                                 levelOffset += mipLevelStorageSizes[mipLevel];
1556                         }
1557
1558                         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, static_cast<deUint32>(regions.size()), &regions[0]);
1559                 }
1560                 {
1561                         const VkBufferMemoryBarrier     bufferBarriers[] =
1562                         {
1563                                 {
1564                                         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,        // VkStructureType    sType;
1565                                         DE_NULL,                                                                        // const void*        pNext;
1566                                         VK_ACCESS_TRANSFER_WRITE_BIT,                           // VkAccessFlags      srcAccessMask;
1567                                         VK_ACCESS_HOST_READ_BIT,                                        // VkAccessFlags      dstAccessMask;
1568                                         VK_QUEUE_FAMILY_IGNORED,                                        // uint32_t           srcQueueFamilyIndex;
1569                                         VK_QUEUE_FAMILY_IGNORED,                                        // uint32_t           dstQueueFamilyIndex;
1570                                         *colorBuffer,                                                           // VkBuffer           buffer;
1571                                         0ull,                                                                           // VkDeviceSize       offset;
1572                                         VK_WHOLE_SIZE,                                                          // VkDeviceSize       size;
1573                                 },
1574                         };
1575
1576                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1577                                                                         0u, DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1578                 }
1579
1580                 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1581                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1582         }
1583
1584         // Verify results (per mip level)
1585         {
1586                 invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1587
1588                 const tcu::TextureFormat                        format                  = mapVkFormat(caseDef.colorFormat);
1589
1590                 VkDeviceSize                                            levelOffset             = 0ull;
1591                 bool                                                            allOk                   = true;
1592
1593                 for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1594                 {
1595                         const IVec4&                                            mipSize                 = mipLevelSizes[mipLevel];
1596                         const void*     const                                   pLevelData              = static_cast<const deUint8*>(colorBufferAlloc->getHostPtr()) + levelOffset;
1597                         const int                                                       levelDepth              = maxLayersOrDepth(mipSize);
1598                         const tcu::ConstPixelBufferAccess       resultImage             (format, mipSize.x(), mipSize.y(), levelDepth, pLevelData);
1599                         tcu::TextureLevel                                       textureLevel    (format, mipSize.x(), mipSize.y(), levelDepth);
1600                         const tcu::PixelBufferAccess            expectedImage   = textureLevel.getAccess();
1601                         const std::string                                       comparisonName  = "Mip level " + de::toString(mipLevel);
1602                         bool                                                            ok                              = false;
1603
1604                         generateExpectedImage(expectedImage, mipSize.swizzle(0, 1), 0);
1605
1606                         if (isFloatFormat(caseDef.colorFormat))
1607                                 ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", comparisonName.c_str(), expectedImage, resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1608                         else
1609                                 ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", comparisonName.c_str(), expectedImage, resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT);
1610
1611                         allOk           =  allOk && ok; // keep testing all levels, even if we know it's a fail overall
1612                         levelOffset += mipLevelStorageSizes[mipLevel];
1613                 }
1614
1615                 return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1616         }
1617 }
1618
1619 std::string getSizeDescription (const IVec4& size)
1620 {
1621         std::ostringstream str;
1622
1623         const char* const description[4] =
1624         {
1625                 "width", "height", "depth", "layers"
1626         };
1627
1628         int numMaxComponents = 0;
1629
1630         for (int i = 0; i < 4; ++i)
1631         {
1632                 if (size[i] == MAX_SIZE)
1633                 {
1634                         if (numMaxComponents > 0)
1635                                 str << "_";
1636
1637                         str << description[i];
1638                         ++numMaxComponents;
1639                 }
1640         }
1641
1642         if (numMaxComponents == 0)
1643                 str << "small";
1644
1645         return str.str();
1646 }
1647
1648 inline std::string getFormatString (const VkFormat format)
1649 {
1650         std::string name(getFormatName(format));
1651         return de::toLower(name.substr(10));
1652 }
1653
1654 std::string getFormatString (const VkFormat colorFormat, const VkFormat depthStencilFormat)
1655 {
1656         std::ostringstream str;
1657         str << getFormatString(colorFormat);
1658         if (depthStencilFormat != VK_FORMAT_UNDEFINED)
1659                 str << "_" << getFormatString(depthStencilFormat);
1660         return str.str();
1661 }
1662
1663 std::string getShortImageViewTypeName (const VkImageViewType imageViewType)
1664 {
1665         std::string s(getImageViewTypeName(imageViewType));
1666         return de::toLower(s.substr(19));
1667 }
1668
1669 inline BVec4 bvecFromMask (deUint32 mask)
1670 {
1671         return BVec4((mask >> 0) & 1,
1672                                  (mask >> 1) & 1,
1673                                  (mask >> 2) & 1,
1674                                  (mask >> 3) & 1);
1675 }
1676
1677 vector<IVec4> genSizeCombinations (const IVec4& baselineSize, const deUint32 sizeMask, const VkImageViewType imageViewType)
1678 {
1679         vector<IVec4>           sizes;
1680         std::set<deUint32>      masks;
1681
1682         for (deUint32 i = 0; i < (1u << 4); ++i)
1683         {
1684                 // Cube images have square faces
1685                 if (isCube(imageViewType) && ((i & MASK_WH) != 0))
1686                         i |= MASK_WH;
1687
1688                 masks.insert(i & sizeMask);
1689         }
1690
1691         for (std::set<deUint32>::const_iterator it = masks.begin(); it != masks.end(); ++it)
1692                 sizes.push_back(tcu::select(IVec4(MAX_SIZE), baselineSize, bvecFromMask(*it)));
1693
1694         return sizes;
1695 }
1696
1697 void addTestCasesWithFunctions (tcu::TestCaseGroup* group, AllocationKind allocationKind)
1698 {
1699         const struct
1700         {
1701                 VkImageViewType         viewType;
1702                 IVec4                           baselineSize;   //!< image size: (dimX, dimY, dimZ, arraySize)
1703                 deUint32                        sizeMask;               //!< if a dimension is masked, generate a huge size case for it
1704         } testCase[] =
1705         {
1706                 { VK_IMAGE_VIEW_TYPE_1D,                        IVec4(54,  1, 1,   1),  MASK_W                  },
1707                 { VK_IMAGE_VIEW_TYPE_1D_ARRAY,          IVec4(54,  1, 1,   4),  MASK_W_LAYERS   },
1708                 { VK_IMAGE_VIEW_TYPE_2D,                        IVec4(44, 23, 1,   1),  MASK_WH                 },
1709                 { VK_IMAGE_VIEW_TYPE_2D_ARRAY,          IVec4(44, 23, 1,   4),  MASK_WH_LAYERS  },
1710                 { VK_IMAGE_VIEW_TYPE_3D,                        IVec4(22, 31, 7,   1),  MASK_WHD                },
1711                 { VK_IMAGE_VIEW_TYPE_CUBE,                      IVec4(35, 35, 1,   6),  MASK_WH                 },
1712                 { VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,        IVec4(35, 35, 1, 2*6),  MASK_WH_LAYERS  },
1713         };
1714
1715         const VkFormat format[] =
1716         {
1717                 VK_FORMAT_R8G8B8A8_UNORM,
1718                 VK_FORMAT_R32_UINT,
1719                 VK_FORMAT_R16G16_SINT,
1720                 VK_FORMAT_R32G32B32A32_SFLOAT,
1721         };
1722
1723         const VkFormat depthStencilFormat[] =
1724         {
1725                 VK_FORMAT_UNDEFINED,                    // don't use a depth/stencil attachment
1726                 VK_FORMAT_D16_UNORM,
1727                 VK_FORMAT_S8_UINT,
1728                 VK_FORMAT_D24_UNORM_S8_UINT,    // one of the following mixed formats must be supported
1729                 VK_FORMAT_D32_SFLOAT_S8_UINT,
1730         };
1731
1732         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCase); ++caseNdx)
1733         {
1734                 MovePtr<tcu::TestCaseGroup>     imageGroup(new tcu::TestCaseGroup(group->getTestContext(), getShortImageViewTypeName(testCase[caseNdx].viewType).c_str(), ""));
1735
1736                 // Generate attachment size cases
1737                 {
1738                         const vector<IVec4> sizes = genSizeCombinations(testCase[caseNdx].baselineSize, testCase[caseNdx].sizeMask, testCase[caseNdx].viewType);
1739
1740                         MovePtr<tcu::TestCaseGroup>     smallGroup(new tcu::TestCaseGroup(group->getTestContext(), "small", ""));
1741                         MovePtr<tcu::TestCaseGroup>     hugeGroup (new tcu::TestCaseGroup(group->getTestContext(), "huge",  ""));
1742
1743                         imageGroup->addChild(smallGroup.get());
1744                         imageGroup->addChild(hugeGroup.get());
1745
1746                         for (vector<IVec4>::const_iterator sizeIter = sizes.begin(); sizeIter != sizes.end(); ++sizeIter)
1747                         {
1748                                 // The first size is the baseline size, put it in a dedicated group
1749                                 if (sizeIter == sizes.begin())
1750                                 {
1751                                         for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1752                                         for (int formatNdx   = 0; formatNdx   < DE_LENGTH_OF_ARRAY(format);             ++formatNdx)
1753                                         {
1754                                                 const CaseDef caseDef =
1755                                                 {
1756                                                         testCase[caseNdx].viewType,                     // VkImageViewType      imageType;
1757                                                         *sizeIter,                                                      // IVec4                        imageSizeHint;
1758                                                         format[formatNdx],                                      // VkFormat                     colorFormat;
1759                                                         depthStencilFormat[dsFormatNdx],        // VkFormat                     depthStencilFormat;
1760                                                         allocationKind                                          // AllocationKind       allocationKind;
1761                                                 };
1762                                                 addFunctionCaseWithPrograms(smallGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]), "", initPrograms, testAttachmentSize, caseDef);
1763                                         }
1764                                 }
1765                                 else // All huge cases go into a separate group
1766                                 {
1767                                         if (allocationKind != ALLOCATION_KIND_DEDICATED)
1768                                         {
1769                                                 MovePtr<tcu::TestCaseGroup>     sizeGroup       (new tcu::TestCaseGroup(group->getTestContext(), getSizeDescription(*sizeIter).c_str(), ""));
1770                                                 const VkFormat                          colorFormat     = VK_FORMAT_R8G8B8A8_UNORM;
1771
1772                                                 // Use the same color format for all cases, to reduce the number of permutations
1773                                                 for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1774                                                 {
1775                                                         const CaseDef caseDef =
1776                                                         {
1777                                                                 testCase[caseNdx].viewType,                     // VkImageViewType      viewType;
1778                                                                 *sizeIter,                                                      // IVec4                        imageSizeHint;
1779                                                                 colorFormat,                                            // VkFormat                     colorFormat;
1780                                                                 depthStencilFormat[dsFormatNdx],        // VkFormat                     depthStencilFormat;
1781                                                                 allocationKind                                          // AllocationKind       allocationKind;
1782                                                         };
1783                                                         addFunctionCaseWithPrograms(sizeGroup.get(), getFormatString(colorFormat, depthStencilFormat[dsFormatNdx]), "", initPrograms, testAttachmentSize, caseDef);
1784                                                 }
1785                                                 hugeGroup->addChild(sizeGroup.release());
1786                                         }
1787                                 }
1788                         }
1789                         smallGroup.release();
1790                         hugeGroup.release();
1791                 }
1792
1793                 // Generate mip map cases
1794                 {
1795                         MovePtr<tcu::TestCaseGroup>     mipmapGroup(new tcu::TestCaseGroup(group->getTestContext(), "mipmap", ""));
1796
1797                         for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1798                         for (int formatNdx   = 0; formatNdx   < DE_LENGTH_OF_ARRAY(format);             ++formatNdx)
1799                         {
1800                                 const CaseDef caseDef =
1801                                 {
1802                                         testCase[caseNdx].viewType,                     // VkImageViewType      imageType;
1803                                         testCase[caseNdx].baselineSize,         // IVec4                        imageSizeHint;
1804                                         format[formatNdx],                                      // VkFormat                     colorFormat;
1805                                         depthStencilFormat[dsFormatNdx],        // VkFormat                     depthStencilFormat;
1806                                         allocationKind                                          // AllocationKind       allocationKind;
1807                                 };
1808                                 addFunctionCaseWithPrograms(mipmapGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]), "", initPrograms, testRenderToMipMaps, caseDef);
1809                         }
1810                         imageGroup->addChild(mipmapGroup.release());
1811                 }
1812
1813                 group->addChild(imageGroup.release());
1814         }
1815 }
1816
1817 void addCoreRenderToImageTests (tcu::TestCaseGroup* group)
1818 {
1819         addTestCasesWithFunctions(group, ALLOCATION_KIND_SUBALLOCATED);
1820 }
1821
1822 void addDedicatedAllocationRenderToImageTests (tcu::TestCaseGroup* group)
1823 {
1824         addTestCasesWithFunctions(group, ALLOCATION_KIND_DEDICATED);
1825 }
1826
1827 } // anonymous ns
1828
1829 tcu::TestCaseGroup* createRenderToImageTests (tcu::TestContext& testCtx)
1830 {
1831         de::MovePtr<tcu::TestCaseGroup> renderToImageTests      (new tcu::TestCaseGroup(testCtx, "render_to_image", "Render to image tests"));
1832
1833         renderToImageTests->addChild(createTestGroup(testCtx, "core",                                   "Core render to image tests",                                                           addCoreRenderToImageTests));
1834         renderToImageTests->addChild(createTestGroup(testCtx, "dedicated_allocation",   "Render to image tests for dedicated memory allocation",        addDedicatedAllocationRenderToImageTests));
1835
1836         return renderToImageTests.release();
1837 }
1838
1839 } // pipeline
1840 } // vkt