| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2019 Valve Corporation. |
| * Copyright (c) 2019 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 EXT_discard_rectangles tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktDrawDiscardRectanglesTests.hpp" |
| |
| #include "vkDefs.hpp" |
| #include "vkRef.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| #include "vktTestCase.hpp" |
| #include "vktDrawBufferObjectUtil.hpp" |
| #include "vktDrawImageObjectUtil.hpp" |
| |
| #include "tcuTestCase.hpp" |
| #include "tcuVector.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| |
| #include "deUniquePtr.hpp" |
| #include "deSharedPtr.hpp" |
| |
| namespace vkt |
| { |
| namespace Draw |
| { |
| |
| namespace |
| { |
| using namespace vk; |
| using de::UniquePtr; |
| using de::SharedPtr; |
| using de::MovePtr; |
| using tcu::Vec4; |
| using tcu::Vec2; |
| using tcu::UVec2; |
| using tcu::UVec4; |
| |
| enum TestMode |
| { |
| TEST_MODE_INCLUSIVE = 0, |
| TEST_MODE_EXCLUSIVE, |
| TEST_MODE_COUNT |
| }; |
| |
| enum TestScissorMode |
| { |
| TEST_SCISSOR_MODE_NONE = 0, |
| TEST_SCISSOR_MODE_STATIC, |
| TEST_SCISSOR_MODE_DYNAMIC, |
| TEST_SCISSOR_MODE_COUNT |
| }; |
| |
| #define NUM_RECT_TESTS 6 |
| #define NUM_DYNAMIC_DISCARD_TYPE_TESTS 2 |
| |
| struct TestParams |
| { |
| TestMode testMode; |
| deUint32 numRectangles; |
| deBool dynamicDiscardRectangles; |
| TestScissorMode scissorMode; |
| deBool useDynamicRendering; |
| }; |
| |
| template<typename T> |
| inline VkDeviceSize sizeInBytes(const std::vector<T>& vec) |
| { |
| return vec.size() * sizeof(vec[0]); |
| } |
| |
| VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const UVec2& size, VkImageUsageFlags usage) |
| { |
| const VkImageCreateInfo imageParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkImageCreateFlags)0, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| format, // VkFormat format; |
| makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // deUint32 queueFamilyIndexCount; |
| DE_NULL, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| return imageParams; |
| } |
| |
| VkPipelineDiscardRectangleStateCreateInfoEXT makeDiscardRectangleStateCreateInfo (const deBool dynamicDiscardRectangle, |
| const VkDiscardRectangleModeEXT discardRectangleMode, |
| const deUint32 discardRectangleCount, |
| const VkRect2D *pDiscardRectangles) |
| { |
| const VkPipelineDiscardRectangleStateCreateInfoEXT discardRectanglesCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDiscardRectangleStateCreateFlagsEXT flags; |
| discardRectangleMode, // VkDiscardRectangleModeEXT discardRectangleMode; |
| discardRectangleCount, // deUint32 discardRectangleCount; |
| dynamicDiscardRectangle ? DE_NULL : pDiscardRectangles // const VkRect2D* pDiscardRectangles; |
| }; |
| return discardRectanglesCreateInfo; |
| } |
| |
| Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkPipelineLayout pipelineLayout, |
| const VkRenderPass renderPass, |
| const VkShaderModule vertexModule, |
| const VkShaderModule fragmentModule, |
| const UVec2 renderSize, |
| const deBool dynamicDiscardRectangle, |
| const VkDiscardRectangleModeEXT discardRectangleMode, |
| const deUint32 discardRectangleCount, |
| const VkRect2D* pDiscardRectangles, |
| const TestScissorMode scissorMode, |
| const VkRect2D rectScissor) |
| { |
| const VkVertexInputBindingDescription vertexInputBindingDescription = |
| { |
| 0u, // uint32_t binding; |
| sizeof(Vec4), // uint32_t stride; |
| VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; |
| }; |
| |
| const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = |
| { |
| { |
| 0u, // uint32_t location; |
| 0u, // uint32_t binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u, // uint32_t offset; |
| }, |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; |
| 1u, // uint32_t vertexBindingDescriptionCount; |
| &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount; |
| vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; |
| }; |
| |
| const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology topology; |
| VK_FALSE, // VkBool32 primitiveRestartEnable; |
| }; |
| |
| |
| VkViewport viewport = makeViewport(0.0f, 0.0f, static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), 0.0f, 1.0f); |
| const VkRect2D rectScissorRenderSize = { { 0, 0 }, { renderSize.x(), renderSize.y() } }; |
| |
| const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags; |
| 1u, // uint32_t viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // uint32_t scissorCount; |
| scissorMode != TEST_SCISSOR_MODE_NONE ? &rectScissor : &rectScissorRenderSize, // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClampEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBiasConstantFactor; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float depthBiasSlopeFactor; |
| 1.0f, // float lineWidth; |
| }; |
| |
| const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE // VkBool32 alphaToOneEnable; |
| }; |
| |
| const VkStencilOpState stencilOpState = makeStencilOpState( |
| VK_STENCIL_OP_KEEP, // stencil fail |
| VK_STENCIL_OP_KEEP, // depth & stencil pass |
| VK_STENCIL_OP_KEEP, // depth only fail |
| VK_COMPARE_OP_ALWAYS, // compare op |
| 0u, // compare mask |
| 0u, // write mask |
| 0u); // reference |
| |
| VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthTestEnable; |
| VK_FALSE, // VkBool32 depthWriteEnable; |
| VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp; |
| VK_FALSE, // VkBool32 depthBoundsTestEnable; |
| VK_FALSE, // VkBool32 stencilTestEnable; |
| stencilOpState, // VkStencilOpState front; |
| stencilOpState, // VkStencilOpState back; |
| 0.0f, // float minDepthBounds; |
| 1.0f, // float maxDepthBounds; |
| }; |
| |
| const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = |
| { |
| VK_FALSE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; |
| colorComponentsAll, // VkColorComponentFlags colorWriteMask; |
| }; |
| |
| const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_COPY, // VkLogicOp logicOp; |
| 1u, // deUint32 attachmentCount; |
| &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; |
| { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; |
| }; |
| |
| const VkPipelineShaderStageCreateInfo pShaderStages[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; |
| vertexModule, // VkShaderModule module; |
| "main", // const char* pName; |
| DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; |
| }, |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; |
| fragmentModule, // VkShaderModule module; |
| "main", // const char* pName; |
| DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; |
| }, |
| }; |
| |
| const VkPipelineDiscardRectangleStateCreateInfoEXT discardRectangleStateCreateInfo = makeDiscardRectangleStateCreateInfo(dynamicDiscardRectangle, discardRectangleMode, discardRectangleCount, pDiscardRectangles); |
| |
| const VkDynamicState dynamicStateDiscardRectangles = VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT; |
| const VkDynamicState dynamicStateScissor = VK_DYNAMIC_STATE_SCISSOR; |
| std::vector<VkDynamicState> dynamicStates; |
| |
| if (dynamicDiscardRectangle) |
| dynamicStates.push_back(dynamicStateDiscardRectangles); |
| if (scissorMode == TEST_SCISSOR_MODE_DYNAMIC) |
| dynamicStates.push_back(dynamicStateScissor); |
| |
| const VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineDynamicStateCreateFlags flags; |
| (deUint32)dynamicStates.size(), // deUint32 dynamicStateCount; |
| dynamicStates.data() // const VkDynamicState* pDynamicStates; |
| }; |
| |
| VkGraphicsPipelineCreateInfo graphicsPipelineInfo = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| &discardRectangleStateCreateInfo, // const void* pNext; |
| (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; |
| 2u, // deUint32 stageCount; |
| pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; |
| &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| &pipelineDynamicStateCreateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| pipelineLayout, // VkPipelineLayout layout; |
| renderPass, // VkRenderPass renderPass; |
| 0u, // deUint32 subpass; |
| DE_NULL, // VkPipeline basePipelineHandle; |
| 0, // deInt32 basePipelineIndex; |
| }; |
| |
| VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, |
| &discardRectangleStateCreateInfo, |
| 0u, |
| 1u, |
| &colorAttachmentFormat, |
| VK_FORMAT_UNDEFINED, |
| VK_FORMAT_UNDEFINED |
| }; |
| |
| // when pipeline is created without render pass we are using dynamic rendering |
| if (renderPass == DE_NULL) |
| graphicsPipelineInfo.pNext = &renderingCreateInfo; |
| |
| return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo); |
| } |
| |
| void generateDiscardRectangles(const UVec2& renderSize, deUint32 numRect, std::vector<VkRect2D>& rectangles) |
| { |
| deUint32 cellHight = renderSize.y() - 10; |
| deUint32 cellWidth = (renderSize.x() - 10) / (2 * numRect - 1); |
| |
| DE_ASSERT(rectangles.size() == 0); |
| |
| for (deUint32 i = 0; i < numRect; i++) |
| { |
| VkRect2D rect; |
| rect.extent.height = cellHight; |
| rect.extent.width = cellWidth; |
| rect.offset.x = 5u + i * 2 * cellWidth; |
| rect.offset.y = 5u; |
| rectangles.push_back(rect); |
| } |
| } |
| |
| //! Renders a colorful grid of rectangles. |
| tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat format, |
| const UVec2& renderSize, |
| const TestMode testMode, |
| const Vec4& color, |
| const deUint32 numRectangles, |
| const std::vector<VkRect2D> rectangles, |
| const deBool enableScissor, |
| const VkRect2D scissor) |
| { |
| tcu::TextureLevel image(format, renderSize.x(), renderSize.y()); |
| const Vec4 rectColor = testMode == TEST_MODE_INCLUSIVE ? Vec4(0.0f, 1.0f, 0.0f, 1.0f) : color; |
| const Vec4 clearColor = testMode == TEST_MODE_INCLUSIVE ? color : Vec4(0.0f, 1.0f, 0.0f, 1.0f); |
| |
| if (!enableScissor) |
| { |
| // Clear the image with clearColor |
| tcu::clear(image.getAccess(), clearColor); |
| |
| // Now draw the discard rectangles taking into account the selected mode. |
| for (deUint32 i = 0; i < numRectangles; i++) |
| { |
| tcu::clear(tcu::getSubregion(image.getAccess(), rectangles[i].offset.x, rectangles[i].offset.y, |
| rectangles[i].extent.width, rectangles[i].extent.height), |
| rectColor); |
| } |
| } |
| else |
| { |
| // Clear the image with the original clear color |
| tcu::clear(image.getAccess(), color); |
| // Clear the scissor are with the clearColor which depends on the selected mode |
| tcu::clear(tcu::getSubregion(image.getAccess(), scissor.offset.x, scissor.offset.y, |
| scissor.extent.width, scissor.extent.height), |
| clearColor); |
| |
| // Now draw the discard rectangles taking into account both the scissor area and |
| // the selected mode. |
| for (deUint32 rect = 0; rect < numRectangles; rect++) |
| { |
| for (deUint32 x = rectangles[rect].offset.x; x < (rectangles[rect].offset.x + rectangles[rect].extent.width); x++) |
| { |
| for(deUint32 y = rectangles[rect].offset.y; y < (rectangles[rect].offset.y + rectangles[rect].extent.height); y++) |
| { |
| if ((x >= (deUint32)scissor.offset.x) && (x < (scissor.offset.x + scissor.extent.width)) && |
| (y >= (deUint32)scissor.offset.y) && (y < (scissor.offset.y + scissor.extent.height))) |
| { |
| image.getAccess().setPixel(rectColor, x, y); |
| } |
| } |
| } |
| } |
| } |
| return image; |
| } |
| |
| class DiscardRectanglesTestInstance : public TestInstance |
| { |
| public: |
| DiscardRectanglesTestInstance (Context& context, |
| TestParams params); |
| virtual ~DiscardRectanglesTestInstance (void) {} |
| virtual tcu::TestStatus iterate (void); |
| |
| private: |
| const TestParams m_params; |
| const Vec4 m_clearColor; |
| const UVec2 m_renderSize; |
| std::vector<Vec4> m_vertices; |
| std::vector<VkRect2D> m_rectangles; |
| |
| Move<VkImage> m_colorImage; |
| MovePtr<Allocation> m_colorImageAlloc; |
| Move<VkImageView> m_colorAttachment; |
| SharedPtr<Buffer> m_colorBuffer; |
| SharedPtr<Buffer> m_vertexBuffer; |
| Move<VkShaderModule> m_vertexModule; |
| Move<VkShaderModule> m_fragmentModule; |
| Move<VkRenderPass> m_renderPass; |
| Move<VkFramebuffer> m_framebuffer; |
| Move<VkPipelineLayout> m_pipelineLayout; |
| Move<VkPipeline> m_pipeline; |
| Move<VkCommandPool> m_cmdPool; |
| Move<VkCommandBuffer> m_cmdBuffer; |
| }; |
| |
| DiscardRectanglesTestInstance::DiscardRectanglesTestInstance (Context& context, |
| TestParams params) |
| : TestInstance (context) |
| , m_params (params) |
| , m_clearColor (Vec4(1.0f, 0.0f, 0.0f, 1.0f)) |
| , m_renderSize (UVec2(340, 100)) |
| { |
| } |
| |
| tcu::TestStatus DiscardRectanglesTestInstance::iterate (void) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const InstanceInterface& vki = m_context.getInstanceInterface(); |
| const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice(); |
| const VkDevice device = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| const VkDiscardRectangleModeEXT discardRectangleMode = m_params.testMode == TEST_MODE_EXCLUSIVE ? VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT : VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT; |
| const VkRect2D rectScissor = { { 90, 25 }, { 160, 50} }; |
| const VkImageSubresourceRange colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| const VkDeviceSize colorBufferSize = m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)); |
| |
| // Check for VK_EXT_discard_rectangles support and maximum number of active discard rectangles |
| { |
| VkPhysicalDeviceDiscardRectanglePropertiesEXT discardRectangleProperties; |
| deMemset(&discardRectangleProperties, 0, sizeof(VkPhysicalDeviceDiscardRectanglePropertiesEXT)); |
| discardRectangleProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT; |
| |
| VkPhysicalDeviceProperties2 physicalDeviceProperties; |
| physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; |
| physicalDeviceProperties.pNext = &discardRectangleProperties; |
| |
| vki.getPhysicalDeviceProperties2(physicalDevice, &physicalDeviceProperties); |
| |
| if (discardRectangleProperties.maxDiscardRectangles == 0) |
| { |
| throw tcu::NotSupportedError("Implementation doesn't support discard rectangles"); |
| } |
| |
| if (discardRectangleProperties.maxDiscardRectangles < 4) |
| { |
| std::ostringstream message; |
| message << "Implementation doesn't support the minimum value for maxDiscardRectangles: " << discardRectangleProperties.maxDiscardRectangles << " < 4"; |
| return tcu::TestStatus::fail(message.str()); |
| } |
| |
| if (discardRectangleProperties.maxDiscardRectangles < m_params.numRectangles) |
| { |
| std::ostringstream message; |
| message << "Implementation doesn't support the required number of discard rectangles: " << discardRectangleProperties.maxDiscardRectangles << " < " << m_params.numRectangles; |
| throw tcu::NotSupportedError(message.str()); |
| } |
| } |
| |
| // Color attachment |
| { |
| m_colorImage = makeImage(vk, device, makeImageCreateInfo(colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)); |
| m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any); |
| m_colorBuffer = Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible); |
| m_colorAttachment = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange); |
| |
| // Zero colorBuffer. |
| const Allocation alloc = m_colorBuffer->getBoundMemory(); |
| deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize)); |
| flushAlloc(vk, device, alloc); |
| } |
| |
| // Initialize the pipeline and other variables |
| { |
| // Draw a quad covering the whole framebuffer |
| m_vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); |
| m_vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f)); |
| m_vertices.push_back(Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); |
| m_vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f)); |
| VkDeviceSize vertexBufferSize = sizeInBytes(m_vertices); |
| m_vertexBuffer = Buffer::createAndAlloc (vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator, MemoryRequirement::HostVisible); |
| |
| |
| deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), m_vertices.data(), static_cast<std::size_t>(vertexBufferSize)); |
| flushAlloc(vk, device, m_vertexBuffer->getBoundMemory()); |
| |
| m_vertexModule = createShaderModule (vk, device, m_context.getBinaryCollection().get("vert"), 0u); |
| m_fragmentModule = createShaderModule (vk, device, m_context.getBinaryCollection().get("frag"), 0u); |
| |
| if (!m_params.useDynamicRendering) |
| { |
| m_renderPass = makeRenderPass (vk, device, colorFormat); |
| m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, m_colorAttachment.get(), |
| static_cast<deUint32>(m_renderSize.x()), |
| static_cast<deUint32>(m_renderSize.y())); |
| } |
| |
| m_pipelineLayout = makePipelineLayout (vk, device); |
| |
| generateDiscardRectangles(m_renderSize, m_params.numRectangles, m_rectangles); |
| m_pipeline = makeGraphicsPipeline (vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule, m_renderSize, |
| m_params.dynamicDiscardRectangles, discardRectangleMode, m_params.numRectangles, |
| m_rectangles.data(), m_params.scissorMode, rectScissor); |
| m_cmdPool = createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); |
| m_cmdBuffer = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| } |
| |
| // Write command buffer and submit it |
| { |
| beginCommandBuffer(vk, *m_cmdBuffer); |
| |
| const VkClearValue clearValue = makeClearValueColor(m_clearColor); |
| const VkRect2D renderArea = |
| { |
| makeOffset2D(0, 0), |
| makeExtent2D(m_renderSize.x(), m_renderSize.y()), |
| }; |
| |
| if (m_params.useDynamicRendering) |
| { |
| initialTransitionColor2DImage(vk, *m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); |
| beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR); |
| } |
| else |
| { |
| const VkRenderPassBeginInfo renderPassBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *m_renderPass, // VkRenderPass renderPass; |
| *m_framebuffer, // VkFramebuffer framebuffer; |
| renderArea, // VkRect2D renderArea; |
| 1u, // uint32_t clearValueCount; |
| &clearValue, // const VkClearValue* pClearValues; |
| }; |
| vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| } |
| |
| vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); |
| { |
| const VkBuffer vertexBuffer = m_vertexBuffer->object(); |
| const VkDeviceSize vertexBufferOffset = 0ull; |
| vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset); |
| } |
| if (m_params.dynamicDiscardRectangles) |
| { |
| vk.cmdSetDiscardRectangleEXT(*m_cmdBuffer, 0u, m_params.numRectangles, m_rectangles.data()); |
| } |
| if (m_params.scissorMode == TEST_SCISSOR_MODE_DYNAMIC) |
| { |
| vk.cmdSetScissor(*m_cmdBuffer, 0u, 1u, &rectScissor); |
| } |
| vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u); // two triangles |
| |
| if (m_params.useDynamicRendering) |
| vk.cmdEndRendering(*m_cmdBuffer); |
| else |
| vk.cmdEndRenderPass(*m_cmdBuffer); |
| |
| copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, m_colorBuffer->object(), tcu::IVec2(m_renderSize.x(), m_renderSize.y()), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colorSubresourceRange.layerCount); |
| |
| VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); |
| submitCommandsAndWait(vk, device, queue, *m_cmdBuffer); |
| } |
| |
| // Verify results |
| { |
| const Allocation alloc = m_colorBuffer->getBoundMemory(); |
| invalidateAlloc(vk, device, alloc); |
| |
| const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(colorFormat), m_renderSize.x(), m_renderSize.y(), 1u, alloc.getHostPtr()); |
| const tcu::TextureLevel referenceImage = generateReferenceImage(mapVkFormat(colorFormat), m_renderSize, m_params.testMode, m_clearColor, |
| m_params.numRectangles, m_rectangles, m_params.scissorMode != TEST_SCISSOR_MODE_NONE, rectScissor); |
| if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT)) |
| TCU_FAIL("Rendered image is not correct"); |
| } |
| return tcu::TestStatus::pass("OK"); |
| } |
| |
| class DiscardRectanglesTestCase : public TestCase |
| { |
| public: |
| DiscardRectanglesTestCase (tcu::TestContext &context, |
| const char *name, |
| const char *description, |
| TestParams params); |
| virtual ~DiscardRectanglesTestCase (void) {} |
| |
| virtual TestInstance* createInstance (Context& context) const; |
| virtual void initPrograms (SourceCollections& programCollection) const; |
| virtual void checkSupport (Context& context) const; |
| |
| private: |
| const TestParams m_params; |
| }; |
| |
| DiscardRectanglesTestCase::DiscardRectanglesTestCase (tcu::TestContext &context, |
| const char *name, |
| const char *description, |
| TestParams params) |
| : TestCase (context, name, description) |
| , m_params (params) |
| { |
| } |
| |
| void DiscardRectanglesTestCase::initPrograms(SourceCollections& programCollection) const |
| { |
| // Vertex |
| { |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" |
| << "\n" |
| << "layout(location = 0) in highp vec4 position;\n" |
| << "layout(location = 0) out highp vec4 vsColor;\n" |
| << "\n" |
| << "out gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << "};\n" |
| << "\n" |
| << "void main (void)\n" |
| << "{\n" |
| << " gl_Position = position;\n" |
| << " vsColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n" |
| << "}\n"; |
| programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); |
| } |
| |
| // Fragment |
| { |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" |
| << "\n" |
| << "layout(location = 0) in highp vec4 vsColor;\n" |
| << "layout(location = 0) out highp vec4 fsColor;\n" |
| << "\n" |
| << "void main (void)\n" |
| << "{\n" |
| << " fsColor = vsColor;\n" |
| << "}\n"; |
| programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); |
| } |
| } |
| |
| void DiscardRectanglesTestCase::checkSupport (Context& context) const |
| { |
| context.requireDeviceFunctionality("VK_EXT_discard_rectangles"); |
| if (m_params.useDynamicRendering) |
| context.requireDeviceFunctionality("VK_KHR_dynamic_rendering"); |
| } |
| |
| TestInstance* DiscardRectanglesTestCase::createInstance (Context& context) const |
| { |
| return new DiscardRectanglesTestInstance(context, m_params); |
| } |
| |
| void createTests (tcu::TestCaseGroup* testGroup, bool useDynamicRendering) |
| { |
| tcu::TestContext& testCtx = testGroup->getTestContext(); |
| deUint32 numRect [NUM_RECT_TESTS] = { 1, 2, 3, 4, 8, 16}; |
| std::string modeName [TEST_MODE_COUNT] = { "inclusive_", "exclusive_" }; |
| std::string scissorName [TEST_SCISSOR_MODE_COUNT] = { "", "scissor_", "dynamic_scissor_" }; |
| std::string dynamicName [NUM_DYNAMIC_DISCARD_TYPE_TESTS] = { "", "dynamic_discard_" }; |
| |
| for (deUint32 dynamic = 0 ; dynamic < NUM_DYNAMIC_DISCARD_TYPE_TESTS; dynamic++) |
| { |
| for (deUint32 scissor = 0 ; scissor < TEST_SCISSOR_MODE_COUNT; scissor++) |
| { |
| for (deUint32 mode = 0; mode < TEST_MODE_COUNT; mode++) |
| { |
| for (deUint32 rect = 0; rect < NUM_RECT_TESTS; rect++) |
| { |
| std::ostringstream name; |
| TestParams params; |
| |
| params.testMode = (TestMode) mode; |
| params.dynamicDiscardRectangles = dynamic ? DE_TRUE : DE_FALSE; |
| params.scissorMode = (TestScissorMode) scissor; |
| params.numRectangles = numRect[rect]; |
| params.useDynamicRendering = useDynamicRendering; |
| name << dynamicName[dynamic] << scissorName[scissor] << modeName[mode] << "rect_" << numRect[rect]; |
| |
| testGroup->addChild(new DiscardRectanglesTestCase(testCtx, name.str().c_str(), "", params)); |
| } |
| } |
| } |
| } |
| } |
| } // Anonymous |
| |
| tcu::TestCaseGroup* createDiscardRectanglesTests (tcu::TestContext& testCtx, bool useDynamicRendering) |
| { |
| return createTestGroup(testCtx, "discard_rectangles", "Discard Rectangles tests", createTests, useDynamicRendering); |
| } |
| |
| } // Draw |
| } //vkt |