Merge "Report Android extension pack tests as not supported" am: 03c395c60f
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / fragment_ops / vktFragmentOperationsScissorTests.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 tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktFragmentOperationsScissorTests.hpp"
26 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktFragmentOperationsMakeUtil.hpp"
30
31 #include "vkDefs.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkImageUtil.hpp"
37
38 #include "tcuTestLog.hpp"
39 #include "tcuVector.hpp"
40 #include "tcuImageCompare.hpp"
41
42 #include "deUniquePtr.hpp"
43 #include "deRandom.hpp"
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 //! What primitives will be drawn by the test case.
61 enum TestPrimitive
62 {
63         TEST_PRIMITIVE_POINTS,                  //!< Many points.
64         TEST_PRIMITIVE_LINES,                   //!< Many short lines.
65         TEST_PRIMITIVE_TRIANGLES,               //!< Many small triangles.
66         TEST_PRIMITIVE_BIG_LINE,                //!< One line crossing the whole render area.
67         TEST_PRIMITIVE_BIG_TRIANGLE,    //!< One triangle covering the whole render area.
68 };
69
70 struct VertexData
71 {
72         Vec4    position;
73         Vec4    color;
74 };
75
76 //! Parameters used by the test case.
77 struct CaseDef
78 {
79         Vec4                    renderArea;             //!< (ox, oy, w, h), where origin (0,0) is the top-left corner of the viewport. Width and height are in range [0, 1].
80         Vec4                    scissorArea;    //!< scissored area (ox, oy, w, h)
81         TestPrimitive   primitive;
82 };
83
84 template<typename T>
85 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
86 {
87         return vec.size() * sizeof(vec[0]);
88 }
89
90 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
91 {
92         const VkImageCreateInfo imageParams =
93         {
94                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                    // VkStructureType                      sType;
95                 DE_NULL,                                                                                // const void*                          pNext;
96                 (VkImageCreateFlags)0,                                                  // VkImageCreateFlags           flags;
97                 VK_IMAGE_TYPE_2D,                                                               // VkImageType                          imageType;
98                 format,                                                                                 // VkFormat                                     format;
99                 makeExtent3D(size.x(), size.y(), 1),                    // VkExtent3D                           extent;
100                 1u,                                                                                             // deUint32                                     mipLevels;
101                 1u,                                                                                             // deUint32                                     arrayLayers;
102                 VK_SAMPLE_COUNT_1_BIT,                                                  // VkSampleCountFlagBits        samples;
103                 VK_IMAGE_TILING_OPTIMAL,                                                // VkImageTiling                        tiling;
104                 usage,                                                                                  // VkImageUsageFlags            usage;
105                 VK_SHARING_MODE_EXCLUSIVE,                                              // VkSharingMode                        sharingMode;
106                 0u,                                                                                             // deUint32                                     queueFamilyIndexCount;
107                 DE_NULL,                                                                                // const deUint32*                      pQueueFamilyIndices;
108                 VK_IMAGE_LAYOUT_UNDEFINED,                                              // VkImageLayout                        initialLayout;
109         };
110         return imageParams;
111 }
112
113 //! A single-attachment, single-subpass render pass.
114 Move<VkRenderPass> makeRenderPass (const DeviceInterface&       vk,
115                                                                    const VkDevice                       device,
116                                                                    const VkFormat                       colorFormat)
117 {
118         const VkAttachmentDescription colorAttachmentDescription =
119         {
120                 (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags         flags;
121                 colorFormat,                                                                            // VkFormat                                                     format;
122                 VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits                        samples;
123                 VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
124                 VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                          storeOp;
125                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                           stencilLoadOp;
126                 VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          stencilStoreOp;
127                 VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout                                        initialLayout;
128                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        finalLayout;
129         };
130
131         const VkAttachmentReference colorAttachmentRef =
132         {
133                 0u,                                                                                                     // deUint32                     attachment;
134                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
135         };
136
137         const VkSubpassDescription subpassDescription =
138         {
139                 (VkSubpassDescriptionFlags)0,                                           // VkSubpassDescriptionFlags            flags;
140                 VK_PIPELINE_BIND_POINT_GRAPHICS,                                        // VkPipelineBindPoint                          pipelineBindPoint;
141                 0u,                                                                                                     // deUint32                                                     inputAttachmentCount;
142                 DE_NULL,                                                                                        // const VkAttachmentReference*         pInputAttachments;
143                 1u,                                                                                                     // deUint32                                                     colorAttachmentCount;
144                 &colorAttachmentRef,                                                            // const VkAttachmentReference*         pColorAttachments;
145                 DE_NULL,                                                                                        // const VkAttachmentReference*         pResolveAttachments;
146                 DE_NULL,                                                                                        // const VkAttachmentReference*         pDepthStencilAttachment;
147                 0u,                                                                                                     // deUint32                                                     preserveAttachmentCount;
148                 DE_NULL                                                                                         // const deUint32*                                      pPreserveAttachments;
149         };
150
151         const VkRenderPassCreateInfo renderPassInfo =
152         {
153                 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                      // VkStructureType                                      sType;
154                 DE_NULL,                                                                                        // const void*                                          pNext;
155                 (VkRenderPassCreateFlags)0,                                                     // VkRenderPassCreateFlags                      flags;
156                 1u,                                                                                                     // deUint32                                                     attachmentCount;
157                 &colorAttachmentDescription,                                            // const VkAttachmentDescription*       pAttachments;
158                 1u,                                                                                                     // deUint32                                                     subpassCount;
159                 &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
160                 0u,                                                                                                     // deUint32                                                     dependencyCount;
161                 DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
162         };
163
164         return createRenderPass(vk, device, &renderPassInfo);
165 }
166
167 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&           vk,
168                                                                            const VkDevice                               device,
169                                                                            const VkPipelineLayout               pipelineLayout,
170                                                                            const VkRenderPass                   renderPass,
171                                                                            const VkShaderModule                 vertexModule,
172                                                                            const VkShaderModule                 fragmentModule,
173                                                                            const IVec2                                  renderSize,
174                                                                            const IVec4                                  scissorArea,    //!< (ox, oy, w, h)
175                                                                            const VkPrimitiveTopology    topology)
176 {
177         const VkVertexInputBindingDescription vertexInputBindingDescription =
178         {
179                 0u,                                                             // uint32_t                             binding;
180                 sizeof(VertexData),                             // uint32_t                             stride;
181                 VK_VERTEX_INPUT_RATE_VERTEX,    // VkVertexInputRate    inputRate;
182         };
183
184         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
185         {
186                 {
187                         0u,                                                                     // uint32_t                     location;
188                         0u,                                                                     // uint32_t                     binding;
189                         VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat                     format;
190                         0u,                                                                     // uint32_t                     offset;
191                 },
192                 {
193                         1u,                                                                     // uint32_t                     location;
194                         0u,                                                                     // uint32_t                     binding;
195                         VK_FORMAT_R32G32B32A32_SFLOAT,          // VkFormat                     format;
196                         sizeof(Vec4),                                           // uint32_t                     offset;
197                 },
198         };
199
200         const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
201         {
202                 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,              // VkStructureType                             sType;
203                 DE_NULL,                                                                                                                // const void*                                 pNext;
204                 (VkPipelineVertexInputStateCreateFlags)0,                                               // VkPipelineVertexInputStateCreateFlags       flags;
205                 1u,                                                                                                                             // uint32_t                                    vertexBindingDescriptionCount;
206                 &vertexInputBindingDescription,                                                                 // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
207                 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),                   // uint32_t                                    vertexAttributeDescriptionCount;
208                 vertexInputAttributeDescriptions,                                                               // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
209         };
210
211         const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
212         {
213                 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    // VkStructureType                             sType;
214                 DE_NULL,                                                                                                                // const void*                                 pNext;
215                 (VkPipelineInputAssemblyStateCreateFlags)0,                                             // VkPipelineInputAssemblyStateCreateFlags     flags;
216                 topology,                                                                                                               // VkPrimitiveTopology                         topology;
217                 VK_FALSE,                                                                                                               // VkBool32                                    primitiveRestartEnable;
218         };
219
220         const VkViewport viewport = makeViewport(
221                 0.0f, 0.0f,
222                 static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
223                 0.0f, 1.0f);
224
225         const VkRect2D scissor = {
226                 makeOffset2D(scissorArea.x(), scissorArea.y()),
227                 makeExtent2D(static_cast<deUint32>(scissorArea.z()), static_cast<deUint32>(scissorArea.w())),
228         };
229
230         const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
231         {
232                 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                  // VkStructureType                             sType;
233                 DE_NULL,                                                                                                                // const void*                                 pNext;
234                 (VkPipelineViewportStateCreateFlags)0,                                                  // VkPipelineViewportStateCreateFlags          flags;
235                 1u,                                                                                                                             // uint32_t                                    viewportCount;
236                 &viewport,                                                                                                              // const VkViewport*                           pViewports;
237                 1u,                                                                                                                             // uint32_t                                    scissorCount;
238                 &scissor,                                                                                                               // const VkRect2D*                             pScissors;
239         };
240
241         const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
242         {
243                 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,             // VkStructureType                          sType;
244                 DE_NULL,                                                                                                                // const void*                              pNext;
245                 (VkPipelineRasterizationStateCreateFlags)0,                                             // VkPipelineRasterizationStateCreateFlags  flags;
246                 VK_FALSE,                                                                                                               // VkBool32                                 depthClampEnable;
247                 VK_FALSE,                                                                                                               // VkBool32                                 rasterizerDiscardEnable;
248                 VK_POLYGON_MODE_FILL,                                                                                   // VkPolygonMode                                                        polygonMode;
249                 VK_CULL_MODE_NONE,                                                                                              // VkCullModeFlags                                                      cullMode;
250                 VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                // VkFrontFace                                                          frontFace;
251                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthBiasEnable;
252                 0.0f,                                                                                                                   // float                                                                        depthBiasConstantFactor;
253                 0.0f,                                                                                                                   // float                                                                        depthBiasClamp;
254                 0.0f,                                                                                                                   // float                                                                        depthBiasSlopeFactor;
255                 1.0f,                                                                                                                   // float                                                                        lineWidth;
256         };
257
258         const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
259         {
260                 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
261                 DE_NULL,                                                                                                                // const void*                                                          pNext;
262                 (VkPipelineMultisampleStateCreateFlags)0,                                               // VkPipelineMultisampleStateCreateFlags        flags;
263                 VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
264                 VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
265                 0.0f,                                                                                                                   // float                                                                        minSampleShading;
266                 DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
267                 VK_FALSE,                                                                                                               // VkBool32                                                                     alphaToCoverageEnable;
268                 VK_FALSE                                                                                                                // VkBool32                                                                     alphaToOneEnable;
269         };
270
271         const VkStencilOpState stencilOpState = makeStencilOpState(
272                 VK_STENCIL_OP_KEEP,                             // stencil fail
273                 VK_STENCIL_OP_KEEP,                             // depth & stencil pass
274                 VK_STENCIL_OP_KEEP,                             // depth only fail
275                 VK_COMPARE_OP_ALWAYS,                   // compare op
276                 0u,                                                             // compare mask
277                 0u,                                                             // write mask
278                 0u);                                                    // reference
279
280         VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
281         {
282                 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,             // VkStructureType                                                      sType;
283                 DE_NULL,                                                                                                                // const void*                                                          pNext;
284                 (VkPipelineDepthStencilStateCreateFlags)0,                                              // VkPipelineDepthStencilStateCreateFlags       flags;
285                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthTestEnable;
286                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthWriteEnable;
287                 VK_COMPARE_OP_LESS,                                                                                             // VkCompareOp                                                          depthCompareOp;
288                 VK_FALSE,                                                                                                               // VkBool32                                                                     depthBoundsTestEnable;
289                 VK_FALSE,                                                                                                               // VkBool32                                                                     stencilTestEnable;
290                 stencilOpState,                                                                                                 // VkStencilOpState                                                     front;
291                 stencilOpState,                                                                                                 // VkStencilOpState                                                     back;
292                 0.0f,                                                                                                                   // float                                                                        minDepthBounds;
293                 1.0f,                                                                                                                   // float                                                                        maxDepthBounds;
294         };
295
296         const VkColorComponentFlags                                     colorComponentsAll                                      = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
297         const VkPipelineColorBlendAttachmentState       pipelineColorBlendAttachmentState       =
298         {
299                 VK_FALSE,                                               // VkBool32                                     blendEnable;
300                 VK_BLEND_FACTOR_ONE,                    // VkBlendFactor                        srcColorBlendFactor;
301                 VK_BLEND_FACTOR_ZERO,                   // VkBlendFactor                        dstColorBlendFactor;
302                 VK_BLEND_OP_ADD,                                // VkBlendOp                            colorBlendOp;
303                 VK_BLEND_FACTOR_ONE,                    // VkBlendFactor                        srcAlphaBlendFactor;
304                 VK_BLEND_FACTOR_ZERO,                   // VkBlendFactor                        dstAlphaBlendFactor;
305                 VK_BLEND_OP_ADD,                                // VkBlendOp                            alphaBlendOp;
306                 colorComponentsAll,                             // VkColorComponentFlags        colorWriteMask;
307         };
308
309         const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
310         {
311                 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,               // VkStructureType                                                              sType;
312                 DE_NULL,                                                                                                                // const void*                                                                  pNext;
313                 (VkPipelineColorBlendStateCreateFlags)0,                                                // VkPipelineColorBlendStateCreateFlags                 flags;
314                 VK_FALSE,                                                                                                               // VkBool32                                                                             logicOpEnable;
315                 VK_LOGIC_OP_COPY,                                                                                               // VkLogicOp                                                                    logicOp;
316                 1u,                                                                                                                             // deUint32                                                                             attachmentCount;
317                 &pipelineColorBlendAttachmentState,                                                             // const VkPipelineColorBlendAttachmentState*   pAttachments;
318                 { 0.0f, 0.0f, 0.0f, 0.0f },                                                                             // float                                                                                blendConstants[4];
319         };
320
321         const VkPipelineShaderStageCreateInfo pShaderStages[] =
322         {
323                 {
324                         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
325                         DE_NULL,                                                                                                        // const void*                                                  pNext;
326                         (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
327                         VK_SHADER_STAGE_VERTEX_BIT,                                                                     // VkShaderStageFlagBits                                stage;
328                         vertexModule,                                                                                           // VkShaderModule                                               module;
329                         "main",                                                                                                         // const char*                                                  pName;
330                         DE_NULL,                                                                                                        // const VkSpecializationInfo*                  pSpecializationInfo;
331                 },
332                 {
333                         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
334                         DE_NULL,                                                                                                        // const void*                                                  pNext;
335                         (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
336                         VK_SHADER_STAGE_FRAGMENT_BIT,                                                           // VkShaderStageFlagBits                                stage;
337                         fragmentModule,                                                                                         // VkShaderModule                                               module;
338                         "main",                                                                                                         // const char*                                                  pName;
339                         DE_NULL,                                                                                                        // const VkSpecializationInfo*                  pSpecializationInfo;
340                 }
341         };
342
343         const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
344         {
345                 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
346                 DE_NULL,                                                                                        // const void*                                                                          pNext;
347                 (VkPipelineCreateFlags)0,                                                       // VkPipelineCreateFlags                                                        flags;
348                 DE_LENGTH_OF_ARRAY(pShaderStages),                                      // deUint32                                                                                     stageCount;
349                 pShaderStages,                                                                          // const VkPipelineShaderStageCreateInfo*                       pStages;
350                 &vertexInputStateInfo,                                                          // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
351                 &pipelineInputAssemblyStateInfo,                                        // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
352                 DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
353                 &pipelineViewportStateInfo,                                                     // const VkPipelineViewportStateCreateInfo*                     pViewportState;
354                 &pipelineRasterizationStateInfo,                                        // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
355                 &pipelineMultisampleStateInfo,                                          // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
356                 &pipelineDepthStencilStateInfo,                                         // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
357                 &pipelineColorBlendStateInfo,                                           // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
358                 DE_NULL,                                                                                        // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
359                 pipelineLayout,                                                                         // VkPipelineLayout                                                                     layout;
360                 renderPass,                                                                                     // VkRenderPass                                                                         renderPass;
361                 0u,                                                                                                     // deUint32                                                                                     subpass;
362                 DE_NULL,                                                                                        // VkPipeline                                                                           basePipelineHandle;
363                 0,                                                                                                      // deInt32                                                                                      basePipelineIndex;
364         };
365
366         return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
367 }
368
369 inline VertexData makeVertex (const float x, const float y, const Vec4& color)
370 {
371         const VertexData data = { Vec4(x, y, 0.0f, 1.0f), color };
372         return data;
373 }
374
375 std::vector<VertexData> genVertices (const TestPrimitive primitive, const Vec4& renderArea, const Vec4& primitiveColor)
376 {
377         std::vector<VertexData> vertices;
378         de::Random                              rng                     (1234);
379
380         const float     x0              = 2.0f * renderArea.x() - 1.0f;
381         const float y0          = 2.0f * renderArea.y() - 1.0f;
382         const float     rx              = 2.0f * renderArea.z();
383         const float     ry              = 2.0f * renderArea.w();
384         const float     size    = 0.2f;
385
386         switch (primitive)
387         {
388                 case TEST_PRIMITIVE_POINTS:
389                         for (int i = 0; i < 50; ++i)
390                         {
391                                 const float x = x0 + rng.getFloat(0.0f, rx);
392                                 const float y = y0 + rng.getFloat(0.0f, ry);
393                                 vertices.push_back(makeVertex(x, y, primitiveColor));
394                         }
395                         break;
396
397                 case TEST_PRIMITIVE_LINES:
398                         for (int i = 0; i < 30; ++i)
399                         {
400                                 const float x = x0 + rng.getFloat(0.0f, rx - size);
401                                 const float y = y0 + rng.getFloat(0.0f, ry - size);
402                                 vertices.push_back(makeVertex(x,        y,        primitiveColor));
403                                 vertices.push_back(makeVertex(x + size, y + size, primitiveColor));
404                         }
405                         break;
406
407                 case TEST_PRIMITIVE_TRIANGLES:
408                         for (int i = 0; i < 20; ++i)
409                         {
410                                 const float x = x0 + rng.getFloat(0.0f, rx - size);
411                                 const float y = y0 + rng.getFloat(0.0f, ry - size);
412                                 vertices.push_back(makeVertex(x,             y,        primitiveColor));
413                                 vertices.push_back(makeVertex(x + size/2.0f, y + size, primitiveColor));
414                                 vertices.push_back(makeVertex(x + size,      y,        primitiveColor));
415                         }
416                         break;
417
418                 case TEST_PRIMITIVE_BIG_LINE:
419                         vertices.push_back(makeVertex(x0,      y0,      primitiveColor));
420                         vertices.push_back(makeVertex(x0 + rx, y0 + ry, primitiveColor));
421                         break;
422
423                 case TEST_PRIMITIVE_BIG_TRIANGLE:
424                         vertices.push_back(makeVertex(x0,           y0,      primitiveColor));
425                         vertices.push_back(makeVertex(x0 + rx/2.0f, y0 + ry, primitiveColor));
426                         vertices.push_back(makeVertex(x0 + rx,      y0,      primitiveColor));
427                         break;
428         }
429
430         return vertices;
431 }
432
433 VkPrimitiveTopology     getTopology (const TestPrimitive primitive)
434 {
435         switch (primitive)
436         {
437                 case TEST_PRIMITIVE_POINTS:                     return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
438
439                 case TEST_PRIMITIVE_LINES:
440                 case TEST_PRIMITIVE_BIG_LINE:           return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
441
442                 case TEST_PRIMITIVE_TRIANGLES:
443                 case TEST_PRIMITIVE_BIG_TRIANGLE:       return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
444
445                 default:
446                         DE_ASSERT(0);
447                         return VK_PRIMITIVE_TOPOLOGY_LAST;
448         }
449 }
450
451 void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
452 {
453         deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
454         flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size);
455 }
456
457 //! Transform from normalized coords to framebuffer space.
458 inline IVec4 getAreaRect (const Vec4& area, const int width, const int height)
459 {
460         return IVec4(static_cast<deInt32>(static_cast<float>(width)  * area.x()),
461                                  static_cast<deInt32>(static_cast<float>(height) * area.y()),
462                                  static_cast<deInt32>(static_cast<float>(width)  * area.z()),
463                                  static_cast<deInt32>(static_cast<float>(height) * area.w()));
464 }
465
466 void applyScissor (tcu::PixelBufferAccess imageAccess, const Vec4& floatScissorArea, const Vec4& clearColor)
467 {
468         const IVec4     scissorRect     (getAreaRect(floatScissorArea, imageAccess.getWidth(), imageAccess.getHeight()));
469         const int       sx0                     = scissorRect.x();
470         const int       sx1                     = scissorRect.x() + scissorRect.z();
471         const int       sy0                     = scissorRect.y();
472         const int       sy1                     = scissorRect.y() + scissorRect.w();
473
474         for (int y = 0; y < imageAccess.getHeight(); ++y)
475         for (int x = 0; x < imageAccess.getWidth(); ++x)
476         {
477                 // Fragments outside fail the scissor test.
478                 if (x < sx0 || x >= sx1 || y < sy0 || y >= sy1)
479                         imageAccess.setPixel(clearColor, x, y);
480         }
481 }
482
483 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
484 {
485         DE_UNREF(caseDef);
486
487         // Vertex shader
488         {
489                 const bool usePointSize = (caseDef.primitive == TEST_PRIMITIVE_POINTS);
490
491                 std::ostringstream src;
492                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
493                         << "\n"
494                         << "layout(location = 0) in  vec4 in_position;\n"
495                         << "layout(location = 1) in  vec4 in_color;\n"
496                         << "layout(location = 0) out vec4 o_color;\n"
497                         << "\n"
498                         << "out gl_PerVertex {\n"
499                         << "    vec4  gl_Position;\n"
500                         << (usePointSize ? "    float gl_PointSize;\n" : "")
501                         << "};\n"
502                         << "\n"
503                         << "void main(void)\n"
504                         << "{\n"
505                         << "    gl_Position  = in_position;\n"
506                         << (usePointSize ? "    gl_PointSize = 1.0;\n" : "")
507                         << "    o_color      = in_color;\n"
508                         << "}\n";
509
510                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
511         }
512
513         // Fragment shader
514         {
515                 std::ostringstream src;
516                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
517                         << "\n"
518                         << "layout(location = 0) in  vec4 in_color;\n"
519                         << "layout(location = 0) out vec4 o_color;\n"
520                         << "\n"
521                         << "void main(void)\n"
522                         << "{\n"
523                         << "    o_color = in_color;\n"
524                         << "}\n";
525
526                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
527         }
528 }
529
530 class ScissorRenderer
531 {
532 public:
533         ScissorRenderer (Context& context, const CaseDef caseDef, const IVec2& renderSize, const VkFormat colorFormat, const Vec4& primitiveColor, const Vec4& clearColor)
534                 : m_renderSize                          (renderSize)
535                 , m_colorFormat                         (colorFormat)
536                 , m_colorSubresourceRange       (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
537                 , m_primitiveColor                      (primitiveColor)
538                 , m_clearColor                          (clearColor)
539                 , m_vertices                            (genVertices(caseDef.primitive, caseDef.renderArea, m_primitiveColor))
540                 , m_vertexBufferSize            (sizeInBytes(m_vertices))
541                 , m_topology                            (getTopology(caseDef.primitive))
542         {
543                 const DeviceInterface&          vk                                      = context.getDeviceInterface();
544                 const VkDevice                          device                          = context.getDevice();
545                 const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
546                 Allocator&                                      allocator                       = context.getDefaultAllocator();
547
548                 m_colorImage                    = makeImage(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
549                 m_colorImageAlloc               = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
550                 m_colorAttachment               = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
551
552                 m_vertexBuffer                  = makeBuffer(vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
553                 m_vertexBufferAlloc             = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
554
555                 {
556                         deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
557                         flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize);
558                 }
559
560                 m_vertexModule                          = createShaderModule    (vk, device, context.getBinaryCollection().get("vert"), 0u);
561                 m_fragmentModule                        = createShaderModule    (vk, device, context.getBinaryCollection().get("frag"), 0u);
562                 m_renderPass                            = makeRenderPass                (vk, device, m_colorFormat);
563                 m_framebuffer                           = makeFramebuffer               (vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
564                                                                                                                          static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
565                 m_pipelineLayout                        = makePipelineLayout    (vk, device);
566                 m_cmdPool                                       = createCommandPool             (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
567                 m_cmdBuffer                                     = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
568
569         }
570
571         void draw (Context& context, const Vec4& scissorAreaFloat, const VkBuffer colorBuffer) const
572         {
573                 const DeviceInterface&          vk                      = context.getDeviceInterface();
574                 const VkDevice                          device          = context.getDevice();
575                 const VkQueue                           queue           = context.getUniversalQueue();
576
577                 // New pipeline, because we're modifying scissor (we don't use dynamic state).
578                 const Unique<VkPipeline>        pipeline        (makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule,
579                                                                                                  m_renderSize, getAreaRect(scissorAreaFloat, m_renderSize.x(), m_renderSize.y()), m_topology));
580
581                 beginCommandBuffer(vk, *m_cmdBuffer);
582
583                 const VkClearValue                      clearValue      = makeClearValueColor(m_clearColor);
584                 const VkRect2D                          renderArea      =
585                 {
586                         makeOffset2D(0, 0),
587                         makeExtent2D(m_renderSize.x(), m_renderSize.y()),
588                 };
589                 const VkRenderPassBeginInfo renderPassBeginInfo =
590                 {
591                         VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,               // VkStructureType         sType;
592                         DE_NULL,                                                                                // const void*             pNext;
593                         *m_renderPass,                                                                  // VkRenderPass            renderPass;
594                         *m_framebuffer,                                                                 // VkFramebuffer           framebuffer;
595                         renderArea,                                                                             // VkRect2D                renderArea;
596                         1u,                                                                                             // uint32_t                clearValueCount;
597                         &clearValue,                                                                    // const VkClearValue*     pClearValues;
598                 };
599                 vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
600
601                 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
602                 {
603                         const VkDeviceSize vertexBufferOffset = 0ull;
604                         vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
605                 }
606
607                 vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u);
608                 vk.cmdEndRenderPass(*m_cmdBuffer);
609
610                 // Prepare color image for copy
611                 {
612                         const VkImageMemoryBarrier barriers[] =
613                         {
614                                 {
615                                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                         // VkStructureType                      sType;
616                                         DE_NULL,                                                                                                        // const void*                          pNext;
617                                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,                                           // VkAccessFlags                        outputMask;
618                                         VK_ACCESS_TRANSFER_READ_BIT,                                                            // VkAccessFlags                        inputMask;
619                                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                       // VkImageLayout                        oldLayout;
620                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                                           // VkImageLayout                        newLayout;
621                                         VK_QUEUE_FAMILY_IGNORED,                                                                        // deUint32                                     srcQueueFamilyIndex;
622                                         VK_QUEUE_FAMILY_IGNORED,                                                                        // deUint32                                     destQueueFamilyIndex;
623                                         *m_colorImage,                                                                                          // VkImage                                      image;
624                                         m_colorSubresourceRange,                                                                        // VkImageSubresourceRange      subresourceRange;
625                                 },
626                         };
627
628                         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
629                                 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
630                 }
631                 // Color image -> host buffer
632                 {
633                         const VkBufferImageCopy region =
634                         {
635                                 0ull,                                                                                                                                           // VkDeviceSize                bufferOffset;
636                                 0u,                                                                                                                                                     // uint32_t                    bufferRowLength;
637                                 0u,                                                                                                                                                     // uint32_t                    bufferImageHeight;
638                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),                      // VkImageSubresourceLayers    imageSubresource;
639                                 makeOffset3D(0, 0, 0),                                                                                                          // VkOffset3D                  imageOffset;
640                                 makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),                                           // VkExtent3D                  imageExtent;
641                         };
642
643                         vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
644                 }
645                 // Buffer write barrier
646                 {
647                         const VkBufferMemoryBarrier barriers[] =
648                         {
649                                 {
650                                         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,                // VkStructureType    sType;
651                                         DE_NULL,                                                                                // const void*        pNext;
652                                         VK_ACCESS_TRANSFER_WRITE_BIT,                                   // VkAccessFlags      srcAccessMask;
653                                         VK_ACCESS_HOST_READ_BIT,                                                // VkAccessFlags      dstAccessMask;
654                                         VK_QUEUE_FAMILY_IGNORED,                                                // uint32_t           srcQueueFamilyIndex;
655                                         VK_QUEUE_FAMILY_IGNORED,                                                // uint32_t           dstQueueFamilyIndex;
656                                         colorBuffer,                                                                    // VkBuffer           buffer;
657                                         0ull,                                                                                   // VkDeviceSize       offset;
658                                         VK_WHOLE_SIZE,                                                                  // VkDeviceSize       size;
659                                 },
660                         };
661
662                         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
663                                 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
664                 }
665
666                 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
667                 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
668         }
669
670 private:
671         const IVec2                                             m_renderSize;
672         const VkFormat                                  m_colorFormat;
673         const VkImageSubresourceRange   m_colorSubresourceRange;
674         const Vec4                                              m_primitiveColor;
675         const Vec4                                              m_clearColor;
676         const std::vector<VertexData>   m_vertices;
677         const VkDeviceSize                              m_vertexBufferSize;
678         const VkPrimitiveTopology               m_topology;
679
680         Move<VkImage>                                   m_colorImage;
681         MovePtr<Allocation>                             m_colorImageAlloc;
682         Move<VkImageView>                               m_colorAttachment;
683         Move<VkBuffer>                                  m_vertexBuffer;
684         MovePtr<Allocation>                             m_vertexBufferAlloc;
685         Move<VkShaderModule>                    m_vertexModule;
686         Move<VkShaderModule>                    m_fragmentModule;
687         Move<VkRenderPass>                              m_renderPass;
688         Move<VkFramebuffer>                             m_framebuffer;
689         Move<VkPipelineLayout>                  m_pipelineLayout;
690         Move<VkCommandPool>                             m_cmdPool;
691         Move<VkCommandBuffer>                   m_cmdBuffer;
692
693         // "deleted"
694                                                 ScissorRenderer (const ScissorRenderer&);
695         ScissorRenderer&        operator=               (const ScissorRenderer&);
696 };
697
698 tcu::TestStatus test (Context& context, const CaseDef caseDef)
699 {
700         const DeviceInterface&                  vk                                                      = context.getDeviceInterface();
701         const VkDevice                                  device                                          = context.getDevice();
702         Allocator&                                              allocator                                       = context.getDefaultAllocator();
703
704         const IVec2                                             renderSize                                      (128, 128);
705         const VkFormat                                  colorFormat                                     = VK_FORMAT_R8G8B8A8_UNORM;
706         const Vec4                                              scissorFullArea                         (0.0f, 0.0f, 1.0f, 1.0f);
707         const Vec4                                              primitiveColor                          (1.0f, 1.0f, 1.0f, 1.0f);
708         const Vec4                                              clearColor                                      (0.5f, 0.5f, 1.0f, 1.0f);
709
710         const VkDeviceSize                              colorBufferSize                         = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
711         const Unique<VkBuffer>                  colorBufferFull                         (makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
712         const UniquePtr<Allocation>             colorBufferFullAlloc            (bindBuffer(vk, device, allocator, *colorBufferFull, MemoryRequirement::HostVisible));
713
714         const Unique<VkBuffer>                  colorBufferScissored            (makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
715         const UniquePtr<Allocation>             colorBufferScissoredAlloc       (bindBuffer(vk, device, allocator, *colorBufferScissored, MemoryRequirement::HostVisible));
716
717         zeroBuffer(vk, device, *colorBufferFullAlloc, colorBufferSize);
718         zeroBuffer(vk, device, *colorBufferScissoredAlloc, colorBufferSize);
719
720         // Draw
721         {
722                 const ScissorRenderer renderer (context, caseDef, renderSize, colorFormat, primitiveColor, clearColor);
723
724                 renderer.draw(context, scissorFullArea, *colorBufferFull);
725                 renderer.draw(context, caseDef.scissorArea, *colorBufferScissored);
726         }
727
728         // Log image
729         {
730                 invalidateMappedMemoryRange(vk, device, colorBufferFullAlloc->getMemory(), 0ull, colorBufferSize);
731                 invalidateMappedMemoryRange(vk, device, colorBufferScissoredAlloc->getMemory(), 0ull, colorBufferSize);
732
733                 const tcu::ConstPixelBufferAccess       resultImage             (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferScissoredAlloc->getHostPtr());
734                 tcu::PixelBufferAccess                          referenceImage  (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferFullAlloc->getHostPtr());
735
736                 // Apply scissor to the full image, so we can compare it with the result image.
737                 applyScissor (referenceImage, caseDef.scissorArea, clearColor);
738
739                 // Images should now match.
740                 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage, resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
741                         return tcu::TestStatus::fail("Rendered image is not correct");
742         }
743
744         return tcu::TestStatus::pass("OK");
745 }
746
747 //! \note The ES 2.0 scissoring tests included color/depth/stencil clear cases, but these operations are not affected by scissor test in Vulkan.
748 //!       Scissor is part of the pipeline state and pipeline only affects the drawing commands.
749 void createTestsInGroup (tcu::TestCaseGroup* scissorGroup)
750 {
751         tcu::TestContext& testCtx = scissorGroup->getTestContext();
752
753         struct TestSpec
754         {
755                 const char*             name;
756                 const char*             description;
757                 CaseDef                 caseDef;
758         };
759
760         const Vec4      areaFull                        (0.0f, 0.0f, 1.0f, 1.0f);
761         const Vec4      areaCropped                     (0.2f, 0.2f, 0.6f, 0.6f);
762         const Vec4      areaCroppedMore         (0.4f, 0.4f, 0.2f, 0.2f);
763         const Vec4      areaLeftHalf            (0.0f, 0.0f, 0.5f, 1.0f);
764         const Vec4      areaRightHalf           (0.5f, 0.0f, 0.5f, 1.0f);
765
766         // Points
767         {
768                 MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "points", ""));
769
770                 const TestSpec  cases[] =
771                 {
772                         { "inside",                             "Points fully inside the scissor area",         { areaFull,             areaFull,               TEST_PRIMITIVE_POINTS } },
773                         { "partially_inside",   "Points partially inside the scissor area",     { areaFull,             areaCropped,    TEST_PRIMITIVE_POINTS } },
774                         { "outside",                    "Points fully outside the scissor area",        { areaLeftHalf, areaRightHalf,  TEST_PRIMITIVE_POINTS } },
775                 };
776
777                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
778                         addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
779
780                 scissorGroup->addChild(primitiveGroup.release());
781         }
782
783         // Lines
784         {
785                 MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "lines", ""));
786
787                 const TestSpec  cases[] =
788                 {
789                         { "inside",                             "Lines fully inside the scissor area",          { areaFull,             areaFull,                       TEST_PRIMITIVE_LINES    } },
790                         { "partially_inside",   "Lines partially inside the scissor area",      { areaFull,             areaCropped,            TEST_PRIMITIVE_LINES    } },
791                         { "outside",                    "Lines fully outside the scissor area",         { areaLeftHalf, areaRightHalf,          TEST_PRIMITIVE_LINES    } },
792                         { "crossing",                   "A line crossing the scissor area",                     { areaFull,             areaCroppedMore,        TEST_PRIMITIVE_BIG_LINE } },
793                 };
794
795                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
796                         addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
797
798                 scissorGroup->addChild(primitiveGroup.release());
799         }
800
801         // Triangles
802         {
803                 MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "triangles", ""));
804
805                 const TestSpec  cases[] =
806                 {
807                         { "inside",                             "Triangles fully inside the scissor area",              { areaFull,             areaFull,                       TEST_PRIMITIVE_TRIANGLES        } },
808                         { "partially_inside",   "Triangles partially inside the scissor area",  { areaFull,             areaCropped,            TEST_PRIMITIVE_TRIANGLES        } },
809                         { "outside",                    "Triangles fully outside the scissor area",             { areaLeftHalf, areaRightHalf,          TEST_PRIMITIVE_TRIANGLES        } },
810                         { "crossing",                   "A triangle crossing the scissor area",                 { areaFull,             areaCroppedMore,        TEST_PRIMITIVE_BIG_TRIANGLE     } },
811                 };
812
813                 for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
814                         addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
815
816                 scissorGroup->addChild(primitiveGroup.release());
817         }
818
819         // Mulit-viewport scissor
820         {
821                 scissorGroup->addChild(createScissorMultiViewportTests(testCtx));
822         }
823 }
824
825 } // anonymous
826
827 tcu::TestCaseGroup* createScissorTests (tcu::TestContext& testCtx)
828 {
829         return createTestGroup(testCtx, "scissor", "Scissor tests", createTestsInGroup);
830 }
831
832 } // FragmentOperations
833 } // vkt