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