Add negative viewport height tests
authorMaciej Jesionowski <maciej.jesionowski@mobica.com>
Wed, 16 Nov 2016 15:30:29 +0000 (16:30 +0100)
committerPyry Haulos <phaulos@google.com>
Thu, 8 Dec 2016 19:41:42 +0000 (15:41 -0400)
Part of VK_KHR_maintenance1 extension

New tests:
- dEQP-VK.draw.negative_viewport_height.*

Issue: #532

Change-Id: I7591ba5d53fc6b252d6fffbd77b1e6c165eefe74

android/cts/master/vk-master.txt
external/vulkancts/modules/vulkan/draw/CMakeLists.txt
external/vulkancts/modules/vulkan/draw/vktDrawNegativeViewportHeightTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/draw/vktDrawNegativeViewportHeightTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/draw/vktDrawTests.cpp
external/vulkancts/mustpass/1.0.2/vk-default.txt

index 79ebe48..00792ad 100644 (file)
@@ -122359,6 +122359,14 @@ dEQP-VK.draw.shader_draw_parameters.draw_index.draw
 dEQP-VK.draw.shader_draw_parameters.draw_index.draw_instanced
 dEQP-VK.draw.shader_draw_parameters.draw_index.draw_indexed
 dEQP-VK.draw.shader_draw_parameters.draw_index.draw_indexed_instanced
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_none
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_front
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_back
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_both
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_none
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_front
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_back
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_both
 dEQP-VK.compute.basic.empty_shader
 dEQP-VK.compute.basic.ubo_to_ssbo_single_invocation
 dEQP-VK.compute.basic.ubo_to_ssbo_single_group
