Reset GL_FRAMEBUFFER_SRGB state for ES tests am: 695727058b
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / fragment_ops / vktFragmentOperationsScissorMultiViewportTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2014 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Scissor multi viewport tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktFragmentOperationsMakeUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkQueryUtil.hpp"
36
37 #include "tcuTestLog.hpp"
38 #include "tcuVector.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuTextureUtil.hpp"
41
42 #include "deUniquePtr.hpp"
43 #include "deMath.h"
44
45 namespace vkt
46 {
47 namespace FragmentOperations
48 {
49 using namespace vk;
50 using de::UniquePtr;
51 using de::MovePtr;
52 using tcu::Vec4;
53 using tcu::Vec2;
54 using tcu::IVec2;
55 using tcu::IVec4;
56
57 namespace
58 {
59
60 enum Constants
61 {
62         MIN_MAX_VIEWPORTS = 16,         //!< Minimum number of viewports for an implementation supporting multiViewport.
63 };
64
65 template<typename T>
66 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
67 {
68         return vec.size() * sizeof(vec[0]);
69 }
70
71 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
72 {
73         const VkImageCreateInfo imageParams =
74         {
75                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                    // VkStructureType                      sType;
76                 DE_NULL,                                                                                // const void*                          pNext;
77                 (VkImageCreateFlags)0,                                                  // VkImageCreateFlags           flags;
78                 VK_IMAGE_TYPE_2D,                                                               // VkImageType                          imageType;
79                 format,                                                                                 // VkFormat                                     format;
80                 makeExtent3D(size.x(), size.y(), 1),                    // VkExtent3D                           extent;
81                 1u,                                                                                             // deUint32                                     mipLevels;
82                 1u,                                                                                             // deUint32                                     arrayLayers;
83                 VK_SAMPLE_COUNT_1_BIT,                                                  // VkSampleCountFlagBits        samples;
84                 VK_IMAGE_TILING_OPTIMAL,                                                // VkImageTiling                        tiling;
85                 usage,                                                                                  // VkImageUsageFlags            usage;
86                 VK_SHARING_MODE_EXCLUSIVE,                                              // VkSharingMode                        sharingMode;
87                 0u,                                                                                             // deUint32                                     queueFamilyIndexCount;
88                 DE_NULL,                                                                                // const deUint32*                      pQueueFamilyIndices;
89                 VK_IMAGE_LAYOUT_UNDEFINED,                                              // VkImageLayout                        initialLayout;
90         };
91         return imageParams;
92 }
93
94 //! A single-attachment, single-subpass render pass.
95 Move<VkRenderPass> makeRenderPass (const DeviceInterface&       vk,
96                                                                    const VkDevice                       device,
97                                                                    const VkFormat                       colorFormat)
98 {
99         const VkAttachmentDescription colorAttachmentDescription =
100         {
101                 (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags         flags;
102                 colorFormat,                                                                            // VkFormat                                                     format;
103                 VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits                        samples;
104                 VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
105                 VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                          storeOp;
106                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                           stencilLoadOp;
107                 VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          stencilStoreOp;
108                 VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout                                        initialLayout;
109                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        finalLayout;
110         };
111
112         const VkAttachmentReference colorAttachmentRef =
113         {
114                 0u,                                                                                                     // deUint32                     attachment;
115                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
116         };
117
118         const VkSubpassDescription subpassDescription =
119         {
120                 (VkSubpassDescriptionFlags)0,                                           // VkSubpassDescriptionFlags            flags;
121                 VK_PIPELINE_BIND_POINT_GRAPHICS,                                        // VkPipelineBindPoint                          pipelineBindPoint;
122                 0u,                                                                                                     // deUint32                                                     inputAttachmentCount;
123                 DE_NULL,                                                                                        // const VkAttachmentReference*         pInputAttachments;
124                 1u,                                                                                                     // deUint32                                                     colorAttachmentCount;
125                 &colorAttachmentRef,                                                            // const VkAttachmentReference*         pColorAttachments;
126                 DE_NULL,                                                                                        // const VkAttachmentReference*         pResolveAttachments;
127                 DE_NULL,                                                                                        // const VkAttachmentReference*         pDepthStencilAttachment;
128                 0u,                                                                                                     // deUint32                                                     preserveAttachmentCount;
129                 DE_NULL                                                                                         // const deUint32*                                      pPreserveAttachments;
130         };
131
132         const VkRenderPassCreateInfo renderPassInfo =
133         {
134                 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                      // VkStructureType                                      sType;
135                 DE_NULL,                                                                                        // const void*                                          pNext;
136                 (VkRenderPassCreateFlags)0,                                                     // VkRenderPassCreateFlags                      flags;
137                 1u,                                                                                                     // deUint32                                                     attachmentCount;
138                 &colorAttachmentDescription,                                            // const VkAttachmentDescription*       pAttachments;
139                 1u,                                                                                                     // deUint32                                                     subpassCount;
140                 &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
141                 0u,                                                                                                     // deUint32                                                     dependencyCount;
142                 DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
143         };
144
145         return createRenderPass(vk, device, &renderPassInfo);
146 }
147
148 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&           vk,
149                                                                            const VkDevice                               device,
150                                                                            const VkPipelineLayout               pipelineLayout,
151                                                                            const VkRenderPass                   renderPass,
152                                                                            const VkShaderModule                 vertexModule,
153                                                                            const VkShaderModule                 geometryModule,
154                                                                            const VkShaderModule                 fragmentModule,
155                                                                            const IVec2                                  renderSize,
156                                                                            const int                                    numViewports,
157                                                                            const std::vector<IVec4>             scissors)
158 {
159         const VkVertexInputBindingDescription vertexInputBindingDescription =
160         {
161                 0u,                                                             // uint32_t                             binding;
162                 sizeof(Vec4),                                   // uint32_t                             stride;
163                 VK_VERTEX_INPUT_RATE_VERTEX,    // VkVertexInputRate    inputRate;
164         };
165
166         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
167         {
168                 {
169                         0u,                                                                     // uint32_t                     location;
170                         0u,                                                                     // uint32_t                     binding;
171                         VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat                     format;
172                         0u,                                                                     // uint32_t                     offset;
173                 },
174         };
175
176         const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
177         {
178                 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,              // VkStructureType                             sType;
179                 DE_NULL,                                                                                                                // const void*                                 pNext;
180                 (VkPipelineVertexInputStateCreateFlags)0,                                               // VkPipelineVertexInputStateCreateFlags       flags;
181                 1u,                                                                                                                             // uint32_t                                    vertexBindingDescriptionCount;
182                 &vertexInputBindingDescription,                                                                 // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
183                 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),                   // uint32_t                                    vertexAttributeDescriptionCount;
184                 vertexInputAttributeDescriptions,                                                               // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
185         };
186
187         const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
188         {
189                 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    // VkStructureType                             sType;
190                 DE_NULL,                                                                                                                // const void*                                 pNext;
191                 (VkPipelineInputAssemblyStateCreateFlags)0,                                             // VkPipelineInputAssemblyStateCreateFlags     flags;
192                 VK_PRIMITIVE_TOPOLOGY_POINT_LIST,                                                               // VkPrimitiveTopology                         topology;
193                 VK_FALSE,                                                                                                               // VkBool32                                    primitiveRestartEnable;
194         };
195
196         const VkViewport defaultViewport = makeViewport(
197                 0.0f, 0.0f,
198                 static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
199                 0.0f, 1.0f);
200         const std::vector<VkViewport> viewports(numViewports, defaultViewport);
201
202         DE_ASSERT(numViewports == static_cast<int>(scissors.size()));
203
204         std::vector<VkRect2D> rectScissors;
205         rectScissors.reserve(numViewports);
206
207         for (std::vector<IVec4>::const_iterator it = scissors.begin(); it != scissors.end(); ++it)
208         {
209                 const VkRect2D rect =
210                 {
211                         makeOffset2D(it->x(), it->y()),
212                         makeExtent2D(static_cast<deUint32>(it->z()), static_cast<deUint32>(it->w())),
213                 };
214                 rectScissors.push_back(rect);
215         }
216
217         const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
218         {
219                 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                  // VkStructureType                             sType;
220                 DE_NULL,                                                                                                                // const void*                                 pNext;
221                 (VkPipelineViewportStateCreateFlags)0,                                                  // VkPipelineViewportStateCreateFlags          flags;
222                 static_cast<deUint32>(numViewports),                                                    // uint32_t                                    viewportCount;
223                 &viewports[0],                                                                                                  // const VkViewport*                           pViewports;
224                 static_cast<deUint32>(numViewports),                                                    // uint32_t                                    scissorCount;
225                 &rectScissors[0],                                                                                               // const VkRect2D*                             pScissors;
226         };
227
228         const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
229         {
230                 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,             // VkStructureType                          sType;
231                 DE_NULL,                                                                                                                // const void*                              pNext;
232                 (VkPipelineRasterizationStateCreateFlags)0,                                             // VkPipelineRasterizationStateCreateFlags  flags;
233                 VK_FALSE,                                                                                                               // VkBool32                                 depthClampEnable;
234                 VK_FALSE,                                                                                                               // VkBool32                                 rasterizerDiscardEnable;
235                 VK_POLYGON_MODE_FILL,                                                                                   // VkPolygonMode                                                        polygonMode;
236                 VK_CULL_MODE_NONE,                                                                                              // VkCullModeFlags                                                      cullMode;
237                 VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                // VkFrontFace                                                          frontFace;
238                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthBiasEnable;
239                 0.0f,                                                                                                                   // float                                                                        depthBiasConstantFactor;
240                 0.0f,                                                                                                                   // float                                                                        depthBiasClamp;
241                 0.0f,                                                                                                                   // float                                                                        depthBiasSlopeFactor;
242                 1.0f,                                                                                                                   // float                                                                        lineWidth;
243         };
244
245         const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
246         {
247                 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
248                 DE_NULL,                                                                                                                // const void*                                                          pNext;
249                 (VkPipelineMultisampleStateCreateFlags)0,                                               // VkPipelineMultisampleStateCreateFlags        flags;
250                 VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
251                 VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
252                 0.0f,                                                                                                                   // float                                                                        minSampleShading;
253                 DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
254                 VK_FALSE,                                                                                                               // VkBool32                                                                     alphaToCoverageEnable;
255                 VK_FALSE                                                                                                                // VkBool32                                                                     alphaToOneEnable;
256         };
257
258         const VkStencilOpState stencilOpState = makeStencilOpState(
259                 VK_STENCIL_OP_KEEP,                             // stencil fail
260                 VK_STENCIL_OP_KEEP,                             // depth & stencil pass
261                 VK_STENCIL_OP_KEEP,                             // depth only fail
262                 VK_COMPARE_OP_ALWAYS,                   // compare op
263                 0u,                                                             // compare mask
264                 0u,                                                             // write mask
265                 0u);                                                    // reference
266
267         VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
268         {
269                 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,             // VkStructureType                                                      sType;
270                 DE_NULL,                                                                                                                // const void*                                                          pNext;
271                 (VkPipelineDepthStencilStateCreateFlags)0,                                              // VkPipelineDepthStencilStateCreateFlags       flags;
272                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthTestEnable;
273                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthWriteEnable;
274                 VK_COMPARE_OP_LESS,                                                                                             // VkCompareOp                                                          depthCompareOp;
275                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthBoundsTestEnable;
276                 VK_FALSE,                                                                                                               // VkBool32                                                                     stencilTestEnable;
277                 stencilOpState,                                                                                                 // VkStencilOpState                                                     front;
278                 stencilOpState,                                                                                                 // VkStencilOpState                                                     back;
279                 0.0f,                                                                                                                   // float                                                                        minDepthBounds;
280                 1.0f,                                                                                                                   // float                                                                        maxDepthBounds;
281         };
282
283         const VkColorComponentFlags                                     colorComponentsAll                                      = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
284         const VkPipelineColorBlendAttachmentState       pipelineColorBlendAttachmentState       =
285         {
286                 VK_FALSE,                                               // VkBool32                                     blendEnable;
287                 VK_BLEND_FACTOR_ONE,                    // VkBlendFactor                        srcColorBlendFactor;
288                 VK_BLEND_FACTOR_ZERO,                   // VkBlendFactor                        dstColorBlendFactor;
289                 VK_BLEND_OP_ADD,                                // VkBlendOp                            colorBlendOp;
290                 VK_BLEND_FACTOR_ONE,                    // VkBlendFactor                        srcAlphaBlendFactor;
291                 VK_BLEND_FACTOR_ZERO,                   // VkBlendFactor                        dstAlphaBlendFactor;
292                 VK_BLEND_OP_ADD,                                // VkBlendOp                            alphaBlendOp;
293                 colorComponentsAll,                             // VkColorComponentFlags        colorWriteMask;
294         };
295
296         const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
297         {
298                 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,               // VkStructureType                                                              sType;
299                 DE_NULL,                                                                                                                // const void*                                                                  pNext;
300                 (VkPipelineColorBlendStateCreateFlags)0,                                                // VkPipelineColorBlendStateCreateFlags                 flags;
301                 VK_FALSE,                                                                                                               // VkBool32                                                                             logicOpEnable;
302                 VK_LOGIC_OP_COPY,                                                                                               // VkLogicOp                                                                    logicOp;
303                 1u,                                                                                                                             // deUint32                                                                             attachmentCount;
304                 &pipelineColorBlendAttachmentState,                                                             // const VkPipelineColorBlendAttachmentState*   pAttachments;
305                 { 0.0f, 0.0f, 0.0f, 0.0f },                                                                             // float                                                                                blendConstants[4];
306         };
307
308         const VkPipelineShaderStageCreateInfo pShaderStages[] =
309         {
310                 {
311                         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
312                         DE_NULL,                                                                                                        // const void*                                                  pNext;
313                         (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
314                         VK_SHADER_STAGE_VERTEX_BIT,                                                                     // VkShaderStageFlagBits                                stage;
315                         vertexModule,                                                                                           // VkShaderModule                                               module;
316                         "main",                                                                                                         // const char*                                                  pName;
317                         DE_NULL,                                                                                                        // const VkSpecializationInfo*                  pSpecializationInfo;
318                 },
319                 {
320                         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
321                         DE_NULL,                                                                                                        // const void*                                                  pNext;
322                         (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
323                         VK_SHADER_STAGE_GEOMETRY_BIT,                                                           // VkShaderStageFlagBits                                stage;
324                         geometryModule,                                                                                         // VkShaderModule                                               module;
325                         "main",                                                                                                         // const char*                                                  pName;
326                         DE_NULL,                                                                                                        // const VkSpecializationInfo*                  pSpecializationInfo;
327                 },
328                 {
329                         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
330                         DE_NULL,                                                                                                        // const void*                                                  pNext;
331                         (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
332                         VK_SHADER_STAGE_FRAGMENT_BIT,                                                           // VkShaderStageFlagBits                                stage;
333                         fragmentModule,                                                                                         // VkShaderModule                                               module;
334                         "main",                                                                                                         // const char*                                                  pName;
335                         DE_NULL,                                                                                                        // const VkSpecializationInfo*                  pSpecializationInfo;
336                 },
337         };
338
339         const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
340         {
341                 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
342                 DE_NULL,                                                                                        // const void*                                                                          pNext;
343                 (VkPipelineCreateFlags)0,                                                       // VkPipelineCreateFlags                                                        flags;
344                 DE_LENGTH_OF_ARRAY(pShaderStages),                                      // deUint32                                                                                     stageCount;
345                 pShaderStages,                                                                          // const VkPipelineShaderStageCreateInfo*                       pStages;
346                 &vertexInputStateInfo,                                                          // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
347                 &pipelineInputAssemblyStateInfo,                                        // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
348                 DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
349                 &pipelineViewportStateInfo,                                                     // const VkPipelineViewportStateCreateInfo*                     pViewportState;
350                 &pipelineRasterizationStateInfo,                                        // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
351                 &pipelineMultisampleStateInfo,                                          // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
352                 &pipelineDepthStencilStateInfo,                                         // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
353                 &pipelineColorBlendStateInfo,                                           // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
354                 DE_NULL,                                                                                        // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
355                 pipelineLayout,                                                                         // VkPipelineLayout                                                                     layout;
356                 renderPass,                                                                                     // VkRenderPass                                                                         renderPass;
357                 0u,                                                                                                     // deUint32                                                                                     subpass;
358                 DE_NULL,                                                                                        // VkPipeline                                                                           basePipelineHandle;
359                 0,                                                                                                      // deInt32                                                                                      basePipelineIndex;
360         };
361
362         return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
363 }
364
365 void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
366 {
367         deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
368         flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size);
369 }
370
371 void requireFeatureMultiViewport (const InstanceInterface& vki, const VkPhysicalDevice physDevice)
372 {
373         const VkPhysicalDeviceFeatures  features        = getPhysicalDeviceFeatures(vki, physDevice);
374         const VkPhysicalDeviceLimits    limits          = getPhysicalDeviceProperties(vki, physDevice).limits;
375
376         if (!features.geometryShader)
377                 TCU_THROW(NotSupportedError, "Required feature is not supported: geometryShader");
378
379         if (!features.multiViewport)
380                 TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport");
381
382         if (limits.maxViewports < MIN_MAX_VIEWPORTS)
383                 TCU_THROW(NotSupportedError, "Implementation doesn't support minimum required number of viewports");
384 }
385
386 std::vector<IVec4> generateScissors (const int numScissors, const IVec2& renderSize)
387 {
388         // Scissor rects will be arranged in a grid-like fashion.
389
390         const int numCols               = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numScissors)));
391         const int numRows               = deCeilFloatToInt32(static_cast<float>(numScissors) / static_cast<float>(numCols));
392         const int rectWidth             = renderSize.x() / numCols;
393         const int rectHeight    = renderSize.y() / numRows;
394
395         std::vector<IVec4> scissors;
396         scissors.reserve(numScissors);
397
398         int x = 0;
399         int y = 0;
400
401         for (int scissorNdx = 0; scissorNdx < numScissors; ++scissorNdx)
402         {
403                 const bool nextRow = (scissorNdx != 0) && (scissorNdx % numCols == 0);
404                 if (nextRow)
405                 {
406                         x  = 0;
407                         y += rectHeight;
408                 }
409
410                 scissors.push_back(IVec4(x, y, rectWidth, rectHeight));
411
412                 x += rectWidth;
413         }
414
415         return scissors;
416 }
417
418 std::vector<Vec4> generateColors (const int numColors)
419 {
420         const Vec4 colors[] =
421         {
422                 Vec4(0.18f, 0.42f, 0.17f, 1.0f),
423                 Vec4(0.29f, 0.62f, 0.28f, 1.0f),
424                 Vec4(0.59f, 0.84f, 0.44f, 1.0f),
425                 Vec4(0.96f, 0.95f, 0.72f, 1.0f),
426                 Vec4(0.94f, 0.55f, 0.39f, 1.0f),
427                 Vec4(0.82f, 0.19f, 0.12f, 1.0f),
428                 Vec4(0.46f, 0.15f, 0.26f, 1.0f),
429                 Vec4(0.24f, 0.14f, 0.24f, 1.0f),
430                 Vec4(0.49f, 0.31f, 0.26f, 1.0f),
431                 Vec4(0.78f, 0.52f, 0.33f, 1.0f),
432                 Vec4(0.94f, 0.82f, 0.31f, 1.0f),
433                 Vec4(0.98f, 0.65f, 0.30f, 1.0f),
434                 Vec4(0.22f, 0.65f, 0.53f, 1.0f),
435                 Vec4(0.67f, 0.81f, 0.91f, 1.0f),
436                 Vec4(0.43f, 0.44f, 0.75f, 1.0f),
437                 Vec4(0.26f, 0.24f, 0.48f, 1.0f),
438         };
439
440         DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
441
442         return std::vector<Vec4>(colors, colors + numColors);
443 }
444
445 //! Renders a colorful grid of rectangles.
446 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat      format,
447                                                                                   const IVec2&                          renderSize,
448                                                                                   const Vec4&                           clearColor,
449                                                                                   const std::vector<IVec4>&     scissors,
450                                                                                   const std::vector<Vec4>&      scissorColors)
451 {
452         DE_ASSERT(scissors.size() == scissorColors.size());
453
454         tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
455         tcu::clear(image.getAccess(), clearColor);
456
457         for (std::size_t i = 0; i < scissors.size(); ++i)
458         {
459                 tcu::clear(
460                         tcu::getSubregion(image.getAccess(), scissors[i].x(), scissors[i].y(), scissors[i].z(), scissors[i].w()),
461                         scissorColors[i]);
462         }
463
464         return image;
465 }
466
467 void initPrograms (SourceCollections& programCollection, const int numViewports)
468 {
469         DE_UNREF(numViewports);
470
471         // Vertex shader
472         {
473                 std::ostringstream src;
474                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
475                         << "\n"
476                         << "layout(location = 0) in  vec4 in_color;\n"
477                         << "layout(location = 0) out vec4 out_color;\n"
478                         << "\n"
479                         << "void main(void)\n"
480                         << "{\n"
481                         << "    out_color = in_color;\n"
482                         << "}\n";
483
484                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
485         }
486
487         // Geometry shader
488         {
489                 // Each input point generates a fullscreen quad.
490
491                 std::ostringstream src;
492                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
493                         << "\n"
494                         << "layout(points) in;\n"
495                         << "layout(triangle_strip, max_vertices=4) out;\n"
496                         << "\n"
497                         << "out gl_PerVertex {\n"
498                         << "    vec4 gl_Position;\n"
499                         << "};\n"
500                         << "\n"
501                         << "layout(location = 0) in  vec4 in_color[];\n"
502                         << "layout(location = 0) out vec4 out_color;\n"
503                         << "\n"
504                         << "void main(void)\n"
505                         << "{\n"
506                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
507                         << "    gl_Position      = vec4(-1.0, -1.0, 0.0, 1.0);\n"
508                         << "    out_color        = in_color[0];\n"
509                         << "    EmitVertex();"
510                         << "\n"
511                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
512                         << "    gl_Position      = vec4(-1.0, 1.0, 0.0, 1.0);\n"
513                         << "    out_color        = in_color[0];\n"
514                         << "    EmitVertex();"
515                         << "\n"
516                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
517                         << "    gl_Position      = vec4(1.0, -1.0, 0.0, 1.0);\n"
518                         << "    out_color        = in_color[0];\n"
519                         << "    EmitVertex();"
520                         << "\n"
521                         << "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
522                         << "    gl_Position      = vec4(1.0, 1.0, 0.0, 1.0);\n"
523                         << "    out_color        = in_color[0];\n"
524                         << "    EmitVertex();"
525                         << "}\n";
526
527                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
528         }
529
530         // Fragment shader
531         {
532                 std::ostringstream src;
533                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
534                         << "\n"
535                         << "layout(location = 0) in  vec4 in_color;\n"
536                         << "layout(location = 0) out vec4 out_color;\n"
537                         << "\n"
538                         << "void main(void)\n"
539                         << "{\n"
540                         << "    out_color = in_color;\n"
541                         << "}\n";
542
543                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
544         }
545 }
546
547 class ScissorRenderer
548 {
549 public:
550         ScissorRenderer (Context&                                       context,
551                                          const IVec2&                           renderSize,
552                                          const int                                      numViewports,
553                                          const std::vector<IVec4>&      scissors,
554                                          const VkFormat                         colorFormat,
555                                          const Vec4&                            clearColor,
556                                          const std::vector<Vec4>&       vertices)
557                 : m_renderSize                          (renderSize)
558                 , m_colorFormat                         (colorFormat)
559                 , m_colorSubresourceRange       (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
560                 , m_clearColor                          (clearColor)
561                 , m_numViewports                        (numViewports)
562                 , m_vertexBufferSize            (sizeInBytes(vertices))
563         {
564                 const DeviceInterface&          vk                                      = context.getDeviceInterface();
565                 const VkDevice                          device                          = context.getDevice();
566                 const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
567                 Allocator&                                      allocator                       = context.getDefaultAllocator();
568
569                 m_colorImage            = makeImage                             (vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
570                 m_colorImageAlloc       = bindImage                             (vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
571                 m_colorAttachment       = makeImageView                 (vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
572
573                 m_vertexBuffer          = makeBuffer                    (vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
574                 m_vertexBufferAlloc     = bindBuffer                    (vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
575
576                 {
577                         deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
578                         flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize);
579                 }
580
581                 m_vertexModule          = createShaderModule    (vk, device, context.getBinaryCollection().get("vert"), 0u);
582                 m_geometryModule        = createShaderModule    (vk, device, context.getBinaryCollection().get("geom"), 0u);
583                 m_fragmentModule        = createShaderModule    (vk, device, context.getBinaryCollection().get("frag"), 0u);
584                 m_renderPass            = makeRenderPass                (vk, device, m_colorFormat);
585                 m_framebuffer           = makeFramebuffer               (vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
586                                                                                                          static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
587                 m_pipelineLayout        = makePipelineLayout    (vk, device);
588                 m_pipeline                      = makeGraphicsPipeline  (vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_geometryModule, *m_fragmentModule,
589                                                                                                          m_renderSize, m_numViewports, scissors);
590                 m_cmdPool                       = createCommandPool             (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
591                 m_cmdBuffer                     = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
592         }
593
594         void draw (Context& context, const VkBuffer colorBuffer) const
595         {
596                 const DeviceInterface&          vk                      = context.getDeviceInterface();
597                 const VkDevice                          device          = context.getDevice();
598                 const VkQueue                           queue           = context.getUniversalQueue();
599
600                 beginCommandBuffer(vk, *m_cmdBuffer);
601
602                 const VkClearValue                      clearValue      = makeClearValueColor(m_clearColor);
603                 const VkRect2D                          renderArea      =
604                 {
605                         makeOffset2D(0, 0),
606                         makeExtent2D(m_renderSize.x(), m_renderSize.y()),
607                 };
608                 const VkRenderPassBeginInfo renderPassBeginInfo =
609                 {
610                         VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,               // VkStructureType         sType;
611                         DE_NULL,                                                                                // const void*             pNext;
612                         *m_renderPass,                                                                  // VkRenderPass            renderPass;
613                         *m_framebuffer,                                                                 // VkFramebuffer           framebuffer;
614                         renderArea,                                                                             // VkRect2D                renderArea;
615                         1u,                                                                                             // uint32_t                clearValueCount;
616                         &clearValue,                                                                    // const VkClearValue*     pClearValues;
617                 };
618                 vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
619
620                 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
621                 {
622                         const VkDeviceSize vertexBufferOffset = 0ull;
623                         vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
624                 }
625                 vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports), 1u, 0u, 0u);    // one vertex per viewport
626                 vk.cmdEndRenderPass(*m_cmdBuffer);
627
628                 // Prepare color image for copy
629                 {
630                         const VkImageMemoryBarrier barriers[] =
631                         {
632                                 {
633                                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                         // VkStructureType                      sType;
634                                         DE_NULL,                                                                                                        // const void*                          pNext;
635                                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,                                           // VkAccessFlags                        outputMask;
636                                         VK_ACCESS_TRANSFER_READ_BIT,                                                            // VkAccessFlags                        inputMask;
637                                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                       // VkImageLayout                        oldLayout;
638                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                                           // VkImageLayout                        newLayout;
639                                         VK_QUEUE_FAMILY_IGNORED,                                                                        // deUint32                                     srcQueueFamilyIndex;
640                                         VK_QUEUE_FAMILY_IGNORED,                                                                        // deUint32                                     destQueueFamilyIndex;
641                                         *m_colorImage,                                                                                          // VkImage                                      image;
642                                         m_colorSubresourceRange,                                                                        // VkImageSubresourceRange      subresourceRange;
643                                 },
644                         };
645
646                         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
647                                 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
648                 }
649                 // Color image -> host buffer
650                 {
651                         const VkBufferImageCopy region =
652                         {
653                                 0ull,                                                                                                                                           // VkDeviceSize                bufferOffset;
654                                 0u,                                                                                                                                                     // uint32_t                    bufferRowLength;
655                                 0u,                                                                                                                                                     // uint32_t                    bufferImageHeight;
656                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),                      // VkImageSubresourceLayers    imageSubresource;
657                                 makeOffset3D(0, 0, 0),                                                                                                          // VkOffset3D                  imageOffset;
658                                 makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),                                           // VkExtent3D                  imageExtent;
659                         };
660
661                         vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
662                 }
663                 // Buffer write barrier
664                 {
665                         const VkBufferMemoryBarrier barriers[] =
666                         {
667                                 {
668                                         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,                // VkStructureType    sType;
669                                         DE_NULL,                                                                                // const void*        pNext;
670                                         VK_ACCESS_TRANSFER_WRITE_BIT,                                   // VkAccessFlags      srcAccessMask;
671                                         VK_ACCESS_HOST_READ_BIT,                                                // VkAccessFlags      dstAccessMask;
672                                         VK_QUEUE_FAMILY_IGNORED,                                                // uint32_t           srcQueueFamilyIndex;
673                                         VK_QUEUE_FAMILY_IGNORED,                                                // uint32_t           dstQueueFamilyIndex;
674                                         colorBuffer,                                                                    // VkBuffer           buffer;
675                                         0ull,                                                                                   // VkDeviceSize       offset;
676                                         VK_WHOLE_SIZE,                                                                  // VkDeviceSize       size;
677                                 },
678                         };
679
680                         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
681                                 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
682                 }
683
684                 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
685                 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
686         }
687
688 private:
689         const IVec2                                             m_renderSize;
690         const VkFormat                                  m_colorFormat;
691         const VkImageSubresourceRange   m_colorSubresourceRange;
692         const Vec4                                              m_clearColor;
693         const int                                               m_numViewports;
694         const VkDeviceSize                              m_vertexBufferSize;
695
696         Move<VkImage>                                   m_colorImage;
697         MovePtr<Allocation>                             m_colorImageAlloc;
698         Move<VkImageView>                               m_colorAttachment;
699         Move<VkBuffer>                                  m_vertexBuffer;
700         MovePtr<Allocation>                             m_vertexBufferAlloc;
701         Move<VkShaderModule>                    m_vertexModule;
702         Move<VkShaderModule>                    m_geometryModule;
703         Move<VkShaderModule>                    m_fragmentModule;
704         Move<VkRenderPass>                              m_renderPass;
705         Move<VkFramebuffer>                             m_framebuffer;
706         Move<VkPipelineLayout>                  m_pipelineLayout;
707         Move<VkPipeline>                                m_pipeline;
708         Move<VkCommandPool>                             m_cmdPool;
709         Move<VkCommandBuffer>                   m_cmdBuffer;
710
711         // "deleted"
712                                                 ScissorRenderer (const ScissorRenderer&);
713         ScissorRenderer&        operator=               (const ScissorRenderer&);
714 };
715
716 tcu::TestStatus test (Context& context, const int numViewports)
717 {
718         requireFeatureMultiViewport(context.getInstanceInterface(), context.getPhysicalDevice());
719
720         const DeviceInterface&                  vk                                      = context.getDeviceInterface();
721         const VkDevice                                  device                          = context.getDevice();
722         Allocator&                                              allocator                       = context.getDefaultAllocator();
723
724         const IVec2                                             renderSize                      (128, 128);
725         const VkFormat                                  colorFormat                     = VK_FORMAT_R8G8B8A8_UNORM;
726         const Vec4                                              clearColor                      (0.5f, 0.5f, 0.5f, 1.0f);
727         const std::vector<Vec4>                 vertexColors            = generateColors(numViewports);
728         const std::vector<IVec4>                scissors                        = generateScissors(numViewports, renderSize);
729
730         const VkDeviceSize                              colorBufferSize         = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
731         const Unique<VkBuffer>                  colorBuffer                     (makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
732         const UniquePtr<Allocation>             colorBufferAlloc        (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
733
734         zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize);
735
736         {
737                 context.getTestContext().getLog()
738                         << tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
739                         << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
740         }
741
742         // Draw
743         {
744                 const ScissorRenderer renderer (context, renderSize, numViewports, scissors, colorFormat, clearColor, vertexColors);
745                 renderer.draw(context, *colorBuffer);
746         }
747
748         // Log image
749         {
750                 invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), 0ull, colorBufferSize);
751
752                 const tcu::ConstPixelBufferAccess       resultImage             (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr());
753                 const tcu::TextureLevel                         referenceImage  = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, scissors, vertexColors);
754
755                 // Images should now match.
756                 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
757                         return tcu::TestStatus::fail("Rendered image is not correct");
758         }
759
760         return tcu::TestStatus::pass("OK");
761 }
762
763 } // anonymous
764
765 tcu::TestCaseGroup* createScissorMultiViewportTests     (tcu::TestContext& testCtx)
766 {
767         MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "multi_viewport", ""));
768
769         for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
770                 addFunctionCaseWithPrograms(group.get(), "scissor_" + de::toString(numViewports), "", initPrograms, test, numViewports);
771
772         return group.release();
773 }
774
775 } // FragmentOperations
776 } // vkt