VK_KHR_maintenance2: View block-compressed add check shader_read_only_optimal
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / clipping / vktClippingTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Clipping tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktClippingTests.hpp"
25 #include "vktTestCase.hpp"
26 #include "vktTestGroupUtil.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktClippingUtil.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "tcuTestLog.hpp"
33 #include "deUniquePtr.hpp"
34 #include "deStringUtil.hpp"
35 #include "deRandom.hpp"
36
37 namespace vkt
38 {
39 namespace clipping
40 {
41 namespace
42 {
43 using namespace vk;
44 using de::MovePtr;
45 using tcu::UVec2;
46 using tcu::Vec4;
47 using tcu::IVec2;
48
49 enum Constants
50 {
51         RENDER_SIZE                                                             = 16,
52         RENDER_SIZE_LARGE                                               = 128,
53         NUM_RENDER_PIXELS                                               = RENDER_SIZE * RENDER_SIZE,
54         NUM_PATCH_CONTROL_POINTS                                = 3,
55         MAX_NUM_SHADER_MODULES                                  = 5,
56         MAX_CLIP_DISTANCES                                              = 8,
57         MAX_CULL_DISTANCES                                              = 8,
58         MAX_COMBINED_CLIP_AND_CULL_DISTANCES    = 8,
59 };
60
61 struct Shader
62 {
63         VkShaderStageFlagBits   stage;
64         const ProgramBinary*    binary;
65
66         Shader (const VkShaderStageFlagBits stage_, const ProgramBinary& binary_)
67                 : stage         (stage_)
68                 , binary        (&binary_)
69         {
70         }
71 };
72
73 //! Sets up a graphics pipeline and enables simple draw calls to predefined attachments.
74 //! Clip volume uses wc = 1.0, which gives clip coord ranges: x = [-1, 1], y = [-1, 1], z = [0, 1]
75 //! Clip coords (-1,-1) map to viewport coords (0, 0).
76 class DrawContext
77 {
78 public:
79                                                                         DrawContext             (Context&                                               context,
80                                                                                                          const std::vector<Shader>&             shaders,
81                                                                                                          const std::vector<Vec4>&               vertices,
82                                                                                                          const VkPrimitiveTopology              primitiveTopology,
83                                                                                                          const deUint32                                 renderSize                      = static_cast<deUint32>(RENDER_SIZE),
84                                                                                                          const bool                                             depthClampEnable        = false,
85                                                                                                          const bool                                             blendEnable                     = false,
86                                                                                                          const float                                    lineWidth                       = 1.0f);
87
88         void                                                    draw                    (void);
89         tcu::ConstPixelBufferAccess             getColorPixels  (void) const;
90
91 private:
92         Context&                                                m_context;
93         const VkFormat                                  m_colorFormat;
94         const VkImageSubresourceRange   m_colorSubresourceRange;
95         const UVec2                                             m_renderSize;
96         const VkExtent3D                                m_imageExtent;
97         const VkPrimitiveTopology               m_primitiveTopology;
98         const bool                                              m_depthClampEnable;
99         const bool                                              m_blendEnable;
100         const deUint32                                  m_numVertices;
101         const float                                             m_lineWidth;
102         const deUint32                                  m_numPatchControlPoints;
103         MovePtr<Buffer>                                 m_vertexBuffer;
104         MovePtr<Image>                                  m_colorImage;
105         MovePtr<Buffer>                                 m_colorAttachmentBuffer;
106         Move<VkImageView>                               m_colorImageView;
107         Move<VkRenderPass>                              m_renderPass;
108         Move<VkFramebuffer>                             m_framebuffer;
109         Move<VkPipelineLayout>                  m_pipelineLayout;
110         Move<VkPipeline>                                m_pipeline;
111         Move<VkCommandPool>                             m_cmdPool;
112         Move<VkCommandBuffer>                   m_cmdBuffer;
113         Move<VkShaderModule>                    m_shaderModules[MAX_NUM_SHADER_MODULES];
114
115                                                                         DrawContext             (const DrawContext&);   // "deleted"
116         DrawContext&                                    operator=               (const DrawContext&);   // "deleted"
117 };
118
119 DrawContext::DrawContext (Context&                                              context,
120                                                   const std::vector<Shader>&    shaders,
121                                                   const std::vector<Vec4>&              vertices,
122                                                   const VkPrimitiveTopology             primitiveTopology,
123                                                   const deUint32                                renderSize,
124                                                   const bool                                    depthClampEnable,
125                                                   const bool                                    blendEnable,
126                                                   const float                                   lineWidth)
127         : m_context                                     (context)
128         , m_colorFormat                         (VK_FORMAT_R8G8B8A8_UNORM)
129         , m_colorSubresourceRange       (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
130         , m_renderSize                          (renderSize, renderSize)
131         , m_imageExtent                         (makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u))
132         , m_primitiveTopology           (primitiveTopology)
133         , m_depthClampEnable            (depthClampEnable)
134         , m_blendEnable                         (blendEnable)
135         , m_numVertices                         (static_cast<deUint32>(vertices.size()))
136         , m_lineWidth                           (lineWidth)
137         , m_numPatchControlPoints       (NUM_PATCH_CONTROL_POINTS)              // we're treating patches as triangles
138 {
139         const DeviceInterface&  vk                      = m_context.getDeviceInterface();
140         const VkDevice                  device          = m_context.getDevice();
141         Allocator&                              allocator       = m_context.getDefaultAllocator();
142
143         // Command buffer
144         {
145                 m_cmdPool       = makeCommandPool(vk, device, m_context.getUniversalQueueFamilyIndex());
146                 m_cmdBuffer     = makeCommandBuffer(vk, device, *m_cmdPool);
147         }
148
149         // Color attachment image
150         {
151                 const VkImageUsageFlags usage                   = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
152                 const VkImageCreateInfo imageCreateInfo =
153                 {
154                         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,            // VkStructureType          sType;
155                         DE_NULL,                                                                        // const void*              pNext;
156                         (VkImageCreateFlags)0,                                          // VkImageCreateFlags       flags;
157                         VK_IMAGE_TYPE_2D,                                                       // VkImageType              imageType;
158                         m_colorFormat,                                                          // VkFormat                 format;
159                         m_imageExtent,                                                          // VkExtent3D               extent;
160                         1u,                                                                                     // uint32_t                 mipLevels;
161                         1u,                                                                                     // uint32_t                 arrayLayers;
162                         VK_SAMPLE_COUNT_1_BIT,                                          // VkSampleCountFlagBits    samples;
163                         VK_IMAGE_TILING_OPTIMAL,                                        // VkImageTiling            tiling;
164                         usage,                                                                          // VkImageUsageFlags        usage;
165                         VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode            sharingMode;
166                         VK_QUEUE_FAMILY_IGNORED,                                        // uint32_t                 queueFamilyIndexCount;
167                         DE_NULL,                                                                        // const uint32_t*          pQueueFamilyIndices;
168                         VK_IMAGE_LAYOUT_UNDEFINED,                                      // VkImageLayout            initialLayout;
169                 };
170
171                 m_colorImage = MovePtr<Image>(new Image(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
172                 m_colorImageView = makeImageView(vk, device, **m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
173
174                 // Buffer to copy attachment data after rendering
175
176                 const VkDeviceSize bitmapSize = tcu::getPixelSize(mapVkFormat(m_colorFormat)) * m_renderSize.x() * m_renderSize.y();
177                 m_colorAttachmentBuffer = MovePtr<Buffer>(new Buffer(
178                         vk, device, allocator, makeBufferCreateInfo(bitmapSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible));
179
180                 {
181                         const Allocation& alloc = m_colorAttachmentBuffer->getAllocation();
182                         deMemset(alloc.getHostPtr(), 0, (size_t)bitmapSize);
183                         flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bitmapSize);
184                 }
185         }
186
187         // Vertex buffer
188         {
189                 const VkDeviceSize bufferSize = vertices.size() * sizeof(vertices[0]);
190                 m_vertexBuffer = MovePtr<Buffer>(new Buffer(
191                         vk, device, allocator, makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible));
192
193                 const Allocation& alloc = m_vertexBuffer->getAllocation();
194                 deMemcpy(alloc.getHostPtr(), &vertices[0], (size_t)bufferSize);
195                 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bufferSize);
196         }
197
198         // Pipeline layout
199         {
200                 m_pipelineLayout = makePipelineLayoutWithoutDescriptors(vk, device);
201         }
202
203         // Renderpass
204         {
205                 const VkAttachmentDescription colorAttachmentDescription =
206                 {
207                         (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags         flags;
208                         m_colorFormat,                                                                          // VkFormat                                                     format;
209                         VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits                        samples;
210                         VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
211                         VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                          storeOp;
212                         VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                           stencilLoadOp;
213                         VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          stencilStoreOp;
214                         VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout                                        initialLayout;
215                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        finalLayout;
216                 };
217
218                 const VkAttachmentReference colorAttachmentReference =
219                 {
220                         0u,                                                                                                     // deUint32                     attachment;
221                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
222                 };
223
224                 const VkAttachmentReference depthAttachmentReference =
225                 {
226                         VK_ATTACHMENT_UNUSED,                                                           // deUint32                     attachment;
227                         VK_IMAGE_LAYOUT_UNDEFINED                                                       // VkImageLayout        layout;
228                 };
229
230                 const VkSubpassDescription subpassDescription =
231                 {
232                         (VkSubpassDescriptionFlags)0,                                           // VkSubpassDescriptionFlags            flags;
233                         VK_PIPELINE_BIND_POINT_GRAPHICS,                                        // VkPipelineBindPoint                          pipelineBindPoint;
234                         0u,                                                                                                     // deUint32                                                     inputAttachmentCount;
235                         DE_NULL,                                                                                        // const VkAttachmentReference*         pInputAttachments;
236                         1u,                                                                                                     // deUint32                                                     colorAttachmentCount;
237                         &colorAttachmentReference,                                                      // const VkAttachmentReference*         pColorAttachments;
238                         DE_NULL,                                                                                        // const VkAttachmentReference*         pResolveAttachments;
239                         &depthAttachmentReference,                                                      // const VkAttachmentReference*         pDepthStencilAttachment;
240                         0u,                                                                                                     // deUint32                                                     preserveAttachmentCount;
241                         DE_NULL                                                                                         // const deUint32*                                      pPreserveAttachments;
242                 };
243
244                 const VkRenderPassCreateInfo renderPassInfo =
245                 {
246                         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                      // VkStructureType                                      sType;
247                         DE_NULL,                                                                                        // const void*                                          pNext;
248                         (VkRenderPassCreateFlags)0,                                                     // VkRenderPassCreateFlags                      flags;
249                         1u,                                                                                                     // deUint32                                                     attachmentCount;
250                         &colorAttachmentDescription,                                            // const VkAttachmentDescription*       pAttachments;
251                         1u,                                                                                                     // deUint32                                                     subpassCount;
252                         &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
253                         0u,                                                                                                     // deUint32                                                     dependencyCount;
254                         DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
255                 };
256
257                 m_renderPass = createRenderPass(vk, device, &renderPassInfo);
258         }
259
260         // Framebuffer
261         {
262                 const VkFramebufferCreateInfo framebufferInfo = {
263                         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,              // VkStructureType                             sType;
264                         DE_NULL,                                                                                // const void*                                 pNext;
265                         (VkFramebufferCreateFlags)0,                                    // VkFramebufferCreateFlags                    flags;
266                         *m_renderPass,                                                                  // VkRenderPass                                renderPass;
267                         1u,                                                                                             // uint32_t                                    attachmentCount;
268                         &m_colorImageView.get(),                                                // const VkImageView*                          pAttachments;
269                         m_renderSize.x(),                                                               // uint32_t                                    width;
270                         m_renderSize.y(),                                                               // uint32_t                                    height;
271                         1u,                                                                                             // uint32_t                                    layers;
272                 };
273
274                 m_framebuffer = createFramebuffer(vk, device, &framebufferInfo);
275         }
276
277         // Graphics pipeline
278         {
279                 const deUint32  vertexStride    = sizeof(Vec4);
280                 const VkFormat  vertexFormat    = VK_FORMAT_R32G32B32A32_SFLOAT;
281
282                 const VkVertexInputBindingDescription bindingDesc =
283                 {
284                         0u,                                                                     // uint32_t                             binding;
285                         vertexStride,                                           // uint32_t                             stride;
286                         VK_VERTEX_INPUT_RATE_VERTEX,            // VkVertexInputRate    inputRate;
287                 };
288                 const VkVertexInputAttributeDescription attributeDesc =
289                 {
290                         0u,                                                                     // uint32_t                     location;
291                         0u,                                                                     // uint32_t                     binding;
292                         vertexFormat,                                           // VkFormat                     format;
293                         0u,                                                                     // uint32_t                     offset;
294                 };
295
296                 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
297                 {
298                         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,              // VkStructureType                             sType;
299                         DE_NULL,                                                                                                                // const void*                                 pNext;
300                         (VkPipelineVertexInputStateCreateFlags)0,                                               // VkPipelineVertexInputStateCreateFlags       flags;
301                         1u,                                                                                                                             // uint32_t                                    vertexBindingDescriptionCount;
302                         &bindingDesc,                                                                                                   // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
303                         1u,                                                                                                                             // uint32_t                                    vertexAttributeDescriptionCount;
304                         &attributeDesc,                                                                                                 // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
305                 };
306
307                 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
308                 {
309                         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    // VkStructureType                             sType;
310                         DE_NULL,                                                                                                                // const void*                                 pNext;
311                         (VkPipelineInputAssemblyStateCreateFlags)0,                                             // VkPipelineInputAssemblyStateCreateFlags     flags;
312                         m_primitiveTopology,                                                                                    // VkPrimitiveTopology                         topology;
313                         VK_FALSE,                                                                                                               // VkBool32                                    primitiveRestartEnable;
314                 };
315
316                 const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
317                 {
318                         VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,              // VkStructureType                             sType;
319                         DE_NULL,                                                                                                                // const void*                                 pNext;
320                         (VkPipelineTessellationStateCreateFlags)0,                                              // VkPipelineTessellationStateCreateFlags      flags;
321                         m_numPatchControlPoints,                                                                                // uint32_t                                    patchControlPoints;
322                 };
323
324                 const VkViewport viewport = makeViewport(
325                         0.0f, 0.0f,
326                         static_cast<float>(m_renderSize.x()), static_cast<float>(m_renderSize.y()),
327                         0.0f, 1.0f);
328
329                 const VkRect2D scissor = {
330                         makeOffset2D(0, 0),
331                         makeExtent2D(m_renderSize.x(), m_renderSize.y()),
332                 };
333
334                 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
335                 {
336                         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,  // VkStructureType                             sType;
337                         DE_NULL,                                                                                                // const void*                                 pNext;
338                         (VkPipelineViewportStateCreateFlags)0,                                  // VkPipelineViewportStateCreateFlags          flags;
339                         1u,                                                                                                             // uint32_t                                    viewportCount;
340                         &viewport,                                                                                              // const VkViewport*                           pViewports;
341                         1u,                                                                                                             // uint32_t                                    scissorCount;
342                         &scissor,                                                                                               // const VkRect2D*                             pScissors;
343                 };
344
345                 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
346                 {
347                         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,             // VkStructureType                          sType;
348                         DE_NULL,                                                                                                                // const void*                              pNext;
349                         (VkPipelineRasterizationStateCreateFlags)0,                                             // VkPipelineRasterizationStateCreateFlags  flags;
350                         m_depthClampEnable,                                                                                             // VkBool32                                 depthClampEnable;
351                         VK_FALSE,                                                                                                               // VkBool32                                 rasterizerDiscardEnable;
352                         VK_POLYGON_MODE_FILL,                                                                                   // VkPolygonMode                                                        polygonMode;
353                         VK_CULL_MODE_NONE,                                                                                              // VkCullModeFlags                                                      cullMode;
354                         VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                // VkFrontFace                                                          frontFace;
355                         VK_FALSE,                                                                                                               // VkBool32                                                                     depthBiasEnable;
356                         0.0f,                                                                                                                   // float                                                                        depthBiasConstantFactor;
357                         0.0f,                                                                                                                   // float                                                                        depthBiasClamp;
358                         0.0f,                                                                                                                   // float                                                                        depthBiasSlopeFactor;
359                         m_lineWidth,                                                                                                    // float                                                                        lineWidth;
360                 };
361
362                 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
363                 {
364                         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,       // VkStructureType                                                      sType;
365                         DE_NULL,                                                                                                        // const void*                                                          pNext;
366                         (VkPipelineMultisampleStateCreateFlags)0,                                       // VkPipelineMultisampleStateCreateFlags        flags;
367                         VK_SAMPLE_COUNT_1_BIT,                                                                          // VkSampleCountFlagBits                                        rasterizationSamples;
368                         VK_FALSE,                                                                                                       // VkBool32                                                                     sampleShadingEnable;
369                         0.0f,                                                                                                           // float                                                                        minSampleShading;
370                         DE_NULL,                                                                                                        // const VkSampleMask*                                          pSampleMask;
371                         VK_FALSE,                                                                                                       // VkBool32                                                                     alphaToCoverageEnable;
372                         VK_FALSE                                                                                                        // VkBool32                                                                     alphaToOneEnable;
373                 };
374
375                 const VkStencilOpState stencilOpState = makeStencilOpState(
376                         VK_STENCIL_OP_KEEP,             // stencil fail
377                         VK_STENCIL_OP_KEEP,             // depth & stencil pass
378                         VK_STENCIL_OP_KEEP,             // depth only fail
379                         VK_COMPARE_OP_NEVER,    // compare op
380                         0u,                                             // compare mask
381                         0u,                                             // write mask
382                         0u);                                    // reference
383
384                 const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
385                 {
386                         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,     // VkStructureType                                                      sType;
387                         DE_NULL,                                                                                                        // const void*                                                          pNext;
388                         (VkPipelineDepthStencilStateCreateFlags)0,                                      // VkPipelineDepthStencilStateCreateFlags       flags;
389                         VK_FALSE,                                                                                                       // VkBool32                                                                     depthTestEnable;
390                         VK_FALSE,                                                                                                       // VkBool32                                                                     depthWriteEnable;
391                         VK_COMPARE_OP_LESS,                                                                                     // VkCompareOp                                                          depthCompareOp;
392                         VK_FALSE,                                                                                                       // VkBool32                                                                     depthBoundsTestEnable;
393                         VK_FALSE,                                                                                                       // VkBool32                                                                     stencilTestEnable;
394                         stencilOpState,                                                                                         // VkStencilOpState                                                     front;
395                         stencilOpState,                                                                                         // VkStencilOpState                                                     back;
396                         0.0f,                                                                                                           // float                                                                        minDepthBounds;
397                         1.0f,                                                                                                           // float                                                                        maxDepthBounds;
398                 };
399
400                 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
401                 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
402                 {
403                         m_blendEnable,                                          // VkBool32                                     blendEnable;
404                         VK_BLEND_FACTOR_SRC_ALPHA,                      // VkBlendFactor                        srcColorBlendFactor;
405                         VK_BLEND_FACTOR_ONE,                            // VkBlendFactor                        dstColorBlendFactor;
406                         VK_BLEND_OP_ADD,                                        // VkBlendOp                            colorBlendOp;
407                         VK_BLEND_FACTOR_SRC_ALPHA,                      // VkBlendFactor                        srcAlphaBlendFactor;
408                         VK_BLEND_FACTOR_ONE,                            // VkBlendFactor                        dstAlphaBlendFactor;
409                         VK_BLEND_OP_ADD,                                        // VkBlendOp                            alphaBlendOp;
410                         colorComponentsAll,                                     // VkColorComponentFlags        colorWriteMask;
411                 };
412
413                 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
414                 {
415                         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,       // VkStructureType                                                              sType;
416                         DE_NULL,                                                                                                        // const void*                                                                  pNext;
417                         (VkPipelineColorBlendStateCreateFlags)0,                                        // VkPipelineColorBlendStateCreateFlags                 flags;
418                         VK_FALSE,                                                                                                       // VkBool32                                                                             logicOpEnable;
419                         VK_LOGIC_OP_COPY,                                                                                       // VkLogicOp                                                                    logicOp;
420                         1u,                                                                                                                     // deUint32                                                                             attachmentCount;
421                         &pipelineColorBlendAttachmentState,                                                     // const VkPipelineColorBlendAttachmentState*   pAttachments;
422                         { 0.0f, 0.0f, 0.0f, 0.0f },                                                                     // float                                                                                blendConstants[4];
423                 };
424
425                 // Create shader stages
426
427                 std::vector<VkPipelineShaderStageCreateInfo>    shaderStages;
428                 VkShaderStageFlags                                                              stageFlags = (VkShaderStageFlags)0;
429
430                 DE_ASSERT(shaders.size() <= MAX_NUM_SHADER_MODULES);
431                 for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx)
432                 {
433                         m_shaderModules[shaderNdx] = createShaderModule(vk, device, *shaders[shaderNdx].binary, (VkShaderModuleCreateFlags)0);
434
435                         const VkPipelineShaderStageCreateInfo pipelineShaderStageInfo =
436                         {
437                                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,    // VkStructureType                                              sType;
438                                 DE_NULL,                                                                                                // const void*                                                  pNext;
439                                 (VkPipelineShaderStageCreateFlags)0,                                    // VkPipelineShaderStageCreateFlags             flags;
440                                 shaders[shaderNdx].stage,                                                               // VkShaderStageFlagBits                                stage;
441                                 *m_shaderModules[shaderNdx],                                                    // VkShaderModule                                               module;
442                                 "main",                                                                                                 // const char*                                                  pName;
443                                 DE_NULL,                                                                                                // const VkSpecializationInfo*                  pSpecializationInfo;
444                         };
445
446                         shaderStages.push_back(pipelineShaderStageInfo);
447                         stageFlags |= shaders[shaderNdx].stage;
448                 }
449
450                 DE_ASSERT(
451                         (m_primitiveTopology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) ||
452                         (stageFlags & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)));
453
454                 const bool tessellationEnabled = (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
455                 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
456                 {
457                         VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,                                                // VkStructureType                                                                      sType;
458                         DE_NULL,                                                                                                                                // const void*                                                                          pNext;
459                         (VkPipelineCreateFlags)0,                                                                                               // VkPipelineCreateFlags                                                        flags;
460                         static_cast<deUint32>(shaderStages.size()),                                                             // deUint32                                                                                     stageCount;
461                         &shaderStages[0],                                                                                                               // const VkPipelineShaderStageCreateInfo*                       pStages;
462                         &vertexInputStateInfo,                                                                                                  // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
463                         &pipelineInputAssemblyStateInfo,                                                                                // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
464                         (tessellationEnabled ? &pipelineTessellationStateInfo : DE_NULL),               // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
465                         &pipelineViewportStateInfo,                                                                                             // const VkPipelineViewportStateCreateInfo*                     pViewportState;
466                         &pipelineRasterizationStateInfo,                                                                                // const VkPipelineRasterizationStateCreateInfo*        pRasterizationState;
467                         &pipelineMultisampleStateInfo,                                                                                  // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
468                         &pipelineDepthStencilStateInfo,                                                                                 // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
469                         &pipelineColorBlendStateInfo,                                                                                   // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
470                         DE_NULL,                                                                                                                                // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
471                         *m_pipelineLayout,                                                                                                              // VkPipelineLayout                                                                     layout;
472                         *m_renderPass,                                                                                                                  // VkRenderPass                                                                         renderPass;
473                         0u,                                                                                                                                             // deUint32                                                                                     subpass;
474                         DE_NULL,                                                                                                                                // VkPipeline                                                                           basePipelineHandle;
475                         0,                                                                                                                                              // deInt32                                                                                      basePipelineIndex;
476                 };
477
478                 m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
479         }
480
481         // Record commands
482         {
483                 const VkDeviceSize zeroOffset = 0ull;
484
485                 beginCommandBuffer(vk, *m_cmdBuffer);
486
487                 // Begin render pass
488                 {
489                         const VkClearValue      clearValue = makeClearValueColor(Vec4(0.0f, 0.0f, 0.0f, 1.0f));
490                         const VkRect2D          renderArea =
491                         {
492                                 makeOffset2D(0, 0),
493                                 makeExtent2D(m_renderSize.x(), m_renderSize.y())
494                         };
495
496                         const VkRenderPassBeginInfo renderPassBeginInfo = {
497                                 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,               // VkStructureType         sType;
498                                 DE_NULL,                                                                                // const void*             pNext;
499                                 *m_renderPass,                                                                  // VkRenderPass            renderPass;
500                                 *m_framebuffer,                                                                 // VkFramebuffer           framebuffer;
501                                 renderArea,                                                                             // VkRect2D                renderArea;
502                                 1u,                                                                                             // uint32_t                clearValueCount;
503                                 &clearValue,                                                                    // const VkClearValue*     pClearValues;
504                         };
505
506                         vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
507                 }
508
509                 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
510                 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &(**m_vertexBuffer), &zeroOffset);
511
512                 vk.cmdDraw(*m_cmdBuffer, m_numVertices, 1u, 0u, 1u);
513                 vk.cmdEndRenderPass(*m_cmdBuffer);
514
515                 // Barrier: draw -> copy from image
516                 {
517                         const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(
518                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
519                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
520                                 **m_colorImage, m_colorSubresourceRange);
521
522                         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0,
523                                 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
524                 }
525
526                 {
527                         const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), m_imageExtent);
528                         vk.cmdCopyImageToBuffer(*m_cmdBuffer, **m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_colorAttachmentBuffer, 1u, &copyRegion);
529                 }
530
531                 // Barrier: copy to buffer -> host read
532                 {
533                         const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(
534                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
535                                 **m_colorAttachmentBuffer, 0ull, VK_WHOLE_SIZE);
536
537                         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
538                                 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
539                 }
540
541                 endCommandBuffer(vk, *m_cmdBuffer);
542         }
543 }
544
545 void DrawContext::draw (void)
546 {
547         const DeviceInterface&  vk                      = m_context.getDeviceInterface();
548         const VkDevice                  device          = m_context.getDevice();
549         const VkQueue                   queue           = m_context.getUniversalQueue();
550         tcu::TestLog&                   log                     = m_context.getTestContext().getLog();
551
552         submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
553
554         log << tcu::LogImageSet("attachments", "") << tcu::LogImage("color0", "", getColorPixels()) << tcu::TestLog::EndImageSet;
555 }
556
557 tcu::ConstPixelBufferAccess DrawContext::getColorPixels (void) const
558 {
559         const DeviceInterface&  vk                      = m_context.getDeviceInterface();
560         const VkDevice                  device          = m_context.getDevice();
561
562         const Allocation& alloc = m_colorAttachmentBuffer->getAllocation();
563         invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
564
565         return tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), m_imageExtent.width, m_imageExtent.height, m_imageExtent.depth, alloc.getHostPtr());
566 }
567
568 std::vector<Vec4> genVertices (const VkPrimitiveTopology topology, const Vec4& offset, const float slope)
569 {
570         const float p  = 1.0f;
571         const float hp = 0.5f;
572         const float z  = 0.0f;
573         const float w  = 1.0f;
574
575         std::vector<Vec4> vertices;
576
577         // We're setting adjacent vertices to zero where needed, as we don't use them in meaningful way.
578
579         switch (topology)
580         {
581                 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
582                         vertices.push_back(offset + Vec4(0.0f, 0.0f, slope/2.0f + z, w));
583                         vertices.push_back(offset + Vec4( -hp,  -hp,              z, w));
584                         vertices.push_back(offset + Vec4(  hp,  -hp,      slope + z, w));
585                         vertices.push_back(offset + Vec4( -hp,   hp,              z, w));
586                         vertices.push_back(offset + Vec4(  hp,   hp,      slope + z, w));
587                         break;
588
589                 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
590                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
591                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // line 0
592                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));
593                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // line 1
594                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));
595                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // line 2
596                         break;
597
598                 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
599                         vertices.push_back(Vec4());
600                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
601                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // line 0
602                         vertices.push_back(Vec4());
603                         vertices.push_back(Vec4());
604                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));
605                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // line 1
606                         vertices.push_back(Vec4());
607                         vertices.push_back(Vec4());
608                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));
609                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // line 2
610                         vertices.push_back(Vec4());
611                         break;
612
613                 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
614                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
615                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // line 0
616                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // line 1
617                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // line 2
618                         break;
619
620                 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
621                         vertices.push_back(Vec4());
622                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
623                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // line 0
624                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // line 1
625                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // line 2
626                         vertices.push_back(Vec4());
627                         break;
628
629                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
630                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));
631                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
632                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // triangle 0
633                         vertices.push_back(offset + Vec4(-p,  p,         z, w));
634                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));
635                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // triangle 1
636                         break;
637
638                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
639                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));
640                         vertices.push_back(Vec4());
641                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
642                         vertices.push_back(Vec4());
643                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // triangle 0
644                         vertices.push_back(Vec4());
645                         vertices.push_back(offset + Vec4(-p,  p,         z, w));
646                         vertices.push_back(Vec4());
647                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));
648                         vertices.push_back(Vec4());
649                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // triangle 1
650                         vertices.push_back(Vec4());
651                         break;
652
653                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
654                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
655                         vertices.push_back(offset + Vec4(-p,  p,         z, w));
656                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // triangle 0
657                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // triangle 1
658                         break;
659
660                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
661                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
662                         vertices.push_back(Vec4());
663                         vertices.push_back(offset + Vec4(-p,  p,         z, w));
664                         vertices.push_back(Vec4());
665                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));        // triangle 0
666                         vertices.push_back(Vec4());
667                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // triangle 1
668                         vertices.push_back(Vec4());
669                         break;
670
671                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
672                         vertices.push_back(offset + Vec4( p, -p, slope + z, w));
673                         vertices.push_back(offset + Vec4(-p, -p,         z, w));
674                         vertices.push_back(offset + Vec4(-p,  p,         z, w));        // triangle 0
675                         vertices.push_back(offset + Vec4( p,  p, slope + z, w));        // triangle 1
676                         break;
677
678                 case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
679                         DE_ASSERT(0);
680                         break;
681
682                 default:
683                         DE_ASSERT(0);
684                         break;
685         }
686         return vertices;
687 }
688
689 bool inline isColorInRange (const Vec4& color, const Vec4& minColor, const Vec4& maxColor)
690 {
691         return (minColor.x() <= color.x() && color.x() <= maxColor.x())
692                 && (minColor.y() <= color.y() && color.y() <= maxColor.y())
693                 && (minColor.z() <= color.z() && color.z() <= maxColor.z())
694                 && (minColor.w() <= color.w() && color.w() <= maxColor.w());
695 }
696
697 //! Count pixels that match color within threshold, in the specified region.
698 int countPixels (const tcu::ConstPixelBufferAccess pixels, const IVec2& regionOffset, const IVec2& regionSize, const Vec4& color, const Vec4& colorThreshold)
699 {
700         const Vec4      minColor        = color - colorThreshold;
701         const Vec4      maxColor        = color + colorThreshold;
702         const int       xEnd            = regionOffset.x() + regionSize.x();
703         const int       yEnd            = regionOffset.y() + regionSize.y();
704         int                     numPixels       = 0;
705
706         DE_ASSERT(xEnd <= pixels.getWidth());
707         DE_ASSERT(yEnd <= pixels.getHeight());
708
709         for (int y = regionOffset.y(); y < yEnd; ++y)
710         for (int x = regionOffset.x(); x < xEnd; ++x)
711         {
712                 if (isColorInRange(pixels.getPixel(x, y), minColor, maxColor))
713                         ++numPixels;
714         }
715
716         return numPixels;
717 }
718
719 int countPixels (const tcu::ConstPixelBufferAccess pixels, const Vec4& color, const Vec4& colorThreshold)
720 {
721         return countPixels(pixels, IVec2(), IVec2(pixels.getWidth(), pixels.getHeight()), color, colorThreshold);
722 }
723
724 //! Clipping against the default clip volume.
725 namespace ClipVolume
726 {
727
728 //! Used by wide lines test.
729 enum LineOrientation
730 {
731         LINE_ORIENTATION_AXIS_ALIGNED,
732         LINE_ORIENTATION_DIAGONAL,
733 };
734
735 const VkPointClippingBehaviorKHR invalidClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_KHR_LAST;
736
737 VkPointClippingBehaviorKHR getClippingBehavior (const InstanceInterface& vk, VkPhysicalDevice physicalDevice)
738 {
739         VkPhysicalDevicePointClippingPropertiesKHR      behaviorProperties      =
740         {
741                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR,        // VkStructureType                              sType
742                 DE_NULL,                                                                                                                        // void*                                                pNext
743                 invalidClippingBehavior                                                                                         // VkPointClippingBehaviorKHR   pointClippingBehavior
744         };
745         VkPhysicalDeviceProperties2KHR                          properties2;
746
747         DE_ASSERT(getPointClippingBehaviorKHRName(invalidClippingBehavior) == DE_NULL);
748
749         deMemset(&properties2, 0, sizeof(properties2));
750
751         properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
752         properties2.pNext = &behaviorProperties;
753
754         vk.getPhysicalDeviceProperties2KHR(physicalDevice, &properties2);
755
756         return behaviorProperties.pointClippingBehavior;
757 }
758
759 void addSimplePrograms (SourceCollections& programCollection, const float pointSize = 0.0f)
760 {
761         // Vertex shader
762         {
763                 const bool usePointSize = pointSize > 0.0f;
764
765                 std::ostringstream src;
766                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
767                         << "\n"
768                         << "layout(location = 0) in vec4 v_position;\n"
769                         << "\n"
770                         << "out gl_PerVertex {\n"
771                         << "    vec4  gl_Position;\n"
772                         << (usePointSize ? "    float gl_PointSize;\n" : "")
773                         << "};\n"
774                         << "\n"
775                         << "void main (void)\n"
776                         << "{\n"
777                         << "    gl_Position = v_position;\n"
778                         << (usePointSize ? "    gl_PointSize = " + de::floatToString(pointSize, 1) + ";\n" : "")
779                         << "}\n";
780
781                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
782         }
783
784         // Fragment shader
785         {
786                 std::ostringstream src;
787                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
788                         << "\n"
789                         << "layout(location = 0) out vec4 o_color;\n"
790                         << "\n"
791                         << "void main (void)\n"
792                         << "{\n"
793                         << "    o_color = vec4(1.0, gl_FragCoord.z, 0.0, 1.0);\n"
794                         << "}\n";
795
796                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
797         }
798 }
799
800 void initPrograms (SourceCollections& programCollection, const VkPrimitiveTopology topology)
801 {
802         const float pointSize = (topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? 1.0f : 0.0f);
803         addSimplePrograms(programCollection, pointSize);
804 }
805
806 void initPrograms (SourceCollections& programCollection, const LineOrientation lineOrientation)
807 {
808         DE_UNREF(lineOrientation);
809         addSimplePrograms(programCollection);
810 }
811
812 void initProgramsPointSize (SourceCollections& programCollection)
813 {
814         addSimplePrograms(programCollection, 0.75f * RENDER_SIZE);
815 }
816
817 //! Primitives fully inside the clip volume.
818 tcu::TestStatus testPrimitivesInside (Context& context, const VkPrimitiveTopology topology)
819 {
820         int minExpectedBlackPixels = 0;
821
822         switch (topology)
823         {
824                 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
825                         // We draw only 5 points.
826                         minExpectedBlackPixels = NUM_RENDER_PIXELS - 5;
827                         break;
828
829                 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
830                 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
831                 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
832                 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
833                         // Allow for some error.
834                         minExpectedBlackPixels = NUM_RENDER_PIXELS - 3 * RENDER_SIZE;
835                         break;
836
837                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
838                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
839                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
840                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
841                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
842                         // All render area should be covered.
843                         minExpectedBlackPixels = 0;
844                         break;
845
846                 default:
847                         DE_ASSERT(0);
848                         break;
849         }
850
851         std::vector<Shader> shaders;
852         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
853         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
854
855         tcu::TestLog&   log                     = context.getTestContext().getLog();
856         int                             numPassed       = 0;
857
858         static const struct
859         {
860                 const char* const       desc;
861                 float                           zPos;
862         } cases[] =
863         {
864                 { "Draw primitives at near clipping plane, z = 0.0",    0.0f, },
865                 { "Draw primitives at z = 0.5",                                                 0.5f, },
866                 { "Draw primitives at far clipping plane, z = 1.0",             1.0f, },
867         };
868
869         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
870         {
871                 log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
872
873                 const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f);
874                 DrawContext drawContext(context, shaders, vertices, topology);
875                 drawContext.draw();
876
877                 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
878                 if (numBlackPixels >= minExpectedBlackPixels)
879                         ++numPassed;
880         }
881
882         return (numPassed == DE_LENGTH_OF_ARRAY(cases) ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
883 }
884
885 //! Primitives fully outside the clip volume.
886 tcu::TestStatus testPrimitivesOutside (Context& context, const VkPrimitiveTopology topology)
887 {
888         std::vector<Shader> shaders;
889         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
890         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
891
892         tcu::TestLog&   log                     = context.getTestContext().getLog();
893         int                             numPassed       = 0;
894
895         static const struct
896         {
897                 const char* const       desc;
898                 float                           zPos;
899         } cases[] =
900         {
901                 { "Draw primitives in front of the near clipping plane, z < 0.0",       -0.5f, },
902                 { "Draw primitives behind the far clipping plane, z > 1.0",                      1.5f, },
903         };
904
905         log << tcu::TestLog::Message << "Drawing primitives outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage;
906
907         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
908         {
909                 log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
910
911                 const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f);
912                 DrawContext drawContext(context, shaders, vertices, topology);
913                 drawContext.draw();
914
915                 // All pixels must be black -- nothing is drawn.
916                 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
917                 if (numBlackPixels == NUM_RENDER_PIXELS)
918                         ++numPassed;
919         }
920
921         return (numPassed == DE_LENGTH_OF_ARRAY(cases) ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
922 }
923
924 //! Primitives partially outside the clip volume, but depth clamped
925 tcu::TestStatus testPrimitivesDepthClamp (Context& context, const VkPrimitiveTopology topology)
926 {
927         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_DEPTH_CLAMP);
928
929         std::vector<Shader> shaders;
930         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
931         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
932
933         const int               numCases                = 4;
934         const IVec2             regionSize              = IVec2(RENDER_SIZE/2, RENDER_SIZE);    //! size of the clamped region
935         const int               regionPixels    = regionSize.x() * regionSize.y();
936         tcu::TestLog&   log                             = context.getTestContext().getLog();
937         int                             numPassed               = 0;
938
939         static const struct
940         {
941                 const char* const       desc;
942                 float                           zPos;
943                 bool                            depthClampEnable;
944                 IVec2                           regionOffset;
945                 Vec4                            color;
946         } cases[numCases] =
947         {
948                 { "Draw primitives intersecting the near clipping plane, depth clamp disabled", -0.5f,  false,  IVec2(0, 0),                            Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
949                 { "Draw primitives intersecting the near clipping plane, depth clamp enabled",  -0.5f,  true,   IVec2(0, 0),                            Vec4(1.0f, 0.0f, 0.0f, 1.0f) },
950                 { "Draw primitives intersecting the far clipping plane, depth clamp disabled",   0.5f,  false,  IVec2(RENDER_SIZE/2, 0),        Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
951                 { "Draw primitives intersecting the far clipping plane, depth clamp enabled",    0.5f,  true,   IVec2(RENDER_SIZE/2, 0),        Vec4(1.0f, 1.0f, 0.0f, 1.0f) },
952         };
953
954         // Per case minimum number of colored pixels.
955         int caseMinPixels[numCases] = { 0, 0, 0, 0 };
956
957         switch (topology)
958         {
959                 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
960                         caseMinPixels[0] = caseMinPixels[2] = regionPixels - 1;
961                         caseMinPixels[1] = caseMinPixels[3] = 2;
962                         break;
963
964                 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
965                 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
966                 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
967                 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
968                         caseMinPixels[0] = regionPixels;
969                         caseMinPixels[1] = RENDER_SIZE - 2;
970                         caseMinPixels[2] = regionPixels;
971                         caseMinPixels[3] = 2 * (RENDER_SIZE - 2);
972                         break;
973
974                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
975                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
976                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
977                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
978                 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
979                         caseMinPixels[0] = caseMinPixels[1] = caseMinPixels[2] = caseMinPixels[3] = regionPixels;
980                         break;
981
982                 default:
983                         DE_ASSERT(0);
984                         break;
985         }
986
987         for (int caseNdx = 0; caseNdx < numCases; ++caseNdx)
988         {
989                 log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
990
991                 const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 1.0f);
992                 DrawContext drawContext(context, shaders, vertices, topology, static_cast<deUint32>(RENDER_SIZE), cases[caseNdx].depthClampEnable);
993                 drawContext.draw();
994
995                 const int numPixels = countPixels(drawContext.getColorPixels(), cases[caseNdx].regionOffset, regionSize, cases[caseNdx].color, Vec4());
996
997                 if (numPixels >= caseMinPixels[caseNdx])
998                         ++numPassed;
999         }
1000
1001         return (numPassed == numCases ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
1002 }
1003
1004 //! Large point clipping
1005 //! Spec: If the primitive under consideration is a point, then clipping passes it unchanged if it lies within the clip volume;
1006 //!       otherwise, it is discarded.
1007 tcu::TestStatus testLargePoints (Context& context)
1008 {
1009         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_LARGE_POINTS);
1010
1011         bool pointClippingOutside = true;
1012
1013         if (de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_maintenance2"))
1014         {
1015                 VkPointClippingBehaviorKHR clippingBehavior = getClippingBehavior(context.getInstanceInterface(), context.getPhysicalDevice());
1016
1017                 switch (clippingBehavior)
1018                 {
1019                         case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR:            pointClippingOutside = true;                            break;
1020                         case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR:      pointClippingOutside = false;                           break;
1021                         case invalidClippingBehavior:                                                           TCU_FAIL("Clipping behavior read failure");     break;
1022                         default:
1023                         {
1024                                 TCU_FAIL("Unexpected clipping behavior reported");
1025                         }
1026                 }
1027         }
1028         else
1029         {
1030                 //TODO: Now we have 2 cases {some-points-drawn|nothing}, we should have {all-points-drawn|some-points-drawn|nothing}
1031                 return tcu::TestStatus::pass("OK");
1032         }
1033
1034         std::vector<Shader> shaders;
1035         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
1036         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
1037
1038         std::vector<Vec4> vertices;
1039         {
1040                 const float delta       = 0.1f;  // much smaller than the point size
1041                 const float p           = 1.0f + delta;
1042
1043                 vertices.push_back(Vec4(  -p,   -p, 0.1f, 1.0f));
1044                 vertices.push_back(Vec4(  -p,    p, 0.2f, 1.0f));
1045                 vertices.push_back(Vec4(   p,    p, 0.4f, 1.0f));
1046                 vertices.push_back(Vec4(   p,   -p, 0.6f, 1.0f));
1047                 vertices.push_back(Vec4(0.0f,   -p, 0.8f, 1.0f));
1048                 vertices.push_back(Vec4(   p, 0.0f, 0.9f, 1.0f));
1049                 vertices.push_back(Vec4(0.0f,    p, 0.1f, 1.0f));
1050                 vertices.push_back(Vec4(  -p, 0.0f, 0.2f, 1.0f));
1051         }
1052
1053         tcu::TestLog&   log     = context.getTestContext().getLog();
1054
1055         log << tcu::TestLog::Message << "Drawing several large points just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage;
1056
1057         DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
1058         drawContext.draw();
1059
1060         const int       numBlackPixels  = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
1061         bool            result                  = false;
1062
1063         if (pointClippingOutside)
1064         {
1065                 // All pixels must be black -- nothing is drawn.
1066                 result = (numBlackPixels == NUM_RENDER_PIXELS);
1067         }
1068         else
1069         {
1070                 // Rendering pixels without clipping: some pixels should not be black -- something is drawn.
1071                 result = (numBlackPixels < NUM_RENDER_PIXELS);
1072         }
1073
1074         return (result ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
1075 }
1076
1077 //! Wide line clipping
1078 //! Spec: If the primitive is a line segment, then clipping does nothing to it if it lies entirely within the clip volume, and discards it
1079 //!       if it lies entirely outside the volume.
1080 tcu::TestStatus testWideLines (Context& context, const LineOrientation lineOrientation)
1081 {
1082         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_WIDE_LINES);
1083
1084         std::vector<Shader> shaders;
1085         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
1086         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
1087
1088         const float delta = 0.1f;  // much smaller than the line width
1089
1090         std::vector<Vec4> vertices;
1091         if (lineOrientation == LINE_ORIENTATION_AXIS_ALIGNED)
1092         {
1093                 // Axis-aligned lines just outside the clip volume.
1094                 const float p = 1.0f + delta;
1095                 const float q = 0.9f;
1096
1097                 vertices.push_back(Vec4(-p, -q, 0.1f, 1.0f));
1098                 vertices.push_back(Vec4(-p,  q, 0.9f, 1.0f));   // line 0
1099                 vertices.push_back(Vec4(-q,  p, 0.1f, 1.0f));
1100                 vertices.push_back(Vec4( q,  p, 0.9f, 1.0f));   // line 1
1101                 vertices.push_back(Vec4( p,  q, 0.1f, 1.0f));
1102                 vertices.push_back(Vec4( p, -q, 0.9f, 1.0f));   // line 2
1103                 vertices.push_back(Vec4( q, -p, 0.1f, 1.0f));
1104                 vertices.push_back(Vec4(-q, -p, 0.9f, 1.0f));   // line 3
1105         }
1106         else if (lineOrientation == LINE_ORIENTATION_DIAGONAL)
1107         {
1108                 // Diagonal lines just outside the clip volume.
1109                 const float p = 2.0f + delta;
1110
1111                 vertices.push_back(Vec4(  -p, 0.0f, 0.1f, 1.0f));
1112                 vertices.push_back(Vec4(0.0f,   -p, 0.9f, 1.0f));       // line 0
1113                 vertices.push_back(Vec4(0.0f,   -p, 0.1f, 1.0f));
1114                 vertices.push_back(Vec4(   p, 0.0f, 0.9f, 1.0f));       // line 1
1115                 vertices.push_back(Vec4(   p, 0.0f, 0.1f, 1.0f));
1116                 vertices.push_back(Vec4(0.0f,    p, 0.9f, 1.0f));       // line 2
1117                 vertices.push_back(Vec4(0.0f,    p, 0.1f, 1.0f));
1118                 vertices.push_back(Vec4(  -p, 0.0f, 0.9f, 1.0f));       // line 3
1119         }
1120         else
1121                 DE_ASSERT(0);
1122
1123         const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits;
1124
1125         const float             lineWidth       = std::min(static_cast<float>(RENDER_SIZE), limits.lineWidthRange[1]);
1126         tcu::TestLog&   log                     = context.getTestContext().getLog();
1127
1128         log << tcu::TestLog::Message << "Drawing several wide lines just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage
1129                 << tcu::TestLog::Message << "Line width is " << lineWidth << "." << tcu::TestLog::EndMessage;
1130
1131         DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, static_cast<deUint32>(RENDER_SIZE), false, false, lineWidth);
1132         drawContext.draw();
1133
1134         // All pixels must be black -- nothing is drawn.
1135         const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
1136
1137         return (numBlackPixels == NUM_RENDER_PIXELS ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
1138 }
1139
1140 } // ClipVolume ns
1141
1142 namespace ClipDistance
1143 {
1144
1145 struct CaseDefinition
1146 {
1147         const VkPrimitiveTopology       topology;
1148         const bool                                      dynamicIndexing;
1149         const bool                                      enableTessellation;
1150         const bool                                      enableGeometry;
1151         const int                                       numClipDistances;
1152         const int                                       numCullDistances;
1153
1154         CaseDefinition (const VkPrimitiveTopology       topology_,
1155                                         const int                                       numClipDistances_,
1156                                         const int                                       numCullDistances_,
1157                                         const bool                                      enableTessellation_,
1158                                         const bool                                      enableGeometry_,
1159                                         const bool                                      dynamicIndexing_)
1160                 : topology                                      (topology_)
1161                 , dynamicIndexing                       (dynamicIndexing_)
1162                 , enableTessellation            (enableTessellation_)
1163                 , enableGeometry                        (enableGeometry_)
1164                 , numClipDistances                      (numClipDistances_)
1165                 , numCullDistances                      (numCullDistances_)
1166         {
1167         }
1168 };
1169
1170 void initPrograms (SourceCollections& programCollection, const CaseDefinition caseDef)
1171 {
1172         DE_ASSERT(caseDef.numClipDistances + caseDef.numCullDistances <= MAX_COMBINED_CLIP_AND_CULL_DISTANCES);
1173
1174         std::string perVertexBlock;
1175         {
1176                 std::ostringstream str;
1177                 str << "gl_PerVertex {\n"
1178                         << "    vec4  gl_Position;\n";
1179                 if (caseDef.numClipDistances > 0)
1180                         str << "    float gl_ClipDistance[" << caseDef.numClipDistances << "];\n";
1181                 if (caseDef.numCullDistances > 0)
1182                         str << "    float gl_CullDistance[" << caseDef.numCullDistances << "];\n";
1183                 str << "}";
1184                 perVertexBlock = str.str();
1185         }
1186
1187         // Vertex shader
1188         {
1189                 std::ostringstream src;
1190                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1191                         << "\n"
1192                         << "layout(location = 0) in  vec4 v_position;\n"
1193                         << "layout(location = 0) out vec4 out_color;\n"
1194                         << "\n"
1195                         << "out " << perVertexBlock << ";\n"
1196                         << "\n"
1197                         << "void main (void)\n"
1198                         << "{\n"
1199                         << "    gl_Position = v_position;\n"
1200                         << "    out_color   = vec4(1.0, 0.5 * (v_position.x + 1.0), 0.0, 1.0);\n"
1201                         << "\n"
1202                         << "    const int barNdx = gl_VertexIndex / 6;\n";
1203                 if (caseDef.dynamicIndexing)
1204                 {
1205                         if (caseDef.numClipDistances > 0)
1206                                 src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
1207                                         << "        gl_ClipDistance[i] = (barNdx == i ? v_position.y : 0.0);\n";
1208                         if (caseDef.numCullDistances > 0)
1209                                 src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
1210                                         << "        gl_CullDistance[i] = 0.0;\n";
1211                 }
1212                 else
1213                 {
1214                         for (int i = 0; i < caseDef.numClipDistances; ++i)
1215                                 src << "    gl_ClipDistance[" << i << "] = (barNdx == " << i << " ? v_position.y : 0.0);\n";
1216                         for (int i = 0; i < caseDef.numCullDistances; ++i)
1217                                 src << "    gl_CullDistance[" << i << "] = 0.0;\n";             // don't cull anything
1218                 }
1219                 src     << "}\n";
1220
1221                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1222         }
1223
1224         if (caseDef.enableTessellation)
1225         {
1226                 std::ostringstream src;
1227                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1228                         << "\n"
1229                         << "layout(vertices = " << NUM_PATCH_CONTROL_POINTS << ") out;\n"
1230                         << "\n"
1231                         << "layout(location = 0) in  vec4 in_color[];\n"
1232                         << "layout(location = 0) out vec4 out_color[];\n"
1233                         << "\n"
1234                         << "in " << perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
1235                         << "\n"
1236                         << "out " << perVertexBlock << " gl_out[];\n"
1237                         << "\n"
1238                         << "void main (void)\n"
1239                         << "{\n"
1240                         << "    gl_TessLevelInner[0] = 1.0;\n"
1241                         << "    gl_TessLevelInner[1] = 1.0;\n"
1242                         << "\n"
1243                         << "    gl_TessLevelOuter[0] = 1.0;\n"
1244                         << "    gl_TessLevelOuter[1] = 1.0;\n"
1245                         << "    gl_TessLevelOuter[2] = 1.0;\n"
1246                         << "    gl_TessLevelOuter[3] = 1.0;\n"
1247                         << "\n"
1248                         << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1249                         << "    out_color[gl_InvocationID]          = in_color[gl_InvocationID];\n"
1250                         << "\n";
1251                 if (caseDef.dynamicIndexing)
1252                 {
1253                         if (caseDef.numClipDistances > 0)
1254                                 src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
1255                                         << "        gl_out[gl_InvocationID].gl_ClipDistance[i] = gl_in[gl_InvocationID].gl_ClipDistance[i];\n";
1256                         if (caseDef.numCullDistances > 0)
1257                                 src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
1258                                         << "        gl_out[gl_InvocationID].gl_CullDistance[i] = gl_in[gl_InvocationID].gl_CullDistance[i];\n";
1259                 }
1260                 else
1261                 {
1262                         for (int i = 0; i < caseDef.numClipDistances; ++i)
1263                                 src << "    gl_out[gl_InvocationID].gl_ClipDistance[" << i << "] = gl_in[gl_InvocationID].gl_ClipDistance[" << i << "];\n";
1264                         for (int i = 0; i < caseDef.numCullDistances; ++i)
1265                                 src << "    gl_out[gl_InvocationID].gl_CullDistance[" << i << "] = gl_in[gl_InvocationID].gl_CullDistance[" << i << "];\n";
1266                 }
1267                 src << "}\n";
1268
1269                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
1270         }
1271
1272         if (caseDef.enableTessellation)
1273         {
1274                 DE_ASSERT(NUM_PATCH_CONTROL_POINTS == 3);  // assumed in shader code
1275
1276                 std::ostringstream src;
1277                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1278                         << "\n"
1279                         << "layout(triangles, equal_spacing, ccw) in;\n"
1280                         << "\n"
1281                         << "layout(location = 0) in  vec4 in_color[];\n"
1282                         << "layout(location = 0) out vec4 out_color;\n"
1283                         << "\n"
1284                         << "in " << perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
1285                         << "\n"
1286                         << "out " << perVertexBlock << ";\n"
1287                         << "\n"
1288                         << "void main (void)\n"
1289                         << "{\n"
1290                         << "    vec3 px     = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n"
1291                         << "    vec3 py     = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n"
1292                         << "    vec3 pz     = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
1293                         << "    gl_Position = vec4(px + py + pz, 1.0);\n"
1294                         << "    out_color   = (in_color[0] + in_color[1] + in_color[2]) / 3.0;\n"
1295                         << "\n";
1296                 if (caseDef.dynamicIndexing)
1297                 {
1298                         if (caseDef.numClipDistances > 0)
1299                                 src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
1300                                         << "        gl_ClipDistance[i] = gl_TessCoord.x * gl_in[0].gl_ClipDistance[i]\n"
1301                                         << "                           + gl_TessCoord.y * gl_in[1].gl_ClipDistance[i]\n"
1302                                         << "                           + gl_TessCoord.z * gl_in[2].gl_ClipDistance[i];\n";
1303                         if (caseDef.numCullDistances > 0)
1304                                 src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
1305                                         << "        gl_CullDistance[i] = gl_TessCoord.x * gl_in[0].gl_CullDistance[i]\n"
1306                                         << "                           + gl_TessCoord.y * gl_in[1].gl_CullDistance[i]\n"
1307                                         << "                           + gl_TessCoord.z * gl_in[2].gl_CullDistance[i];\n";
1308                 }
1309                 else
1310                 {
1311                         for (int i = 0; i < caseDef.numClipDistances; ++i)
1312                                 src << "    gl_ClipDistance[" << i << "] = gl_TessCoord.x * gl_in[0].gl_ClipDistance[" << i << "]\n"
1313                                         << "                       + gl_TessCoord.y * gl_in[1].gl_ClipDistance[" << i << "]\n"
1314                                         << "                       + gl_TessCoord.z * gl_in[2].gl_ClipDistance[" << i << "];\n";
1315                         for (int i = 0; i < caseDef.numCullDistances; ++i)
1316                                 src << "    gl_CullDistance[" << i << "] = gl_TessCoord.x * gl_in[0].gl_CullDistance[" << i << "]\n"
1317                                         << "                       + gl_TessCoord.y * gl_in[1].gl_CullDistance[" << i << "]\n"
1318                                         << "                       + gl_TessCoord.z * gl_in[2].gl_CullDistance[" << i << "];\n";
1319                 }
1320                 src << "}\n";
1321
1322                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
1323         }
1324
1325         if (caseDef.enableGeometry)
1326         {
1327                 std::ostringstream src;
1328                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1329                         << "\n"
1330                         << "layout(triangles) in;\n"
1331                         << "layout(triangle_strip, max_vertices = 3) out;\n"
1332                         << "\n"
1333                         << "layout(location = 0) in  vec4 in_color[];\n"
1334                         << "layout(location = 0) out vec4 out_color;\n"
1335                         << "\n"
1336                         << "in " << perVertexBlock << " gl_in[];\n"
1337                         << "\n"
1338                         << "out " << perVertexBlock << ";\n"
1339                         << "\n"
1340                         << "void main (void)\n"
1341                         << "{\n";
1342                 for (int vertNdx = 0; vertNdx < 3; ++vertNdx)
1343                 {
1344                         if (vertNdx > 0)
1345                                 src << "\n";
1346                         src << "    gl_Position = gl_in[" << vertNdx << "].gl_Position;\n"
1347                                 << "    out_color   = in_color[" << vertNdx << "];\n";
1348                         if (caseDef.dynamicIndexing)
1349                         {
1350                                 if (caseDef.numClipDistances > 0)
1351                                         src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
1352                                                 << "        gl_ClipDistance[i] = gl_in[" << vertNdx << "].gl_ClipDistance[i];\n";
1353                                 if (caseDef.numCullDistances > 0)
1354                                         src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
1355                                                 << "        gl_CullDistance[i] = gl_in[" << vertNdx << "].gl_CullDistance[i];\n";
1356                         }
1357                         else
1358                         {
1359                                 for (int i = 0; i < caseDef.numClipDistances; ++i)
1360                                         src << "    gl_ClipDistance[" << i << "] = gl_in[" << vertNdx << "].gl_ClipDistance[" << i << "];\n";
1361                                 for (int i = 0; i < caseDef.numCullDistances; ++i)
1362                                         src << "    gl_CullDistance[" << i << "] = gl_in[" << vertNdx << "].gl_CullDistance[" << i << "];\n";
1363                         }
1364                         src << "    EmitVertex();\n";
1365                 }
1366                 src     << "}\n";
1367
1368                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
1369         }
1370
1371         // Fragment shader
1372         {
1373                 std::ostringstream src;
1374                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1375                         << "\n"
1376                         << "layout(location = 0) in flat vec4 in_color;\n"
1377                         << "layout(location = 0) out vec4 o_color;\n"
1378                         << "\n"
1379                         << "void main (void)\n"
1380                         << "{\n"
1381                         << "    o_color = vec4(in_color.rgb + vec3(0.0, 0.0, 0.5), 1.0);\n"  // mix with a constant color in case variable wasn't passed correctly through stages
1382                         << "}\n";
1383
1384                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1385         }
1386 }
1387
1388 tcu::TestStatus testClipDistance (Context& context, const CaseDefinition caseDef)
1389 {
1390         // Check test requirements
1391         {
1392                 const InstanceInterface&                vki                     = context.getInstanceInterface();
1393                 const VkPhysicalDevice                  physDevice      = context.getPhysicalDevice();
1394                 const VkPhysicalDeviceLimits    limits          = getPhysicalDeviceProperties(vki, physDevice).limits;
1395
1396                 FeatureFlags requirements = (FeatureFlags)0;
1397
1398                 if (caseDef.numClipDistances > 0)
1399                         requirements |= FEATURE_SHADER_CLIP_DISTANCE;
1400                 if (caseDef.numCullDistances > 0)
1401                         requirements |= FEATURE_SHADER_CULL_DISTANCE;
1402                 if (caseDef.enableTessellation)
1403                         requirements |= FEATURE_TESSELLATION_SHADER;
1404                 if (caseDef.enableGeometry)
1405                         requirements |= FEATURE_GEOMETRY_SHADER;
1406
1407                 requireFeatures(vki, physDevice, requirements);
1408
1409                 // Check limits for supported features
1410
1411                 if (caseDef.numClipDistances > 0 && limits.maxClipDistances < MAX_CLIP_DISTANCES)
1412                         return tcu::TestStatus::fail("maxClipDistances smaller than the minimum required by the spec");
1413                 if (caseDef.numCullDistances > 0 && limits.maxCullDistances < MAX_CULL_DISTANCES)
1414                         return tcu::TestStatus::fail("maxCullDistances smaller than the minimum required by the spec");
1415                 if (caseDef.numCullDistances > 0 && limits.maxCombinedClipAndCullDistances < MAX_COMBINED_CLIP_AND_CULL_DISTANCES)
1416                         return tcu::TestStatus::fail("maxCombinedClipAndCullDistances smaller than the minimum required by the spec");
1417         }
1418
1419         std::vector<Shader> shaders;
1420         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
1421         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
1422         if (caseDef.enableTessellation)
1423         {
1424                 shaders.push_back(Shader(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,              context.getBinaryCollection().get("tesc")));
1425                 shaders.push_back(Shader(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,   context.getBinaryCollection().get("tese")));
1426         }
1427         if (caseDef.enableGeometry)
1428                 shaders.push_back(Shader(VK_SHADER_STAGE_GEOMETRY_BIT,  context.getBinaryCollection().get("geom")));
1429
1430         const int numBars = MAX_COMBINED_CLIP_AND_CULL_DISTANCES;
1431
1432         std::vector<Vec4> vertices;
1433         {
1434                 const float     dx = 2.0f / numBars;
1435                 for (int i = 0; i < numBars; ++i)
1436                 {
1437                         const float x = -1.0f + dx * static_cast<float>(i);
1438
1439                         vertices.push_back(Vec4(x,      -1.0f, 0.0f, 1.0f));
1440                         vertices.push_back(Vec4(x,       1.0f, 0.0f, 1.0f));
1441                         vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f));
1442
1443                         vertices.push_back(Vec4(x,       1.0f, 0.0f, 1.0f));
1444                         vertices.push_back(Vec4(x + dx,  1.0f, 0.0f, 1.0f));
1445                         vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f));
1446                 }
1447         }
1448
1449         tcu::TestLog& log = context.getTestContext().getLog();
1450
1451         log << tcu::TestLog::Message << "Drawing " << numBars << " colored bars, clipping the first " << caseDef.numClipDistances << tcu::TestLog::EndMessage
1452                 << tcu::TestLog::Message << "Using " << caseDef.numClipDistances << " ClipDistance(s) and " << caseDef.numCullDistances << " CullDistance(s)" << tcu::TestLog::EndMessage
1453                 << tcu::TestLog::Message << "Expecting upper half of the clipped bars to be black." << tcu::TestLog::EndMessage;
1454
1455         DrawContext drawContext(context, shaders, vertices, caseDef.topology);
1456         drawContext.draw();
1457
1458         // Count black pixels in the whole image.
1459         const int numBlackPixels                = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
1460         const IVec2     clipRegion                      = IVec2(caseDef.numClipDistances * RENDER_SIZE / numBars, RENDER_SIZE / 2);
1461         const int expectedClippedPixels = clipRegion.x() * clipRegion.y();
1462         // Make sure the bottom half has no black pixels (possible if image became corrupted).
1463         const int guardPixels                   = countPixels(drawContext.getColorPixels(), IVec2(0, RENDER_SIZE/2), clipRegion, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
1464
1465         return (numBlackPixels == expectedClippedPixels && guardPixels == 0 ? tcu::TestStatus::pass("OK")
1466                                                                                                                                                 : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
1467 }
1468
1469 } // ClipDistance ns
1470
1471 namespace ClipDistanceComplementarity
1472 {
1473
1474 void initPrograms (SourceCollections& programCollection, const int numClipDistances)
1475 {
1476         // Vertex shader
1477         {
1478                 DE_ASSERT(numClipDistances > 0);
1479                 const int clipDistanceLastNdx = numClipDistances - 1;
1480
1481                 std::ostringstream src;
1482                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1483                         << "\n"
1484                         << "layout(location = 0) in vec4 v_position;    // we are passing ClipDistance in w component\n"
1485                         << "\n"
1486                         << "out gl_PerVertex {\n"
1487                         << "    vec4  gl_Position;\n"
1488                         << "    float gl_ClipDistance[" << numClipDistances << "];\n"
1489                         << "};\n"
1490                         << "\n"
1491                         << "void main (void)\n"
1492                         << "{\n"
1493                         << "    gl_Position        = vec4(v_position.xyz, 1.0);\n";
1494                 for (int i = 0; i < clipDistanceLastNdx; ++i)
1495                         src << "    gl_ClipDistance[" << i << "] = 0.0;\n";
1496                 src << "    gl_ClipDistance[" << clipDistanceLastNdx << "] = v_position.w;\n"
1497                         << "}\n";
1498
1499                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1500         }
1501
1502         // Fragment shader
1503         {
1504                 std::ostringstream src;
1505                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1506                         << "\n"
1507                         << "layout(location = 0) out vec4 o_color;\n"
1508                         << "\n"
1509                         << "void main (void)\n"
1510                         << "{\n"
1511                         << "    o_color = vec4(1.0, 1.0, 1.0, 0.5);\n"
1512                         << "}\n";
1513
1514                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1515         }
1516 }
1517
1518 tcu::TestStatus testComplementarity (Context& context, const int numClipDistances)
1519 {
1520         // Check test requirements
1521         {
1522                 const InstanceInterface&                vki                     = context.getInstanceInterface();
1523                 const VkPhysicalDevice                  physDevice      = context.getPhysicalDevice();
1524
1525                 requireFeatures(vki, physDevice, FEATURE_SHADER_CLIP_DISTANCE);
1526         }
1527
1528         std::vector<Shader> shaders;
1529         shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,    context.getBinaryCollection().get("vert")));
1530         shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,  context.getBinaryCollection().get("frag")));
1531
1532         std::vector<Vec4> vertices;
1533         {
1534                 de::Random      rnd                                             (1234);
1535                 const int       numSections                             = 16;
1536                 const int       numVerticesPerSection   = 4;    // logical verticies, due to triangle list topology we actually use 6 per section
1537
1538                 DE_ASSERT(RENDER_SIZE_LARGE % numSections == 0);
1539
1540                 std::vector<float> clipDistances(numVerticesPerSection * numSections);
1541                 for (int i = 0; i < static_cast<int>(clipDistances.size()); ++i)
1542                         clipDistances[i] = rnd.getFloat(-1.0f, 1.0f);
1543
1544                 // Two sets of identical primitives, but with a different ClipDistance sign.
1545                 for (int setNdx = 0; setNdx < 2; ++setNdx)
1546                 {
1547                         const float sign = (setNdx == 0 ? 1.0f : -1.0f);
1548                         const float     dx       = 2.0f / static_cast<float>(numSections);
1549
1550                         for (int i = 0; i < numSections; ++i)
1551                         {
1552                                 const int       ndxBase = numVerticesPerSection * i;
1553                                 const float x           = -1.0f + dx * static_cast<float>(i);
1554                                 const Vec4      p0              = Vec4(x,      -1.0f, 0.0f, sign * clipDistances[ndxBase + 0]);
1555                                 const Vec4      p1              = Vec4(x,       1.0f, 0.0f, sign * clipDistances[ndxBase + 1]);
1556                                 const Vec4      p2              = Vec4(x + dx,  1.0f, 0.0f, sign * clipDistances[ndxBase + 2]);
1557                                 const Vec4      p3              = Vec4(x + dx, -1.0f, 0.0f, sign * clipDistances[ndxBase + 3]);
1558
1559                                 vertices.push_back(p0);
1560                                 vertices.push_back(p1);
1561                                 vertices.push_back(p2);
1562
1563                                 vertices.push_back(p2);
1564                                 vertices.push_back(p3);
1565                                 vertices.push_back(p0);
1566                         }
1567                 }
1568         }
1569
1570         tcu::TestLog& log = context.getTestContext().getLog();
1571
1572         log << tcu::TestLog::Message << "Draw two sets of primitives with blending, differing only with ClipDistance sign." << tcu::TestLog::EndMessage
1573                 << tcu::TestLog::Message << "Using " << numClipDistances << " clipping plane(s), one of them possibly having negative values." << tcu::TestLog::EndMessage
1574                 << tcu::TestLog::Message << "Expecting a uniform gray area, no missing (black) nor overlapped (white) pixels." << tcu::TestLog::EndMessage;
1575
1576         DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, static_cast<deUint32>(RENDER_SIZE_LARGE), false, true);
1577         drawContext.draw();
1578
1579         const int numGrayPixels         = countPixels(drawContext.getColorPixels(), Vec4(0.5f, 0.5f, 0.5f, 1.0f), Vec4(0.02f, 0.02f, 0.02f, 0.0f));
1580         const int numExpectedPixels     = RENDER_SIZE_LARGE * RENDER_SIZE_LARGE;
1581
1582         return (numGrayPixels == numExpectedPixels ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
1583 }
1584
1585 } // ClipDistanceComplementarity ns
1586
1587 void addClippingTests (tcu::TestCaseGroup* clippingTestsGroup)
1588 {
1589         tcu::TestContext& testCtx = clippingTestsGroup->getTestContext();
1590
1591         // Clipping against the clip volume
1592         {
1593                 using namespace ClipVolume;
1594
1595                 static const VkPrimitiveTopology cases[] =
1596                 {
1597                         VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
1598                         VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
1599                         VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
1600                         VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
1601                         VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
1602                         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1603                         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
1604                         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1605                         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
1606                         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
1607                 };
1608
1609                 MovePtr<tcu::TestCaseGroup> clipVolumeGroup(new tcu::TestCaseGroup(testCtx, "clip_volume", "clipping with the clip volume"));
1610
1611                 // Fully inside the clip volume
1612                 {
1613                         MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "inside", ""));
1614
1615                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
1616                                 addFunctionCaseWithPrograms<VkPrimitiveTopology>(
1617                                         group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesInside, cases[caseNdx]);
1618
1619                         clipVolumeGroup->addChild(group.release());
1620                 }
1621
1622                 // Fully outside the clip volume
1623                 {
1624                         MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "outside", ""));
1625
1626                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
1627                                 addFunctionCaseWithPrograms<VkPrimitiveTopology>(
1628                                         group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesOutside, cases[caseNdx]);
1629
1630                         clipVolumeGroup->addChild(group.release());
1631                 }
1632
1633                 // Depth clamping
1634                 {
1635                         MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "depth_clamp", ""));
1636
1637                         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
1638                                 addFunctionCaseWithPrograms<VkPrimitiveTopology>(
1639                                         group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesDepthClamp, cases[caseNdx]);
1640
1641                         clipVolumeGroup->addChild(group.release());
1642                 }
1643
1644                 // Large points and wide lines
1645                 {
1646                         // \note For both points and lines, if an unsupported size/width is selected, the nearest supported size will be chosen.
1647                         //       We do have to check for feature support though.
1648
1649                         MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "clipped", ""));
1650
1651                         addFunctionCaseWithPrograms(group.get(), "large_points", "", initProgramsPointSize, testLargePoints);
1652
1653                         addFunctionCaseWithPrograms<LineOrientation>(group.get(), "wide_lines_axis_aligned", "", initPrograms, testWideLines, LINE_ORIENTATION_AXIS_ALIGNED);
1654                         addFunctionCaseWithPrograms<LineOrientation>(group.get(), "wide_lines_diagonal",         "", initPrograms, testWideLines, LINE_ORIENTATION_DIAGONAL);
1655
1656                         clipVolumeGroup->addChild(group.release());
1657                 }
1658
1659                 clippingTestsGroup->addChild(clipVolumeGroup.release());
1660         }
1661
1662         // User-defined clip planes
1663         {
1664                 MovePtr<tcu::TestCaseGroup> clipDistanceGroup(new tcu::TestCaseGroup(testCtx, "user_defined", "user-defined clip planes"));
1665
1666                 // ClipDistance, CullDistance and maxCombinedClipAndCullDistances usage
1667                 {
1668                         using namespace ClipDistance;
1669
1670                         static const struct
1671                         {
1672                                 const char* const       groupName;
1673                                 const char* const       description;
1674                                 bool                            useCullDistance;
1675                         } caseGroups[] =
1676                         {
1677                                 { "clip_distance",              "use ClipDistance",                                                                             false },
1678                                 { "clip_cull_distance", "use ClipDistance and CullDistance at the same time",   true  },
1679                         };
1680
1681                         const deUint32 flagTessellation = 1u << 0;
1682                         const deUint32 flagGeometry             = 1u << 1;
1683
1684                         for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(caseGroups); ++groupNdx)
1685                         for (int indexingMode = 0; indexingMode < 2; ++indexingMode)
1686                         {
1687                                 const bool                      dynamicIndexing = (indexingMode == 1);
1688                                 const std::string       mainGroupName   = de::toString(caseGroups[groupNdx].groupName) + (dynamicIndexing ? "_dynamic_index" : "");
1689
1690                                 MovePtr<tcu::TestCaseGroup>     mainGroup(new tcu::TestCaseGroup(testCtx, mainGroupName.c_str(), ""));
1691
1692                                 for (deUint32 shaderMask = 0u; shaderMask <= (flagTessellation | flagGeometry); ++shaderMask)
1693                                 {
1694                                         const bool                      useTessellation = (shaderMask & flagTessellation) != 0;
1695                                         const bool                      useGeometry             = (shaderMask & flagGeometry) != 0;
1696                                         const std::string       shaderGroupName = std::string("vert") + (useTessellation ? "_tess" : "") + (useGeometry ? "_geom" : "");
1697
1698                                         MovePtr<tcu::TestCaseGroup>     shaderGroup(new tcu::TestCaseGroup(testCtx, shaderGroupName.c_str(), ""));
1699
1700                                         for (int numClipPlanes = 1; numClipPlanes <= MAX_CLIP_DISTANCES; ++numClipPlanes)
1701                                         {
1702                                                 const int                                       numCullPlanes   = (caseGroups[groupNdx].useCullDistance
1703                                                                                                                                                 ? std::min(static_cast<int>(MAX_CULL_DISTANCES), MAX_COMBINED_CLIP_AND_CULL_DISTANCES - numClipPlanes)
1704                                                                                                                                                 : 0);
1705                                                 const std::string                       caseName                = de::toString(numClipPlanes) + (numCullPlanes > 0 ? "_" + de::toString(numCullPlanes) : "");
1706                                                 const VkPrimitiveTopology       topology                = (useTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
1707
1708                                                 addFunctionCaseWithPrograms<CaseDefinition>(
1709                                                         shaderGroup.get(), caseName, caseGroups[groupNdx].description, initPrograms, testClipDistance,
1710                                                         CaseDefinition(topology, numClipPlanes, numCullPlanes, useTessellation, useGeometry, dynamicIndexing));
1711                                         }
1712                                         mainGroup->addChild(shaderGroup.release());
1713                                 }
1714                                 clipDistanceGroup->addChild(mainGroup.release());
1715                         }
1716                 }
1717
1718                 // Complementarity criterion (i.e. clipped and not clipped areas must add up to a complete primitive with no holes nor overlap)
1719                 {
1720                         using namespace ClipDistanceComplementarity;
1721
1722                         MovePtr<tcu::TestCaseGroup>     group(new tcu::TestCaseGroup(testCtx, "complementarity", ""));
1723
1724                         for (int numClipDistances = 1; numClipDistances <= MAX_CLIP_DISTANCES; ++numClipDistances)
1725                                 addFunctionCaseWithPrograms<int>(group.get(), de::toString(numClipDistances).c_str(), "", initPrograms, testComplementarity, numClipDistances);
1726
1727                         clippingTestsGroup->addChild(group.release());
1728                 }
1729
1730                 clippingTestsGroup->addChild(clipDistanceGroup.release());
1731         }
1732 }
1733
1734 } // anonymous
1735
1736 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
1737 {
1738         return createTestGroup(testCtx, "clipping", "Clipping tests", addClippingTests);
1739 }
1740
1741 } // clipping
1742 } // vkt