index 5a83703..2fc7101 100644 (file)
@@ -13,6 +13,8 @@ set(DEQP_VK_DRAW_SRCS
        vktDrawShaderDrawParametersTests.cpp
        vktDrawSimpleTest.hpp
        vktDrawSimpleTest.cpp
+       vktDrawNegativeViewportHeightTests.hpp
+       vktDrawNegativeViewportHeightTests.cpp
        vktDrawBaseClass.hpp
        vktDrawBaseClass.cpp
        vktDrawCreateInfoUtil.hpp
diff --git a/external/vulkancts/modules/vulkan/draw/vktDrawNegativeViewportHeightTests.cpp b/external/vulkancts/modules/vulkan/draw/vktDrawNegativeViewportHeightTests.cpp
new file mode 100644 (file)
index 0000000..01f9c10
--- /dev/null
@@ -0,0 +1,558 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Negative viewport height (part of VK_KHR_maintenance1)
+ *//*--------------------------------------------------------------------*/
+
+#include "vktDrawNegativeViewportHeightTests.hpp"
+#include "vktDrawCreateInfoUtil.hpp"
+#include "vktDrawImageObjectUtil.hpp"
+#include "vktDrawBufferObjectUtil.hpp"
+#include "vktTestGroupUtil.hpp"
+#include "vktTestCaseUtil.hpp"
+
+#include "vkPrograms.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkImageUtil.hpp"
+
+#include "tcuVector.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuImageCompare.hpp"
+
+#include "deSharedPtr.hpp"
+
+namespace vkt
+{
+namespace Draw
+{
+namespace
+{
+using namespace vk;
+using tcu::Vec4;
+using de::SharedPtr;
+using de::MovePtr;
+
+enum Constants
+{
+       WIDTH   = 256,
+       HEIGHT  = WIDTH/2,
+};
+
+struct TestParams
+{
+       VkFrontFace                             frontFace;
+       VkCullModeFlagBits              cullMode;
+};
+
+class NegativeViewportHeightTestInstance : public TestInstance
+{
+public:
+                                                                       NegativeViewportHeightTestInstance      (Context& context, const TestParams& params);
+       tcu::TestStatus                                 iterate                                                         (void);
+       tcu::ConstPixelBufferAccess             draw                                                            (const VkViewport viewport);
+       MovePtr<tcu::TextureLevel>              generateReferenceImage                          (void) const;
+       bool                                                    isCulled                                                        (const VkFrontFace triangleFace) const;
+
+private:
+       const TestParams                                m_params;
+       const VkFormat                                  m_colorAttachmentFormat;
+       SharedPtr<Image>                                m_colorTargetImage;
+       Move<VkImageView>                               m_colorTargetView;
+       SharedPtr<Buffer>                               m_vertexBuffer;
+       Move<VkRenderPass>                              m_renderPass;
+       Move<VkFramebuffer>                             m_framebuffer;
+       Move<VkPipelineLayout>                  m_pipelineLayout;
+       Move<VkPipeline>                                m_pipeline;
+};
+
+NegativeViewportHeightTestInstance::NegativeViewportHeightTestInstance (Context& context, const TestParams& params)
+       : TestInstance                          (context)
+       , m_params                                      (params)
+       , m_colorAttachmentFormat       (VK_FORMAT_R8G8B8A8_UNORM)
+{
+       const DeviceInterface&  vk              = m_context.getDeviceInterface();
+       const VkDevice                  device  = m_context.getDevice();
+
+       // Vertex data
+       {
+               std::vector<Vec4> vertexData;
+
+               // CCW triangle
+               vertexData.push_back(Vec4(-0.8f, -0.6f, 0.0f, 1.0f));   //  0-----2
+               vertexData.push_back(Vec4(-0.8f,  0.6f, 0.0f, 1.0f));   //   |  /
+               vertexData.push_back(Vec4(-0.2f, -0.6f, 0.0f, 1.0f));   //  1|/
+
+               // CW triangle
+               vertexData.push_back(Vec4( 0.2f, -0.6f, 0.0f, 1.0f));   //  0-----1
+               vertexData.push_back(Vec4( 0.8f, -0.6f, 0.0f, 1.0f));   //    \  |
+               vertexData.push_back(Vec4( 0.8f,  0.6f, 0.0f, 1.0f));   //      \|2
+
+               const VkDeviceSize dataSize = vertexData.size() * sizeof(Vec4);
+               m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
+                                                                                               m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
+
+               deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &vertexData[0], static_cast<std::size_t>(dataSize));
+               flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
+       }
+
+       // Render pass
+       {
+               const VkExtent3D                targetImageExtent               = { WIDTH, HEIGHT, 1 };
+               const VkImageUsageFlags targetImageUsageFlags   = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+               const ImageCreateInfo   targetImageCreateInfo(
+                       VK_IMAGE_TYPE_2D,                                               // imageType,
+                       m_colorAttachmentFormat,                                // format,
+                       targetImageExtent,                                              // extent,
+                       1u,                                                                             // mipLevels,
+                       1u,                                                                             // arrayLayers,
+                       VK_SAMPLE_COUNT_1_BIT,                                  // samples,
+                       VK_IMAGE_TILING_OPTIMAL,                                // tiling,
+                       targetImageUsageFlags);                                 // usage,
+
+               m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator());
+
+               RenderPassCreateInfo    renderPassCreateInfo;
+               renderPassCreateInfo.addAttachment(AttachmentDescription(
+                       m_colorAttachmentFormat,                                // format
+                       VK_SAMPLE_COUNT_1_BIT,                                  // samples
+                       VK_ATTACHMENT_LOAD_OP_LOAD,                             // loadOp
+                       VK_ATTACHMENT_STORE_OP_STORE,                   // storeOp
+                       VK_ATTACHMENT_LOAD_OP_DONT_CARE,                // stencilLoadOp
+                       VK_ATTACHMENT_STORE_OP_DONT_CARE,               // stencilStoreOp
+                       VK_IMAGE_LAYOUT_GENERAL,                                // initialLayout
+                       VK_IMAGE_LAYOUT_GENERAL));                              // finalLayout
+
+               const VkAttachmentReference colorAttachmentReference =
+               {
+                       0u,
+                       VK_IMAGE_LAYOUT_GENERAL
+               };
+
+               renderPassCreateInfo.addSubpass(SubpassDescription(
+                       VK_PIPELINE_BIND_POINT_GRAPHICS,                // pipelineBindPoint
+                       (VkSubpassDescriptionFlags)0,                   // flags
+                       0u,                                                                             // inputAttachmentCount
+                       DE_NULL,                                                                // inputAttachments
+                       1u,                                                                             // colorAttachmentCount
+                       &colorAttachmentReference,                              // colorAttachments
+                       DE_NULL,                                                                // resolveAttachments
+                       AttachmentReference(),                                  // depthStencilAttachment
+                       0u,                                                                             // preserveAttachmentCount
+                       DE_NULL));                                                              // preserveAttachments
+
+               m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
+       }
+
+       // Framebuffer
+       {
+               const ImageViewCreateInfo colorTargetViewInfo (m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
+               m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
+
+               std::vector<VkImageView> colorAttachments(1);
+               colorAttachments[0] = *m_colorTargetView;
+
+               const FramebufferCreateInfo     framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
+               m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
+       }
+
+       // Vertex input
+
+       const VkVertexInputBindingDescription           vertexInputBindingDescription =
+       {
+               0u,                                                                             // uint32_t             binding;
+               sizeof(Vec4),                                                   // uint32_t             stride;
+               VK_VERTEX_INPUT_RATE_VERTEX,                    // VkVertexInputRate    inputRate;
+       };
+
+       const VkVertexInputAttributeDescription         vertexInputAttributeDescription =
+       {
+               0u,                                                                             // uint32_t    location;
+               0u,                                                                             // uint32_t    binding;
+               VK_FORMAT_R32G32B32A32_SFLOAT,                  // VkFormat    format;
+               0u                                                                              // uint32_t    offset;
+       };
+
+       const PipelineCreateInfo::VertexInputState      vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
+                                                                                                                                                                                                               1, &vertexInputAttributeDescription);
+
+       // Graphics pipeline
+
+       const VkRect2D scissor =
+       {
+               { 0,            0               },              // x, y
+               { WIDTH,        HEIGHT  },              // width, height
+       };
+
+       std::vector<VkDynamicState>             dynamicStates;
+       dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
+
+       const Unique<VkShaderModule>    vertexModule    (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
+       const Unique<VkShaderModule>    fragmentModule  (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
+
+       const PipelineLayoutCreateInfo  pipelineLayoutCreateInfo;
+       m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
+
+       const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
+
+       PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
+       pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule,   "main", VK_SHADER_STAGE_VERTEX_BIT));
+       pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
+       pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState       (vertexInputState));
+       pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
+       pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState        (1, &colorBlendAttachmentState));
+       pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState          (1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
+       pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState      ());
+       pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState        (
+               VK_FALSE,                                       // depthClampEnable
+               VK_FALSE,                                       // rasterizerDiscardEnable
+               VK_POLYGON_MODE_FILL,           // polygonMode
+               m_params.cullMode,                      // cullMode
+               m_params.frontFace,                     // frontFace
+               VK_FALSE,                                       // depthBiasEnable
+               0.0f,                                           // depthBiasConstantFactor
+               0.0f,                                           // depthBiasClamp
+               0.0f,                                           // depthBiasSlopeFactor
+               1.0f));                                         // lineWidth
+       pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState       ());
+       pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState           (dynamicStates));
+
+       m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
+}
+
+tcu::ConstPixelBufferAccess NegativeViewportHeightTestInstance::draw (const VkViewport viewport)
+{
+       const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
+       const VkDevice                  device                          = m_context.getDevice();
+       const VkQueue                   queue                           = m_context.getUniversalQueue();
+       const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+
+       // Command buffer
+
+       const CmdPoolCreateInfo         cmdPoolCreateInfo       (queueFamilyIndex);
+       const Unique<VkCommandPool>     cmdPool                         (createCommandPool(vk, device, &cmdPoolCreateInfo));
+
+       const VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
+       {
+               VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,         // VkStructureType                      sType;
+               DE_NULL,                                                                                        // const void*                          pNext;
+               *cmdPool,                                                                                       // VkCommandPool                        commandPool;
+               VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                        // VkCommandBufferLevel         level;
+               1u,                                                                                                     // deUint32                                     bufferCount;
+       };
+       const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, &cmdBufferAllocateInfo));
+
+       // Draw
+
+       {
+               const CmdBufferBeginInfo beginInfo;
+               vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
+       }
+
+       vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &viewport);
+
+       {
+               const VkClearColorValue         clearColor                      = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f).color;
+               const ImageSubresourceRange subresourceRange    (VK_IMAGE_ASPECT_COLOR_BIT);
+
+               initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL);
+               vk.cmdClearColorImage(*cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
+       }
+       {
+               const VkMemoryBarrier memBarrier =
+               {
+                       VK_STRUCTURE_TYPE_MEMORY_BARRIER,                                                                                               // VkStructureType    sType;
+                       DE_NULL,                                                                                                                                                // const void*        pNext;
+                       VK_ACCESS_TRANSFER_WRITE_BIT,                                                                                                   // VkAccessFlags      srcAccessMask;
+                       VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT              // VkAccessFlags      dstAccessMask;
+               };
+
+               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
+       }
+       {
+               const VkRect2D                          renderArea              = { { 0, 0 }, { WIDTH, HEIGHT } };
+               const RenderPassBeginInfo       renderPassBegin (*m_renderPass, *m_framebuffer, renderArea);
+
+               vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBegin, VK_SUBPASS_CONTENTS_INLINE);
+       }
+       {
+               const VkDeviceSize      offset  = 0;
+               const VkBuffer          buffer  = m_vertexBuffer->object();
+
+               vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
+       }
+
+       vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
+       vk.cmdDraw(*cmdBuffer, 6, 1, 0, 0);
+       vk.cmdEndRenderPass(*cmdBuffer);
+       vk.endCommandBuffer(*cmdBuffer);
+
+       // Submit
+       {
+               const VkFenceCreateInfo fenceInfo       =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,            // VkStructureType       sType;
+                       DE_NULL,                                                                        // const void*           pNext;
+                       (VkFenceCreateFlags)0,                                          // VkFenceCreateFlags    flags;
+               };
+               const Unique<VkFence>   fence           (createFence(vk, device, &fenceInfo));
+               const VkSubmitInfo              submitInfo      =
+               {
+                       VK_STRUCTURE_TYPE_SUBMIT_INFO,                          // VkStructureType                sType;
+                       DE_NULL,                                                                        // const void*                    pNext;
+                       0,                                                                                      // uint32_t                       waitSemaphoreCount;
+                       DE_NULL,                                                                        // const VkSemaphore*             pWaitSemaphores;
+                       (const VkPipelineStageFlags*)DE_NULL,           // const VkPipelineStageFlags*    pWaitDstStageMask;
+                       1,                                                                                      // uint32_t                       commandBufferCount;
+                       &cmdBuffer.get(),                                                       // const VkCommandBuffer*         pCommandBuffers;
+                       0,                                                                                      // uint32_t                       signalSemaphoreCount;
+                       DE_NULL                                                                         // const VkSemaphore*             pSignalSemaphores;
+               };
+
+               VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
+               VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), VK_TRUE, ~0ull));
+       }
+
+       // Get result
+       {
+               const VkOffset3D zeroOffset = { 0, 0, 0 };
+               return m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
+       }
+}
+
+//! Determine if a triangle with triangleFace orientation will be culled or not
+bool NegativeViewportHeightTestInstance::isCulled (const VkFrontFace triangleFace) const
+{
+       const bool isFrontFacing = (triangleFace == m_params.frontFace);
+
+       if (m_params.cullMode == VK_CULL_MODE_FRONT_BIT && isFrontFacing)
+               return true;
+       if (m_params.cullMode == VK_CULL_MODE_BACK_BIT  && !isFrontFacing)
+               return true;
+
+       return m_params.cullMode == VK_CULL_MODE_FRONT_AND_BACK;
+}
+
+MovePtr<tcu::TextureLevel> NegativeViewportHeightTestInstance::generateReferenceImage (void) const
+{
+       DE_ASSERT(HEIGHT == WIDTH/2);
+
+       MovePtr<tcu::TextureLevel>              image   (new tcu::TextureLevel(mapVkFormat(m_colorAttachmentFormat), WIDTH, HEIGHT));
+       const tcu::PixelBufferAccess    access  (image->getAccess());
+       const Vec4                                              black   (0.0f, 0.0f, 0.0f, 1.0f);
+       const Vec4                                              white   (1.0f);
+       const Vec4                                              gray    (0.5f, 0.5f, 0.5f, 1.0f);
+
+       tcu::clear(access, black);
+
+       const int p1 =      static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.6f) / 2.0f);
+       const int p2 = p1 + static_cast<int>(static_cast<float>(HEIGHT) * (2.0f * 0.6f) / 2.0f);
+
+       // left triangle (CCW -> CW after y-flip)
+       if (!isCulled(VK_FRONT_FACE_CLOCKWISE))
+       {
+               const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_CLOCKWISE ? white : gray);
+
+               for (int y = p1; y <= p2; ++y)
+               for (int x = p1; x <  y;  ++x)
+                       access.setPixel(color, x, y);
+       }
+
+       // right triangle (CW -> CCW after y-flip)
+       if (!isCulled(VK_FRONT_FACE_COUNTER_CLOCKWISE))
+       {
+               const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE ? white : gray);
+
+               for (int y = p1;        y <= p2;          ++y)
+               for (int x = WIDTH - y; x <  p2 + HEIGHT; ++x)
+                       access.setPixel(color, x, y);
+       }
+
+       return image;
+}
+
+std::string getCullModeStr (const VkCullModeFlagBits cullMode)
+{
+       // Cull mode flags are a bit special, because there's a meaning to 0 and or'ed flags.
+       // The function getCullModeFlagsStr() doesn't work too well in this case.
+
+       switch (cullMode)
+       {
+               case VK_CULL_MODE_NONE:                         return "VK_CULL_MODE_NONE";
+               case VK_CULL_MODE_FRONT_BIT:            return "VK_CULL_MODE_FRONT_BIT";
+               case VK_CULL_MODE_BACK_BIT:                     return "VK_CULL_MODE_BACK_BIT";
+               case VK_CULL_MODE_FRONT_AND_BACK:       return "VK_CULL_MODE_FRONT_AND_BACK";
+
+               default:
+                       DE_ASSERT(0);
+                       return std::string();
+       }
+}
+
+tcu::TestStatus NegativeViewportHeightTestInstance::iterate (void)
+{
+       // Check requirements
+
+       if (!de::contains(m_context.getDeviceExtensions().begin(), m_context.getDeviceExtensions().end(), std::string("VK_KHR_maintenance1")))
+               TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_maintenance1");
+
+       // Set up the viewport and draw
+
+       const VkViewport viewport =
+       {
+               0.0f,                                                   // float    x;
+               static_cast<float>(HEIGHT),             // float    y;
+               static_cast<float>(WIDTH),              // float    width;
+               -static_cast<float>(HEIGHT),    // float    height;
+               0.0f,                                                   // float    minDepth;
+               1.0f,                                                   // float    maxDepth;
+       };
+
+       const tcu::ConstPixelBufferAccess       resultImage     = draw(viewport);
+
+       // Verify the results
+
+       tcu::TestLog&                           log                             = m_context.getTestContext().getLog();
+       MovePtr<tcu::TextureLevel>      referenceImage  = generateReferenceImage();
+
+       log << tcu::TestLog::Message
+               << "Drawing two triangles with negative viewport height, which will cause a y-flip. This changes the sign of the triangle's area."
+               << tcu::TestLog::EndMessage;
+       log << tcu::TestLog::Message
+               << "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."
+               << " Front face is white, back face is gray."
+               << tcu::TestLog::EndMessage;
+       log << tcu::TestLog::Message
+               << "Front face: " << getFrontFaceName(m_params.frontFace) << "\n"
+               << "Cull mode: "  << getCullModeStr  (m_params.cullMode)  << "\n"
+               << tcu::TestLog::EndMessage;
+
+       if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
+               return tcu::TestStatus::fail("Rendered image is incorrect");
+       else
+               return tcu::TestStatus::pass("Pass");
+}
+
+class NegativeViewportHeightTest : public TestCase
+{
+public:
+       NegativeViewportHeightTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
+               : TestCase      (testCtx, name, description)
+               , m_params      (params)
+       {
+       }
+
+       void initPrograms (SourceCollections& programCollection) const
+       {
+               // Vertex shader
+               {
+                       std::ostringstream src;
+                       src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
+                               << "\n"
+                               << "layout(location = 0) in vec4 in_position;\n"
+                               << "\n"
+                               << "out gl_PerVertex {\n"
+                               << "    vec4  gl_Position;\n"
+                               << "};\n"
+                               << "\n"
+                               << "void main(void)\n"
+                               << "{\n"
+                               << "    gl_Position = in_position;\n"
+                               << "}\n";
+
+                       programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+               }
+
+               // Fragment shader
+               {
+                       std::ostringstream src;
+                       src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
+                               << "\n"
+                               << "layout(location = 0) out vec4 out_color;\n"
+                               << "\n"
+                               << "void main(void)\n"
+                               << "{\n"
+                               << "    if (gl_FrontFacing)\n"
+                               << "        out_color = vec4(1.0);\n"
+                               << "    else\n"
+                               << "        out_color = vec4(vec3(0.5), 1.0);\n"
+                               << "}\n";
+
+                       programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+               }
+       }
+
+       virtual TestInstance* createInstance (Context& context) const
+       {
+               return new NegativeViewportHeightTestInstance(context, m_params);
+       }
+
+private:
+       const TestParams        m_params;
+};
+
+void populateTestGroup (tcu::TestCaseGroup* testGroup)
+{
+       const struct
+       {
+               const char* const       name;
+               VkFrontFace                     frontFace;
+       } frontFace[] =
+       {
+               { "front_ccw",  VK_FRONT_FACE_COUNTER_CLOCKWISE },
+               { "front_cw",   VK_FRONT_FACE_CLOCKWISE                 },
+       };
+
+       const struct
+       {
+               const char* const       name;
+               VkCullModeFlagBits      cullMode;
+       } cullMode[] =
+       {
+               { "cull_none",  VK_CULL_MODE_NONE                       },
+               { "cull_front", VK_CULL_MODE_FRONT_BIT          },
+               { "cull_back",  VK_CULL_MODE_BACK_BIT           },
+               { "cull_both",  VK_CULL_MODE_FRONT_AND_BACK     },
+       };
+
+       for (int ndxFrontFace = 0; ndxFrontFace < DE_LENGTH_OF_ARRAY(frontFace); ++ndxFrontFace)
+       for (int ndxCullMode  = 0; ndxCullMode  < DE_LENGTH_OF_ARRAY(cullMode);  ++ndxCullMode)
+       {
+               const TestParams params =
+               {
+                       frontFace[ndxFrontFace].frontFace,
+                       cullMode[ndxCullMode].cullMode,
+               };
+               std::ostringstream      name;
+               name << frontFace[ndxFrontFace].name << "_" << cullMode[ndxCullMode].name;
+
+               testGroup->addChild(new NegativeViewportHeightTest(testGroup->getTestContext(), name.str(), "", params));
+       }
+}
+
+}      // anonymous
+
+tcu::TestCaseGroup*    createNegativeViewportHeightTests (tcu::TestContext& testCtx)
+{
+       return createTestGroup(testCtx, "negative_viewport_height", "Negative viewport height (VK_KHR_maintenance1)", populateTestGroup);
+}
+
+}      // Draw
+}      // vkt
diff --git a/external/vulkancts/modules/vulkan/draw/vktDrawNegativeViewportHeightTests.hpp b/external/vulkancts/modules/vulkan/draw/vktDrawNegativeViewportHeightTests.hpp
new file mode 100644 (file)
index 0000000..9f56b35
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _VKTDRAWNEGATIVEVIEWPORTHEIGHTTESTS_HPP
+#define _VKTDRAWNEGATIVEVIEWPORTHEIGHTTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Negative viewport height (part of VK_KHR_maintenance1)
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace Draw
+{
+
+tcu::TestCaseGroup*    createNegativeViewportHeightTests (tcu::TestContext& testCtx);
+
+}      // Draw
+}      // vkt
+
+#endif // _VKTDRAWNEGATIVEVIEWPORTHEIGHTTESTS_HPP
index 301698e..58094cf 100644 (file)
@@ -31,6 +31,7 @@
 #include "vktTestGroupUtil.hpp"
 #include "vktBasicDrawTests.hpp"
 #include "vktDrawShaderDrawParametersTests.hpp"
