01f9c1095c70be770dbe4ebccdd9d2dbefa6a76c
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / draw / vktDrawNegativeViewportHeightTests.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 Negative viewport height (part of VK_KHR_maintenance1)
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktDrawNegativeViewportHeightTests.hpp"
25 #include "vktDrawCreateInfoUtil.hpp"
26 #include "vktDrawImageObjectUtil.hpp"
27 #include "vktDrawBufferObjectUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktTestCaseUtil.hpp"
30
31 #include "vkPrograms.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkImageUtil.hpp"
34
35 #include "tcuVector.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuImageCompare.hpp"
38
39 #include "deSharedPtr.hpp"
40
41 namespace vkt
42 {
43 namespace Draw
44 {
45 namespace
46 {
47 using namespace vk;
48 using tcu::Vec4;
49 using de::SharedPtr;
50 using de::MovePtr;
51
52 enum Constants
53 {
54         WIDTH   = 256,
55         HEIGHT  = WIDTH/2,
56 };
57
58 struct TestParams
59 {
60         VkFrontFace                             frontFace;
61         VkCullModeFlagBits              cullMode;
62 };
63
64 class NegativeViewportHeightTestInstance : public TestInstance
65 {
66 public:
67                                                                         NegativeViewportHeightTestInstance      (Context& context, const TestParams& params);
68         tcu::TestStatus                                 iterate                                                         (void);
69         tcu::ConstPixelBufferAccess             draw                                                            (const VkViewport viewport);
70         MovePtr<tcu::TextureLevel>              generateReferenceImage                          (void) const;
71         bool                                                    isCulled                                                        (const VkFrontFace triangleFace) const;
72
73 private:
74         const TestParams                                m_params;
75         const VkFormat                                  m_colorAttachmentFormat;
76         SharedPtr<Image>                                m_colorTargetImage;
77         Move<VkImageView>                               m_colorTargetView;
78         SharedPtr<Buffer>                               m_vertexBuffer;
79         Move<VkRenderPass>                              m_renderPass;
80         Move<VkFramebuffer>                             m_framebuffer;
81         Move<VkPipelineLayout>                  m_pipelineLayout;
82         Move<VkPipeline>                                m_pipeline;
83 };
84
85 NegativeViewportHeightTestInstance::NegativeViewportHeightTestInstance (Context& context, const TestParams& params)
86         : TestInstance                          (context)
87         , m_params                                      (params)
88         , m_colorAttachmentFormat       (VK_FORMAT_R8G8B8A8_UNORM)
89 {
90         const DeviceInterface&  vk              = m_context.getDeviceInterface();
91         const VkDevice                  device  = m_context.getDevice();
92
93         // Vertex data
94         {
95                 std::vector<Vec4> vertexData;
96
97                 // CCW triangle
98                 vertexData.push_back(Vec4(-0.8f, -0.6f, 0.0f, 1.0f));   //  0-----2
99                 vertexData.push_back(Vec4(-0.8f,  0.6f, 0.0f, 1.0f));   //   |  /
100                 vertexData.push_back(Vec4(-0.2f, -0.6f, 0.0f, 1.0f));   //  1|/
101
102                 // CW triangle
103                 vertexData.push_back(Vec4( 0.2f, -0.6f, 0.0f, 1.0f));   //  0-----1
104                 vertexData.push_back(Vec4( 0.8f, -0.6f, 0.0f, 1.0f));   //    \  |
105                 vertexData.push_back(Vec4( 0.8f,  0.6f, 0.0f, 1.0f));   //      \|2
106
107                 const VkDeviceSize dataSize = vertexData.size() * sizeof(Vec4);
108                 m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
109                                                                                                 m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
110
111                 deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &vertexData[0], static_cast<std::size_t>(dataSize));
112                 flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
113         }
114
115         // Render pass
116         {
117                 const VkExtent3D                targetImageExtent               = { WIDTH, HEIGHT, 1 };
118                 const VkImageUsageFlags targetImageUsageFlags   = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
119
120                 const ImageCreateInfo   targetImageCreateInfo(
121                         VK_IMAGE_TYPE_2D,                                               // imageType,
122                         m_colorAttachmentFormat,                                // format,
123                         targetImageExtent,                                              // extent,
124                         1u,                                                                             // mipLevels,
125                         1u,                                                                             // arrayLayers,
126                         VK_SAMPLE_COUNT_1_BIT,                                  // samples,
127                         VK_IMAGE_TILING_OPTIMAL,                                // tiling,
128                         targetImageUsageFlags);                                 // usage,
129
130                 m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator());
131
132                 RenderPassCreateInfo    renderPassCreateInfo;
133                 renderPassCreateInfo.addAttachment(AttachmentDescription(
134                         m_colorAttachmentFormat,                                // format
135                         VK_SAMPLE_COUNT_1_BIT,                                  // samples
136                         VK_ATTACHMENT_LOAD_OP_LOAD,                             // loadOp
137                         VK_ATTACHMENT_STORE_OP_STORE,                   // storeOp
138                         VK_ATTACHMENT_LOAD_OP_DONT_CARE,                // stencilLoadOp
139                         VK_ATTACHMENT_STORE_OP_DONT_CARE,               // stencilStoreOp
140                         VK_IMAGE_LAYOUT_GENERAL,                                // initialLayout
141                         VK_IMAGE_LAYOUT_GENERAL));                              // finalLayout
142
143                 const VkAttachmentReference colorAttachmentReference =
144                 {
145                         0u,
146                         VK_IMAGE_LAYOUT_GENERAL
147                 };
148
149                 renderPassCreateInfo.addSubpass(SubpassDescription(
150                         VK_PIPELINE_BIND_POINT_GRAPHICS,                // pipelineBindPoint
151                         (VkSubpassDescriptionFlags)0,                   // flags
152                         0u,                                                                             // inputAttachmentCount
153                         DE_NULL,                                                                // inputAttachments
154                         1u,                                                                             // colorAttachmentCount
155                         &colorAttachmentReference,                              // colorAttachments
156                         DE_NULL,                                                                // resolveAttachments
157                         AttachmentReference(),                                  // depthStencilAttachment
158                         0u,                                                                             // preserveAttachmentCount
159                         DE_NULL));                                                              // preserveAttachments
160
161                 m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
162         }
163
164         // Framebuffer
165         {
166                 const ImageViewCreateInfo colorTargetViewInfo (m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
167                 m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
168
169                 std::vector<VkImageView> colorAttachments(1);
170                 colorAttachments[0] = *m_colorTargetView;
171
172                 const FramebufferCreateInfo     framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
173                 m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
174         }
175
176         // Vertex input
177
178         const VkVertexInputBindingDescription           vertexInputBindingDescription =
179         {
180                 0u,                                                                             // uint32_t             binding;
181                 sizeof(Vec4),                                                   // uint32_t             stride;
182                 VK_VERTEX_INPUT_RATE_VERTEX,                    // VkVertexInputRate    inputRate;
183         };
184
185         const VkVertexInputAttributeDescription         vertexInputAttributeDescription =
186         {
187                 0u,                                                                             // uint32_t    location;
188                 0u,                                                                             // uint32_t    binding;
189                 VK_FORMAT_R32G32B32A32_SFLOAT,                  // VkFormat    format;
190                 0u                                                                              // uint32_t    offset;
191         };
192
193         const PipelineCreateInfo::VertexInputState      vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
194                                                                                                                                                                                                                 1, &vertexInputAttributeDescription);
195
196         // Graphics pipeline
197
198         const VkRect2D scissor =
199         {
200                 { 0,            0               },              // x, y
201                 { WIDTH,        HEIGHT  },              // width, height
202         };
203
204         std::vector<VkDynamicState>             dynamicStates;
205         dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
206
207         const Unique<VkShaderModule>    vertexModule    (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
208         const Unique<VkShaderModule>    fragmentModule  (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
209
210         const PipelineLayoutCreateInfo  pipelineLayoutCreateInfo;
211         m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
212
213         const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
214
215         PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
216         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule,   "main", VK_SHADER_STAGE_VERTEX_BIT));
217         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
218         pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState       (vertexInputState));
219         pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
220         pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState        (1, &colorBlendAttachmentState));
221         pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState          (1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
222         pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState      ());
223         pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState        (
224                 VK_FALSE,                                       // depthClampEnable
225                 VK_FALSE,                                       // rasterizerDiscardEnable
226                 VK_POLYGON_MODE_FILL,           // polygonMode
227                 m_params.cullMode,                      // cullMode
228                 m_params.frontFace,                     // frontFace
229                 VK_FALSE,                                       // depthBiasEnable
230                 0.0f,                                           // depthBiasConstantFactor
231                 0.0f,                                           // depthBiasClamp
232                 0.0f,                                           // depthBiasSlopeFactor
233                 1.0f));                                         // lineWidth
234         pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState       ());
235         pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState           (dynamicStates));
236
237         m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
238 }
239
240 tcu::ConstPixelBufferAccess NegativeViewportHeightTestInstance::draw (const VkViewport viewport)
241 {
242         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
243         const VkDevice                  device                          = m_context.getDevice();
244         const VkQueue                   queue                           = m_context.getUniversalQueue();
245         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
246
247         // Command buffer
248
249         const CmdPoolCreateInfo         cmdPoolCreateInfo       (queueFamilyIndex);
250         const Unique<VkCommandPool>     cmdPool                         (createCommandPool(vk, device, &cmdPoolCreateInfo));
251
252         const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
253         {
254                 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,         // VkStructureType                      sType;
255                 DE_NULL,                                                                                        // const void*                          pNext;
256                 *cmdPool,                                                                                       // VkCommandPool                        commandPool;
257                 VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                        // VkCommandBufferLevel         level;
258                 1u,                                                                                                     // deUint32                                     bufferCount;
259         };
260         const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, &cmdBufferAllocateInfo));
261
262         // Draw
263
264         {
265                 const CmdBufferBeginInfo beginInfo;
266                 vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
267         }
268
269         vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &viewport);
270
271         {
272                 const VkClearColorValue         clearColor                      = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f).color;
273                 const ImageSubresourceRange subresourceRange    (VK_IMAGE_ASPECT_COLOR_BIT);
274
275                 initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL);
276                 vk.cmdClearColorImage(*cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
277         }
278         {
279                 const VkMemoryBarrier memBarrier =
280                 {
281                         VK_STRUCTURE_TYPE_MEMORY_BARRIER,                                                                                               // VkStructureType    sType;
282                         DE_NULL,                                                                                                                                                // const void*        pNext;
283                         VK_ACCESS_TRANSFER_WRITE_BIT,                                                                                                   // VkAccessFlags      srcAccessMask;
284                         VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT              // VkAccessFlags      dstAccessMask;
285                 };
286
287                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
288         }
289         {
290                 const VkRect2D                          renderArea              = { { 0, 0 }, { WIDTH, HEIGHT } };
291                 const RenderPassBeginInfo       renderPassBegin (*m_renderPass, *m_framebuffer, renderArea);
292
293                 vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE);
294         }
295         {
296                 const VkDeviceSize      offset  = 0;
297                 const VkBuffer          buffer  = m_vertexBuffer->object();
298
299                 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
300         }
301
302         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
303         vk.cmdDraw(*cmdBuffer, 6, 1, 0, 0);
304         vk.cmdEndRenderPass(*cmdBuffer);
305         vk.endCommandBuffer(*cmdBuffer);
306
307         // Submit
308         {
309                 const VkFenceCreateInfo fenceInfo       =
310                 {
311                         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,            // VkStructureType       sType;
312                         DE_NULL,                                                                        // const void*           pNext;
313                         (VkFenceCreateFlags)0,                                          // VkFenceCreateFlags    flags;
314                 };
315                 const Unique<VkFence>   fence           (createFence(vk, device, &fenceInfo));
316                 const VkSubmitInfo              submitInfo      =
317                 {
318                         VK_STRUCTURE_TYPE_SUBMIT_INFO,                          // VkStructureType                sType;
319                         DE_NULL,                                                                        // const void*                    pNext;
320                         0,                                                                                      // uint32_t                       waitSemaphoreCount;
321                         DE_NULL,                                                                        // const VkSemaphore*             pWaitSemaphores;
322                         (const VkPipelineStageFlags*)DE_NULL,           // const VkPipelineStageFlags*    pWaitDstStageMask;
323                         1,                                                                                      // uint32_t                       commandBufferCount;
324                         &cmdBuffer.get(),                                                       // const VkCommandBuffer*         pCommandBuffers;
325                         0,                                                                                      // uint32_t                       signalSemaphoreCount;
326                         DE_NULL                                                                         // const VkSemaphore*             pSignalSemaphores;
327                 };
328
329                 VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
330                 VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), VK_TRUE, ~0ull));
331         }
332
333         // Get result
334         {
335                 const VkOffset3D zeroOffset = { 0, 0, 0 };
336                 return m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
337         }
338 }
339
340 //! Determine if a triangle with triangleFace orientation will be culled or not
341 bool NegativeViewportHeightTestInstance::isCulled (const VkFrontFace triangleFace) const
342 {
343         const bool isFrontFacing = (triangleFace == m_params.frontFace);
344
345         if (m_params.cullMode == VK_CULL_MODE_FRONT_BIT && isFrontFacing)
346                 return true;
347         if (m_params.cullMode == VK_CULL_MODE_BACK_BIT  && !isFrontFacing)
348                 return true;
349
350         return m_params.cullMode == VK_CULL_MODE_FRONT_AND_BACK;
351 }
352
353 MovePtr<tcu::TextureLevel> NegativeViewportHeightTestInstance::generateReferenceImage (void) const
354 {
355         DE_ASSERT(HEIGHT == WIDTH/2);
356
357         MovePtr<tcu::TextureLevel>              image   (new tcu::TextureLevel(mapVkFormat(m_colorAttachmentFormat), WIDTH, HEIGHT));
358         const tcu::PixelBufferAccess    access  (image->getAccess());
359         const Vec4                                              black   (0.0f, 0.0f, 0.0f, 1.0f);
360         const Vec4                                              white   (1.0f);
361         const Vec4                                              gray    (0.5f, 0.5f, 0.5f, 1.0f);
362
363         tcu::clear(access, black);
364
365         const int p1 =      static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.6f) / 2.0f);
366         const int p2 = p1 + static_cast<int>(static_cast<float>(HEIGHT) * (2.0f * 0.6f) / 2.0f);
367
368         // left triangle (CCW -> CW after y-flip)
369         if (!isCulled(VK_FRONT_FACE_CLOCKWISE))
370         {
371                 const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_CLOCKWISE ? white : gray);
372
373                 for (int y = p1; y <= p2; ++y)
374                 for (int x = p1; x <  y;  ++x)
375                         access.setPixel(color, x, y);
376         }
377
378         // right triangle (CW -> CCW after y-flip)
379         if (!isCulled(VK_FRONT_FACE_COUNTER_CLOCKWISE))
380         {
381                 const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE ? white : gray);
382
383                 for (int y = p1;        y <= p2;          ++y)
384                 for (int x = WIDTH - y; x <  p2 + HEIGHT; ++x)
385                         access.setPixel(color, x, y);
386         }
387
388         return image;
389 }
390
391 std::string getCullModeStr (const VkCullModeFlagBits cullMode)
392 {
393         // Cull mode flags are a bit special, because there's a meaning to 0 and or'ed flags.
394         // The function getCullModeFlagsStr() doesn't work too well in this case.
395
396         switch (cullMode)
397         {
398                 case VK_CULL_MODE_NONE:                         return "VK_CULL_MODE_NONE";
399                 case VK_CULL_MODE_FRONT_BIT:            return "VK_CULL_MODE_FRONT_BIT";
400                 case VK_CULL_MODE_BACK_BIT:                     return "VK_CULL_MODE_BACK_BIT";
401                 case VK_CULL_MODE_FRONT_AND_BACK:       return "VK_CULL_MODE_FRONT_AND_BACK";
402
403                 default:
404                         DE_ASSERT(0);
405                         return std::string();
406         }
407 }
408
409 tcu::TestStatus NegativeViewportHeightTestInstance::iterate (void)
410 {
411         // Check requirements
412
413         if (!de::contains(m_context.getDeviceExtensions().begin(), m_context.getDeviceExtensions().end(), std::string("VK_KHR_maintenance1")))
414                 TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_maintenance1");
415
416         // Set up the viewport and draw
417
418         const VkViewport viewport =
419         {
420                 0.0f,                                                   // float    x;
421                 static_cast<float>(HEIGHT),             // float    y;
422                 static_cast<float>(WIDTH),              // float    width;
423                 -static_cast<float>(HEIGHT),    // float    height;
424                 0.0f,                                                   // float    minDepth;
425                 1.0f,                                                   // float    maxDepth;
426         };
427
428         const tcu::ConstPixelBufferAccess       resultImage     = draw(viewport);
429
430         // Verify the results
431
432         tcu::TestLog&                           log                             = m_context.getTestContext().getLog();
433         MovePtr<tcu::TextureLevel>      referenceImage  = generateReferenceImage();
434
435         log << tcu::TestLog::Message
436                 << "Drawing two triangles with negative viewport height, which will cause a y-flip. This changes the sign of the triangle's area."
437                 << tcu::TestLog::EndMessage;
438         log << tcu::TestLog::Message
439                 << "After the flip, the triangle on the left is CW and the triangle on the right is CCW. Right angles of the both triangles should be at the bottom of the image."
440                 << " Front face is white, back face is gray."
441                 << tcu::TestLog::EndMessage;
442         log << tcu::TestLog::Message
443                 << "Front face: " << getFrontFaceName(m_params.frontFace) << "\n"
444                 << "Cull mode: "  << getCullModeStr  (m_params.cullMode)  << "\n"
445                 << tcu::TestLog::EndMessage;
446
447         if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
448                 return tcu::TestStatus::fail("Rendered image is incorrect");
449         else
450                 return tcu::TestStatus::pass("Pass");
451 }
452
453 class NegativeViewportHeightTest : public TestCase
454 {
455 public:
456         NegativeViewportHeightTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
457                 : TestCase      (testCtx, name, description)
458                 , m_params      (params)
459         {
460         }
461
462         void initPrograms (SourceCollections& programCollection) const
463         {
464                 // Vertex shader
465                 {
466                         std::ostringstream src;
467                         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
468                                 << "\n"
469                                 << "layout(location = 0) in vec4 in_position;\n"
470                                 << "\n"
471                                 << "out gl_PerVertex {\n"
472                                 << "    vec4  gl_Position;\n"
473                                 << "};\n"
474                                 << "\n"
475                                 << "void main(void)\n"
476                                 << "{\n"
477                                 << "    gl_Position = in_position;\n"
478                                 << "}\n";
479
480                         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
481                 }
482
483                 // Fragment shader
484                 {
485                         std::ostringstream src;
486                         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
487                                 << "\n"
488                                 << "layout(location = 0) out vec4 out_color;\n"
489                                 << "\n"
490                                 << "void main(void)\n"
491                                 << "{\n"
492                                 << "    if (gl_FrontFacing)\n"
493                                 << "        out_color = vec4(1.0);\n"
494                                 << "    else\n"
495                                 << "        out_color = vec4(vec3(0.5), 1.0);\n"
496                                 << "}\n";
497
498                         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
499                 }
500         }
501
502         virtual TestInstance* createInstance (Context& context) const
503         {
504                 return new NegativeViewportHeightTestInstance(context, m_params);
505         }
506
507 private:
508         const TestParams        m_params;
509 };
510
511 void populateTestGroup (tcu::TestCaseGroup* testGroup)
512 {
513         const struct
514         {
515                 const char* const       name;
516                 VkFrontFace                     frontFace;
517         } frontFace[] =
518         {
519                 { "front_ccw",  VK_FRONT_FACE_COUNTER_CLOCKWISE },
520                 { "front_cw",   VK_FRONT_FACE_CLOCKWISE                 },
521         };
522
523         const struct
524         {
525                 const char* const       name;
526                 VkCullModeFlagBits      cullMode;
527         } cullMode[] =
528         {
529                 { "cull_none",  VK_CULL_MODE_NONE                       },
530                 { "cull_front", VK_CULL_MODE_FRONT_BIT          },
531                 { "cull_back",  VK_CULL_MODE_BACK_BIT           },
532                 { "cull_both",  VK_CULL_MODE_FRONT_AND_BACK     },
533         };
534
535         for (int ndxFrontFace = 0; ndxFrontFace < DE_LENGTH_OF_ARRAY(frontFace); ++ndxFrontFace)
536         for (int ndxCullMode  = 0; ndxCullMode  < DE_LENGTH_OF_ARRAY(cullMode);  ++ndxCullMode)
537         {
538                 const TestParams params =
539                 {
540                         frontFace[ndxFrontFace].frontFace,
541                         cullMode[ndxCullMode].cullMode,
542                 };
543                 std::ostringstream      name;
544                 name << frontFace[ndxFrontFace].name << "_" << cullMode[ndxCullMode].name;
545
546                 testGroup->addChild(new NegativeViewportHeightTest(testGroup->getTestContext(), name.str(), "", params));
547         }
548 }
549
550 }       // anonymous
551
552 tcu::TestCaseGroup*     createNegativeViewportHeightTests (tcu::TestContext& testCtx)
553 {
554         return createTestGroup(testCtx, "negative_viewport_height", "Negative viewport height (VK_KHR_maintenance1)", populateTestGroup);
555 }
556
557 }       // Draw
558 }       // vkt