From 5f04f70275d07063bdabd36cfa807541d1f611bd Mon Sep 17 00:00:00 2001 From: Peter Siket Date: Wed, 18 May 2016 13:31:42 +0200 Subject: [PATCH] OpenGL rasterization tests are ported. --- external/vulkancts/modules/vulkan/CMakeLists.txt | 3 + .../modules/vulkan/rasterization/CMakeLists.txt | 15 + .../vulkan/rasterization/vktRasterizationTests.cpp | 2931 ++++++++++++++++++++ .../vulkan/rasterization/vktRasterizationTests.hpp | 41 + .../vulkancts/modules/vulkan/vktTestPackage.cpp | 2 + framework/common/CMakeLists.txt | 2 + .../common/tcuRasterizationVerifier.cpp | 86 +- .../common/tcuRasterizationVerifier.hpp | 49 +- .../gles2/functional/es2fRasterizationTests.cpp | 16 +- .../gles3/functional/es3fRasterizationTests.cpp | 16 +- .../functional/es31fTextureMultisampleTests.cpp | 9 +- modules/glshared/CMakeLists.txt | 2 - 12 files changed, 3123 insertions(+), 49 deletions(-) create mode 100644 external/vulkancts/modules/vulkan/rasterization/CMakeLists.txt create mode 100644 external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp create mode 100644 external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.hpp rename modules/glshared/glsRasterizationTestUtil.cpp => framework/common/tcuRasterizationVerifier.cpp (98%) rename modules/glshared/glsRasterizationTestUtil.hpp => framework/common/tcuRasterizationVerifier.hpp (78%) diff --git a/external/vulkancts/modules/vulkan/CMakeLists.txt b/external/vulkancts/modules/vulkan/CMakeLists.txt index 4a5b5db..630828c 100644 --- a/external/vulkancts/modules/vulkan/CMakeLists.txt +++ b/external/vulkancts/modules/vulkan/CMakeLists.txt @@ -17,6 +17,7 @@ add_subdirectory(image) add_subdirectory(wsi) add_subdirectory(sparse_resources) add_subdirectory(tessellation) +add_subdirectory(rasterization) include_directories( api @@ -36,6 +37,7 @@ include_directories( wsi sparse_resources tessellation + rasterization ) set(DEQP_VK_COMMON_SRCS @@ -78,6 +80,7 @@ set(DEQP_VK_COMMON_LIBS deqp-vk-wsi deqp-vk-sparse-resources deqp-vk-tessellation + deqp-vk-rasterization ) add_library(deqp-vk-common STATIC ${DEQP_VK_COMMON_SRCS}) diff --git a/external/vulkancts/modules/vulkan/rasterization/CMakeLists.txt b/external/vulkancts/modules/vulkan/rasterization/CMakeLists.txt new file mode 100644 index 0000000..f6a0302 --- /dev/null +++ b/external/vulkancts/modules/vulkan/rasterization/CMakeLists.txt @@ -0,0 +1,15 @@ +include_directories(..) + +set(DEQP_VK_RASTERIZATION_SRCS + vktRasterizationTests.cpp + vktRasterizationTests.hpp + ) + +set(DEQP_VK_RASTERIZATION_LIBS + deqp-vk-common + tcutil + vkutil + ) + +add_library(deqp-vk-rasterization STATIC ${DEQP_VK_RASTERIZATION_SRCS}) +target_link_libraries(deqp-vk-rasterization ${DEQP_VK_RASTERIZATION_LIBS}) diff --git a/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp b/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp new file mode 100644 index 0000000..3792b36 --- /dev/null +++ b/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp @@ -0,0 +1,2931 @@ +/*------------------------------------------------------------------------ + * Vulkan Conformance Tests + * ------------------------ + * + * Copyright (c) 2016 The Khronos Group Inc. + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2014 The Android Open Source Project + * + * 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 Functional rasterization tests. + *//*--------------------------------------------------------------------*/ + +#include "vktRasterizationTests.hpp" +#include "tcuRasterizationVerifier.hpp" +#include "tcuSurface.hpp" +#include "tcuRenderTarget.hpp" +#include "tcuVectorUtil.hpp" +#include "tcuStringTemplate.hpp" +#include "tcuTextureUtil.hpp" +#include "tcuResultCollector.hpp" +#include "vkImageUtil.hpp" +#include "deStringUtil.hpp" +#include "deRandom.hpp" +#include "vktTestCase.hpp" +#include "vktTestCaseUtil.hpp" +#include "vktTestGroupUtil.hpp" +#include "vkPrograms.hpp" +#include "vkMemUtil.hpp" +#include "vkRefUtil.hpp" +#include "vkQueryUtil.hpp" +#include "vkBuilderUtil.hpp" +#include "vkTypeUtil.hpp" + +#include + +using namespace vk; + +namespace vkt +{ +namespace rasterization +{ +namespace +{ + +using tcu::RasterizationArguments; +using tcu::TriangleSceneSpec; +using tcu::PointSceneSpec; +using tcu::LineSceneSpec; +using tcu::LineInterpolationMethod; + +static const char* const s_shaderVertexTemplate = "#version 310 es\n" + "layout(location = 0) in highp vec4 a_position;\n" + "layout(location = 1) in highp vec4 a_color;\n" + "layout(location = 0) ${INTERPOLATION}out highp vec4 v_color;\n" + "layout (set=0, binding=0) uniform PointSize {\n" + " highp float u_pointSize;\n" + "};\n" + "void main ()\n" + "{\n" + " gl_Position = a_position;\n" + " gl_PointSize = u_pointSize;\n" + " v_color = a_color;\n" + "}\n"; + +static const char* const s_shaderFragmentTemplate = "#version 310 es\n" + "layout(location = 0) out highp vec4 fragColor;\n" + "layout(location = 0) ${INTERPOLATION}in highp vec4 v_color;\n" + "void main ()\n" + "{\n" + " fragColor = v_color;\n" + "}\n"; +enum InterpolationCaseFlags +{ + INTERPOLATIONFLAGS_NONE = 0, + INTERPOLATIONFLAGS_PROJECTED = (1 << 1), + INTERPOLATIONFLAGS_FLATSHADE = (1 << 2), +}; + +enum PrimitiveWideness +{ + PRIMITIVEWIDENESS_NARROW = 0, + PRIMITIVEWIDENESS_WIDE, + + PRIMITIVEWIDENESS_LAST +}; + +class BaseRenderingTestCase : public TestCase +{ +public: + BaseRenderingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deBool flatshade = DE_FALSE); + virtual ~BaseRenderingTestCase (void); + + virtual void initPrograms (vk::SourceCollections& programCollection) const; + +protected: + const VkSampleCountFlagBits m_sampleCount; + const deBool m_flatshade; +}; + +BaseRenderingTestCase::BaseRenderingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount, deBool flatshade) + : TestCase(context, name, description) + , m_sampleCount (sampleCount) + , m_flatshade (flatshade) +{ +} + +void BaseRenderingTestCase::initPrograms (vk::SourceCollections& programCollection) const +{ + tcu::StringTemplate vertexSource (s_shaderVertexTemplate); + tcu::StringTemplate fragmentSource (s_shaderFragmentTemplate); + std::map params; + + params["INTERPOLATION"] = (m_flatshade) ? ("flat ") : (""); + + programCollection.glslSources.add("vertext_shader") << glu::VertexSource(vertexSource.specialize(params)); + programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fragmentSource.specialize(params)); +} + +BaseRenderingTestCase::~BaseRenderingTestCase (void) +{ +} + +class BaseRenderingTestInstance : public TestInstance +{ +public: + enum { + DEFAULT_RENDER_SIZE = 256 + }; + + BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deUint32 renderSize = DEFAULT_RENDER_SIZE); + ~BaseRenderingTestInstance (void); + +protected: + void addImageTransitionBarrier (VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const; + void drawPrimitives (tcu::Surface& result, const std::vector& vertexData, VkPrimitiveTopology primitiveTopology); + void drawPrimitives (tcu::Surface& result, const std::vector& vertexData, const std::vector& coloDrata, VkPrimitiveTopology primitiveTopology); + virtual float getLineWidth (void) const; + virtual float getPointSize (void) const; + + virtual + const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const; + + virtual + const VkPipelineColorBlendStateCreateInfo* getColorBlendStateCreateInfo (void) const; + + const tcu::TextureFormat& getTextureFormat (void) const; + + const deUint32 m_renderSize; + const VkSampleCountFlagBits m_sampleCount; + const deUint32 m_subpixelBits; + const deBool m_multisampling; + + const VkFormat m_imageFormat; + const tcu::TextureFormat m_textureFormat; + Move m_commandPool; + + Move m_image; + de::MovePtr m_imageMemory; + Move m_imageView; + + Move m_resolvedImage; + de::MovePtr m_resolvedImageMemory; + Move m_resolvedImageView; + + Move m_renderPass; + Move m_frameBuffer; + + Move m_descriptorPool; + Move m_descriptorSet; + Move m_descriptorSetLayout; + + Move m_uniformBuffer; + de::MovePtr m_uniformBufferMemory; + const VkDeviceSize m_uniformBufferSize; + + Move m_pipelineLayout; + + Move m_vertexShaderModule; + Move m_fragmentShaderModule; + + Move m_fence; + + Move m_resultBuffer; + de::MovePtr m_resultBufferMemory; + const VkDeviceSize m_resultBufferSize; + +}; + +BaseRenderingTestInstance::BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount, deUint32 renderSize) + : TestInstance (context) + , m_renderSize (renderSize) + , m_sampleCount (sampleCount) + , m_subpixelBits (context.getDeviceProperties().limits.subPixelPrecisionBits) + , m_multisampling (m_sampleCount != VK_SAMPLE_COUNT_1_BIT) + , m_imageFormat (VK_FORMAT_R8G8B8A8_UNORM) + , m_textureFormat (vk::mapVkFormat(m_imageFormat)) + , m_uniformBufferSize (sizeof(float)) + , m_resultBufferSize (renderSize * renderSize * m_textureFormat.getPixelSize()) +{ + const DeviceInterface& vkd = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); + Allocator& allocator = m_context.getDefaultAllocator(); + DescriptorPoolBuilder descriptorPoolBuilder; + DescriptorSetLayoutBuilder descriptorSetLayoutBuilder; + + // Command Pool + { + const VkCommandPoolCreateInfo cmdPoolCreateInfo = + { + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, // VkCommandPoolCreateFlags flags; + queueFamilyIndex // deUint32 queueFamilyIndex; + }; + + m_commandPool = createCommandPool(vkd, vkDevice, &cmdPoolCreateInfo, DE_NULL); + } + + // Image + { + const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + VkImageFormatProperties properties; + + if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(), + m_imageFormat, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TILING_OPTIMAL, + imageUsage, + 0, + &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED)) + { + TCU_THROW(NotSupportedError, "Format not supported"); + } + + if ((properties.sampleCounts & m_sampleCount) != m_sampleCount) + { + TCU_THROW(NotSupportedError, "Format not supported"); + } + + const VkImageCreateInfo imageCreateInfo = + { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageCreateFlags flags; + VK_IMAGE_TYPE_2D, // VkImageType imageType; + m_imageFormat, // VkFormat format; + { m_renderSize, m_renderSize, 1u }, // VkExtent3D extent; + 1u, // deUint32 mipLevels; + 1u, // deUint32 arrayLayers; + m_sampleCount, // VkSampleCountFlagBits samples; + VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; + imageUsage, // VkImageUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyIndexCount; + &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; + VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; + }; + + m_image = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL); + + m_imageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_image), MemoryRequirement::Any); + VK_CHECK(vkd.bindImageMemory(vkDevice, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset())); + } + + // Image View + { + const VkImageViewCreateInfo imageViewCreateInfo = + { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageViewCreateFlags flags; + *m_image, // VkImage image; + VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; + m_imageFormat, // VkFormat format; + getFormatComponentMapping(m_imageFormat), // VkComponentMapping components; + { + VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; + 0u, // deUint32 baseMipLevel; + 1u, // deUint32 mipLevels; + 0u, // deUint32 baseArrayLayer; + 1u, // deUint32 arraySize; + }, // VkImageSubresourceRange subresourceRange; + }; + + m_imageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL); + } + + if (m_multisampling) + { + { + // Resolved Image + const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + VkImageFormatProperties properties; + + if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(), + m_imageFormat, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TILING_OPTIMAL, + imageUsage, + 0, + &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED)) + { + TCU_THROW(NotSupportedError, "Format not supported"); + } + + const VkImageCreateInfo imageCreateInfo = + { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageCreateFlags flags; + VK_IMAGE_TYPE_2D, // VkImageType imageType; + m_imageFormat, // VkFormat format; + { m_renderSize, m_renderSize, 1u }, // VkExtent3D extent; + 1u, // deUint32 mipLevels; + 1u, // deUint32 arrayLayers; + VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; + VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; + imageUsage, // VkImageUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyIndexCount; + &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; + VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; + }; + + m_resolvedImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL); + m_resolvedImageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_resolvedImage), MemoryRequirement::Any); + VK_CHECK(vkd.bindImageMemory(vkDevice, *m_resolvedImage, m_resolvedImageMemory->getMemory(), m_resolvedImageMemory->getOffset())); + } + + // Resolved Image View + { + const VkImageViewCreateInfo imageViewCreateInfo = + { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkImageViewCreateFlags flags; + *m_resolvedImage, // VkImage image; + VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; + m_imageFormat, // VkFormat format; + getFormatComponentMapping(m_imageFormat), // VkComponentMapping components; + { + VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; + 0u, // deUint32 baseMipLevel; + 1u, // deUint32 mipLevels; + 0u, // deUint32 baseArrayLayer; + 1u, // deUint32 arraySize; + }, // VkImageSubresourceRange subresourceRange; + }; + + m_resolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL); + } + + } + + // Render Pass + { + const VkImageLayout imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + const VkAttachmentDescription attachmentDesc[] = + { + { + 0u, // VkAttachmentDescriptionFlags flags; + m_imageFormat, // VkFormat format; + m_sampleCount, // VkSampleCountFlagBits samples; + VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; + VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; + VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; + VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; + imageLayout, // VkImageLayout initialLayout; + imageLayout, // VkImageLayout finalLayout; + }, + { + 0u, // VkAttachmentDescriptionFlags flags; + m_imageFormat, // VkFormat format; + VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; + VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; + VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; + VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; + VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; + imageLayout, // VkImageLayout initialLayout; + imageLayout, // VkImageLayout finalLayout; + } + }; + + const VkAttachmentReference attachmentRef = + { + 0u, // deUint32 attachment; + imageLayout, // VkImageLayout layout; + }; + + const VkAttachmentReference resolveAttachmentRef = + { + 1u, // deUint32 attachment; + imageLayout, // VkImageLayout layout; + }; + + const VkSubpassDescription subpassDesc = + { + 0u, // VkSubpassDescriptionFlags flags; + VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; + 0u, // deUint32 inputAttachmentCount; + DE_NULL, // const VkAttachmentReference* pInputAttachments; + 1u, // deUint32 colorAttachmentCount; + &attachmentRef, // const VkAttachmentReference* pColorAttachments; + m_multisampling ? &resolveAttachmentRef : DE_NULL, // const VkAttachmentReference* pResolveAttachments; + DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; + 0u, // deUint32 preserveAttachmentCount; + DE_NULL, // const VkAttachmentReference* pPreserveAttachments; + }; + + const VkRenderPassCreateInfo renderPassCreateInfo = + { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkRenderPassCreateFlags flags; + m_multisampling ? 2u : 1u, // deUint32 attachmentCount; + attachmentDesc, // const VkAttachmentDescription* pAttachments; + 1u, // deUint32 subpassCount; + &subpassDesc, // const VkSubpassDescription* pSubpasses; + 0u, // deUint32 dependencyCount; + DE_NULL, // const VkSubpassDependency* pDependencies; + }; + + m_renderPass = createRenderPass(vkd, vkDevice, &renderPassCreateInfo, DE_NULL); + } + + // FrameBuffer + { + const VkImageView attachments[] = + { + *m_imageView, + *m_resolvedImageView + }; + + const VkFramebufferCreateInfo framebufferCreateInfo = + { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkFramebufferCreateFlags flags; + *m_renderPass, // VkRenderPass renderPass; + m_multisampling ? 2u : 1u, // deUint32 attachmentCount; + attachments, // const VkImageView* pAttachments; + m_renderSize, // deUint32 width; + m_renderSize, // deUint32 height; + 1u, // deUint32 layers; + }; + + m_frameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL); + } + + // Uniform Buffer + { + const VkBufferCreateInfo bufferCreateInfo = + { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkBufferCreateFlags flags; + m_uniformBufferSize, // VkDeviceSize size; + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyIndexCount; + &queueFamilyIndex // const deUint32* pQueueFamilyIndices; + }; + + m_uniformBuffer = createBuffer(vkd, vkDevice, &bufferCreateInfo); + m_uniformBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_uniformBuffer), MemoryRequirement::HostVisible); + + VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_uniformBuffer, m_uniformBufferMemory->getMemory(), m_uniformBufferMemory->getOffset())); + } + + // Descriptors + { + descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + m_descriptorPool = descriptorPoolBuilder.build(vkd, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); + + descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL); + m_descriptorSetLayout = descriptorSetLayoutBuilder.build(vkd, vkDevice); + + const VkDescriptorSetAllocateInfo descriptorSetParams = + { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + DE_NULL, + *m_descriptorPool, + 1u, + &m_descriptorSetLayout.get(), + }; + + m_descriptorSet = allocateDescriptorSet(vkd, vkDevice, &descriptorSetParams); + + const VkDescriptorBufferInfo descriptorBufferInfo = + { + *m_uniformBuffer, // VkBuffer buffer; + 0u, // VkDeviceSize offset; + VK_WHOLE_SIZE // VkDeviceSize range; + }; + + const VkWriteDescriptorSet writeDescritporSet = + { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType; + DE_NULL, // const void* pNext; + *m_descriptorSet, // VkDescriptorSet destSet; + 0, // deUint32 destBinding; + 0, // deUint32 destArrayElement; + 1u, // deUint32 count; + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType descriptorType; + DE_NULL, // const VkDescriptorImageInfo* pImageInfo; + &descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo; + DE_NULL // const VkBufferView* pTexelBufferView; + }; + + vkd.updateDescriptorSets(vkDevice, 1u, &writeDescritporSet, 0u, DE_NULL); + } + + // Pipeline Layout + { + const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineLayoutCreateFlags flags; + 1u, // deUint32 descriptorSetCount; + &m_descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts; + 0u, // deUint32 pushConstantRangeCount; + DE_NULL // const VkPushConstantRange* pPushConstantRanges; + }; + + m_pipelineLayout = createPipelineLayout(vkd, vkDevice, &pipelineLayoutCreateInfo); + } + + // Shaders + { + m_vertexShaderModule = createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("vertext_shader"), 0); + m_fragmentShaderModule = createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("fragment_shader"), 0); + } + + // Fence + { + const VkFenceCreateInfo fenceParams = + { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + VK_FENCE_CREATE_SIGNALED_BIT // VkFenceCreateFlags flags; + }; + + m_fence = createFence(vkd, vkDevice, &fenceParams); + } + + // Result Buffer + { + const VkBufferCreateInfo bufferCreateInfo = + { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkBufferCreateFlags flags; + m_resultBufferSize, // VkDeviceSize size; + VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyIndexCount; + &queueFamilyIndex // const deUint32* pQueueFamilyIndices; + }; + + m_resultBuffer = createBuffer(vkd, vkDevice, &bufferCreateInfo); + m_resultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_resultBuffer), MemoryRequirement::HostVisible); + + VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_resultBuffer, m_resultBufferMemory->getMemory(), m_resultBufferMemory->getOffset())); + } + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Sample count = " << getSampleCountFlagsStr(m_sampleCount) << tcu::TestLog::EndMessage; + m_context.getTestContext().getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage; +} + +BaseRenderingTestInstance::~BaseRenderingTestInstance (void) +{ +} + + +void BaseRenderingTestInstance::addImageTransitionBarrier(VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const +{ + + const DeviceInterface& vkd = m_context.getDeviceInterface(); + + const VkImageSubresourceRange subResourcerange = + { + VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; + 0, // deUint32 baseMipLevel; + 1, // deUint32 levelCount; + 0, // deUint32 baseArrayLayer; + 1 // deUint32 layerCount; + }; + + const VkImageMemoryBarrier imageBarrier = + { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; + DE_NULL, // const void* pNext; + srcAccessMask, // VkAccessFlags srcAccessMask; + dstAccessMask, // VkAccessFlags dstAccessMask; + oldLayout, // VkImageLayout oldLayout; + newLayout, // VkImageLayout newLayout; + VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; + VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex; + image, // VkImage image; + subResourcerange // VkImageSubresourceRange subresourceRange; + }; + + vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &imageBarrier); +} + +void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector& vertexData, VkPrimitiveTopology primitiveTopology) +{ + // default to color white + const std::vector colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + + drawPrimitives(result, vertexData, colorData, primitiveTopology); +} + +void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector& positionData, const std::vector& colorData, VkPrimitiveTopology primitiveTopology) +{ + const DeviceInterface& vkd = m_context.getDeviceInterface(); + const VkDevice vkDevice = m_context.getDevice(); + const VkQueue queue = m_context.getUniversalQueue(); + const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); + Allocator& allocator = m_context.getDefaultAllocator(); + const size_t attributeBatchSize = positionData.size() * sizeof(tcu::Vec4); + + Move commandBuffer; + Move graphicsPipeline; + Move vertexBuffer; + de::MovePtr vertexBufferMemory; + + // Create Graphics Pipeline + { + const VkPipelineShaderStageCreateInfo shaderStageParams[2] = + { + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineShaderStageCreateFlags flags; + VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStage stage; + *m_vertexShaderModule, // VkShader shader; + "main", // const char* pName; + DE_NULL // const VkSpecializationInfo* pSpecializationInfo; + }, + { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineShaderStageCreateFlags flags; + VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStage stage; + *m_fragmentShaderModule, // VkShader shader; + "main", // const char* pName; + DE_NULL // const VkSpecializationInfo* pSpecializationInfo; + } + }; + + const VkVertexInputBindingDescription vertexInputBindingDescription = + { + 0u, // deUint32 binding; + sizeof(tcu::Vec4), // deUint32 strideInBytes; + VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate; + }; + + const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = + { + { + 0u, // deUint32 location; + 0u, // deUint32 binding; + VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; + 0u // deUint32 offsetInBytes; + }, + { + 1u, // deUint32 location; + 0u, // deUint32 binding; + VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; + (deUint32)attributeBatchSize // deUint32 offsetInBytes; + } + }; + + const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineVertexInputStateCreateFlags flags; + 1u, // deUint32 bindingCount; + &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; + 2u, // deUint32 attributeCount; + vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; + }; + + const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineInputAssemblyStateCreateFlags flags; + primitiveTopology, // VkPrimitiveTopology topology; + false // VkBool32 primitiveRestartEnable; + }; + + const VkViewport viewport = + { + 0.0f, // float originX; + 0.0f, // float originY; + m_renderSize, // float width; + m_renderSize, // float height; + 0.0f, // float minDepth; + 1.0f // float maxDepth; + }; + + const VkRect2D scissor = + { + { 0, 0 }, // VkOffset2D offset; + { m_renderSize, m_renderSize } // VkExtent2D extent; + }; + + const VkPipelineViewportStateCreateInfo viewportStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineViewportStateCreateFlags flags; + 1u, // deUint32 viewportCount; + &viewport, // const VkViewport* pViewports; + 1u, // deUint32 scissorCount; + &scissor // const VkRect2D* pScissors; + }; + + const VkPipelineMultisampleStateCreateInfo multisampleStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineMultisampleStateCreateFlags flags; + m_sampleCount, // VkSampleCountFlagBits rasterizationSamples; + VK_FALSE, // VkBool32 sampleShadingEnable; + 0.0f, // float minSampleShading; + DE_NULL, // const VkSampleMask* pSampleMask; + VK_FALSE, // VkBool32 alphaToCoverageEnable; + VK_FALSE // VkBool32 alphaToOneEnable; + }; + + const VkGraphicsPipelineCreateInfo graphicsPipelineParams = + { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkPipelineCreateFlags flags; + 2u, // deUint32 stageCount; + shaderStageParams, // const VkPipelineShaderStageCreateInfo* pStages; + &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; + &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; + DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; + &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; + getRasterizationStateCreateInfo(), // const VkPipelineRasterStateCreateInfo* pRasterizationState; + &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; + DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; + getColorBlendStateCreateInfo(), // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; + DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; + *m_pipelineLayout, // VkPipelineLayout layout; + *m_renderPass, // VkRenderPass renderPass; + 0u, // deUint32 subpass; + 0u, // VkPipeline basePipelineHandle; + 0u // deInt32 basePipelineIndex; + }; + + graphicsPipeline = createGraphicsPipeline(vkd, vkDevice, DE_NULL, &graphicsPipelineParams); + } + + // Create Vertex Buffer + { + const VkBufferCreateInfo vertexBufferParams = + { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkBufferCreateFlags flags; + attributeBatchSize * 2, // VkDeviceSize size; + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage; + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; + 1u, // deUint32 queueFamilyCount; + &queueFamilyIndex // const deUint32* pQueueFamilyIndices; + }; + + vertexBuffer = createBuffer(vkd, vkDevice, &vertexBufferParams); + vertexBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible); + + VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset())); + + // Load vertices into vertex buffer + deMemcpy(vertexBufferMemory->getHostPtr(), positionData.data(), attributeBatchSize); + deMemcpy(reinterpret_cast(vertexBufferMemory->getHostPtr()) + attributeBatchSize, colorData.data(), attributeBatchSize); + flushMappedMemoryRange(vkd, vkDevice, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset(), vertexBufferParams.size); + } + + // Create Command Buffer + { + const VkCommandBufferAllocateInfo cmdBufferAllocateInfo = + { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + *m_commandPool, // VkCommandPool commandPool; + VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level; + 1 // deUint32 commandBufferCount; + }; + + commandBuffer = allocateCommandBuffer(vkd, vkDevice, &cmdBufferAllocateInfo); + } + + // Begin Command Buffer + { + const VkCommandBufferBeginInfo cmdBufferBeginInfo = + { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // VkCmdBufferOptimizeFlags flags; + DE_NULL // const VkCommandBufferInheritanceInfo* pInheritanceInfo; + }; + + VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &cmdBufferBeginInfo)); + } + + addImageTransitionBarrier(*commandBuffer, *m_image, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags srcStageMask + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VkPipelineStageFlags dstStageMask + 0, // VkAccessFlags srcAccessMask + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask + VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout; + + if (m_multisampling) { + addImageTransitionBarrier(*commandBuffer, *m_resolvedImage, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags srcStageMask + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VkPipelineStageFlags dstStageMask + 0, // VkAccessFlags srcAccessMask + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask + VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout; + } + + // Begin Render Pass + { + const VkClearValue clearValue = makeClearValueColorF32(0.0, 0.0, 0.0, 1.0); + + 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; + { + { 0, 0 }, + { m_renderSize, m_renderSize } + }, // VkRect2D renderArea; + 1u, // deUint32 clearValueCount; + &clearValue // const VkClearValue* pClearValues; + }; + + vkd.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + } + + const VkDeviceSize vertexBufferOffset = 0; + + vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline); + vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1, &m_descriptorSet.get(), 0u, DE_NULL); + vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset); + vkd.cmdDraw(*commandBuffer, (deUint32)positionData.size(), 1, 0, 0); + vkd.cmdEndRenderPass(*commandBuffer); + + // Copy Image + { + + const VkBufferMemoryBarrier bufferBarrier = + { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; + DE_NULL, // const void* pNext; + VK_ACCESS_TRANSFER_WRITE_BIT, // VkMemoryOutputFlags outputMask; + VK_ACCESS_HOST_READ_BIT, // VkMemoryInputFlags inputMask; + VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; + VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex; + *m_resultBuffer, // VkBuffer buffer; + 0u, // VkDeviceSize offset; + m_resultBufferSize // VkDeviceSize size; + }; + + const VkBufferImageCopy copyRegion = + { + 0u, // VkDeviceSize bufferOffset; + m_renderSize, // deUint32 bufferRowLength; + m_renderSize, // deUint32 bufferImageHeight; + { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u }, // VkImageSubresourceCopy imageSubresource; + { 0, 0, 0 }, // VkOffset3D imageOffset; + { m_renderSize, m_renderSize, 1u } // VkExtent3D imageExtent; + }; + + addImageTransitionBarrier(*commandBuffer, + m_multisampling ? *m_resolvedImage : *m_image, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask + VK_PIPELINE_STAGE_TRANSFER_BIT, // VkPipelineStageFlags dstStageMask + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask + VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout; + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); // VkImageLayout newLayout;) + + if (m_multisampling) + vkd.cmdCopyImageToBuffer(*commandBuffer, *m_resolvedImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_resultBuffer, 1, ©Region); + else + vkd.cmdCopyImageToBuffer(*commandBuffer, *m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_resultBuffer, 1, ©Region); + + vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &bufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL); + } + + VK_CHECK(vkd.endCommandBuffer(*commandBuffer)); + + // Set Point Size + { + float pointSize = getPointSize(); + deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, m_uniformBufferSize); + flushMappedMemoryRange(vkd, vkDevice, m_uniformBufferMemory->getMemory(), m_uniformBufferMemory->getOffset(), m_uniformBufferSize); + } + + // Submit + { + const VkSubmitInfo submitInfo = + { + VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0u, // deUint32 waitSemaphoreCount; + DE_NULL, // const VkSemaphore* pWaitSemaphores; + DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask; + 1u, // deUint32 commandBufferCount; + &commandBuffer.get(), // const VkCommandBuffer* pCommandBuffers; + 0u, // deUint32 signalSemaphoreCount; + DE_NULL, // const VkSemaphore* pSignalSemaphores; + }; + + VK_CHECK(vkd.resetFences(vkDevice, 1, &m_fence.get())); + VK_CHECK(vkd.queueSubmit(queue, 1, &submitInfo, *m_fence)); + VK_CHECK(vkd.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */)); + } + + invalidateMappedMemoryRange(vkd, vkDevice, m_resultBufferMemory->getMemory(), m_resultBufferMemory->getOffset(), m_resultBufferSize); + tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1), m_resultBufferMemory->getHostPtr())); +} + +float BaseRenderingTestInstance::getLineWidth (void) const +{ + return 1.0f; +} + +float BaseRenderingTestInstance::getPointSize (void) const +{ + return 1.0f; +} + +const VkPipelineRasterizationStateCreateInfo* BaseRenderingTestInstance::getRasterizationStateCreateInfo (void) const +{ + static VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineRasterizationStateCreateFlags flags; + false, // VkBool32 depthClipEnable; + false, // VkBool32 rasterizerDiscardEnable; + VK_POLYGON_MODE_FILL, // VkFillMode fillMode; + VK_CULL_MODE_NONE, // VkCullMode cullMode; + VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; + VK_FALSE, // VkBool32 depthBiasEnable; + 0.0f, // float depthBias; + 0.0f, // float depthBiasClamp; + 0.0f, // float slopeScaledDepthBias; + getLineWidth(), // float lineWidth; + }; + + rasterizationStateCreateInfo.lineWidth = getLineWidth(); + return &rasterizationStateCreateInfo; +} + +const VkPipelineColorBlendStateCreateInfo* BaseRenderingTestInstance::getColorBlendStateCreateInfo (void) const +{ + static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = + { + false, // VkBool32 blendEnable; + VK_BLEND_FACTOR_ONE, // VkBlend srcBlendColor; + VK_BLEND_FACTOR_ZERO, // VkBlend destBlendColor; + VK_BLEND_OP_ADD, // VkBlendOp blendOpColor; + VK_BLEND_FACTOR_ONE, // VkBlend srcBlendAlpha; + VK_BLEND_FACTOR_ZERO, // VkBlend destBlendAlpha; + VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha; + (VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT) // VkChannelFlags channelWriteMask; + }; + + static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineColorBlendStateCreateFlags flags; + false, // VkBool32 logicOpEnable; + VK_LOGIC_OP_COPY, // VkLogicOp logicOp; + 1u, // deUint32 attachmentCount; + &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; + { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4]; + }; + + return &colorBlendStateParams; +} + +const tcu::TextureFormat& BaseRenderingTestInstance::getTextureFormat (void) const +{ + return m_textureFormat; +} + +class BaseTriangleTestInstance : public BaseRenderingTestInstance +{ +public: + BaseTriangleTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount); + virtual tcu::TestStatus iterate (void); + +private: + virtual void generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles) = DE_NULL; + + int m_iteration; + const int m_iterationCount; + VkPrimitiveTopology m_primitiveTopology; + bool m_allIterationsPassed; +}; + +BaseTriangleTestInstance::BaseTriangleTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount) + : BaseRenderingTestInstance (context, sampleCount) + , m_iteration (0) + , m_iterationCount (3) + , m_primitiveTopology (primitiveTopology) + , m_allIterationsPassed (true) +{ +} + +tcu::TestStatus BaseTriangleTestInstance::iterate (void) +{ + const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); + const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), iterationDescription, iterationDescription); + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + std::vector triangles; + + generateTriangles(m_iteration, drawBuffer, triangles); + + // draw image + drawPrimitives(resultImage, drawBuffer, m_primitiveTopology); + + // compare + { + bool compareOk; + RasterizationArguments args; + TriangleSceneSpec scene; + + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + + args.numSamples = m_multisampling ? 1 : 0; + args.subpixelBits = m_subpixelBits; + args.redBits = colorBits[0]; + args.greenBits = colorBits[1]; + args.blueBits = colorBits[2]; + + scene.triangles.swap(triangles); + + compareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog()); + + if (!compareOk) + m_allIterationsPassed = false; + } + + // result + if (++m_iteration == m_iterationCount) + { + if (m_allIterationsPassed) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Incorrect rasterization"); + } + else + return tcu::TestStatus::incomplete(); +} + +class BaseLineTestInstance : public BaseRenderingTestInstance +{ +public: + BaseLineTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount); + virtual tcu::TestStatus iterate (void); + virtual float getLineWidth (void) const; + +private: + virtual void generateLines (int iteration, std::vector& outData, std::vector& outLines) = DE_NULL; + + int m_iteration; + const int m_iterationCount; + VkPrimitiveTopology m_primitiveTopology; + const PrimitiveWideness m_primitiveWideness; + bool m_allIterationsPassed; + float m_maxLineWidth; + std::vector m_lineWidths; +}; + +BaseLineTestInstance::BaseLineTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount) + : BaseRenderingTestInstance (context, sampleCount) + , m_iteration (0) + , m_iterationCount (3) + , m_primitiveTopology (primitiveTopology) + , m_primitiveWideness (wideness) + , m_allIterationsPassed (true) + , m_maxLineWidth (1.0f) +{ + DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST); + + if (!context.getDeviceProperties().limits.strictLines) + TCU_THROW(NotSupportedError, "Strict rasterization is not supported"); + + // create line widths + if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW) + { + m_lineWidths.resize(m_iterationCount, 1.0f); + } + else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) + { + if (!m_context.getDeviceFeatures().wideLines) + TCU_THROW(NotSupportedError , "wide line support required"); + + const float* range = context.getDeviceProperties().limits.lineWidthRange; + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage; + + // no wide line support + if (range[1] <= 1.0f) + TCU_THROW(NotSupportedError, "wide line support required"); + + // set hand picked sizes + m_lineWidths.push_back(5.0f); + m_lineWidths.push_back(10.0f); + m_lineWidths.push_back(range[1]); + DE_ASSERT((int)m_lineWidths.size() == m_iterationCount); + + m_maxLineWidth = range[1]; + } + else + DE_ASSERT(false); +} + +tcu::TestStatus BaseLineTestInstance::iterate (void) +{ + const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); + const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), iterationDescription, iterationDescription); + const float lineWidth = getLineWidth(); + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + std::vector lines; + + // supported? + if (lineWidth <= m_maxLineWidth) + { + // gen data + generateLines(m_iteration, drawBuffer, lines); + + // draw image + drawPrimitives(resultImage, drawBuffer, m_primitiveTopology); + + // compare + { + RasterizationArguments args; + LineSceneSpec scene; + + + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + + args.numSamples = m_multisampling ? 1 : 0; + args.subpixelBits = m_subpixelBits; + args.redBits = colorBits[0]; + args.greenBits = colorBits[1]; + args.blueBits = colorBits[2]; + + scene.lines.swap(lines); + scene.lineWidth = lineWidth; + + if (!verifyClippedTriangulatedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog())) + m_allIterationsPassed = false; + } + } + else + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage; + + // result + if (++m_iteration == m_iterationCount) + { + if (m_allIterationsPassed) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Incorrect rasterization"); + } + else + return tcu::TestStatus::incomplete(); +} + + +float BaseLineTestInstance::getLineWidth (void) const +{ + return m_lineWidths[m_iteration]; +} + + +class PointTestInstance : public BaseRenderingTestInstance +{ +public: + PointTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount); + virtual tcu::TestStatus iterate (void); + virtual float getPointSize (void) const; + +private: + virtual void generatePoints (int iteration, std::vector& outData, std::vector& outPoints); + + int m_iteration; + const int m_iterationCount; + const PrimitiveWideness m_primitiveWideness; + bool m_allIterationsPassed; + float m_maxPointSize; + std::vector m_pointSizes; +}; + +PointTestInstance::PointTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount) + : BaseRenderingTestInstance (context, sampleCount) + , m_iteration (0) + , m_iterationCount (3) + , m_primitiveWideness (wideness) + , m_allIterationsPassed (true) + , m_maxPointSize (1.0f) +{ + // create point sizes + if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW) + { + m_pointSizes.resize(m_iterationCount, 1.0f); + } + else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) + { + if (!m_context.getDeviceFeatures().largePoints) + TCU_THROW(NotSupportedError , "large point support required"); + + const float* range = context.getDeviceProperties().limits.pointSizeRange; + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage; + + // no wide line support + if (range[1] <= 1.0f) + TCU_THROW(NotSupportedError , "wide point support required"); + + // set hand picked sizes + m_pointSizes.push_back(10.0f); + m_pointSizes.push_back(25.0f); + m_pointSizes.push_back(range[1]); + DE_ASSERT((int)m_pointSizes.size() == m_iterationCount); + + m_maxPointSize = range[1]; + } + else + DE_ASSERT(false); +} + +tcu::TestStatus PointTestInstance::iterate (void) +{ + const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); + const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), iterationDescription, iterationDescription); + const float pointSize = getPointSize(); + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + std::vector points; + + // supported? + if (pointSize <= m_maxPointSize) + { + // gen data + generatePoints(m_iteration, drawBuffer, points); + + // draw image + drawPrimitives(resultImage, drawBuffer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST); + + // compare + { + bool compareOk; + RasterizationArguments args; + PointSceneSpec scene; + + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + + args.numSamples = m_multisampling ? 1 : 0; + args.subpixelBits = m_subpixelBits; + args.redBits = colorBits[0]; + args.greenBits = colorBits[1]; + args.blueBits = colorBits[2]; + + scene.points.swap(points); + + compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog()); + + if (!compareOk) + m_allIterationsPassed = false; + } + } + else + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point size " << pointSize << " not supported, skipping iteration." << tcu::TestLog::EndMessage; + + // result + if (++m_iteration == m_iterationCount) + { + if (m_allIterationsPassed) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Incorrect rasterization"); + } + else + return tcu::TestStatus::incomplete(); +} + +float PointTestInstance::getPointSize (void) const +{ + return m_pointSizes[m_iteration]; +} + +void PointTestInstance::generatePoints (int iteration, std::vector& outData, std::vector& outPoints) +{ + outData.resize(6); + + switch (iteration) + { + case 0: + // \note: these values are chosen arbitrarily + outData[0] = tcu::Vec4( 0.2f, 0.8f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.5f, 0.3f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f); + outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f); + break; + + case 1: + outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( 0.4f, 1.2f, 0.0f, 1.0f); + break; + + case 2: + outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 0.3f, -0.9f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( -0.4f, -0.1f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( -0.4f, 0.4f, 0.0f, 1.0f); + break; + } + + outPoints.resize(outData.size()); + for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx) + { + outPoints[pointNdx].position = outData[pointNdx]; + outPoints[pointNdx].pointSize = getPointSize(); + } + + // log + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size() << " point(s): (point size = " << getPointSize() << ")" << tcu::TestLog::EndMessage; + for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx) + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point " << (pointNdx+1) << ":\t" << outPoints[pointNdx].position << tcu::TestLog::EndMessage; +} + +template +class BaseTestCase : public BaseRenderingTestCase +{ +public: + BaseTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT) + : BaseRenderingTestCase(context, name, description, sampleCount) + {} + + virtual TestInstance* createInstance (Context& context) const + { + return new ConcreteTestInstance(context, m_sampleCount); + } +}; + +class TrianglesTestInstance : public BaseTriangleTestInstance +{ +public: + TrianglesTestInstance (Context& context, VkSampleCountFlagBits sampleCount) + : BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, sampleCount) + {} + + void generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles); +}; + +void TrianglesTestInstance::generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles) +{ + outData.resize(6); + + switch (iteration) + { + case 0: + // \note: these values are chosen arbitrarily + outData[0] = tcu::Vec4( 0.2f, 0.8f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.5f, 0.3f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f); + outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f); + break; + + case 1: + outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( 0.4f, 1.2f, 0.0f, 1.0f); + break; + + case 2: + outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( -1.1f, -0.1f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( -0.4f, 0.4f, 0.0f, 1.0f); + break; + } + + outTriangles.resize(2); + outTriangles[0].positions[0] = outData[0]; outTriangles[0].sharedEdge[0] = false; + outTriangles[0].positions[1] = outData[1]; outTriangles[0].sharedEdge[1] = false; + outTriangles[0].positions[2] = outData[2]; outTriangles[0].sharedEdge[2] = false; + + outTriangles[1].positions[0] = outData[3]; outTriangles[1].sharedEdge[0] = false; + outTriangles[1].positions[1] = outData[4]; outTriangles[1].sharedEdge[1] = false; + outTriangles[1].positions[2] = outData[5]; outTriangles[1].sharedEdge[2] = false; + + // log + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage; + for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx) + { + m_context.getTestContext().getLog() + << tcu::TestLog::Message + << "Triangle " << (triangleNdx+1) << ":" + << "\n\t" << outTriangles[triangleNdx].positions[0] + << "\n\t" << outTriangles[triangleNdx].positions[1] + << "\n\t" << outTriangles[triangleNdx].positions[2] + << tcu::TestLog::EndMessage; + } +} + +class TriangleStripTestInstance : public BaseTriangleTestInstance +{ +public: + TriangleStripTestInstance (Context& context, VkSampleCountFlagBits sampleCount) + : BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, sampleCount) + {} + + void generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles); +}; + +void TriangleStripTestInstance::generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles) +{ + outData.resize(5); + + switch (iteration) + { + case 0: + // \note: these values are chosen arbitrarily + outData[0] = tcu::Vec4(-0.504f, 0.8f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.2f, -0.2f, 0.0f, 1.0f); + outData[2] = tcu::Vec4(-0.2f, 0.199f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.5f, 0.201f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 1.5f, 0.4f, 0.0f, 1.0f); + break; + + case 1: + outData[0] = tcu::Vec4(-0.499f, 0.129f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, -0.31f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); + break; + + case 2: + outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); + outData[2] = tcu::Vec4(-0.87f, -0.1f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.11f, 0.19f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); + break; + } + + outTriangles.resize(3); + outTriangles[0].positions[0] = outData[0]; outTriangles[0].sharedEdge[0] = false; + outTriangles[0].positions[1] = outData[1]; outTriangles[0].sharedEdge[1] = true; + outTriangles[0].positions[2] = outData[2]; outTriangles[0].sharedEdge[2] = false; + + outTriangles[1].positions[0] = outData[2]; outTriangles[1].sharedEdge[0] = true; + outTriangles[1].positions[1] = outData[1]; outTriangles[1].sharedEdge[1] = false; + outTriangles[1].positions[2] = outData[3]; outTriangles[1].sharedEdge[2] = true; + + outTriangles[2].positions[0] = outData[2]; outTriangles[2].sharedEdge[0] = true; + outTriangles[2].positions[1] = outData[3]; outTriangles[2].sharedEdge[1] = false; + outTriangles[2].positions[2] = outData[4]; outTriangles[2].sharedEdge[2] = false; + + // log + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices." << tcu::TestLog::EndMessage; + for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) + { + m_context.getTestContext().getLog() + << tcu::TestLog::Message + << "\t" << outData[vtxNdx] + << tcu::TestLog::EndMessage; + } +} + +class TriangleFanTestInstance : public BaseTriangleTestInstance +{ +public: + TriangleFanTestInstance (Context& context, VkSampleCountFlagBits sampleCount) + : BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, sampleCount) + {} + + void generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles); +}; + +void TriangleFanTestInstance::generateTriangles (int iteration, std::vector& outData, std::vector& outTriangles) +{ + outData.resize(5); + + switch (iteration) + { + case 0: + // \note: these values are chosen arbitrarily + outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f); + break; + + case 1: + outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); + break; + + case 2: + outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); + break; + } + + outTriangles.resize(3); + outTriangles[0].positions[0] = outData[0]; outTriangles[0].sharedEdge[0] = false; + outTriangles[0].positions[1] = outData[1]; outTriangles[0].sharedEdge[1] = false; + outTriangles[0].positions[2] = outData[2]; outTriangles[0].sharedEdge[2] = true; + + outTriangles[1].positions[0] = outData[0]; outTriangles[1].sharedEdge[0] = true; + outTriangles[1].positions[1] = outData[2]; outTriangles[1].sharedEdge[1] = false; + outTriangles[1].positions[2] = outData[3]; outTriangles[1].sharedEdge[2] = true; + + outTriangles[2].positions[0] = outData[0]; outTriangles[2].sharedEdge[0] = true; + outTriangles[2].positions[1] = outData[3]; outTriangles[2].sharedEdge[1] = false; + outTriangles[2].positions[2] = outData[4]; outTriangles[2].sharedEdge[2] = false; + + // log + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices." << tcu::TestLog::EndMessage; + for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) + { + m_context.getTestContext().getLog() + << tcu::TestLog::Message + << "\t" << outData[vtxNdx] + << tcu::TestLog::EndMessage; + } +} + +template +class WidenessTestCase : public BaseRenderingTestCase +{ +public: + WidenessTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT) + : BaseRenderingTestCase(context, name, description, sampleCount) + , m_wideness(wideness) + {} + + virtual TestInstance* createInstance (Context& context) const + { + return new ConcreteTestInstance(context, m_wideness, m_sampleCount); + } +protected: + const PrimitiveWideness m_wideness; +}; + +class LinesTestInstance : public BaseLineTestInstance +{ +public: + LinesTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount) + : BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, wideness, sampleCount) + {} + + virtual void generateLines (int iteration, std::vector& outData, std::vector& outLines); +}; + +void LinesTestInstance::generateLines (int iteration, std::vector& outData, std::vector& outLines) +{ + outData.resize(6); + + switch (iteration) + { + case 0: + // \note: these values are chosen arbitrarily + outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.3f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( 0.1f, 0.5f, 0.0f, 1.0f); + break; + + case 1: + outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( 0.18f, -0.2f, 0.0f, 1.0f); + break; + + case 2: + outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); + outData[5] = tcu::Vec4( 0.8f, -0.7f, 0.0f, 1.0f); + break; + } + + outLines.resize(3); + outLines[0].positions[0] = outData[0]; + outLines[0].positions[1] = outData[1]; + outLines[1].positions[0] = outData[2]; + outLines[1].positions[1] = outData[3]; + outLines[2].positions[0] = outData[4]; + outLines[2].positions[1] = outData[5]; + + // log + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << getLineWidth() << ")" << tcu::TestLog::EndMessage; + for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx) + { + m_context.getTestContext().getLog() + << tcu::TestLog::Message + << "Line " << (lineNdx+1) << ":" + << "\n\t" << outLines[lineNdx].positions[0] + << "\n\t" << outLines[lineNdx].positions[1] + << tcu::TestLog::EndMessage; + } +} + +class LineStripTestInstance : public BaseLineTestInstance +{ +public: + LineStripTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount) + : BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, wideness, sampleCount) + {} + + virtual void generateLines (int iteration, std::vector& outData, std::vector& outLines); +}; + +void LineStripTestInstance::generateLines (int iteration, std::vector& outData, std::vector& outLines) +{ + outData.resize(4); + + switch (iteration) + { + case 0: + // \note: these values are chosen arbitrarily + outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); + outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); + break; + + case 1: + outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); + outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + break; + + case 2: + outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); + outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); + outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); + outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); + break; + } + + outLines.resize(3); + outLines[0].positions[0] = outData[0]; + outLines[0].positions[1] = outData[1]; + outLines[1].positions[0] = outData[1]; + outLines[1].positions[1] = outData[2]; + outLines[2].positions[0] = outData[2]; + outLines[2].positions[1] = outData[3]; + + // log + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage; + for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) + { + m_context.getTestContext().getLog() + << tcu::TestLog::Message + << "\t" << outData[vtxNdx] + << tcu::TestLog::EndMessage; + } +} + +class FillRuleTestInstance : public BaseRenderingTestInstance +{ +public: + enum FillRuleCaseType + { + FILLRULECASE_BASIC = 0, + FILLRULECASE_REVERSED, + FILLRULECASE_CLIPPED_FULL, + FILLRULECASE_CLIPPED_PARTIAL, + FILLRULECASE_PROJECTED, + + FILLRULECASE_LAST + }; + FillRuleTestInstance (Context& context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount); + virtual tcu::TestStatus iterate (void); + +private: + + virtual const VkPipelineColorBlendStateCreateInfo* getColorBlendStateCreateInfo (void) const; + int getRenderSize (FillRuleCaseType type) const; + int getNumIterations (FillRuleCaseType type) const; + void generateTriangles (int iteration, std::vector& outData) const; + + const FillRuleCaseType m_caseType; + int m_iteration; + const int m_iterationCount; + bool m_allIterationsPassed; + +}; + +FillRuleTestInstance::FillRuleTestInstance (Context& context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount) + : BaseRenderingTestInstance (context, sampleCount, getRenderSize(type)) + , m_caseType (type) + , m_iteration (0) + , m_iterationCount (getNumIterations(type)) + , m_allIterationsPassed (true) +{ + DE_ASSERT(type < FILLRULECASE_LAST); +} + +tcu::TestStatus FillRuleTestInstance::iterate (void) +{ + const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); + const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), iterationDescription, iterationDescription); + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + const int thresholdRed = 1 << (8 - colorBits[0]); + const int thresholdGreen = 1 << (8 - colorBits[1]); + const int thresholdBlue = 1 << (8 - colorBits[2]); + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + + generateTriangles(m_iteration, drawBuffer); + + // draw image + { + const std::vector colorBuffer (drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f)); + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments." << tcu::TestLog::EndMessage; + + drawPrimitives(resultImage, drawBuffer, colorBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + } + + // verify no overdraw + { + const tcu::RGBA triangleColor = tcu::RGBA(127, 127, 127, 255); + bool overdraw = false; + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage; + + for (int y = 0; y < resultImage.getHeight(); ++y) + for (int x = 0; x < resultImage.getWidth(); ++x) + { + const tcu::RGBA color = resultImage.getPixel(x, y); + + // color values are greater than triangle color? Allow lower values for multisampled edges and background. + if ((color.getRed() - triangleColor.getRed()) > thresholdRed || + (color.getGreen() - triangleColor.getGreen()) > thresholdGreen || + (color.getBlue() - triangleColor.getBlue()) > thresholdBlue) + overdraw = true; + } + + // results + if (!overdraw) + m_context.getTestContext().getLog() << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage; + else + { + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Overlapping fragments detected, image is not valid." << tcu::TestLog::EndMessage; + m_allIterationsPassed = false; + } + } + + // verify no missing fragments in the full viewport case + if (m_caseType == FILLRULECASE_CLIPPED_FULL) + { + bool missingFragments = false; + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage; + + for (int y = 0; y < resultImage.getHeight(); ++y) + for (int x = 0; x < resultImage.getWidth(); ++x) + { + const tcu::RGBA color = resultImage.getPixel(x, y); + + // black? (background) + if (color.getRed() <= thresholdRed || + color.getGreen() <= thresholdGreen || + color.getBlue() <= thresholdBlue) + missingFragments = true; + } + + // results + if (!missingFragments) + m_context.getTestContext().getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage; + else + { + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Missing fragments detected, image is not valid." << tcu::TestLog::EndMessage; + + m_allIterationsPassed = false; + } + } + + m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering") + << tcu::TestLog::Image("Result", "Result", resultImage) + << tcu::TestLog::EndImageSet; + + // result + if (++m_iteration == m_iterationCount) + { + if (m_allIterationsPassed) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Found invalid pixels"); + } + else + return tcu::TestStatus::incomplete(); +} + +int FillRuleTestInstance::getRenderSize (FillRuleCaseType type) const +{ + if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL) + return DEFAULT_RENDER_SIZE / 4; + else + return DEFAULT_RENDER_SIZE; +} + +int FillRuleTestInstance::getNumIterations (FillRuleCaseType type) const +{ + if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL) + return 15; + else + return 2; +} + +void FillRuleTestInstance::generateTriangles (int iteration, std::vector& outData) const +{ + switch (m_caseType) + { + case FILLRULECASE_BASIC: + case FILLRULECASE_REVERSED: + case FILLRULECASE_PROJECTED: + { + const int numRows = 4; + const int numColumns = 4; + const float quadSide = 0.15f; + de::Random rnd (0xabcd); + + outData.resize(6 * numRows * numColumns); + + for (int col = 0; col < numColumns; ++col) + for (int row = 0; row < numRows; ++row) + { + const tcu::Vec2 center = tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f, ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f); + const float rotation = (float)(iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f; + const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation)); + const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x()); + const tcu::Vec2 quad[4] = + { + center + sideH + sideV, + center + sideH - sideV, + center - sideH - sideV, + center - sideH + sideV, + }; + + if (m_caseType == FILLRULECASE_BASIC) + { + outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f); + } + else if (m_caseType == FILLRULECASE_REVERSED) + { + outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); + outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f); + } + else if (m_caseType == FILLRULECASE_PROJECTED) + { + const float w0 = rnd.getFloat(0.1f, 4.0f); + const float w1 = rnd.getFloat(0.1f, 4.0f); + const float w2 = rnd.getFloat(0.1f, 4.0f); + const float w3 = rnd.getFloat(0.1f, 4.0f); + + outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0); + outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1); + outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2); + outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2); + outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0); + outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3); + } + else + DE_ASSERT(DE_FALSE); + } + + break; + } + + case FILLRULECASE_CLIPPED_PARTIAL: + case FILLRULECASE_CLIPPED_FULL: + { + const float quadSide = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f); + const tcu::Vec2 center = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f)); + const float rotation = (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f; + const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation)); + const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x()); + const tcu::Vec2 quad[4] = + { + center + sideH + sideV, + center + sideH - sideV, + center - sideH - sideV, + center - sideH + sideV, + }; + + outData.resize(6); + outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); + outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f); + outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); + outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); + outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); + outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f); + break; + } + + default: + DE_ASSERT(DE_FALSE); + } +} + +const VkPipelineColorBlendStateCreateInfo* FillRuleTestInstance::getColorBlendStateCreateInfo (void) const +{ + static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = + { + true, // VkBool32 blendEnable; + VK_BLEND_FACTOR_ONE, // VkBlend srcBlendColor; + VK_BLEND_FACTOR_ONE, // VkBlend destBlendColor; + VK_BLEND_OP_ADD, // VkBlendOp blendOpColor; + VK_BLEND_FACTOR_ONE, // VkBlend srcBlendAlpha; + VK_BLEND_FACTOR_ONE, // VkBlend destBlendAlpha; + VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha; + (VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT) // VkChannelFlags channelWriteMask; + }; + + static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = + { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineColorBlendStateCreateFlags flags; + false, // VkBool32 logicOpEnable; + VK_LOGIC_OP_COPY, // VkLogicOp logicOp; + 1u, // deUint32 attachmentCount; + &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; + { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4]; + }; + + return &colorBlendStateParams; +} + + +class FillRuleTestCase : public BaseRenderingTestCase +{ +public: + FillRuleTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, FillRuleTestInstance::FillRuleCaseType type, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT) + : BaseRenderingTestCase (context, name, description, sampleCount) + , m_type (type) + {} + + virtual TestInstance* createInstance (Context& context) const + { + return new FillRuleTestInstance(context, m_type, m_sampleCount); + } +protected: + const FillRuleTestInstance::FillRuleCaseType m_type; +}; + +class CullingTestInstance : public BaseRenderingTestInstance +{ +public: + CullingTestInstance (Context& context, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace) + : BaseRenderingTestInstance (context, VK_SAMPLE_COUNT_1_BIT, DEFAULT_RENDER_SIZE) + , m_cullMode (cullMode) + , m_primitiveTopology (primitiveTopology) + , m_frontFace (frontFace) + {} + virtual + const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const; + + tcu::TestStatus iterate (void); + +private: + void generateVertices (std::vector& outData) const; + void extractTriangles (std::vector& outTriangles, const std::vector& vertices) const; + bool triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const; + + const VkCullModeFlags m_cullMode; + const VkPrimitiveTopology m_primitiveTopology; + const VkFrontFace m_frontFace; +}; + +tcu::TestStatus CullingTestInstance::iterate (void) +{ + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + std::vector triangles; + + // generate scene + generateVertices(drawBuffer); + extractTriangles(triangles, drawBuffer); + + // draw image + { + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Setting front face to " << m_frontFace << tcu::TestLog::EndMessage; + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Setting cull face to " << m_cullMode << tcu::TestLog::EndMessage; + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Drawing test pattern (" << m_primitiveTopology << ")" << tcu::TestLog::EndMessage; + + drawPrimitives(resultImage, drawBuffer, m_primitiveTopology); + } + + // compare + { + RasterizationArguments args; + TriangleSceneSpec scene; + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + + args.numSamples = m_multisampling ? 1 : 0; + args.subpixelBits = m_subpixelBits; + args.redBits = colorBits[0]; + args.greenBits = colorBits[1]; + args.blueBits = colorBits[2]; + + scene.triangles.swap(triangles); + + if (verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), tcu::VERIFICATIONMODE_WEAK)) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Incorrect rendering"); + } +} + +void CullingTestInstance::generateVertices (std::vector& outData) const +{ + de::Random rnd(543210); + + outData.resize(6); + for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) + { + outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f); + outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f); + outData[vtxNdx].z() = 0.0f; + outData[vtxNdx].w() = 1.0f; + } +} + +void CullingTestInstance::extractTriangles (std::vector& outTriangles, const std::vector& vertices) const +{ + const bool cullDirection = (m_cullMode == VK_CULL_MODE_FRONT_BIT) ^ (m_frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE); + + // No triangles + if (m_cullMode == VK_CULL_MODE_FRONT_AND_BACK) + return; + + switch (m_primitiveTopology) + { + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: + { + for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3) + { + const tcu::Vec4& v0 = vertices[vtxNdx + 0]; + const tcu::Vec4& v1 = vertices[vtxNdx + 1]; + const tcu::Vec4& v2 = vertices[vtxNdx + 2]; + + if (triangleOrder(v0, v1, v2) != cullDirection) + { + TriangleSceneSpec::SceneTriangle tri; + tri.positions[0] = v0; tri.sharedEdge[0] = false; + tri.positions[1] = v1; tri.sharedEdge[1] = false; + tri.positions[2] = v2; tri.sharedEdge[2] = false; + + outTriangles.push_back(tri); + } + } + break; + } + + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: + { + for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx) + { + const tcu::Vec4& v0 = vertices[vtxNdx + 0]; + const tcu::Vec4& v1 = vertices[vtxNdx + 1]; + const tcu::Vec4& v2 = vertices[vtxNdx + 2]; + + if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0))) + { + TriangleSceneSpec::SceneTriangle tri; + tri.positions[0] = v0; tri.sharedEdge[0] = false; + tri.positions[1] = v1; tri.sharedEdge[1] = false; + tri.positions[2] = v2; tri.sharedEdge[2] = false; + + outTriangles.push_back(tri); + } + } + break; + } + + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: + { + for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx) + { + const tcu::Vec4& v0 = vertices[0]; + const tcu::Vec4& v1 = vertices[vtxNdx + 0]; + const tcu::Vec4& v2 = vertices[vtxNdx + 1]; + + if (triangleOrder(v0, v1, v2) != cullDirection) + { + TriangleSceneSpec::SceneTriangle tri; + tri.positions[0] = v0; tri.sharedEdge[0] = false; + tri.positions[1] = v1; tri.sharedEdge[1] = false; + tri.positions[2] = v2; tri.sharedEdge[2] = false; + + outTriangles.push_back(tri); + } + } + break; + } + + default: + DE_ASSERT(false); + } +} + +bool CullingTestInstance::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const +{ + const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w(); + const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w(); + const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w(); + + // cross + return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) > 0; +} + + +const VkPipelineRasterizationStateCreateInfo* CullingTestInstance::getRasterizationStateCreateInfo (void) const +{ + static VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = + { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; + DE_NULL, // const void* pNext; + 0, // VkPipelineRasterizationStateCreateFlags flags; + false, // VkBool32 depthClipEnable; + false, // VkBool32 rasterizerDiscardEnable; + VK_POLYGON_MODE_FILL, // VkFillMode fillMode; + VK_CULL_MODE_NONE, // VkCullMode cullMode; + VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; + VK_FALSE, // VkBool32 depthBiasEnable; + 0.0f, // float depthBias; + 0.0f, // float depthBiasClamp; + 0.0f, // float slopeScaledDepthBias; + getLineWidth(), // float lineWidth; + }; + + rasterizationStateCreateInfo.lineWidth = getLineWidth(); + rasterizationStateCreateInfo.cullMode = m_cullMode; + rasterizationStateCreateInfo.frontFace = m_frontFace; + + return &rasterizationStateCreateInfo; +} + +class CullingTestCase : public BaseRenderingTestCase +{ +public: + CullingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT) + : BaseRenderingTestCase (context, name, description, sampleCount) + , m_cullMode (cullMode) + , m_primitiveTopology (primitiveTopology) + , m_frontFace (frontFace) + {} + + virtual TestInstance* createInstance (Context& context) const + { + return new CullingTestInstance(context, m_cullMode, m_primitiveTopology, m_frontFace); + } +protected: + const VkCullModeFlags m_cullMode; + const VkPrimitiveTopology m_primitiveTopology; + const VkFrontFace m_frontFace; +}; + +class TriangleInterpolationTestInstance : public BaseRenderingTestInstance +{ +public: + + TriangleInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, VkSampleCountFlagBits sampleCount) + : BaseRenderingTestInstance (context, sampleCount, DEFAULT_RENDER_SIZE) + , m_primitiveTopology (primitiveTopology) + , m_projective ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0) + , m_iterationCount (3) + , m_iteration (0) + , m_allIterationsPassed (true) + , m_flatshade ((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0) + {} + + tcu::TestStatus iterate (void); + + +private: + void generateVertices (int iteration, std::vector& outVertices, std::vector& outColors) const; + void extractTriangles (std::vector& outTriangles, const std::vector& vertices, const std::vector& colors) const; + + + VkPrimitiveTopology m_primitiveTopology; + const bool m_projective; + const int m_iterationCount; + int m_iteration; + bool m_allIterationsPassed; + const deBool m_flatshade; +}; + +tcu::TestStatus TriangleInterpolationTestInstance::iterate (void) +{ + const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); + const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription); + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + std::vector colorBuffer; + std::vector triangles; + + // generate scene + generateVertices(m_iteration, drawBuffer, colorBuffer); + extractTriangles(triangles, drawBuffer, colorBuffer); + + // log + { + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage; + for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx) + m_context.getTestContext().getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage; + } + + // draw image + drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitiveTopology); + + // compare + { + RasterizationArguments args; + TriangleSceneSpec scene; + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + + args.numSamples = m_multisampling ? 1 : 0; + args.subpixelBits = m_subpixelBits; + args.redBits = colorBits[0]; + args.greenBits = colorBits[1]; + args.blueBits = colorBits[2]; + + scene.triangles.swap(triangles); + + if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog())) + m_allIterationsPassed = false; + } + + // result + if (++m_iteration == m_iterationCount) + { + if (m_allIterationsPassed) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Found invalid pixel values"); + } + else + return tcu::TestStatus::incomplete(); +} + +void TriangleInterpolationTestInstance::generateVertices (int iteration, std::vector& outVertices, std::vector& outColors) const +{ + // use only red, green and blue + const tcu::Vec4 colors[] = + { + tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), + tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), + tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), + }; + + de::Random rnd(123 + iteration * 1000 + (int)m_primitiveTopology); + + outVertices.resize(6); + outColors.resize(6); + + for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx) + { + outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f); + outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f); + outVertices[vtxNdx].z() = 0.0f; + + if (!m_projective) + outVertices[vtxNdx].w() = 1.0f; + else + { + const float w = rnd.getFloat(0.2f, 4.0f); + + outVertices[vtxNdx].x() *= w; + outVertices[vtxNdx].y() *= w; + outVertices[vtxNdx].z() *= w; + outVertices[vtxNdx].w() = w; + } + + outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)]; + } +} + +void TriangleInterpolationTestInstance::extractTriangles (std::vector& outTriangles, const std::vector& vertices, const std::vector& colors) const +{ + switch (m_primitiveTopology) + { + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: + { + for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3) + { + TriangleSceneSpec::SceneTriangle tri; + tri.positions[0] = vertices[vtxNdx + 0]; + tri.positions[1] = vertices[vtxNdx + 1]; + tri.positions[2] = vertices[vtxNdx + 2]; + tri.sharedEdge[0] = false; + tri.sharedEdge[1] = false; + tri.sharedEdge[2] = false; + + if (m_flatshade) + { + tri.colors[0] = colors[vtxNdx]; + tri.colors[1] = colors[vtxNdx]; + tri.colors[2] = colors[vtxNdx]; + } + else + { + tri.colors[0] = colors[vtxNdx + 0]; + tri.colors[1] = colors[vtxNdx + 1]; + tri.colors[2] = colors[vtxNdx + 2]; + } + + outTriangles.push_back(tri); + } + break; + } + + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: + { + for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx) + { + TriangleSceneSpec::SceneTriangle tri; + tri.positions[0] = vertices[vtxNdx + 0]; + tri.positions[1] = vertices[vtxNdx + 1]; + tri.positions[2] = vertices[vtxNdx + 2]; + tri.sharedEdge[0] = false; + tri.sharedEdge[1] = false; + tri.sharedEdge[2] = false; + + if (m_flatshade) + { + tri.colors[0] = colors[vtxNdx]; + tri.colors[1] = colors[vtxNdx]; + tri.colors[2] = colors[vtxNdx]; + } + else + { + tri.colors[0] = colors[vtxNdx + 0]; + tri.colors[1] = colors[vtxNdx + 1]; + tri.colors[2] = colors[vtxNdx + 2]; + } + + outTriangles.push_back(tri); + } + break; + } + + case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: + { + for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx) + { + TriangleSceneSpec::SceneTriangle tri; + tri.positions[0] = vertices[0]; + tri.positions[1] = vertices[vtxNdx + 0]; + tri.positions[2] = vertices[vtxNdx + 1]; + tri.sharedEdge[0] = false; + tri.sharedEdge[1] = false; + tri.sharedEdge[2] = false; + + if (m_flatshade) + { + tri.colors[0] = colors[vtxNdx]; + tri.colors[1] = colors[vtxNdx]; + tri.colors[2] = colors[vtxNdx]; + } + else + { + tri.colors[0] = colors[0]; + tri.colors[1] = colors[vtxNdx + 0]; + tri.colors[2] = colors[vtxNdx + 1]; + } + + outTriangles.push_back(tri); + } + break; + } + + default: + DE_ASSERT(false); + } +} + +class TriangleInterpolationTestCase : public BaseRenderingTestCase +{ +public: + TriangleInterpolationTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, int flags, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT) + : BaseRenderingTestCase (context, name, description, sampleCount, (flags & INTERPOLATIONFLAGS_FLATSHADE) != 0) + , m_primitiveTopology (primitiveTopology) + , m_flags (flags) + {} + + virtual TestInstance* createInstance (Context& context) const + { + return new TriangleInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_sampleCount); + } +protected: + const VkPrimitiveTopology m_primitiveTopology; + const int m_flags; +}; + +class LineInterpolationTestInstance : public BaseRenderingTestInstance +{ +public: + LineInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount); + + virtual tcu::TestStatus iterate (void); + +private: + void generateVertices (int iteration, std::vector& outVertices, std::vector& outColors) const; + void extractLines (std::vector& outLines, const std::vector& vertices, const std::vector& colors) const; + virtual float getLineWidth (void) const; + + VkPrimitiveTopology m_primitiveTopology; + const bool m_projective; + const int m_iterationCount; + const PrimitiveWideness m_primitiveWideness; + + int m_iteration; + bool m_allIterationsPassed; + float m_maxLineWidth; + std::vector m_lineWidths; + bool m_flatshade; +}; + +LineInterpolationTestInstance::LineInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount) + : BaseRenderingTestInstance (context, sampleCount) + , m_primitiveTopology (primitiveTopology) + , m_projective ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0) + , m_iterationCount (3) + , m_primitiveWideness (wideness) + , m_iteration (0) + , m_allIterationsPassed (true) + , m_maxLineWidth (1.0f) + , m_flatshade ((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0) +{ + DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST); + + if (!context.getDeviceProperties().limits.strictLines) + TCU_THROW(NotSupportedError, "Strict rasterization is not supported"); + + // create line widths + if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW) + { + m_lineWidths.resize(m_iterationCount, 1.0f); + } + else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) + { + if (!m_context.getDeviceFeatures().wideLines) + TCU_THROW(NotSupportedError , "wide line support required"); + + const float* range = context.getDeviceProperties().limits.lineWidthRange; + + m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage; + + // no wide line support + if (range[1] <= 1.0f) + throw tcu::NotSupportedError("wide line support required"); + + // set hand picked sizes + m_lineWidths.push_back(5.0f); + m_lineWidths.push_back(10.0f); + m_lineWidths.push_back(range[1]); + DE_ASSERT((int)m_lineWidths.size() == m_iterationCount); + + m_maxLineWidth = range[1]; + } + else + DE_ASSERT(false); +} + +tcu::TestStatus LineInterpolationTestInstance::iterate (void) +{ + const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); + const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription); + const float lineWidth = getLineWidth(); + tcu::Surface resultImage (m_renderSize, m_renderSize); + std::vector drawBuffer; + std::vector colorBuffer; + std::vector lines; + + // supported? + if (lineWidth <= m_maxLineWidth) + { + // generate scene + generateVertices(m_iteration, drawBuffer, colorBuffer); + extractLines(lines, drawBuffer, colorBuffer); + + // log + { + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage; + for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx) + m_context.getTestContext().getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage; + } + + // draw image + drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitiveTopology); + + // compare + { + RasterizationArguments args; + LineSceneSpec scene; + + tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat()); + + args.numSamples = m_multisampling ? 1 : 0; + args.subpixelBits = m_subpixelBits; + args.redBits = colorBits[0]; + args.greenBits = colorBits[1]; + args.blueBits = colorBits[2]; + + scene.lines.swap(lines); + scene.lineWidth = getLineWidth(); + + if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog())) + m_allIterationsPassed = false; + } + } + else + m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage; + + // result + if (++m_iteration == m_iterationCount) + { + if (m_allIterationsPassed) + return tcu::TestStatus::pass("Pass"); + else + return tcu::TestStatus::fail("Incorrect rasterization"); + } + else + return tcu::TestStatus::incomplete(); +} + +void LineInterpolationTestInstance::generateVertices (int iteration, std::vector& outVertices, std::vector& outColors) const +{ + // use only red, green and blue + const tcu::Vec4 colors[] = + { + tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), + tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), + tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), + }; + + de::Random rnd(123 + iteration * 1000 + (int)m_primitiveTopology); + + outVertices.resize(6); + outColors.resize(6); + + for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx) + { + outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f); + outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f); + outVertices[vtxNdx].z() = 0.0f; + + if (!m_projective) + outVertices[vtxNdx].w() = 1.0f; + else + { + const float w = rnd.getFloat(0.2f, 4.0f); + + outVertices[vtxNdx].x() *= w; + outVertices[vtxNdx].y() *= w; + outVertices[vtxNdx].z() *= w; + outVertices[vtxNdx].w() = w; + } + + outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)]; + } +} + +void LineInterpolationTestInstance::extractLines (std::vector& outLines, const std::vector& vertices, const std::vector& colors) const +{ + switch (m_primitiveTopology) + { + case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: + { + for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2) + { + LineSceneSpec::SceneLine line; + line.positions[0] = vertices[vtxNdx + 0]; + line.positions[1] = vertices[vtxNdx + 1]; + + if (m_flatshade) + { + line.colors[0] = colors[vtxNdx]; + line.colors[1] = colors[vtxNdx]; + } + else + { + line.colors[0] = colors[vtxNdx + 0]; + line.colors[1] = colors[vtxNdx + 1]; + } + + outLines.push_back(line); + } + break; + } + + case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: + { + for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx) + { + LineSceneSpec::SceneLine line; + line.positions[0] = vertices[vtxNdx + 0]; + line.positions[1] = vertices[vtxNdx + 1]; + + if (m_flatshade) + { + line.colors[0] = colors[vtxNdx]; + line.colors[1] = colors[vtxNdx]; + } + else + { + line.colors[0] = colors[vtxNdx + 0]; + line.colors[1] = colors[vtxNdx + 1]; + } + + outLines.push_back(line); + } + break; + } + + default: + DE_ASSERT(false); + } +} + +float LineInterpolationTestInstance::getLineWidth (void) const +{ + return m_lineWidths[m_iteration]; +} + +class LineInterpolationTestCase : public BaseRenderingTestCase +{ +public: + LineInterpolationTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT) + : BaseRenderingTestCase (context, name, description, sampleCount, (flags & INTERPOLATIONFLAGS_FLATSHADE) != 0) + , m_primitiveTopology (primitiveTopology) + , m_flags (flags) + , m_wideness (wideness) + {} + + virtual TestInstance* createInstance (Context& context) const + { + return new LineInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_wideness, m_sampleCount); + } +protected: + const VkPrimitiveTopology m_primitiveTopology; + const int m_flags; + const PrimitiveWideness m_wideness; +}; + +void createRasterizationTests (tcu::TestCaseGroup* rasterizationTests) +{ + tcu::TestContext& testCtx = rasterizationTests->getTestContext(); + + // .primitives + { + tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(testCtx, "primitives", "Primitive rasterization"); + + rasterizationTests->addChild(primitives); + + primitives->addChild(new BaseTestCase (testCtx, "triangles", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result")); + primitives->addChild(new BaseTestCase (testCtx, "triangle_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, verify rasterization result")); + primitives->addChild(new BaseTestCase (testCtx, "triangle_fan", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, verify rasterization result")); + primitives->addChild(new WidenessTestCase (testCtx, "lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result", PRIMITIVEWIDENESS_NARROW)); + primitives->addChild(new WidenessTestCase (testCtx, "line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result", PRIMITIVEWIDENESS_NARROW)); + primitives->addChild(new WidenessTestCase (testCtx, "lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); + primitives->addChild(new WidenessTestCase (testCtx, "line_strip_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); + primitives->addChild(new WidenessTestCase (testCtx, "points", "Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); + } + + // .fill_rules + { + tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(testCtx, "fill_rules", "Primitive fill rules"); + + rasterizationTests->addChild(fillRules); + + fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_BASIC)); + fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad_reverse", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_REVERSED)); + fillRules->addChild(new FillRuleTestCase(testCtx, "clipped_full", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_CLIPPED_FULL)); + fillRules->addChild(new FillRuleTestCase(testCtx, "clipped_partly", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_CLIPPED_PARTIAL)); + fillRules->addChild(new FillRuleTestCase(testCtx, "projected", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_PROJECTED)); + } + + // .culling + { + static const struct CullMode + { + VkCullModeFlags mode; + const char* prefix; + } cullModes[] = + { + { VK_CULL_MODE_FRONT_BIT, "front_" }, + { VK_CULL_MODE_BACK_BIT, "back_" }, + { VK_CULL_MODE_FRONT_AND_BACK, "both_" }, + }; + static const struct PrimitiveType + { + VkPrimitiveTopology type; + const char* name; + } primitiveTypes[] = + { + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles" }, + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip" }, + { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan" }, + }; + static const struct FrontFaceOrder + { + VkFrontFace mode; + const char* postfix; + } frontOrders[] = + { + { VK_FRONT_FACE_COUNTER_CLOCKWISE, "" }, + { VK_FRONT_FACE_CLOCKWISE, "_reverse" }, + }; + + tcu::TestCaseGroup* const culling = new tcu::TestCaseGroup(testCtx, "culling", "Culling"); + + rasterizationTests->addChild(culling); + + for (int cullModeNdx = 0; cullModeNdx < DE_LENGTH_OF_ARRAY(cullModes); ++cullModeNdx) + for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx) + for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders); ++frontOrderNdx) + { + const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix; + + culling->addChild(new CullingTestCase(testCtx, name, "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode)); + } + } + + // .interpolation + { + tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(testCtx, "interpolation", "Test interpolation"); + + rasterizationTests->addChild(interpolation); + + // .basic + { + tcu::TestCaseGroup* const basic = new tcu::TestCaseGroup(testCtx, "basic", "Non-projective interpolation"); + + interpolation->addChild(basic); + + basic->addChild(new TriangleInterpolationTestCase (testCtx, "triangles", "Verify triangle interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, INTERPOLATIONFLAGS_NONE)); + basic->addChild(new TriangleInterpolationTestCase (testCtx, "triangle_strip", "Verify triangle strip interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, INTERPOLATIONFLAGS_NONE)); + basic->addChild(new TriangleInterpolationTestCase (testCtx, "triangle_fan", "Verify triangle fan interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, INTERPOLATIONFLAGS_NONE)); + basic->addChild(new LineInterpolationTestCase (testCtx, "lines", "Verify line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW)); + basic->addChild(new LineInterpolationTestCase (testCtx, "line_strip", "Verify line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW)); + basic->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE)); + basic->addChild(new LineInterpolationTestCase (testCtx, "line_strip_wide","Verify wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE)); + } + + // .projected + { + tcu::TestCaseGroup* const projected = new tcu::TestCaseGroup(testCtx, "projected", "Projective interpolation"); + + interpolation->addChild(projected); + + projected->addChild(new TriangleInterpolationTestCase (testCtx, "triangles", "Verify triangle interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, INTERPOLATIONFLAGS_PROJECTED)); + projected->addChild(new TriangleInterpolationTestCase (testCtx, "triangle_strip", "Verify triangle strip interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, INTERPOLATIONFLAGS_PROJECTED)); + projected->addChild(new TriangleInterpolationTestCase (testCtx, "triangle_fan", "Verify triangle fan interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, INTERPOLATIONFLAGS_PROJECTED)); + projected->addChild(new LineInterpolationTestCase (testCtx, "lines", "Verify line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW)); + projected->addChild(new LineInterpolationTestCase (testCtx, "line_strip", "Verify line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW)); + projected->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE)); + projected->addChild(new LineInterpolationTestCase (testCtx, "line_strip_wide","Verify wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE)); + } + } + + // .flatshading + { + tcu::TestCaseGroup* const flatshading = new tcu::TestCaseGroup(testCtx, "flatshading", "Test flatshading"); + + rasterizationTests->addChild(flatshading); + + flatshading->addChild(new TriangleInterpolationTestCase (testCtx, "triangles", "Verify triangle flatshading", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, INTERPOLATIONFLAGS_FLATSHADE)); + flatshading->addChild(new TriangleInterpolationTestCase (testCtx, "triangle_strip", "Verify triangle strip flatshading", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, INTERPOLATIONFLAGS_FLATSHADE)); + flatshading->addChild(new TriangleInterpolationTestCase (testCtx, "triangle_fan", "Verify triangle fan flatshading", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, INTERPOLATIONFLAGS_FLATSHADE)); + flatshading->addChild(new LineInterpolationTestCase (testCtx, "lines", "Verify line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW)); + flatshading->addChild(new LineInterpolationTestCase (testCtx, "line_strip", "Verify line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW)); + flatshading->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE)); + flatshading->addChild(new LineInterpolationTestCase (testCtx, "line_strip_wide","Verify wide line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE)); + } + + const VkSampleCountFlagBits samples[] = + { + VK_SAMPLE_COUNT_2_BIT, + VK_SAMPLE_COUNT_4_BIT, + VK_SAMPLE_COUNT_8_BIT, + VK_SAMPLE_COUNT_16_BIT, + VK_SAMPLE_COUNT_32_BIT, + VK_SAMPLE_COUNT_64_BIT + }; + + for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++) + { + std::ostringstream caseName; + + caseName << "_multisample_" << (2 << samplesNdx) << "_bit"; + + // .primitives + { + tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(testCtx, ("primitives" + caseName.str()).c_str(), "Primitive rasterization"); + + rasterizationTests->addChild(primitives); + + primitives->addChild(new BaseTestCase (testCtx, "triangles", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result", samples[samplesNdx])); + primitives->addChild(new WidenessTestCase (testCtx, "lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result", PRIMITIVEWIDENESS_NARROW, samples[samplesNdx])); + primitives->addChild(new WidenessTestCase (testCtx, "lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, samples[samplesNdx])); + primitives->addChild(new WidenessTestCase (testCtx, "points", "Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result", PRIMITIVEWIDENESS_WIDE, samples[samplesNdx])); + } + + // .fill_rules + { + tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(testCtx, ("fill_rules" + caseName.str()).c_str(), "Primitive fill rules"); + + rasterizationTests->addChild(fillRules); + + fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_BASIC, samples[samplesNdx])); + fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad_reverse", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_REVERSED, samples[samplesNdx])); + fillRules->addChild(new FillRuleTestCase(testCtx, "clipped_full", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_CLIPPED_FULL, samples[samplesNdx])); + fillRules->addChild(new FillRuleTestCase(testCtx, "clipped_partly", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_CLIPPED_PARTIAL, samples[samplesNdx])); + fillRules->addChild(new FillRuleTestCase(testCtx, "projected", "Verify fill rules", FillRuleTestInstance::FILLRULECASE_PROJECTED, samples[samplesNdx])); + } + + // .interpolation + { + tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(testCtx, ("interpolation" + caseName.str()).c_str(), "Test interpolation"); + + rasterizationTests->addChild(interpolation); + + interpolation->addChild(new TriangleInterpolationTestCase (testCtx, "triangles", "Verify triangle interpolation", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, INTERPOLATIONFLAGS_NONE, samples[samplesNdx])); + interpolation->addChild(new LineInterpolationTestCase (testCtx, "lines", "Verify line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, samples[samplesNdx])); + interpolation->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, samples[samplesNdx])); + } + } +} + +} // anonymous + +tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx) +{ + return createTestGroup(testCtx, "rasterization", "Rasterization Tests", createRasterizationTests); +} + +} // rasterization +} // vkt diff --git a/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.hpp b/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.hpp new file mode 100644 index 0000000..61138e1 --- /dev/null +++ b/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.hpp @@ -0,0 +1,41 @@ +#ifndef _VKTRASTERIZATIONTESTS_HPP +#define _VKTRASTERIZATIONTESTS_HPP +/*------------------------------------------------------------------------ + * Vulkan Conformance Tests + * ------------------------ + * + * Copyright (c) 2016 The Khronos Group Inc. + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2014 The Android Open Source Project + * + * 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 Functional rasterization tests. + *//*--------------------------------------------------------------------*/ + +#include "tcuDefs.hpp" +#include "tcuTestCase.hpp" + +namespace vkt +{ +namespace rasterization +{ + +tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx); + +} // rasterization +} // vkt + +#endif // _VKTRASTERIZATIONTESTS_HPP diff --git a/external/vulkancts/modules/vulkan/vktTestPackage.cpp b/external/vulkancts/modules/vulkan/vktTestPackage.cpp index 8277e91..0bb1689 100644 --- a/external/vulkancts/modules/vulkan/vktTestPackage.cpp +++ b/external/vulkancts/modules/vulkan/vktTestPackage.cpp @@ -67,6 +67,7 @@ #include "vktSynchronization.hpp" #include "vktSparseResourcesTests.hpp" #include "vktTessellationTests.hpp" +#include "vktRasterizationTests.hpp" #include #include @@ -380,6 +381,7 @@ void TestPackage::init (void) addChild(createSynchronizationTests (m_testCtx)); addChild(sparse::createTests (m_testCtx)); addChild(tessellation::createTests (m_testCtx)); + addChild(rasterization::createTests (m_testCtx)); } } // vkt diff --git a/framework/common/CMakeLists.txt b/framework/common/CMakeLists.txt index 61f0399..3266413 100644 --- a/framework/common/CMakeLists.txt +++ b/framework/common/CMakeLists.txt @@ -89,6 +89,8 @@ set(TCUTIL_SRCS tcuTestHierarchyUtil.hpp tcuAstcUtil.cpp tcuAstcUtil.hpp + tcuRasterizationVerifier.cpp + tcuRasterizationVerifier.hpp ) set(TCUTIL_LIBS diff --git a/modules/glshared/glsRasterizationTestUtil.cpp b/framework/common/tcuRasterizationVerifier.cpp similarity index 98% rename from modules/glshared/glsRasterizationTestUtil.cpp rename to framework/common/tcuRasterizationVerifier.cpp index b55df3b..77df56c 100644 --- a/modules/glshared/glsRasterizationTestUtil.cpp +++ b/framework/common/tcuRasterizationVerifier.cpp @@ -1,6 +1,6 @@ /*------------------------------------------------------------------------- - * drawElements Quality Program OpenGL (ES) Module - * ----------------------------------------------- + * drawElements Quality Program Tester Core + * ---------------------------------------- * * Copyright 2014 The Android Open Source Project * @@ -18,10 +18,10 @@ * *//*! * \file - * \brief rasterization test utils. + * \brief Rasterization verifier utils. *//*--------------------------------------------------------------------*/ -#include "glsRasterizationTestUtil.hpp" +#include "tcuRasterizationVerifier.hpp" #include "tcuVector.hpp" #include "tcuSurface.hpp" #include "tcuTestLog.hpp" @@ -34,11 +34,7 @@ #include -namespace deqp -{ -namespace gls -{ -namespace RasterizationTestUtil +namespace tcu { namespace { @@ -612,7 +608,6 @@ struct MultisampleLineInterpolator InterpolationRange interpolate (int primitiveNdx, const tcu::IVec2 pixel, const tcu::IVec2 viewportSize, bool multisample, int subpixelBits) const { - DE_ASSERT(multisample); DE_UNREF(multisample); DE_UNREF(subpixelBits); @@ -867,7 +862,52 @@ bool verifyTriangleGroupInterpolationWithInterpolator (const tcu::Surface& surfa } } -bool verifyMultisampleLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log) + +float calculateIntersectionParameter (const tcu::Vec2 line[2], float w, int componentNdx) +{ + DE_ASSERT(componentNdx < 2); + if (line[1][componentNdx] == line[0][componentNdx]) + return -1.0f; + + return (w - line[0][componentNdx]) / (line[1][componentNdx] - line[0][componentNdx]); +} + +// Clips the given line with a ((-w, -w), (-w, w), (w, w), (w, -w)) rectangle +void applyClippingBox (tcu::Vec2 line[2], float w) +{ + for (int side = 0; side < 4; ++side) + { + const int sign = ((side / 2) * -2) + 1; + const int component = side % 2; + const float t = calculateIntersectionParameter(line, w * sign, component); + + if (t > 0 && t < 1) + { + float newCoord = t * line[1][1 - component] + (1 - t) * line[0][1 - component]; + + if (line[1][component] > w * sign) + { + line[1 - side / 2][component] = w * sign; + line[1 - side / 2][1 - component] = newCoord; + } + else + { + line[side / 2][component] = w * sign; + line[side / 2][1 - component] = newCoord; + } + } + } +} + +enum ClipMode +{ + CLIPMODE_NO_CLIPPING = 0, + CLIPMODE_USE_CLIPPING_BOX, + + CLIPMODE_LAST +}; + +bool verifyMultisampleLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log, ClipMode clipMode) { // Multisampled line == 2 triangles @@ -879,11 +919,17 @@ bool verifyMultisampleLineGroupRasterization (const tcu::Surface& surface, const for (int lineNdx = 0; lineNdx < (int)scene.lines.size(); ++lineNdx) { // Transform to screen space, add pixel offsets, convert back to normalized device space, and test as triangles - const tcu::Vec2 lineNormalizedDeviceSpace[2] = + tcu::Vec2 lineNormalizedDeviceSpace[2] = { tcu::Vec2(scene.lines[lineNdx].positions[0].x() / scene.lines[lineNdx].positions[0].w(), scene.lines[lineNdx].positions[0].y() / scene.lines[lineNdx].positions[0].w()), tcu::Vec2(scene.lines[lineNdx].positions[1].x() / scene.lines[lineNdx].positions[1].w(), scene.lines[lineNdx].positions[1].y() / scene.lines[lineNdx].positions[1].w()), }; + + if (clipMode == CLIPMODE_USE_CLIPPING_BOX) + { + applyClippingBox(lineNormalizedDeviceSpace, 1.0f); + } + const tcu::Vec2 lineScreenSpace[2] = { (lineNormalizedDeviceSpace[0] + tcu::Vec2(1.0f, 1.0f)) * 0.5f * viewportSize, @@ -2356,11 +2402,16 @@ bool verifyLineGroupRasterization (const tcu::Surface& surface, const LineSceneS const bool multisampled = args.numSamples != 0; if (multisampled) - return verifyMultisampleLineGroupRasterization(surface, scene, args, log); + return verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_NO_CLIPPING); else return verifySinglesampleLineGroupRasterization(surface, scene, args, log); } +bool verifyClippedTriangulatedLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log) +{ + return verifyMultisampleLineGroupRasterization(surface, scene, args, log, CLIPMODE_USE_CLIPPING_BOX); +} + bool verifyPointGroupRasterization (const tcu::Surface& surface, const PointSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log) { // Splitting to triangles is a valid solution in multisampled cases and even in non-multisample cases too. @@ -2407,6 +2458,9 @@ LineInterpolationMethod verifyLineGroupInterpolation (const tcu::Surface& surfac } } -} // StateQueryUtil -} // gls -} // deqp +bool verifyTriangulatedLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log) +{ + return verifyMultisampleLineGroupInterpolation(surface, scene, args, log); +} + +} // tcu diff --git a/modules/glshared/glsRasterizationTestUtil.hpp b/framework/common/tcuRasterizationVerifier.hpp similarity index 78% rename from modules/glshared/glsRasterizationTestUtil.hpp rename to framework/common/tcuRasterizationVerifier.hpp index af86283..31f88f8 100644 --- a/modules/glshared/glsRasterizationTestUtil.hpp +++ b/framework/common/tcuRasterizationVerifier.hpp @@ -1,8 +1,8 @@ -#ifndef _GLSRASTERIZATIONTESTUTIL_HPP -#define _GLSRASTERIZATIONTESTUTIL_HPP +#ifndef _TCURASTERIZATIONVERIFIER_HPP +#define _TCURASTERIZATIONVERIFIER_HPP /*------------------------------------------------------------------------- - * drawElements Quality Program OpenGL (ES) Module - * ----------------------------------------------- + * drawElements Quality Program Tester Core + * ---------------------------------------- * * Copyright 2014 The Android Open Source Project * @@ -20,20 +20,16 @@ * *//*! * \file - * \brief rasterization test utils. + * \brief Rasterization verifier utils. *//*--------------------------------------------------------------------*/ -#include "deMath.h" #include "tcuDefs.hpp" #include "tcuTestLog.hpp" +#include "deMath.h" #include -namespace deqp -{ -namespace gls -{ -namespace RasterizationTestUtil +namespace tcu { enum CoverageType @@ -137,6 +133,19 @@ bool verifyTriangleGroupRasterization (const tcu::Surface& surface, const Triang bool verifyLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log); /*--------------------------------------------------------------------*//*! + * \brief Verify clipped line rasterization result + * Verifies pixels in the surface are rasterized within the bounds given + * by RasterizationArguments and by clipping the lines with a (-1, -1), (1, 1) + * square. Lines should not be z-clipped. + * + * Line colors are not used. The line is expected to be white. Lines are + * rasterized as two triangles. + * + * Returns false if invalid rasterization is found. + *//*--------------------------------------------------------------------*/ +bool verifyClippedTriangulatedLineGroupRasterization (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log); + +/*--------------------------------------------------------------------*//*! * \brief Verify point rasterization result * Verifies points in the surface are rasterized within the bounds given * by RasterizationArguments. Points should not be z-clipped. @@ -169,8 +178,18 @@ bool verifyTriangleGroupInterpolation (const tcu::Surface& surface, const Triang *//*--------------------------------------------------------------------*/ LineInterpolationMethod verifyLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log); -} // StateQueryUtil -} // gls -} // deqp +/*--------------------------------------------------------------------*//*! + * \brief Verify line color interpolation is valid + * Verifies the color of a fragments of a colored line is in the + * valid range. Lines should not be z-clipped. + * + * The background is expected to be black. The lines are rasterized + * as two triangles. + * + * Returns false if invalid rasterization interpolation is found. + *//*--------------------------------------------------------------------*/ +bool verifyTriangulatedLineGroupInterpolation (const tcu::Surface& surface, const LineSceneSpec& scene, const RasterizationArguments& args, tcu::TestLog& log); + +} // tcu -#endif // _GLSRASTERIZATIONTESTUTIL_HPP +#endif // _TCURASTERIZATIONVERIFIER_HPP diff --git a/modules/gles2/functional/es2fRasterizationTests.cpp b/modules/gles2/functional/es2fRasterizationTests.cpp index e9529a9..5f8c1c5 100644 --- a/modules/gles2/functional/es2fRasterizationTests.cpp +++ b/modules/gles2/functional/es2fRasterizationTests.cpp @@ -22,7 +22,7 @@ *//*--------------------------------------------------------------------*/ #include "es2fRasterizationTests.hpp" -#include "glsRasterizationTestUtil.hpp" +#include "tcuRasterizationVerifier.hpp" #include "tcuSurface.hpp" #include "tcuRenderTarget.hpp" #include "tcuVectorUtil.hpp" @@ -48,7 +48,11 @@ namespace Functional namespace { -using namespace gls::RasterizationTestUtil; +using tcu::RasterizationArguments; +using tcu::TriangleSceneSpec; +using tcu::PointSceneSpec; +using tcu::LineSceneSpec; +using tcu::LineInterpolationMethod; static const char* const s_shaderVertexTemplate = "attribute highp vec4 a_position;\n" "attribute highp vec4 a_color;\n" @@ -1284,7 +1288,7 @@ CullingTest::IterateResult CullingTest::iterate (void) scene.triangles.swap(triangles); - if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), VERIFICATIONMODE_WEAK)) + if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_WEAK)) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering"); @@ -1667,12 +1671,12 @@ LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void) iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()); switch (iterationResult) { - case LINEINTERPOLATION_STRICTLY_CORRECT: + case tcu::LINEINTERPOLATION_STRICTLY_CORRECT: // line interpolation matches the specification m_result.addResult(QP_TEST_RESULT_PASS, "Pass"); break; - case LINEINTERPOLATION_PROJECTED: + case tcu::LINEINTERPOLATION_PROJECTED: // line interpolation weights are otherwise correct, but they are projected onto major axis m_testCtx.getLog() << tcu::TestLog::Message << "Interpolation was calculated using coordinates projected onto major axis. " @@ -1681,7 +1685,7 @@ LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void) m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Interpolation was calculated using projected coordinateds"); break; - case LINEINTERPOLATION_INCORRECT: + case tcu::LINEINTERPOLATION_INCORRECT: if (scene.lineWidth != 1.0f && m_numSamples > 1) { // multisampled wide lines might not be supported diff --git a/modules/gles3/functional/es3fRasterizationTests.cpp b/modules/gles3/functional/es3fRasterizationTests.cpp index 52286f9..b7705ea 100644 --- a/modules/gles3/functional/es3fRasterizationTests.cpp +++ b/modules/gles3/functional/es3fRasterizationTests.cpp @@ -22,7 +22,7 @@ *//*--------------------------------------------------------------------*/ #include "es3fRasterizationTests.hpp" -#include "glsRasterizationTestUtil.hpp" +#include "tcuRasterizationVerifier.hpp" #include "tcuSurface.hpp" #include "tcuRenderTarget.hpp" #include "tcuVectorUtil.hpp" @@ -50,7 +50,11 @@ namespace Functional namespace { -using namespace gls::RasterizationTestUtil; +using tcu::RasterizationArguments; +using tcu::TriangleSceneSpec; +using tcu::PointSceneSpec; +using tcu::LineSceneSpec; +using tcu::LineInterpolationMethod; static const char* const s_shaderVertexTemplate = "#version 300 es\n" "in highp vec4 a_position;\n" @@ -1561,7 +1565,7 @@ CullingTest::IterateResult CullingTest::iterate (void) scene.triangles.swap(triangles); - if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), VERIFICATIONMODE_WEAK)) + if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_WEAK)) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering"); @@ -2017,12 +2021,12 @@ LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void) iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()); switch (iterationResult) { - case LINEINTERPOLATION_STRICTLY_CORRECT: + case tcu::LINEINTERPOLATION_STRICTLY_CORRECT: // line interpolation matches the specification m_result.addResult(QP_TEST_RESULT_PASS, "Pass"); break; - case LINEINTERPOLATION_PROJECTED: + case tcu::LINEINTERPOLATION_PROJECTED: // line interpolation weights are otherwise correct, but they are projected onto major axis m_testCtx.getLog() << tcu::TestLog::Message << "Interpolation was calculated using coordinates projected onto major axis. " @@ -2031,7 +2035,7 @@ LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void) m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Interpolation was calculated using projected coordinateds"); break; - case LINEINTERPOLATION_INCORRECT: + case tcu::LINEINTERPOLATION_INCORRECT: if (scene.lineWidth != 1.0f && m_numSamples > 1) { // multisampled wide lines might not be supported diff --git a/modules/gles31/functional/es31fTextureMultisampleTests.cpp b/modules/gles31/functional/es31fTextureMultisampleTests.cpp index 88bede3..bf9a51d 100644 --- a/modules/gles31/functional/es31fTextureMultisampleTests.cpp +++ b/modules/gles31/functional/es31fTextureMultisampleTests.cpp @@ -28,7 +28,7 @@ #include "tcuStringTemplate.hpp" #include "tcuTextureUtil.hpp" #include "glsStateQueryUtil.hpp" -#include "glsRasterizationTestUtil.hpp" +#include "tcuRasterizationVerifier.hpp" #include "gluRenderContext.hpp" #include "gluCallLogWrapper.hpp" #include "gluObjectWrapper.hpp" @@ -42,8 +42,6 @@ #include "deRandom.hpp" using namespace glw; -using deqp::gls::RasterizationTestUtil::RasterizationArguments; -using deqp::gls::RasterizationTestUtil::TriangleSceneSpec; namespace deqp { @@ -54,6 +52,9 @@ namespace Functional namespace { +using tcu::RasterizationArguments; +using tcu::TriangleSceneSpec; + static std::string sampleMaskToString (const std::vector& bitfield, int numBits) { std::string result(numBits, '0'); @@ -456,7 +457,7 @@ bool SamplePosRasterizationTest::testMultisampleTexture (int sampleNdx) args.numSamples = 0; args.subpixelBits = m_subpixelBits; - return gls::RasterizationTestUtil::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(), deqp::gls::RasterizationTestUtil::VERIFICATIONMODE_STRICT); + return tcu::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_STRICT); } } diff --git a/modules/glshared/CMakeLists.txt b/modules/glshared/CMakeLists.txt index ebec662..2542646 100644 --- a/modules/glshared/CMakeLists.txt +++ b/modules/glshared/CMakeLists.txt @@ -51,8 +51,6 @@ set(DEQP_GL_SHARED_SRCS glsSamplerObjectTest.cpp glsShaderPerformanceMeasurer.cpp glsShaderPerformanceMeasurer.hpp - glsRasterizationTestUtil.cpp - glsRasterizationTestUtil.hpp glsInteractionTestUtil.cpp glsInteractionTestUtil.hpp glsRandomShaderProgram.cpp -- 2.7.4