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