+#include "vktDrawNegativeViewportHeightTests.hpp"
 
 namespace vkt
 {
@@ -44,12 +45,13 @@ void createChildren (tcu::TestCaseGroup* group)
 {
        tcu::TestContext&       testCtx         = group->getTestContext();
 
-       group->addChild(new SimpleDrawTests                             (testCtx));
-       group->addChild(new DrawIndexedTests                    (testCtx));
-       group->addChild(new IndirectDrawTests                   (testCtx));
-       group->addChild(createBasicDrawTests                    (testCtx));
-       group->addChild(new InstancedTests                              (testCtx));
-       group->addChild(new ShaderDrawParametersTests   (testCtx));
+       group->addChild(new SimpleDrawTests                                     (testCtx));
+       group->addChild(new DrawIndexedTests                            (testCtx));
+       group->addChild(new IndirectDrawTests                           (testCtx));
+       group->addChild(createBasicDrawTests                            (testCtx));
+       group->addChild(new InstancedTests                                      (testCtx));
+       group->addChild(new ShaderDrawParametersTests           (testCtx));
+       group->addChild(createNegativeViewportHeightTests       (testCtx));
 }
 
 } // anonymous
index 77f4e43..8c8fbbd 100644 (file)
@@ -116838,6 +116838,14 @@ dEQP-VK.draw.shader_draw_parameters.draw_index.draw
 dEQP-VK.draw.shader_draw_parameters.draw_index.draw_instanced
 dEQP-VK.draw.shader_draw_parameters.draw_index.draw_indexed
 dEQP-VK.draw.shader_draw_parameters.draw_index.draw_indexed_instanced
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_none
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_front
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_back
+dEQP-VK.draw.negative_viewport_height.front_ccw_cull_both
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_none
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_front
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_back
+dEQP-VK.draw.negative_viewport_height.front_cw_cull_both
 dEQP-VK.compute.basic.empty_shader
 dEQP-VK.compute.basic.ubo_to_ssbo_single_invocation
 dEQP-VK.compute.basic.ubo_to_ssbo_single_group