| /*------------------------------------------------------------------------ |
| * 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 "vkQueryUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| |
| #include "tcuVector.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuTestLog.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; |
| bool zeroViewportHeight; |
| const SharedGroupParams groupParams; |
| }; |
| |
| class NegativeViewportHeightTestInstance : public TestInstance |
| { |
| public: |
| NegativeViewportHeightTestInstance (Context& context, const TestParams& params); |
| tcu::TestStatus iterate (void); |
| void preRenderCommands (VkCommandBuffer cmdBuffer, const VkClearValue& clearColor); |
| void draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport); |
| |
| MovePtr<tcu::TextureLevel> generateReferenceImage (void) const; |
| bool isCulled (const VkFrontFace triangleFace) const; |
| |
| #ifndef CTS_USES_VULKANSC |
| void beginSecondaryCmdBuffer (VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u); |
| #endif // CTS_USES_VULKANSC |
| |
| 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); |
| } |
| |
| 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(), m_context.getUniversalQueueFamilyIndex()); |
| |
| const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat); |
| m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo); |
| |
| // Render pass and framebuffer |
| if (!m_params.groupParams->useDynamicRendering) |
| { |
| 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); |
| |
| std::vector<VkImageView> colorAttachments { *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 = makeRect2D(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)); |
| |
| #ifndef CTS_USES_VULKANSC |
| vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo |
| { |
| vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, |
| DE_NULL, |
| 0u, |
| 1u, |
| &m_colorAttachmentFormat, |
| vk::VK_FORMAT_UNDEFINED, |
| vk::VK_FORMAT_UNDEFINED |
| }; |
| |
| if (m_params.groupParams->useDynamicRendering) |
| pipelineCreateInfo.pNext = &renderingCreateInfo; |
| #endif // CTS_USES_VULKANSC |
| |
| m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo); |
| } |
| |
| void NegativeViewportHeightTestInstance::preRenderCommands(VkCommandBuffer cmdBuffer, const VkClearValue& clearColor) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT); |
| |
| initialTransitionColor2DImage(vk, cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, |
| VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); |
| vk.cmdClearColorImage(cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 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); |
| } |
| |
| void NegativeViewportHeightTestInstance::draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkBuffer buffer = m_vertexBuffer->object(); |
| const VkDeviceSize offset = 0; |
| |
| if (m_params.zeroViewportHeight) |
| { |
| // Set zero viewport height |
| const VkViewport zeroViewportHeight |
| { |
| viewport.x, // float x; |
| viewport.y / 2.0f, // float y; |
| viewport.width, // float width; |
| 0.0f, // float height; |
| viewport.minDepth, // float minDepth; |
| viewport.maxDepth // float maxDepth; |
| }; |
| |
| vk.cmdSetViewport(cmdBuffer, 0u, 1u, &zeroViewportHeight); |
| } |
| else |
| vk.cmdSetViewport(cmdBuffer, 0u, 1u, &viewport); |
| |
| vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &buffer, &offset); |
| vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); |
| vk.cmdDraw(cmdBuffer, 6, 1, 0, 0); |
| } |
| |
| //! 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 blue (0.125f, 0.25f, 0.5f, 1.0f); |
| const Vec4 white (1.0f); |
| const Vec4 gray (0.5f, 0.5f, 0.5f, 1.0f); |
| |
| tcu::clear(access, blue); |
| |
| // Zero viewport height |
| if (m_params.zeroViewportHeight) |
| { |
| return image; |
| } |
| // Negative viewport height |
| else |
| { |
| 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; |
| } |
| } |
| |
| #ifndef CTS_USES_VULKANSC |
| void NegativeViewportHeightTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags) |
| { |
| VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| renderingFlags, // VkRenderingFlagsKHR flags; |
| 0u, // uint32_t viewMask; |
| 1u, // uint32_t colorAttachmentCount; |
| &m_colorAttachmentFormat, // const VkFormat* pColorAttachmentFormats; |
| VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat; |
| VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| }; |
| const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo); |
| |
| VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
| if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) |
| usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; |
| |
| const VkCommandBufferBeginInfo commandBufBeginParams |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| usageFlags, // VkCommandBufferUsageFlags flags; |
| &bufferInheritanceInfo |
| }; |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams)); |
| } |
| #endif // CTS_USES_VULKANSC |
| |
| 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) |
| { |
| // 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; |
| }; |
| VkRect2D rect = makeRect2D(0, 0, WIDTH, HEIGHT); |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| const VkClearValue clearColor = makeClearValueColorF32(0.125f, 0.25f, 0.5f, 1.0f); |
| const CmdPoolCreateInfo cmdPoolCreateInfo (queueFamilyIndex); |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo)); |
| const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| Move<VkCommandBuffer> secCmdBuffer; |
| |
| #ifndef CTS_USES_VULKANSC |
| if (m_params.groupParams->useSecondaryCmdBuffer) |
| { |
| secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| |
| // record secondary command buffer |
| if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) |
| { |
| beginSecondaryCmdBuffer(*secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT); |
| beginRendering(vk, *secCmdBuffer, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, 0u); |
| } |
| else |
| beginSecondaryCmdBuffer(*secCmdBuffer); |
| |
| draw(*secCmdBuffer, viewport); |
| |
| if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) |
| endRendering(vk, *secCmdBuffer); |
| |
| endCommandBuffer(vk, *secCmdBuffer); |
| |
| // record primary command buffer |
| beginCommandBuffer(vk, *cmdBuffer, 0u); |
| |
| preRenderCommands(*cmdBuffer, clearColor); |
| |
| if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) |
| beginRendering(vk, *cmdBuffer, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT); |
| |
| vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer); |
| |
| if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass) |
| endRendering(vk, *cmdBuffer); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| } |
| else if (m_params.groupParams->useDynamicRendering) |
| { |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| preRenderCommands(*cmdBuffer, clearColor); |
| beginRendering(vk, *cmdBuffer, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, 0u); |
| draw(*cmdBuffer, viewport); |
| endRendering(vk, *cmdBuffer); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| } |
| #endif // CTS_USES_VULKANSC |
| |
| if (!m_params.groupParams->useDynamicRendering) |
| { |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| preRenderCommands(*cmdBuffer, clearColor); |
| beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, rect); |
| draw(*cmdBuffer, viewport); |
| endRenderPass(vk, *cmdBuffer); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| } |
| |
| // Submit |
| submitCommandsAndWait(vk, device, queue, cmdBuffer.get()); |
| |
| // Get result |
| const VkOffset3D zeroOffset = { 0, 0, 0 }; |
| const tcu::ConstPixelBufferAccess resultImage = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT); |
| |
| // Verify the results |
| |
| tcu::TestLog& log = m_context.getTestContext().getLog(); |
| MovePtr<tcu::TextureLevel> referenceImage = generateReferenceImage(); |
| |
| // Zero viewport height |
| if (m_params.zeroViewportHeight) |
| { |
| log << tcu::TestLog::Message |
| << "Drawing two triangles with zero viewport height." |
| << tcu::TestLog::EndMessage; |
| log << tcu::TestLog::Message |
| << "Result image should be empty." |
| << tcu::TestLog::EndMessage; |
| } |
| // Negative viewport height |
| else |
| { |
| 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 void checkSupport (Context& context) const |
| { |
| if (m_params.groupParams->useDynamicRendering) |
| context.requireDeviceFunctionality("VK_KHR_dynamic_rendering"); |
| |
| context.requireDeviceFunctionality("VK_KHR_maintenance1"); |
| } |
| |
| virtual TestInstance* createInstance (Context& context) const |
| { |
| return new NegativeViewportHeightTestInstance(context, m_params); |
| } |
| |
| private: |
| const TestParams m_params; |
| }; |
| |
| struct SubGroupParams |
| { |
| bool zeroViewportHeight; |
| const SharedGroupParams groupParams; |
| }; |
| |
| void populateTestGroup (tcu::TestCaseGroup* testGroup, SubGroupParams subGroupParams) |
| { |
| 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, |
| subGroupParams.zeroViewportHeight, |
| subGroupParams.groupParams |
| }; |
| 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, const SharedGroupParams groupParams) |
| { |
| SubGroupParams subGroupParams { false, groupParams }; |
| return createTestGroup(testCtx, "negative_viewport_height", "Negative viewport height (VK_KHR_maintenance1)", populateTestGroup, subGroupParams); |
| } |
| |
| tcu::TestCaseGroup* createZeroViewportHeightTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams) |
| { |
| SubGroupParams subGroupParams{ false, groupParams }; |
| return createTestGroup(testCtx, "zero_viewport_height", "Zero viewport height (VK_KHR_maintenance1)", populateTestGroup, subGroupParams); |
| } |
| |
| } // Draw |
| } // vkt |