blob: a174b8001c47a94136fead3ab4d40c6dd280ba90 [file] [log] [blame]
/*------------------------------------------------------------------------
* 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 "vktTestGroupUtil.hpp"
#include "vktAmberTestCase.hpp"
#include "vktRasterizationTests.hpp"
#include "vktRasterizationFragShaderSideEffectsTests.hpp"
#ifndef CTS_USES_VULKANSC
#include "vktRasterizationProvokingVertexTests.hpp"
#endif // CTS_USES_VULKANSC
#include "tcuRasterizationVerifier.hpp"
#include "tcuSurface.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuResultCollector.hpp"
#include "tcuFloatFormat.hpp"
#include "vkImageUtil.hpp"
#include "deStringUtil.hpp"
#include "deRandom.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkBufferWithMemory.hpp"
#include "vkImageWithMemory.hpp"
#include "vkBarrierUtil.hpp"
#include <vector>
#include <sstream>
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 ResolutionValues
{
RESOLUTION_POT = 256,
RESOLUTION_NPOT = 258
};
enum PrimitiveWideness
{
PRIMITIVEWIDENESS_NARROW = 0,
PRIMITIVEWIDENESS_WIDE,
PRIMITIVEWIDENESS_LAST
};
enum LineStipple
{
LINESTIPPLE_DISABLED = 0,
LINESTIPPLE_STATIC,
LINESTIPPLE_DYNAMIC,
LINESTIPPLE_LAST
};
static const deUint32 lineStippleFactor = 2;
static const deUint32 lineStipplePattern = 0x0F0F;
enum class LineStippleFactorCase
{
DEFAULT = 0,
ZERO,
LARGE,
};
enum PrimitiveStrictness
{
PRIMITIVESTRICTNESS_STRICT = 0,
PRIMITIVESTRICTNESS_NONSTRICT,
PRIMITIVESTRICTNESS_IGNORE,
PRIMITIVESTRICTNESS_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<std::string, std::string> 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:
BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deUint32 renderSize = RESOLUTION_POT, VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM, deUint32 additionalRenderSize = 0);
~BaseRenderingTestInstance (void);
protected:
void addImageTransitionBarrier (VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const;
virtual void drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology);
void drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, const std::vector<tcu::Vec4>& coloDrata, VkPrimitiveTopology primitiveTopology);
void drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology,
VkImage image, VkImage resolvedImage, VkFramebuffer frameBuffer, const deUint32 renderSize, VkBuffer resultBuffer, const Allocation& resultBufferMemory);
virtual float getLineWidth (void) const;
virtual float getPointSize (void) const;
virtual bool getLineStippleDynamic (void) const { return false; }
virtual
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
virtual
VkPipelineRasterizationLineStateCreateInfoEXT initLineRasterizationStateCreateInfo (void) const;
virtual
const VkPipelineRasterizationLineStateCreateInfoEXT* getLineRasterizationStateCreateInfo (void);
virtual
const VkPipelineColorBlendStateCreateInfo* getColorBlendStateCreateInfo (void) const;
const tcu::TextureFormat& getTextureFormat (void) const;
const deUint32 m_renderSize;
const VkSampleCountFlagBits m_sampleCount;
deUint32 m_subpixelBits;
const deBool m_multisampling;
const VkFormat m_imageFormat;
const tcu::TextureFormat m_textureFormat;
Move<VkCommandPool> m_commandPool;
Move<VkImage> m_image;
de::MovePtr<Allocation> m_imageMemory;
Move<VkImageView> m_imageView;
Move<VkImage> m_resolvedImage;
de::MovePtr<Allocation> m_resolvedImageMemory;
Move<VkImageView> m_resolvedImageView;
Move<VkRenderPass> m_renderPass;
Move<VkFramebuffer> m_frameBuffer;
Move<VkDescriptorPool> m_descriptorPool;
Move<VkDescriptorSet> m_descriptorSet;
Move<VkDescriptorSetLayout> m_descriptorSetLayout;
Move<VkBuffer> m_uniformBuffer;
de::MovePtr<Allocation> m_uniformBufferMemory;
const VkDeviceSize m_uniformBufferSize;
Move<VkPipelineLayout> m_pipelineLayout;
Move<VkShaderModule> m_vertexShaderModule;
Move<VkShaderModule> m_fragmentShaderModule;
Move<VkBuffer> m_resultBuffer;
de::MovePtr<Allocation> m_resultBufferMemory;
const VkDeviceSize m_resultBufferSize;
const deUint32 m_additionalRenderSize;
const VkDeviceSize m_additionalResultBufferSize;
VkPipelineRasterizationLineStateCreateInfoEXT m_lineRasterizationStateInfo;
private:
virtual int getIteration (void) const { TCU_THROW(InternalError, "Iteration undefined in the base class"); }
};
BaseRenderingTestInstance::BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount, deUint32 renderSize, VkFormat imageFormat, deUint32 additionalRenderSize)
: 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 (imageFormat)
, m_textureFormat (vk::mapVkFormat(m_imageFormat))
, m_uniformBufferSize (sizeof(float))
, m_resultBufferSize (renderSize * renderSize * m_textureFormat.getPixelSize())
, m_additionalRenderSize(additionalRenderSize)
, m_additionalResultBufferSize(additionalRenderSize * additionalRenderSize * m_textureFormat.getPixelSize())
, m_lineRasterizationStateInfo ()
{
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
m_commandPool = createCommandPool(vkd, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
// 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;
makeComponentMappingRGBA(), // 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;
makeComponentMappingRGBA(), // 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_DONT_CARE, // 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);
}
// 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<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
{
// default to color white
const std::vector<tcu::Vec4> 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<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology)
{
drawPrimitives(result, positionData, colorData, primitiveTopology, *m_image, *m_resolvedImage, *m_frameBuffer, m_renderSize, *m_resultBuffer, *m_resultBufferMemory);
}
void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology,
VkImage image, VkImage resolvedImage, VkFramebuffer frameBuffer, const deUint32 renderSize, VkBuffer resultBuffer, const Allocation& resultBufferMemory)
{
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<VkCommandBuffer> commandBuffer;
Move<VkPipeline> graphicsPipeline;
Move<VkBuffer> vertexBuffer;
de::MovePtr<Allocation> vertexBufferMemory;
const VkPhysicalDeviceProperties properties = m_context.getDeviceProperties();
if (attributeBatchSize > properties.limits.maxVertexInputAttributeOffset)
{
std::stringstream message;
message << "Larger vertex input attribute offset is needed (" << attributeBatchSize << ") than the available maximum (" << properties.limits.maxVertexInputAttributeOffset << ").";
TCU_THROW(NotSupportedError, message.str().c_str());
}
// Create Graphics Pipeline
{
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 std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(renderSize)));
const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(renderSize)));
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;
};
VkPipelineRasterizationStateCreateInfo rasterizationStateInfo = *getRasterizationStateCreateInfo();
const VkPipelineRasterizationLineStateCreateInfoEXT* lineRasterizationStateInfo = getLineRasterizationStateCreateInfo();
if (lineRasterizationStateInfo != DE_NULL && lineRasterizationStateInfo->sType != 0)
appendStructurePtrToVulkanChain(&rasterizationStateInfo.pNext, lineRasterizationStateInfo);
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineDynamicStateCreateFlags flags
0u, // deUint32 dynamicStateCount
DE_NULL // const VkDynamicState* pDynamicStates
};
VkDynamicState dynamicState = VK_DYNAMIC_STATE_LINE_STIPPLE_EXT;
if (getLineStippleDynamic())
{
dynamicStateCreateInfo.dynamicStateCount = 1;
dynamicStateCreateInfo.pDynamicStates = &dynamicState;
}
graphicsPipeline = makeGraphicsPipeline(vkd, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayout, // const VkPipelineLayout pipelineLayout
*m_vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
*m_renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
primitiveTopology, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
&rasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
&multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo,
getColorBlendStateCreateInfo(), // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo,
&dynamicStateCreateInfo); // const VkPipelineDynamicStateCreateInfo* dynamicStateCreateInfo
}
// 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<deUint8*>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, colorData.data(), attributeBatchSize);
flushAlloc(vkd, vkDevice, *vertexBufferMemory);
}
// Create Command Buffer
commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
// Begin Command Buffer
beginCommandBuffer(vkd, *commandBuffer);
addImageTransitionBarrier(*commandBuffer, 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, 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
beginRenderPass(vkd, *commandBuffer, *m_renderPass, frameBuffer, vk::makeRect2D(0, 0, renderSize, renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
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);
if (getLineStippleDynamic())
vkd.cmdSetLineStippleEXT(*commandBuffer, lineStippleFactor, lineStipplePattern);
vkd.cmdDraw(*commandBuffer, (deUint32)positionData.size(), 1, 0, 0);
endRenderPass(vkd, *commandBuffer);
// Copy Image
copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? resolvedImage : image, resultBuffer, tcu::IVec2(renderSize, renderSize));
endCommandBuffer(vkd, *commandBuffer);
// Set Point Size
{
float pointSize = getPointSize();
deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
}
// Submit
submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
invalidateAlloc(vkd, vkDevice, resultBufferMemory);
tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(renderSize, renderSize, 1), 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;
}
VkPipelineRasterizationLineStateCreateInfoEXT BaseRenderingTestInstance::initLineRasterizationStateCreateInfo (void) const
{
VkPipelineRasterizationLineStateCreateInfoEXT lineRasterizationStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, // VkLineRasterizationModeEXT lineRasterizationMode;
VK_FALSE, // VkBool32 stippledLineEnable;
1, // uint32_t lineStippleFactor;
0xFFFF, // uint16_t lineStipplePattern;
};
return lineRasterizationStateInfo;
}
const VkPipelineRasterizationLineStateCreateInfoEXT* BaseRenderingTestInstance::getLineRasterizationStateCreateInfo (void)
{
if (m_lineRasterizationStateInfo.sType != VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT)
m_lineRasterizationStateInfo = initLineRasterizationStateCreateInfo();
return &m_lineRasterizationStateInfo;
}
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, deUint32 renderSize = RESOLUTION_POT);
virtual tcu::TestStatus iterate (void);
protected:
int getIteration (void) const { return m_iteration; }
int getIterationCount (void) const { return m_iterationCount; }
private:
virtual void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) = DE_NULL;
virtual bool compareAndVerify (std::vector<TriangleSceneSpec::SceneTriangle>& triangles,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer);
int m_iteration;
const int m_iterationCount;
VkPrimitiveTopology m_primitiveTopology;
bool m_allIterationsPassed;
};
BaseTriangleTestInstance::BaseTriangleTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount, deUint32 renderSize)
: BaseRenderingTestInstance (context, sampleCount, renderSize)
, 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<tcu::Vec4> drawBuffer;
std::vector<TriangleSceneSpec::SceneTriangle> triangles;
generateTriangles(m_iteration, drawBuffer, triangles);
// draw image
drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
// compare
{
const bool compareOk = compareAndVerify(triangles, resultImage, drawBuffer);
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();
}
bool BaseTriangleTestInstance::compareAndVerify (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage, std::vector<tcu::Vec4>&)
{
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);
return verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
}
class BaseLineTestInstance : public BaseRenderingTestInstance
{
public:
BaseLineTestInstance (Context& context,
VkPrimitiveTopology primitiveTopology,
PrimitiveWideness wideness,
PrimitiveStrictness strictness,
VkSampleCountFlagBits sampleCount,
LineStipple stipple,
VkLineRasterizationModeEXT lineRasterizationMode,
LineStippleFactorCase stippleFactor,
const deUint32 additionalRenderSize = 0,
const deUint32 renderSize = RESOLUTION_POT,
const float narrowLineWidth = 1.0f);
virtual tcu::TestStatus iterate (void);
virtual float getLineWidth (void) const;
bool getLineStippleEnable (void) const { return m_stipple != LINESTIPPLE_DISABLED; }
virtual bool getLineStippleDynamic (void) const { return m_stipple == LINESTIPPLE_DYNAMIC; }
virtual
VkPipelineRasterizationLineStateCreateInfoEXT initLineRasterizationStateCreateInfo (void) const;
virtual
const VkPipelineRasterizationLineStateCreateInfoEXT* getLineRasterizationStateCreateInfo (void);
protected:
int getIteration (void) const { return m_iteration; }
int getIterationCount (void) const { return m_iterationCount; }
private:
virtual void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) = DE_NULL;
virtual bool compareAndVerify (std::vector<LineSceneSpec::SceneLine>& lines,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer);
bool resultHasAlpha (tcu::Surface& result);
int m_iteration;
const int m_iterationCount;
VkPrimitiveTopology m_primitiveTopology;
const PrimitiveWideness m_primitiveWideness;
const PrimitiveStrictness m_primitiveStrictness;
bool m_allIterationsPassed;
bool m_qualityWarning;
float m_maxLineWidth;
std::vector<float> m_lineWidths;
LineStipple m_stipple;
VkLineRasterizationModeEXT m_lineRasterizationMode;
LineStippleFactorCase m_stippleFactor;
Move<VkImage> m_additionalImage;
de::MovePtr<Allocation> m_additionalImageMemory;
Move<VkImageView> m_additionalImageView;
Move<VkImage> m_additionalResolvedImage;
de::MovePtr<Allocation> m_additionalResolvedImageMemory;
Move<VkImageView> m_additionalResolvedImageView;
Move<VkFramebuffer> m_additionalFrameBuffer;
Move<VkBuffer> m_additionalResultBuffer;
de::MovePtr<Allocation> m_additionalResultBufferMemory;
};
BaseLineTestInstance::BaseLineTestInstance (Context& context,
VkPrimitiveTopology primitiveTopology,
PrimitiveWideness wideness,
PrimitiveStrictness strictness,
VkSampleCountFlagBits sampleCount,
LineStipple stipple,
VkLineRasterizationModeEXT lineRasterizationMode,
LineStippleFactorCase stippleFactor,
const deUint32 additionalRenderSize,
const deUint32 renderSize,
const float narrowLineWidth)
: BaseRenderingTestInstance (context, sampleCount, renderSize, VK_FORMAT_R8G8B8A8_UNORM, additionalRenderSize)
, m_iteration (0)
, m_iterationCount (3)
, m_primitiveTopology (primitiveTopology)
, m_primitiveWideness (wideness)
, m_primitiveStrictness (strictness)
, m_allIterationsPassed (true)
, m_qualityWarning (false)
, m_maxLineWidth (1.0f)
, m_stipple (stipple)
, m_lineRasterizationMode (lineRasterizationMode)
, m_stippleFactor (stippleFactor)
{
DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
if (m_lineRasterizationMode != VK_LINE_RASTERIZATION_MODE_EXT_LAST)
{
if (context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"))
{
VkPhysicalDeviceLineRasterizationPropertiesEXT lineRasterizationProperties =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT, // VkStructureType sType;
DE_NULL, // void* pNext;
0u, // deUint32 lineSubPixelPrecisionBits;
};
VkPhysicalDeviceProperties2 deviceProperties2;
deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
deviceProperties2.pNext = &lineRasterizationProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &deviceProperties2);
m_subpixelBits = lineRasterizationProperties.lineSubPixelPrecisionBits;
}
}
// create line widths
if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
{
m_lineWidths.resize(m_iterationCount, narrowLineWidth);
// Bump up m_maxLineWidth for conservative rasterization
if (narrowLineWidth > m_maxLineWidth)
m_maxLineWidth = narrowLineWidth;
}
else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
{
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;
DE_ASSERT(range[1] > 1.0f);
// set hand picked sizes
m_lineWidths.push_back(5.0f);
m_lineWidths.push_back(10.0f);
// Do not pick line width with 0.5 fractional value as rounding direction is not defined.
if (deFloatFrac(range[1]) == 0.5f)
{
m_lineWidths.push_back(range[1] - context.getDeviceProperties().limits.lineWidthGranularity);
}
else
{
m_lineWidths.push_back(range[1]);
}
DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
m_maxLineWidth = range[1];
}
else
DE_ASSERT(false);
// Create image, image view and frame buffer for testing at an additional resolution if required.
if (m_additionalRenderSize != 0)
{
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;
{
const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
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_additionalRenderSize, m_additionalRenderSize, 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_additionalImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
m_additionalImageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_additionalImage), MemoryRequirement::Any);
VK_CHECK(vkd.bindImageMemory(vkDevice, *m_additionalImage, m_additionalImageMemory->getMemory(), m_additionalImageMemory->getOffset()));
}
// Image View
{
const VkImageViewCreateInfo imageViewCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_additionalImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_imageFormat, // VkFormat format;
makeComponentMappingRGBA(), // VkComponentMapping components;
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
m_additionalImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
}
if (m_multisampling)
{
{
const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
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_additionalRenderSize, m_additionalRenderSize, 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_additionalResolvedImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
m_additionalResolvedImageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_additionalResolvedImage), MemoryRequirement::Any);
VK_CHECK(vkd.bindImageMemory(vkDevice, *m_additionalResolvedImage, m_additionalResolvedImageMemory->getMemory(), m_additionalResolvedImageMemory->getOffset()));
}
// Image view
{
const VkImageViewCreateInfo imageViewCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_additionalResolvedImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_imageFormat, // VkFormat format;
makeComponentMappingRGBA(), // VkComponentMapping components;
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
m_additionalResolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
}
}
{
const VkImageView attachments[] =
{
*m_additionalImageView,
*m_additionalResolvedImageView
};
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_additionalRenderSize, // deUint32 width;
m_additionalRenderSize, // deUint32 height;
1u, // deUint32 layers;
};
m_additionalFrameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL);
}
// Framebuffer
{
const VkBufferCreateInfo bufferCreateInfo =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_additionalResultBufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
m_additionalResultBuffer = createBuffer(vkd, vkDevice, &bufferCreateInfo);
m_additionalResultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_additionalResultBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_additionalResultBuffer, m_additionalResultBufferMemory->getMemory(), m_additionalResultBufferMemory->getOffset()));
}
}
}
bool BaseLineTestInstance::resultHasAlpha(tcu::Surface& resultImage)
{
bool hasAlpha = false;
for (int y = 0; y < resultImage.getHeight() && !hasAlpha; ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
{
const tcu::RGBA color = resultImage.getPixel(x, y);
if (color.getAlpha() > 0 && color.getAlpha() < 0xFF)
{
hasAlpha = true;
break;
}
}
return hasAlpha;
}
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<tcu::Vec4> drawBuffer;
std::vector<LineSceneSpec::SceneLine> lines;
// supported?
if (lineWidth <= m_maxLineWidth)
{
// gen data
generateLines(m_iteration, drawBuffer, lines);
// draw image
drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
// compare
{
const bool compareOk = compareAndVerify(lines, resultImage, drawBuffer);
if (!compareOk)
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::fail("Incorrect rasterization");
else if (m_qualityWarning)
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality line rasterization");
else
return tcu::TestStatus::pass("Pass");
}
else
return tcu::TestStatus::incomplete();
}
bool BaseLineTestInstance::compareAndVerify (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
{
const float lineWidth = getLineWidth();
bool result = true;
tcu::Surface additionalResultImage (m_additionalRenderSize, m_additionalRenderSize);
RasterizationArguments args;
LineSceneSpec scene;
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
bool strict = m_primitiveStrictness == PRIMITIVESTRICTNESS_STRICT;
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;
scene.stippleEnable = getLineStippleEnable();
scene.stippleFactor = getLineStippleEnable() ? lineStippleFactor : 1;
scene.stipplePattern = getLineStippleEnable() ? lineStipplePattern : 0xFFFF;
scene.isStrip = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
scene.isSmooth = m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
scene.isRectangular = m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT ||
m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
// Choose verification mode. Smooth lines assume mostly over-rasterization (bloated lines with a falloff).
// Stippled lines lose some precision across segments in a strip, so need a weaker threshold than normal
// lines. For simple cases, check for an exact match (STRICT).
if (scene.isSmooth)
scene.verificationMode = tcu::VERIFICATIONMODE_SMOOTH;
else if (scene.stippleEnable)
scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
else
scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT)
{
// bresenham is "no AA" in GL, so set numSamples to zero.
args.numSamples = 0;
if (!verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog()))
result = false;
}
else
{
if (scene.isSmooth)
{
// Smooth lines get the fractional coverage multiplied into the alpha component,
// so do a sanity check to validate that there is at least one pixel in the image
// with a fractional opacity.
bool hasAlpha = resultHasAlpha(resultImage);
if (!hasAlpha)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Missing alpha transparency (failed)." << tcu::TestLog::EndMessage;
result = false;
}
}
if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), (0 == m_multisampling), strict))
{
// Retry with weaker verification. If it passes, consider it a quality warning.
scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), false, strict))
result = false;
else
m_qualityWarning = true;
}
if (m_additionalRenderSize != 0)
{
const std::vector<tcu::Vec4> colorData(drawBuffer.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
if (scene.isSmooth)
scene.verificationMode = tcu::VERIFICATIONMODE_SMOOTH;
else if (scene.stippleEnable)
scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
else
scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
drawPrimitives(additionalResultImage, drawBuffer, colorData, m_primitiveTopology, *m_additionalImage, *m_additionalResolvedImage, *m_additionalFrameBuffer, m_additionalRenderSize, *m_additionalResultBuffer, *m_additionalResultBufferMemory);
// Compare
if (!verifyRelaxedLineGroupRasterization(additionalResultImage, scene, args, m_context.getTestContext().getLog(), (0 == m_multisampling), strict))
{
if (strict)
{
result = false;
}
else
{
// Retry with weaker verification. If it passes, consider it a quality warning.
scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), (0 == m_multisampling), strict))
result = false;
else
m_qualityWarning = true;
}
}
}
}
return result;
}
float BaseLineTestInstance::getLineWidth (void) const
{
return m_lineWidths[m_iteration];
}
VkPipelineRasterizationLineStateCreateInfoEXT BaseLineTestInstance::initLineRasterizationStateCreateInfo (void) const
{
VkPipelineRasterizationLineStateCreateInfoEXT lineRasterizationStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
m_lineRasterizationMode, // VkLineRasterizationModeEXT lineRasterizationMode;
getLineStippleEnable() ? VK_TRUE : VK_FALSE, // VkBool32 stippledLineEnable;
1, // uint32_t lineStippleFactor;
0xFFFF, // uint16_t lineStipplePattern;
};
if (m_stipple == LINESTIPPLE_STATIC)
{
lineRasterizationStateInfo.lineStippleFactor = lineStippleFactor;
lineRasterizationStateInfo.lineStipplePattern = lineStipplePattern;
}
else if (m_stipple == LINESTIPPLE_DISABLED)
{
if (m_stippleFactor == LineStippleFactorCase::ZERO)
lineRasterizationStateInfo.lineStippleFactor = 0u;
else if (m_stippleFactor == LineStippleFactorCase::LARGE)
lineRasterizationStateInfo.lineStippleFactor = 0xFEDCBA98u;
}
return lineRasterizationStateInfo;
}
const VkPipelineRasterizationLineStateCreateInfoEXT* BaseLineTestInstance::getLineRasterizationStateCreateInfo (void)
{
if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_EXT_LAST)
return DE_NULL;
if (m_lineRasterizationStateInfo.sType != VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT)
m_lineRasterizationStateInfo = initLineRasterizationStateCreateInfo();
return &m_lineRasterizationStateInfo;
}
class PointTestInstance : public BaseRenderingTestInstance
{
public:
PointTestInstance (Context& context,
PrimitiveWideness wideness,
PrimitiveStrictness strictness, // ignored
VkSampleCountFlagBits sampleCount,
LineStipple stipple, // ignored
VkLineRasterizationModeEXT lineRasterizationMode, // ignored
LineStippleFactorCase stippleFactor, // ignored
deUint32 additionalRenderSize, // ignored
deUint32 renderSize = RESOLUTION_POT,
float pointSizeNarrow = 1.0f);
virtual tcu::TestStatus iterate (void);
virtual float getPointSize (void) const;
protected:
int getIteration (void) const { return m_iteration; }
int getIterationCount (void) const { return m_iterationCount; }
private:
virtual void generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints);
virtual bool compareAndVerify (std::vector<PointSceneSpec::ScenePoint>& points,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer);
int m_iteration;
const int m_iterationCount;
const PrimitiveWideness m_primitiveWideness;
bool m_allIterationsPassed;
float m_maxPointSize;
std::vector<float> m_pointSizes;
};
PointTestInstance::PointTestInstance (Context& context,
PrimitiveWideness wideness,
PrimitiveStrictness strictness,
VkSampleCountFlagBits sampleCount,
LineStipple stipple,
VkLineRasterizationModeEXT lineRasterizationMode,
LineStippleFactorCase stippleFactor,
deUint32 additionalRenderSize,
deUint32 renderSize,
float pointSizeNarrow)
: BaseRenderingTestInstance (context, sampleCount, renderSize)
, m_iteration (0)
, m_iterationCount (3)
, m_primitiveWideness (wideness)
, m_allIterationsPassed (true)
, m_maxPointSize (pointSizeNarrow)
{
DE_UNREF(strictness);
DE_UNREF(stipple);
DE_UNREF(lineRasterizationMode);
DE_UNREF(stippleFactor);
DE_UNREF(additionalRenderSize);
// create point sizes
if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
{
m_pointSizes.resize(m_iterationCount, pointSizeNarrow);
}
else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
{
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;
DE_ASSERT(range[1] > 1.0f);
// 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<tcu::Vec4> drawBuffer;
std::vector<PointSceneSpec::ScenePoint> points;
// supported?
if (pointSize <= m_maxPointSize)
{
// gen data
generatePoints(m_iteration, drawBuffer, points);
// draw image
drawPrimitives(resultImage, drawBuffer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
// compare
{
const bool compareOk = compareAndVerify(points, resultImage, drawBuffer);
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();
}
bool PointTestInstance::compareAndVerify (std::vector<PointSceneSpec::ScenePoint>& points,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer)
{
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);
DE_UNREF(drawBuffer);
return verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
}
float PointTestInstance::getPointSize (void) const
{
return m_pointSizes[m_iteration];
}
void PointTestInstance::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& 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 <typename ConcreteTestInstance>
class PointSizeTestCase : public BaseRenderingTestCase
{
public:
PointSizeTestCase (tcu::TestContext& context,
std::string& name,
std::string& description,
deUint32 renderSize,
float pointSize,
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_pointSize (pointSize)
, m_renderSize (renderSize)
{}
virtual TestInstance* createInstance (Context& context) const
{
VkPhysicalDeviceProperties properties (context.getDeviceProperties());
if (m_renderSize > properties.limits.maxViewportDimensions[0] || m_renderSize > properties.limits.maxViewportDimensions[1])
TCU_THROW(NotSupportedError , "Viewport dimensions not supported");
if (m_renderSize > properties.limits.maxFramebufferWidth || m_renderSize > properties.limits.maxFramebufferHeight)
TCU_THROW(NotSupportedError , "Framebuffer width/height not supported");
return new ConcreteTestInstance(context, m_renderSize, m_pointSize);
}
virtual void checkSupport (Context& context) const
{
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
}
protected:
const float m_pointSize;
const deUint32 m_renderSize;
};
class PointSizeTestInstance : public BaseRenderingTestInstance
{
public:
PointSizeTestInstance (Context& context, deUint32 renderSize, float pointSize);
virtual tcu::TestStatus iterate (void);
virtual float getPointSize (void) const;
private:
void generatePointData (PointSceneSpec::ScenePoint& outPoint);
void drawPoint (tcu::PixelBufferAccess& result, tcu::PointSceneSpec::ScenePoint& point);
bool verifyPoint (tcu::TestLog& log, tcu::PixelBufferAccess& access, float pointSize);
bool isPointSizeClamped (float pointSize, float maxPointSizeLimit);
const float m_pointSize;
const float m_maxPointSize;
const deUint32 m_renderSize;
const VkFormat m_format;
};
PointSizeTestInstance::PointSizeTestInstance (Context& context, deUint32 renderSize, float pointSize)
: BaseRenderingTestInstance (context, vk::VK_SAMPLE_COUNT_1_BIT, renderSize, VK_FORMAT_R8_UNORM)
, m_pointSize (pointSize)
, m_maxPointSize (context.getDeviceProperties().limits.pointSizeRange[1])
, m_renderSize (renderSize)
, m_format (VK_FORMAT_R8_UNORM) // Use single-channel format to minimize memory allocation when using large render targets
{
}
tcu::TestStatus PointSizeTestInstance::iterate (void)
{
tcu::TextureLevel resultBuffer (mapVkFormat(m_format), m_renderSize, m_renderSize);
tcu::PixelBufferAccess access (resultBuffer.getAccess());
PointSceneSpec::ScenePoint point;
// Generate data
generatePointData(point);
// Draw
drawPoint(access, point);
// Compare
#ifdef CTS_USES_VULKANSC
if (m_context.getTestContext().getCommandLine().isSubProcess())
#endif // CTS_USES_VULKANSC
{
// pointSize must either be specified pointSize or clamped to device limit pointSizeRange[1]
const float pointSize (deFloatMin(m_pointSize, m_maxPointSize));
const bool compareOk (verifyPoint(m_context.getTestContext().getLog(), access, pointSize));
// Result
if (compareOk)
return isPointSizeClamped(pointSize, m_maxPointSize) ? tcu::TestStatus::pass("Pass, pointSize clamped to pointSizeRange[1]") : tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Incorrect rasterization");
}
return tcu::TestStatus::pass("Pass");
}
float PointSizeTestInstance::getPointSize (void) const
{
return m_pointSize;
}
void PointSizeTestInstance::generatePointData (PointSceneSpec::ScenePoint& outPoint)
{
const tcu::PointSceneSpec::ScenePoint point =
{
tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), // position
tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f), // color
m_pointSize // pointSize
};
outPoint = point;
// log
{
tcu::TestLog& log = m_context.getTestContext().getLog();
log << tcu::TestLog::Message << "Point position: " << de::toString(point.position) << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Point color: " << de::toString(point.color) << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Point size: " << de::toString(point.pointSize) << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Render size: " << de::toString(m_renderSize) << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Format: " << de::toString(m_format) << tcu::TestLog::EndMessage;
}
}
void PointSizeTestInstance::drawPoint (tcu::PixelBufferAccess& result, PointSceneSpec::ScenePoint& point)
{
const tcu::Vec4 positionData (point.position);
const tcu::Vec4 colorData (point.color);
const DeviceInterface& vkd (m_context.getDeviceInterface());
const VkDevice vkDevice (m_context.getDevice());
const VkQueue queue (m_context.getUniversalQueue());
const deUint32 queueFamilyIndex (m_context.getUniversalQueueFamilyIndex());
const size_t attributeBatchSize (sizeof(tcu::Vec4));
Allocator& allocator (m_context.getDefaultAllocator());
Move<VkCommandBuffer> commandBuffer;
Move<VkPipeline> graphicsPipeline;
Move<VkBuffer> vertexBuffer;
de::MovePtr<Allocation> vertexBufferMemory;
// Create Graphics Pipeline
{
const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(m_renderSize)));
const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(m_renderSize)));
const VkVertexInputBindingDescription vertexInputBindingDescription =
{
0u, // deUint32 binding;
(deUint32)(2 * 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)sizeof(tcu::Vec4) // 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;
};
graphicsPipeline = makeGraphicsPipeline(vkd, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayout, // const VkPipelineLayout pipelineLayout
*m_vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
*m_renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
getRasterizationStateCreateInfo(), // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo,
getColorBlendStateCreateInfo()); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
}
// 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, attributeBatchSize);
deMemcpy(reinterpret_cast<deUint8*>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, &colorData, attributeBatchSize);
flushAlloc(vkd, vkDevice, *vertexBufferMemory);
}
// Create Command Buffer
commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
// Begin Command Buffer
beginCommandBuffer(vkd, *commandBuffer);
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;
// Begin Render Pass
beginRenderPass(vkd, *commandBuffer, *m_renderPass, *m_frameBuffer, vk::makeRect2D(0, 0, m_renderSize, m_renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
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, 1, 1, 0, 0);
endRenderPass(vkd, *commandBuffer);
// Copy Image
copyImageToBuffer(vkd, *commandBuffer, *m_image, *m_resultBuffer, tcu::IVec2(m_renderSize, m_renderSize));
endCommandBuffer(vkd, *commandBuffer);
// Set Point Size
{
float pointSize = getPointSize();
deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
}
// Submit
submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
#ifdef CTS_USES_VULKANSC
if (m_context.getTestContext().getCommandLine().isSubProcess())
#endif // CTS_USES_VULKANSC
{
tcu::copy(result, tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1), m_resultBufferMemory->getHostPtr()));
}
}
bool PointSizeTestInstance::verifyPoint (tcu::TestLog& log, tcu::PixelBufferAccess& image, float pointSize)
{
const float expectedPointColor (1.0f);
const float expectedBackgroundColor (0.0f);
deUint32 pointWidth (0u);
deUint32 pointHeight (0u);
bool incorrectlyColoredPixelsFound (false);
bool isOk (true);
// Verify rasterized point width and color
for (size_t x = 0; x < (deUint32)image.getWidth(); x++)
{
float pixelColor = image.getPixel((deUint32)x, image.getHeight() / 2).x();
if (pixelColor == expectedPointColor)
pointWidth++;
if ((pixelColor != expectedPointColor) && (pixelColor != expectedBackgroundColor))
incorrectlyColoredPixelsFound = true;
}
// Verify rasterized point height and color
for (size_t y = 0; y < (deUint32)image.getHeight(); y++)
{
float pixelColor = image.getPixel((deUint32)y, image.getWidth() / 2).x();
if (pixelColor == expectedPointColor)
pointHeight++;
if ((pixelColor != expectedPointColor) && (pixelColor != expectedBackgroundColor))
incorrectlyColoredPixelsFound = true;
}
// Compare amount of rasterized point pixels to expected pointSize.
if ((pointWidth != (deUint32)deRoundFloatToInt32(pointSize)) || (pointHeight != (deUint32)deRoundFloatToInt32(pointSize)))
{
log << tcu::TestLog::Message << "Incorrect point size. Expected pointSize: " << de::toString(pointSize)
<< ". Rasterized point width: " << pointWidth << " pixels, height: "
<< pointHeight << " pixels." << tcu::TestLog::EndMessage;
isOk = false;
}
// Check incorrectly colored pixels
if (incorrectlyColoredPixelsFound)
{
log << tcu::TestLog::Message << "Incorrectly colored pixels found." << tcu::TestLog::EndMessage;
isOk = false;
}
return isOk;
}
bool PointSizeTestInstance::isPointSizeClamped (float pointSize, float maxPointSizeLimit)
{
return (pointSize == maxPointSizeLimit);
}
template <typename ConcreteTestInstance>
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<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
};
void TrianglesTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& 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<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
};
void TriangleStripTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& 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);
void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
};
TriangleFanTestInstance::TriangleFanTestInstance (Context& context, VkSampleCountFlagBits sampleCount)
: BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, sampleCount)
{
#ifndef CTS_USES_VULKANSC
if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
!context.getPortabilitySubsetFeatures().triangleFans)
{
TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
}
#endif // CTS_USES_VULKANSC
}
void TriangleFanTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& 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;
}
}
struct ConservativeTestConfig
{
VkConservativeRasterizationModeEXT conservativeRasterizationMode;
float extraOverestimationSize;
VkPrimitiveTopology primitiveTopology;
bool degeneratePrimitives;
float lineWidth;
deUint32 resolution;
};
float getExtraOverestimationSize (const float overestimationSizeDesired, const VkPhysicalDeviceConservativeRasterizationPropertiesEXT& conservativeRasterizationProperties)
{
const float extraOverestimationSize = overestimationSizeDesired == TCU_INFINITY ? conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize
: overestimationSizeDesired == -TCU_INFINITY ? conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity
: overestimationSizeDesired;
return extraOverestimationSize;
}
template <typename ConcreteTestInstance>
class ConservativeTestCase : public BaseRenderingTestCase
{
public:
ConservativeTestCase (tcu::TestContext& context,
const std::string& name,
const std::string& description,
const ConservativeTestConfig& conservativeTestConfig,
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_conservativeTestConfig (conservativeTestConfig)
{}
virtual void checkSupport (Context& context) const;
virtual TestInstance* createInstance (Context& context) const
{
return new ConcreteTestInstance(context, m_conservativeTestConfig, m_sampleCount);
}
protected:
bool isUseLineSubPixel (Context& context) const;
deUint32 getSubPixelResolution (Context& context) const;
const ConservativeTestConfig m_conservativeTestConfig;
};
template <typename ConcreteTestInstance>
bool ConservativeTestCase<ConcreteTestInstance>::isUseLineSubPixel (Context& context) const
{
return (isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology) && context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"));
}
template <typename ConcreteTestInstance>
deUint32 ConservativeTestCase<ConcreteTestInstance>::getSubPixelResolution (Context& context) const
{
if (isUseLineSubPixel(context))
{
const VkPhysicalDeviceLineRasterizationPropertiesEXT lineRasterizationPropertiesEXT = context.getLineRasterizationPropertiesEXT();
return lineRasterizationPropertiesEXT.lineSubPixelPrecisionBits;
}
else
{
return context.getDeviceProperties().limits.subPixelPrecisionBits;
}
}
template <typename ConcreteTestInstance>
void ConservativeTestCase<ConcreteTestInstance>::checkSupport (Context& context) const
{
context.requireDeviceFunctionality("VK_EXT_conservative_rasterization");
const VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservativeRasterizationProperties = context.getConservativeRasterizationPropertiesEXT();
const deUint32 subPixelPrecisionBits = getSubPixelResolution(context);
const deUint32 subPixelPrecision = 1<<subPixelPrecisionBits;
const bool linesPrecision = isUseLineSubPixel(context);
const float primitiveOverestimationSizeMult = float(subPixelPrecision) * conservativeRasterizationProperties.primitiveOverestimationSize;
const bool topologyLineOrPoint = isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology) || isPrimitiveTopologyPoint(m_conservativeTestConfig.primitiveTopology);
DE_ASSERT(subPixelPrecisionBits < sizeof(deUint32) * 8);
context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "maxExtraPrimitiveOverestimationSize=" << conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize << '\n'
<< "extraPrimitiveOverestimationSizeGranularity=" << conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity << '\n'
<< "degenerateLinesRasterized=" << conservativeRasterizationProperties.degenerateLinesRasterized << '\n'
<< "degenerateTrianglesRasterized=" << conservativeRasterizationProperties.degenerateTrianglesRasterized << '\n'
<< "primitiveOverestimationSize=" << conservativeRasterizationProperties.primitiveOverestimationSize << " (==" << primitiveOverestimationSizeMult << '/' << subPixelPrecision << ")\n"
<< "subPixelPrecisionBits=" << subPixelPrecisionBits << (linesPrecision ? " (using VK_EXT_line_rasterization)" : " (using limits)") << '\n'
<< tcu::TestLog::EndMessage;
if (conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity > conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize)
TCU_FAIL("Granularity cannot be greater than maximum extra size");
if (topologyLineOrPoint)
{
if (!conservativeRasterizationProperties.conservativePointAndLineRasterization)
TCU_THROW(NotSupportedError, "Conservative line and point rasterization is not supported");
}
if (m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT)
{
if (conservativeRasterizationProperties.primitiveUnderestimation == DE_FALSE)
TCU_THROW(NotSupportedError, "Underestimation is not supported");
if (isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology))
{
const float testLineWidth = m_conservativeTestConfig.lineWidth;
if (testLineWidth != 1.0f)
{
const VkPhysicalDeviceLimits& limits = context.getDeviceProperties().limits;
const float lineWidthRange[2] = { limits.lineWidthRange[0], limits.lineWidthRange[1] };
const float lineWidthGranularity = limits.lineWidthGranularity;
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
if (lineWidthGranularity == 0.0f)
TCU_THROW(NotSupportedError, "Wide lines required for test, but are not supported");
DE_ASSERT(lineWidthGranularity > 0.0f && lineWidthRange[0] > 0.0f && lineWidthRange[1] >= lineWidthRange[0]);
if (!de::inBounds(testLineWidth, lineWidthRange[0], lineWidthRange[1]))
TCU_THROW(NotSupportedError, "Tested line width is not supported");
const float n = (testLineWidth - lineWidthRange[0]) / lineWidthGranularity;
if (deFloatFrac(n) != 0.0f || n * lineWidthGranularity + lineWidthRange[0] != testLineWidth)
TCU_THROW(NotSupportedError, "Exact match of line width is required for the test");
}
}
else if (isPrimitiveTopologyPoint(m_conservativeTestConfig.primitiveTopology))
{
const float testPointSize = m_conservativeTestConfig.lineWidth;
if (testPointSize != 1.0f)
{
const VkPhysicalDeviceLimits& limits = context.getDeviceProperties().limits;
const float pointSizeRange[2] = { limits.pointSizeRange[0], limits.pointSizeRange[1] };
const float pointSizeGranularity = limits.pointSizeGranularity;
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
if (pointSizeGranularity == 0.0f)
TCU_THROW(NotSupportedError, "Large points required for test, but are not supported");
DE_ASSERT(pointSizeGranularity > 0.0f && pointSizeRange[0] > 0.0f && pointSizeRange[1] >= pointSizeRange[0]);
if (!de::inBounds(testPointSize, pointSizeRange[0], pointSizeRange[1]))
TCU_THROW(NotSupportedError, "Tested point size is not supported");
const float n = (testPointSize - pointSizeRange[0]) / pointSizeGranularity;
if (deFloatFrac(n) != 0.0f || n * pointSizeGranularity + pointSizeRange[0] != testPointSize)
TCU_THROW(NotSupportedError, "Exact match of point size is required for the test");
}
}
}
else if (m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT)
{
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, conservativeRasterizationProperties);
if (extraOverestimationSize > conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize)
TCU_THROW(NotSupportedError, "Specified overestimation size is not supported");
if (topologyLineOrPoint)
{
if (!conservativeRasterizationProperties.conservativePointAndLineRasterization)
TCU_THROW(NotSupportedError, "Conservative line and point rasterization is not supported");
}
if (isPrimitiveTopologyTriangle(m_conservativeTestConfig.primitiveTopology))
{
if (m_conservativeTestConfig.degeneratePrimitives)
{
// Enforce specification minimum required limit to avoid division by zero
DE_ASSERT(subPixelPrecisionBits >= 4);
// Make sure float precision of 22 bits is enough, i.e. resoultion in subpixel quarters less than float precision
if (m_conservativeTestConfig.resolution * (1<<(subPixelPrecisionBits + 2)) > (1<<21))
TCU_THROW(NotSupportedError, "Subpixel resolution is too high to generate degenerate primitives");
}
}
}
else
TCU_THROW(InternalError, "Non-conservative mode tests are not supported by this class");
}
class ConservativeTraingleTestInstance : public BaseTriangleTestInstance
{
public:
ConservativeTraingleTestInstance (Context& context,
ConservativeTestConfig conservativeTestConfig,
VkSampleCountFlagBits sampleCount)
: BaseTriangleTestInstance (context,
conservativeTestConfig.primitiveTopology,
sampleCount,
conservativeTestConfig.resolution)
, m_conservativeTestConfig (conservativeTestConfig)
, m_conservativeRasterizationProperties (context.getConservativeRasterizationPropertiesEXT())
, m_rasterizationConservativeStateCreateInfo (initRasterizationConservativeStateCreateInfo())
, m_rasterizationStateCreateInfo (initRasterizationStateCreateInfo())
{}
void generateTriangles (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
protected:
virtual const VkPipelineRasterizationLineStateCreateInfoEXT* getLineRasterizationStateCreateInfo (void);
virtual bool compareAndVerify (std::vector<TriangleSceneSpec::SceneTriangle>& triangles,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer);
virtual bool compareAndVerifyOverestimatedNormal (std::vector<TriangleSceneSpec::SceneTriangle>& triangles,
tcu::Surface& resultImage);
virtual bool compareAndVerifyOverestimatedDegenerate (std::vector<TriangleSceneSpec::SceneTriangle>& triangles,
tcu::Surface& resultImage);
virtual bool compareAndVerifyUnderestimatedNormal (std::vector<TriangleSceneSpec::SceneTriangle>& triangles,
tcu::Surface& resultImage);
virtual bool compareAndVerifyUnderestimatedDegenerate (std::vector<TriangleSceneSpec::SceneTriangle>& triangles,
tcu::Surface& resultImage);
void generateNormalTriangles (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
void generateDegenerateTriangles (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
void drawPrimitives (tcu::Surface& result,
const std::vector<tcu::Vec4>& vertexData,
VkPrimitiveTopology primitiveTopology);
private:
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> initRasterizationConservativeStateCreateInfo (void);
const std::vector<VkPipelineRasterizationStateCreateInfo> initRasterizationStateCreateInfo (void);
const ConservativeTestConfig m_conservativeTestConfig;
const VkPhysicalDeviceConservativeRasterizationPropertiesEXT m_conservativeRasterizationProperties;
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> m_rasterizationConservativeStateCreateInfo;
const std::vector<VkPipelineRasterizationStateCreateInfo> m_rasterizationStateCreateInfo;
};
void ConservativeTraingleTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
{
if (m_conservativeTestConfig.degeneratePrimitives)
generateDegenerateTriangles(iteration, outData, outTriangles);
else
generateNormalTriangles(iteration, outData, outTriangles);
}
void ConservativeTraingleTestInstance::generateNormalTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
{
const float halfPixel = 1.0f / float(m_renderSize);
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
const float overestimate = 2.0f * halfPixel * (m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize);
const float overestimateMargin = overestimate;
const float underestimateMargin = 0.0f;
const bool isOverestimate = m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
const float margin = isOverestimate ? overestimateMargin : underestimateMargin;
const char* overestimateIterationComments[] = { "Corner touch", "Any portion pixel coverage", "Edge touch" };
outData.resize(6);
switch (iteration)
{
case 0:
{
// Corner touch
const float edge = 2 * halfPixel + margin;
const float left = -1.0f + edge;
const float right = +1.0f - edge;
const float up = -1.0f + edge;
const float down = +1.0f - edge;
outData[0] = tcu::Vec4( left, down, 0.0f, 1.0f);
outData[1] = tcu::Vec4( left, up, 0.0f, 1.0f);
outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
outData[3] = tcu::Vec4( left, up, 0.0f, 1.0f);
outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
outData[5] = tcu::Vec4(right, up, 0.0f, 1.0f);
break;
}
case 1:
{
// Partial coverage
const float eps = halfPixel / 32.0f;
const float edge = 4.0f * halfPixel + margin - eps;
const float left = -1.0f + edge;
const float right = +1.0f - edge;
const float up = -1.0f + edge;
const float down = +1.0f - edge;
outData[0] = tcu::Vec4( left, down, 0.0f, 1.0f);
outData[1] = tcu::Vec4( left, up, 0.0f, 1.0f);
outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
outData[3] = tcu::Vec4( left, up, 0.0f, 1.0f);
outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
outData[5] = tcu::Vec4(right, up, 0.0f, 1.0f);
break;
}
case 2:
{
// Edge touch
const float edge = 6.0f * halfPixel + margin;
const float left = -1.0f + edge;
const float right = +1.0f - edge;
const float up = -1.0f + edge;
const float down = +1.0f - edge;
outData[0] = tcu::Vec4( left, down, 0.0f, 1.0f);
outData[1] = tcu::Vec4( left, up, 0.0f, 1.0f);
outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
outData[3] = tcu::Vec4( left, up, 0.0f, 1.0f);
outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
outData[5] = tcu::Vec4(right, up, 0.0f, 1.0f);
break;
}
default:
TCU_THROW(InternalError, "Unexpected iteration");
}
outTriangles.resize(outData.size() / 3);
for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
{
outTriangles[ndx].positions[0] = outData[3 * ndx + 0]; outTriangles[ndx].sharedEdge[0] = false;
outTriangles[ndx].positions[1] = outData[3 * ndx + 1]; outTriangles[ndx].sharedEdge[1] = false;
outTriangles[ndx].positions[2] = outData[3 * ndx + 2]; outTriangles[ndx].sharedEdge[2] = false;
}
// log
if (isOverestimate)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Testing " << overestimateIterationComments[iteration] << " "
<< "with rendering " << outTriangles.size() << " triangle(s):"
<< tcu::TestLog::EndMessage;
}
else
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Rendering " << outTriangles.size() << " triangle(s):"
<< tcu::TestLog::EndMessage;
}
for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
{
const deUint32 multiplier = m_renderSize / 2;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Triangle " << (ndx + 1) << ":"
<< "\n\t" << outTriangles[ndx].positions[0] << " == " << (float(multiplier) * outTriangles[ndx].positions[0]) << "/" << multiplier
<< "\n\t" << outTriangles[ndx].positions[1] << " == " << (float(multiplier) * outTriangles[ndx].positions[1]) << "/" << multiplier
<< "\n\t" << outTriangles[ndx].positions[2] << " == " << (float(multiplier) * outTriangles[ndx].positions[2]) << "/" << multiplier
<< tcu::TestLog::EndMessage;
}
}
void ConservativeTraingleTestInstance::generateDegenerateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
{
tcu::TestLog& log = m_context.getTestContext().getLog();
const float pixelSize = 2.0f / float(m_renderSize);
const deUint32 subPixels = 1u << m_context.getDeviceProperties().limits.subPixelPrecisionBits;
const float subPixelSize = pixelSize / float(subPixels);
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
const float totalOverestimate = m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
const float totalOverestimateInSubPixels = deFloatCeil(totalOverestimate * float(subPixels));
const float overestimate = subPixelSize * totalOverestimateInSubPixels;
const float overestimateSafetyMargin = subPixelSize * 0.125f;
const float overestimateMargin = overestimate + overestimateSafetyMargin;
const float underestimateMargin = 0.0f;
const bool isOverestimate = m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
const float margin = isOverestimate ? overestimateMargin : underestimateMargin;
const char* overestimateIterationComments[] = { "Backfacing", "Generate pixels", "Use provoking vertex" };
if (pixelSize < 2 * overestimateMargin)
TCU_THROW(NotSupportedError, "Could not generate degenerate triangle for such overestimate parameters");
outData.clear();
switch (iteration)
{
case 0:
case 1:
case 2:
{
for (int rowNdx = 0; rowNdx < 3; ++rowNdx)
for (int colNdx = 0; colNdx < 4; ++colNdx)
{
const float offsetX = -1.0f + float(4 * (colNdx + 1)) * pixelSize;
const float offsetY = -1.0f + float(4 * (rowNdx + 1)) * pixelSize;
const float left = offsetX + margin;
const float right = offsetX + margin + 0.25f * subPixelSize;
const float up = offsetY + margin;
const float down = offsetY + margin + 0.25f * subPixelSize;
const bool luPresent = (rowNdx & 1) == 0;
const bool rdPresent = (rowNdx & 2) == 0;
const bool luCW = (colNdx & 1) == 0;
const bool rdCW = (colNdx & 2) == 0;
DE_ASSERT(left < right);
DE_ASSERT(up < down);
if (luPresent)
{
if (luCW)
{
// CW triangle left up
outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( left, up, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
}
else
{
// CCW triangle left up
outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( left, up, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
}
}
if (rdPresent)
{
if (rdCW)
{
// CW triangle right down
outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(right, down, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
}
else
{
// CCW triangle right down
outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(right, down, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
}
}
}
break;
}
default:
TCU_THROW(InternalError, "Unexpected iteration");
}
outTriangles.resize(outData.size() / 3);
for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
{
outTriangles[ndx].positions[0] = outData[3 * ndx + 0]; outTriangles[ndx].sharedEdge[0] = false;
outTriangles[ndx].positions[1] = outData[3 * ndx + 1]; outTriangles[ndx].sharedEdge[1] = false;
outTriangles[ndx].positions[2] = outData[3 * ndx + 2]; outTriangles[ndx].sharedEdge[2] = false;
}
// log
if (isOverestimate)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Testing " << overestimateIterationComments[iteration] << " "
<< "with rendering " << outTriangles.size() << " triangle(s):"
<< tcu::TestLog::EndMessage;
}
else
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Rendering " << outTriangles.size() << " triangle(s):"
<< tcu::TestLog::EndMessage;
}
for (int ndx = 0; ndx < (int)outTriangles.size(); ++ndx)
{
const deUint32 multiplierInt = m_renderSize / 2;
const deUint32 multiplierFrac = subPixels;
std::string coordsString;
for (size_t vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
{
const tcu::Vec4& pos = outTriangles[ndx].positions[vertexNdx];
std::ostringstream coordsFloat;
std::ostringstream coordsNatural;
for (int coordNdx = 0; coordNdx < 2; ++coordNdx)
{
const char* sep = (coordNdx < 1) ? "," : "";
const float coord = pos[coordNdx];
const char sign = deSign(coord) < 0 ? '-' : '+';
const float m = deFloatFloor(float(multiplierInt) * deFloatAbs(coord));
const float r = deFloatFrac(float(multiplierInt) * deFloatAbs(coord)) * float(multiplierFrac);
coordsFloat << std::fixed << std::setw(13) << std::setprecision(10) << coord << sep;
coordsNatural << sign << '(' << m << '+' << r << '/' << multiplierFrac << ')' << sep;
}
coordsString += "\n\t[" + coordsFloat.str() + "] == [" + coordsNatural.str() + "] / " + de::toString(multiplierInt);
}
log << tcu::TestLog::Message
<< "Triangle " << (ndx + 1) << ':'
<< coordsString
<< tcu::TestLog::EndMessage;
}
}
void ConservativeTraingleTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
{
if (m_conservativeTestConfig.degeneratePrimitives && getIteration() == 2)
{
// Set provoking vertex color to white
tcu::Vec4 colorProvoking (1.0f, 1.0f, 1.0f, 1.0f);
tcu::Vec4 colorOther (0.0f, 1.0f, 1.0f, 1.0f);
std::vector<tcu::Vec4> colorData;
colorData.reserve(vertexData.size());
for (size_t vertexNdx = 0; vertexNdx < vertexData.size(); ++vertexNdx)
if (vertexNdx % 3 == 0)
colorData.push_back(colorProvoking);
else
colorData.push_back(colorOther);
BaseRenderingTestInstance::drawPrimitives(result, vertexData, colorData, primitiveTopology);
}
else
BaseRenderingTestInstance::drawPrimitives(result, vertexData, primitiveTopology);
}
bool ConservativeTraingleTestInstance::compareAndVerify (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
{
DE_UNREF(drawBuffer);
switch (m_conservativeTestConfig.conservativeRasterizationMode)
{
case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
{
if (m_conservativeTestConfig.degeneratePrimitives)
return compareAndVerifyOverestimatedDegenerate(triangles, resultImage);
else
return compareAndVerifyOverestimatedNormal(triangles, resultImage);
}
case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
{
if (m_conservativeTestConfig.degeneratePrimitives)
return compareAndVerifyUnderestimatedDegenerate(triangles, resultImage);
else
return compareAndVerifyUnderestimatedNormal(triangles, resultImage);
}
default:
TCU_THROW(InternalError, "Unknown conservative rasterization mode");
}
}
bool ConservativeTraingleTestInstance::compareAndVerifyOverestimatedNormal (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
{
DE_UNREF(triangles);
const int start = getIteration() + 1;
const int end = resultImage.getHeight() - start;
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = 0;
int errY = 0;
deUint32 errValue = 0;
bool result = true;
DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
for (int y = start; result && y < end; ++y)
for (int x = start; result && x < end; ++x)
{
if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x,y).getPacked();
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
tcu::Surface expectedImage (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
errorMask.setPixel(x, y, backgroundColor);
expectedImage.setPixel(x, y, backgroundColor);
}
for (int y = start; y < end; ++y)
for (int x = start; x < end; ++x)
{
expectedImage.setPixel(x, y, foregroundColor);
if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
}
log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Expected", "Expected", expectedImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativeTraingleTestInstance::compareAndVerifyOverestimatedDegenerate (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
{
DE_UNREF(triangles);
const char* iterationComments[] = { "Cull back face triangles", "Cull front face triangles", "Cull none" };
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
bool result = true;
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
if (m_conservativeRasterizationProperties.degenerateTrianglesRasterized)
{
if (getIteration() != 0)
{
log << tcu::TestLog::Message << "Triangles expected to be rasterized with at least one pixel of white color each" << tcu::TestLog::EndMessage;
for (int rowNdx = 0; rowNdx < 3; ++rowNdx)
for (int colNdx = 0; colNdx < 4; ++colNdx)
{
referenceImage.setPixel(4 * (colNdx + 1), 4 * (rowNdx + 1), foregroundColor);
// Allow implementations that need to be extra conservative with degenerate triangles,
// which may cause extra coverage.
if (resultImage.getPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1) - 1) == foregroundColor)
referenceImage.setPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1) - 1, foregroundColor);
if (resultImage.getPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1)) == foregroundColor)
referenceImage.setPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1), foregroundColor);
if (resultImage.getPixel(4 * (colNdx + 1), 4 * (rowNdx + 1) - 1) == foregroundColor)
referenceImage.setPixel(4 * (colNdx + 1), 4 * (rowNdx + 1) - 1, foregroundColor);
}
}
else
log << tcu::TestLog::Message << "Triangles expected to be culled due to backfacing culling and all degenerate triangles assumed to be backfacing" << tcu::TestLog::EndMessage;
}
else
log << tcu::TestLog::Message << "Triangles expected to be culled due to degenerateTrianglesRasterized=false" << tcu::TestLog::EndMessage;
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
{
if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
{
result = false;
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
log << tcu::TestLog::Message << "Invalid pixels found for mode '" << iterationComments[getIteration()] << "'"
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativeTraingleTestInstance::compareAndVerifyUnderestimatedNormal (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
{
DE_UNREF(triangles);
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
const tcu::IVec2 viewportSize = tcu::IVec2(resultImage.getWidth(), resultImage.getHeight());
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = -1;
int errY = -1;
deUint32 errValue = 0;
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
bool result = true;
DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
for (size_t triangleNdx = 0; triangleNdx < triangles.size(); ++triangleNdx)
{
const tcu::Vec4& p0 = triangles[triangleNdx].positions[0];
const tcu::Vec4& p1 = triangles[triangleNdx].positions[1];
const tcu::Vec4& p2 = triangles[triangleNdx].positions[2];
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
{
if (calculateUnderestimateTriangleCoverage(p0, p1, p2, tcu::IVec2(x,y), m_subpixelBits, viewportSize) == tcu::COVERAGE_FULL)
referenceImage.setPixel(x, y, foregroundColor);
}
}
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x,y).getPacked();
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Refernce", "Refernce", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativeTraingleTestInstance::compareAndVerifyUnderestimatedDegenerate (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
{
DE_UNREF(triangles);
const char* iterationComments[] = { "Cull back face triangles", "Cull front face triangles", "Cull none" };
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = 0;
int errY = 0;
deUint32 errValue = 0;
bool result = true;
if (m_conservativeRasterizationProperties.degenerateTrianglesRasterized)
{
if (getIteration() != 0)
log << tcu::TestLog::Message << "Triangles expected to be not rendered due to no one triangle can fully cover fragment" << tcu::TestLog::EndMessage;
else
log << tcu::TestLog::Message << "Triangles expected to be culled due to backfacing culling and all degenerate triangles assumed to be backfacing" << tcu::TestLog::EndMessage;
}
else
log << tcu::TestLog::Message << "Triangles expected to be culled due to degenerateTrianglesRasterized=false" << tcu::TestLog::EndMessage;
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != backgroundColor.getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x,y).getPacked();
break;
}
}
if (!result)
{
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
log << tcu::TestLog::Message << "Invalid pixels found for mode '" << iterationComments[getIteration()] << "' starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativeTraingleTestInstance::initRasterizationConservativeStateCreateInfo (void)
{
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> result;
result.reserve(getIterationCount());
for (int iteration = 0; iteration < getIterationCount(); ++iteration)
{
const VkPipelineRasterizationConservativeStateCreateInfoEXT rasterizationConservativeStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineRasterizationConservativeStateCreateFlagsEXT)0, // VkPipelineRasterizationConservativeStateCreateFlagsEXT flags;
m_conservativeTestConfig.conservativeRasterizationMode, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
extraOverestimationSize // float extraPrimitiveOverestimationSize;
};
result.push_back(rasterizationConservativeStateCreateInfo);
}
return result;
}
const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativeTraingleTestInstance::initRasterizationStateCreateInfo (void)
{
std::vector<VkPipelineRasterizationStateCreateInfo> result;
result.reserve(getIterationCount());
for (int iteration = 0; iteration < getIterationCount(); ++iteration)
{
const VkCullModeFlags cullModeFlags = (!m_conservativeTestConfig.degeneratePrimitives) ? VK_CULL_MODE_NONE
: (iteration == 0) ? VK_CULL_MODE_BACK_BIT
: (iteration == 1) ? VK_CULL_MODE_FRONT_BIT
: VK_CULL_MODE_NONE;
const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
&m_rasterizationConservativeStateCreateInfo[iteration], // const void* pNext;
0, // VkPipelineRasterizationStateCreateFlags flags;
false, // VkBool32 depthClampEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
cullModeFlags, // VkCullModeFlags cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
VK_FALSE, // VkBool32 depthBiasEnable;
0.0f, // float depthBiasConstantFactor;
0.0f, // float depthBiasClamp;
0.0f, // float depthBiasSlopeFactor;
getLineWidth(), // float lineWidth;
};
result.push_back(rasterizationStateCreateInfo);
}
return result;
}
const VkPipelineRasterizationStateCreateInfo* ConservativeTraingleTestInstance::getRasterizationStateCreateInfo (void) const
{
return &m_rasterizationStateCreateInfo[getIteration()];
}
const VkPipelineRasterizationLineStateCreateInfoEXT* ConservativeTraingleTestInstance::getLineRasterizationStateCreateInfo (void)
{
return DE_NULL;
}
class ConservativeLineTestInstance : public BaseLineTestInstance
{
public:
ConservativeLineTestInstance (Context& context,
ConservativeTestConfig conservativeTestConfig,
VkSampleCountFlagBits sampleCount);
void generateLines (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<LineSceneSpec::SceneLine>& outLines);
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
protected:
virtual const VkPipelineRasterizationLineStateCreateInfoEXT* getLineRasterizationStateCreateInfo (void);
virtual bool compareAndVerify (std::vector<LineSceneSpec::SceneLine>& lines,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer);
virtual bool compareAndVerifyOverestimatedNormal (std::vector<LineSceneSpec::SceneLine>& lines,
tcu::Surface& resultImage);
virtual bool compareAndVerifyOverestimatedDegenerate (std::vector<LineSceneSpec::SceneLine>& lines,
tcu::Surface& resultImage);
virtual bool compareAndVerifyUnderestimatedNormal (std::vector<LineSceneSpec::SceneLine>& lines,
tcu::Surface& resultImage);
virtual bool compareAndVerifyUnderestimatedDegenerate (std::vector<LineSceneSpec::SceneLine>& lines,
tcu::Surface& resultImage);
void generateNormalLines (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<LineSceneSpec::SceneLine>& outLines);
void generateDegenerateLines (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<LineSceneSpec::SceneLine>& outLines);
void drawPrimitives (tcu::Surface& result,
const std::vector<tcu::Vec4>& vertexData,
VkPrimitiveTopology primitiveTopology);
private:
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> initRasterizationConservativeStateCreateInfo (void);
const std::vector<VkPipelineRasterizationStateCreateInfo> initRasterizationStateCreateInfo (void);
const ConservativeTestConfig m_conservativeTestConfig;
const VkPhysicalDeviceConservativeRasterizationPropertiesEXT m_conservativeRasterizationProperties;
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> m_rasterizationConservativeStateCreateInfo;
const std::vector<VkPipelineRasterizationStateCreateInfo> m_rasterizationStateCreateInfo;
};
ConservativeLineTestInstance::ConservativeLineTestInstance (Context& context,
ConservativeTestConfig conservativeTestConfig,
VkSampleCountFlagBits sampleCount)
: BaseLineTestInstance (
context,
conservativeTestConfig.primitiveTopology,
PRIMITIVEWIDENESS_NARROW,
PRIMITIVESTRICTNESS_IGNORE,
sampleCount,
LINESTIPPLE_DISABLED,
VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,
LineStippleFactorCase::DEFAULT,
0,
conservativeTestConfig.resolution,
conservativeTestConfig.lineWidth
)
, m_conservativeTestConfig (conservativeTestConfig)
, m_conservativeRasterizationProperties (context.getConservativeRasterizationPropertiesEXT())
, m_rasterizationConservativeStateCreateInfo (initRasterizationConservativeStateCreateInfo())
, m_rasterizationStateCreateInfo (initRasterizationStateCreateInfo())
{
}
void ConservativeLineTestInstance::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
{
if (m_conservativeTestConfig.degeneratePrimitives)
generateDegenerateLines(iteration, outData, outLines);
else
generateNormalLines(iteration, outData, outLines);
}
void ConservativeLineTestInstance::generateNormalLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
{
const char* iterationComment = "";
const float halfPixel = 1.0f / float(m_renderSize);
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
const float overestimate = 2.0f * halfPixel * (m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize);
const float overestimateMargin = overestimate;
const float underestimateMargin = 0.0f;
const bool isOverestimate = m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
const float margin = isOverestimate ? overestimateMargin : underestimateMargin;
const float edge = 4 * halfPixel + margin;
const float left = -1.0f + edge;
const float right = +1.0f - edge;
const float up = -1.0f + edge;
const float down = +1.0f - edge;
outData.reserve(2);
if (isOverestimate)
{
const char* iterationComments[] = { "Horizontal up line", "Vertical line", "Horizontal down line" };
iterationComment = iterationComments[iteration];
switch (iteration)
{
case 0:
{
outData.push_back(tcu::Vec4( left, up + halfPixel, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( right, up + halfPixel, 0.0f, 1.0f));
break;
}
case 1:
{
outData.push_back(tcu::Vec4( left + halfPixel, up, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( left + halfPixel, down, 0.0f, 1.0f));
break;
}
case 2:
{
outData.push_back(tcu::Vec4( left, down - halfPixel, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( right, down - halfPixel, 0.0f, 1.0f));
break;
}
default:
TCU_THROW(InternalError, "Unexpected iteration");
}
}
else
{
const char* iterationComments[] = { "Horizontal lines", "Vertical lines", "Diagonal lines" };
const deUint32 subPixels = 1u << m_subpixelBits;
const float subPixelSize = 2.0f * halfPixel / float(subPixels);
const float blockStep = 16.0f * 2.0f * halfPixel;
const float lineWidth = 2.0f * halfPixel * getLineWidth();
const float offsets[] =
{
float(1) * blockStep,
float(2) * blockStep + halfPixel,
float(3) * blockStep + 0.5f * lineWidth + 2.0f * subPixelSize,
float(4) * blockStep + 0.5f * lineWidth - 2.0f * subPixelSize,
};
iterationComment = iterationComments[iteration];
outData.reserve(DE_LENGTH_OF_ARRAY(offsets));
switch (iteration)
{
case 0:
{
for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
{
outData.push_back(tcu::Vec4( left + halfPixel, up + offsets[lineNdx], 0.0f, 1.0f));
outData.push_back(tcu::Vec4(right - halfPixel, up + offsets[lineNdx], 0.0f, 1.0f));
}
break;
}
case 1:
{
for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
{
outData.push_back(tcu::Vec4(left + offsets[lineNdx], up + halfPixel, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(left + offsets[lineNdx], down - halfPixel, 0.0f, 1.0f));
}
break;
}
case 2:
{
for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
{
outData.push_back(tcu::Vec4(left + offsets[lineNdx], up + halfPixel, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( right - halfPixel, down - offsets[lineNdx], 0.0f, 1.0f));
}
break;
}
default:
TCU_THROW(InternalError, "Unexpected iteration");
}
}
DE_ASSERT(outData.size() % 2 == 0);
outLines.resize(outData.size() / 2);
for(size_t lineNdx = 0; lineNdx < outLines.size(); ++lineNdx)
{
outLines[lineNdx].positions[0] = outData[2 * lineNdx + 0];
outLines[lineNdx].positions[1] = outData[2 * lineNdx + 1];
}
// log
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Testing " << iterationComment << " "
<< "with rendering " << outLines.size() << " line(s):"
<< tcu::TestLog::EndMessage;
for (int ndx = 0; ndx < (int)outLines.size(); ++ndx)
{
const deUint32 multiplier = m_renderSize / 2;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Line " << (ndx+1) << ":"
<< "\n\t" << outLines[ndx].positions[0] << " == " << (float(multiplier) * outLines[ndx].positions[0]) << "/" << multiplier
<< "\n\t" << outLines[ndx].positions[1] << " == " << (float(multiplier) * outLines[ndx].positions[1]) << "/" << multiplier
<< tcu::TestLog::EndMessage;
}
}
void ConservativeLineTestInstance::generateDegenerateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
{
const bool isOverestimate = m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
const float pixelSize = 2.0f / float(m_renderSize);
const deUint32 subPixels = 1u << m_context.getDeviceProperties().limits.subPixelPrecisionBits;
const float subPixelSize = pixelSize / float(subPixels);
const char* iterationComments[] = { "Horizontal line", "Vertical line", "Diagonal line" };
outData.clear();
if (isOverestimate)
{
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
const float totalOverestimate = m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
const float totalOverestimateInSubPixels = deFloatCeil(totalOverestimate * float(subPixels));
const float overestimate = subPixelSize * totalOverestimateInSubPixels;
const float overestimateSafetyMargin = subPixelSize * 0.125f;
const float margin = overestimate + overestimateSafetyMargin;
const float originOffset = -1.0f + 1 * pixelSize;
const float originLeft = originOffset + margin;
const float originRight = originOffset + margin + 0.25f * subPixelSize;
const float originUp = originOffset + margin;
const float originDown = originOffset + margin + 0.25f * subPixelSize;
switch (iteration)
{
case 0:
{
outData.push_back(tcu::Vec4( originLeft, originUp, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(originRight, originUp, 0.0f, 1.0f));
break;
}
case 1:
{
outData.push_back(tcu::Vec4( originLeft, originUp, 0.0f, 1.0f));
outData.push_back(tcu::Vec4( originLeft, originDown, 0.0f, 1.0f));
break;
}
case 2:
{
outData.push_back(tcu::Vec4( originLeft, originUp, 0.0f, 1.0f));
outData.push_back(tcu::Vec4(originRight, originDown, 0.0f, 1.0f));
break;
}
default:
TCU_THROW(InternalError, "Unexpected iteration");
}
}
else
{
size_t rowStart = 3 * getIteration();
size_t rowEnd = 3 * (getIteration() + 1);
for (size_t rowNdx = rowStart; rowNdx < rowEnd; ++rowNdx)
for (size_t colNdx = 0; colNdx < 3 * 3; ++colNdx)
{
const float originOffsetY = -1.0f + float(4 * (1 + rowNdx)) * pixelSize;
const float originOffsetX = -1.0f + float(4 * (1 + colNdx)) * pixelSize;
const float x0 = float(rowNdx % 3);
const float y0 = float(rowNdx / 3);
const float x1 = float(colNdx % 3);
const float y1 = float(colNdx / 3);
const tcu::Vec4 p0 = tcu::Vec4(originOffsetX + x0 * pixelSize / 2.0f, originOffsetY + y0 * pixelSize / 2.0f, 0.0f, 1.0f);
const tcu::Vec4 p1 = tcu::Vec4(originOffsetX + x1 * pixelSize / 2.0f, originOffsetY + y1 * pixelSize / 2.0f, 0.0f, 1.0f);
if (x0 == x1 && y0 == y1)
continue;
outData.push_back(p0);
outData.push_back(p1);
}
}
outLines.resize(outData.size() / 2);
for (size_t ndx = 0; ndx < outLines.size(); ++ndx)
{
outLines[ndx].positions[0] = outData[2 * ndx + 0];
outLines[ndx].positions[1] = outData[2 * ndx + 1];
}
// log
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Testing " << iterationComments[iteration] << " "
<< "with rendering " << outLines.size() << " line(s):"
<< tcu::TestLog::EndMessage;
for (int ndx = 0; ndx < (int)outLines.size(); ++ndx)
{
const deUint32 multiplierInt = m_renderSize / 2;
const deUint32 multiplierFrac = subPixels;
std::string coordsString;
for (size_t vertexNdx = 0; vertexNdx < 2; ++vertexNdx)
{
const tcu::Vec4& pos = outLines[ndx].positions[vertexNdx];
std::ostringstream coordsFloat;
std::ostringstream coordsNatural;
for (int coordNdx = 0; coordNdx < 2; ++coordNdx)
{
const char* sep = (coordNdx < 1) ? "," : "";
const float coord = pos[coordNdx];
const char sign = deSign(coord) < 0 ? '-' : '+';
const float m = deFloatFloor(float(multiplierInt) * deFloatAbs(coord));
const float r = deFloatFrac(float(multiplierInt) * deFloatAbs(coord)) * float(multiplierFrac);
coordsFloat << std::fixed << std::setw(13) << std::setprecision(10) << coord << sep;
coordsNatural << sign << '(' << m << '+' << r << '/' << multiplierFrac << ')' << sep;
}
coordsString += "\n\t[" + coordsFloat.str() + "] == [" + coordsNatural.str() + "] / " + de::toString(multiplierInt);
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Line " << (ndx + 1) << ':'
<< coordsString
<< tcu::TestLog::EndMessage;
}
}
void ConservativeLineTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
{
if (m_conservativeTestConfig.degeneratePrimitives)
{
// Set provoking vertex color to white
tcu::Vec4 colorProvoking (1.0f, 1.0f, 1.0f, 1.0f);
tcu::Vec4 colorOther (0.0f, 1.0f, 1.0f, 1.0f);
std::vector<tcu::Vec4> colorData;
colorData.reserve(vertexData.size());
for (size_t vertexNdx = 0; vertexNdx < vertexData.size(); ++vertexNdx)
if (vertexNdx % 2 == 0)
colorData.push_back(colorProvoking);
else
colorData.push_back(colorOther);
BaseRenderingTestInstance::drawPrimitives(result, vertexData, colorData, primitiveTopology);
}
else
BaseRenderingTestInstance::drawPrimitives(result, vertexData, primitiveTopology);
}
bool ConservativeLineTestInstance::compareAndVerify (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
{
DE_UNREF(drawBuffer);
switch (m_conservativeTestConfig.conservativeRasterizationMode)
{
case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
{
if (m_conservativeTestConfig.degeneratePrimitives)
return compareAndVerifyOverestimatedDegenerate(lines, resultImage);
else
return compareAndVerifyOverestimatedNormal(lines, resultImage);
}
case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
{
if (m_conservativeTestConfig.degeneratePrimitives)
return compareAndVerifyUnderestimatedDegenerate(lines, resultImage);
else
return compareAndVerifyUnderestimatedNormal(lines, resultImage);
}
default:
TCU_THROW(InternalError, "Unknown conservative rasterization mode");
}
}
bool ConservativeLineTestInstance::compareAndVerifyOverestimatedNormal (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
{
DE_UNREF(lines);
const int b = 3; // bar width
const int w = resultImage.getWidth() - 1;
const int h = resultImage.getHeight() - 1;
const int xStarts[] = { 1, 1, 1 };
const int xEnds[] = { w - 1, b, w - 1 };
const int yStarts[] = { 1, 1, h - b };
const int yEnds[] = { b, h - 1, h - 1 };
const int xStart = xStarts[getIteration()];
const int xEnd = xEnds[getIteration()];
const int yStart = yStarts[getIteration()];
const int yEnd = yEnds[getIteration()];
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = 0;
int errY = 0;
deUint32 errValue = 0;
bool result = true;
DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
for (int y = yStart; result && y < yEnd; ++y)
for (int x = xStart; result && x < xEnd; ++x)
{
if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x,y).getPacked();
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
errorMask.setPixel(x, y, backgroundColor);
for (int y = yStart; y < yEnd; ++y)
for (int x = xStart; x < xEnd; ++x)
{
if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
errorMask.setPixel(x,y, unexpectedPixelColor);
}
log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativeLineTestInstance::compareAndVerifyOverestimatedDegenerate (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
{
DE_UNREF(lines);
const char* iterationComments[] = { "Horizontal line", "Vertical line", "Diagonal line" };
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
bool result = true;
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
if (m_conservativeRasterizationProperties.degenerateLinesRasterized)
{
log << tcu::TestLog::Message << "Lines expected to be rasterized with white color" << tcu::TestLog::EndMessage;
// This pixel will alway be covered due to the placement of the line.
referenceImage.setPixel(1, 1, foregroundColor);
// Additional pixels will be covered based on the extra bloat added to the primitive.
const float extraOverestimation = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
const int xExtent = 1 + int((extraOverestimation * 2.0f) + 0.5f);
const int yExtent = xExtent;
for (int y = 0; y <= yExtent; ++y)
for (int x = 0; x <= xExtent; ++x)
referenceImage.setPixel(x, y, foregroundColor);
}
else
log << tcu::TestLog::Message << "Lines expected to be culled" << tcu::TestLog::EndMessage;
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
{
result = false;
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
log << tcu::TestLog::Message << "Invalid pixels found for mode " << iterationComments[getIteration()]
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativeLineTestInstance::compareAndVerifyUnderestimatedNormal (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
{
DE_UNREF(lines);
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = -1;
int errY = -1;
tcu::RGBA errValue;
bool result = true;
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
for (int y = 0; y < referenceImage.getHeight(); ++y)
for (int x = 0; x < referenceImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
if (getLineWidth() > 1.0f)
{
const tcu::IVec2 viewportSize(resultImage.getWidth(), resultImage.getHeight());
for (size_t lineNdx = 0; lineNdx < lines.size(); ++lineNdx)
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
{
if (calculateUnderestimateLineCoverage(lines[lineNdx].positions[0], lines[lineNdx].positions[1], getLineWidth(), tcu::IVec2(x,y), viewportSize) == tcu::COVERAGE_FULL)
referenceImage.setPixel(x, y, foregroundColor);
}
}
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
{
if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x,y);
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
errorMask.setPixel(x, y, backgroundColor);
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
}
log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " errValue=" << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativeLineTestInstance::compareAndVerifyUnderestimatedDegenerate (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
{
DE_UNREF(lines);
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
bool result = true;
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
log << tcu::TestLog::Message << "No lines expected to be rasterized" << tcu::TestLog::EndMessage;
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
{
if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
{
result = false;
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
log << tcu::TestLog::Message << "Invalid pixels found" << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativeLineTestInstance::initRasterizationConservativeStateCreateInfo (void)
{
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> result;
result.reserve(getIterationCount());
for (int iteration = 0; iteration < getIterationCount(); ++iteration)
{
const VkPipelineRasterizationConservativeStateCreateInfoEXT rasterizationConservativeStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineRasterizationConservativeStateCreateFlagsEXT)0, // VkPipelineRasterizationConservativeStateCreateFlagsEXT flags;
m_conservativeTestConfig.conservativeRasterizationMode, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
extraOverestimationSize // float extraPrimitiveOverestimationSize;
};
result.push_back(rasterizationConservativeStateCreateInfo);
}
return result;
}
const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativeLineTestInstance::initRasterizationStateCreateInfo (void)
{
std::vector<VkPipelineRasterizationStateCreateInfo> result;
result.reserve(getIterationCount());
for (int iteration = 0; iteration < getIterationCount(); ++iteration)
{
const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
&m_rasterizationConservativeStateCreateInfo[iteration], // const void* pNext;
0, // VkPipelineRasterizationStateCreateFlags flags;
false, // VkBool32 depthClampEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
VK_FALSE, // VkBool32 depthBiasEnable;
0.0f, // float depthBiasConstantFactor;
0.0f, // float depthBiasClamp;
0.0f, // float depthBiasSlopeFactor;
getLineWidth(), // float lineWidth;
};
result.push_back(rasterizationStateCreateInfo);
}
return result;
}
const VkPipelineRasterizationStateCreateInfo* ConservativeLineTestInstance::getRasterizationStateCreateInfo (void) const
{
return &m_rasterizationStateCreateInfo[getIteration()];
}
const VkPipelineRasterizationLineStateCreateInfoEXT* ConservativeLineTestInstance::getLineRasterizationStateCreateInfo (void)
{
return DE_NULL;
}
class ConservativePointTestInstance : public PointTestInstance
{
public:
ConservativePointTestInstance (Context& context,
ConservativeTestConfig conservativeTestConfig,
VkSampleCountFlagBits sampleCount)
: PointTestInstance (
context,
PRIMITIVEWIDENESS_NARROW,
PRIMITIVESTRICTNESS_IGNORE,
sampleCount,
LINESTIPPLE_DISABLED,
VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,
LineStippleFactorCase::DEFAULT,
0,
conservativeTestConfig.resolution,
conservativeTestConfig.lineWidth
)
, m_conservativeTestConfig (conservativeTestConfig)
, m_conservativeRasterizationProperties (context.getConservativeRasterizationPropertiesEXT())
, m_rasterizationConservativeStateCreateInfo (initRasterizationConservativeStateCreateInfo())
, m_rasterizationStateCreateInfo (initRasterizationStateCreateInfo())
, m_renderStart ()
, m_renderEnd ()
{}
void generatePoints (int iteration,
std::vector<tcu::Vec4>& outData,
std::vector<PointSceneSpec::ScenePoint>& outPoints);
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
protected:
virtual const VkPipelineRasterizationLineStateCreateInfoEXT* getLineRasterizationStateCreateInfo (void);
virtual bool compareAndVerify (std::vector<PointSceneSpec::ScenePoint>& points,
tcu::Surface& resultImage,
std::vector<tcu::Vec4>& drawBuffer);
virtual bool compareAndVerifyOverestimated (std::vector<PointSceneSpec::ScenePoint>& points,
tcu::Surface& resultImage);
virtual bool compareAndVerifyUnderestimated (std::vector<PointSceneSpec::ScenePoint>& points,
tcu::Surface& resultImage);
private:
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> initRasterizationConservativeStateCreateInfo (void);
const std::vector<VkPipelineRasterizationStateCreateInfo> initRasterizationStateCreateInfo (void);
const ConservativeTestConfig m_conservativeTestConfig;
const VkPhysicalDeviceConservativeRasterizationPropertiesEXT m_conservativeRasterizationProperties;
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> m_rasterizationConservativeStateCreateInfo;
const std::vector<VkPipelineRasterizationStateCreateInfo> m_rasterizationStateCreateInfo;
std::vector<int> m_renderStart;
std::vector<int> m_renderEnd;
};
void ConservativePointTestInstance::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints)
{
const float pixelSize = 2.0f / float(m_renderSize);
const bool isOverestimate = m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
m_renderStart.clear();
m_renderEnd.clear();
if (isOverestimate)
{
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
const float overestimate = m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
const float halfRenderAreaSize = overestimate + 0.5f;
const float pointCenterOffset = 2.0f + 0.5f * float(iteration) + halfRenderAreaSize;
const float pointEdgeStart = pointCenterOffset - halfRenderAreaSize;
const float pointEdgeEnd = pointEdgeStart + 2 * halfRenderAreaSize;
const int renderStart = int(deFloatFloor(pointEdgeStart)) + int((deFloatFrac(pointEdgeStart) > 0.0f) ? 0 : -1);
const int renderEnd = int(deFloatCeil(pointEdgeEnd)) + int((deFloatFrac(pointEdgeEnd) > 0.0f) ? 0 : 1);
outData.push_back(tcu::Vec4(-1.0f + pixelSize * pointCenterOffset, -1.0f + pixelSize * pointCenterOffset, 0.0f, 1.0f));
m_renderStart.push_back(renderStart);
m_renderEnd.push_back(renderEnd);
}
else
{
const float pointSize = m_conservativeTestConfig.lineWidth;
const float halfRenderAreaSize = pointSize / 2.0f;
switch (iteration)
{
case 0:
{
const float pointCenterOffset = (pointSize + 1.0f + deFloatFrac(pointSize)) / 2.0f;
const float pointEdgeStart = pointCenterOffset - halfRenderAreaSize;
const float pointEdgeEnd = pointEdgeStart + 2.0f * halfRenderAreaSize;
const int renderStart = (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart));
const int renderEnd = (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd));
outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
m_renderStart.push_back(renderStart);
m_renderEnd.push_back(renderEnd);
break;
}
case 1:
{
const float subPixelSize = 1.0f / float(1u<<(m_subpixelBits - 1));
const float pointBottomLeft = 1.0f - subPixelSize;
const float pointCenterOffset = pointBottomLeft + pointSize / 2.0f;
const float pointEdgeStart = pointCenterOffset - halfRenderAreaSize;
const float pointEdgeEnd = pointEdgeStart + 2.0f * halfRenderAreaSize;
const int renderStart = (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart));
const int renderEnd = (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd));
outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
m_renderStart.push_back(renderStart);
m_renderEnd.push_back(renderEnd);
break;
}
case 2:
{
// Edges of a point are considered not covered. Top-left coverage rule is not applicable for underestimate rasterization.
const float pointCenterOffset = (pointSize + deFloatFrac(pointSize)) / 2.0f;
const float pointEdgeStart = pointCenterOffset - halfRenderAreaSize;
const float pointEdgeEnd = pointEdgeStart + 2.0f * halfRenderAreaSize;
const int renderStart = (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart)) + 1;
const int renderEnd = (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd)) - 1;
outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
m_renderStart.push_back(renderStart);
m_renderEnd.push_back(renderEnd);
break;
}
default:
TCU_THROW(InternalError, "Unexpected iteration");
}
}
outPoints.resize(outData.size());
for (size_t ndx = 0; ndx < outPoints.size(); ++ndx)
{
outPoints[ndx].position = outData[ndx];
outPoints[ndx].pointSize = getPointSize();
}
// log
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Testing conservative point rendering "
<< "with rendering " << outPoints.size() << " points(s):"
<< tcu::TestLog::EndMessage;
for (int ndx = 0; ndx < (int)outPoints.size(); ++ndx)
{
const deUint32 multiplier = m_renderSize / 2;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Point " << (ndx+1) << ":"
<< "\n\t" << outPoints[ndx].position << " == " << (float(multiplier) * outPoints[ndx].position) << "/" << multiplier
<< tcu::TestLog::EndMessage;
}
}
bool ConservativePointTestInstance::compareAndVerify (std::vector<PointSceneSpec::ScenePoint>& points, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
{
DE_UNREF(drawBuffer);
switch (m_conservativeTestConfig.conservativeRasterizationMode)
{
case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
{
return compareAndVerifyOverestimated(points, resultImage);
}
case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
{
return compareAndVerifyUnderestimated(points, resultImage);
}
default:
TCU_THROW(InternalError, "Unknown conservative rasterization mode");
}
}
bool ConservativePointTestInstance::compareAndVerifyOverestimated (std::vector<PointSceneSpec::ScenePoint>& points, tcu::Surface& resultImage)
{
DE_UNREF(points);
const char* iterationComments[] = { "Edges and corners", "Partial coverage", "Edges and corners" };
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = 0;
int errY = 0;
deUint32 errValue = 0;
bool result = true;
log << tcu::TestLog::Message << "Points expected to be rasterized with white color" << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Testing " << iterationComments[getIteration()] << tcu::TestLog::EndMessage;
for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
{
const int renderStart = m_renderStart[renderAreaNdx];
const int renderEnd = m_renderEnd[renderAreaNdx];
for (int y = renderStart; result && y < renderEnd; ++y)
for (int x = renderStart; result && x < renderEnd; ++x)
{
if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x, y).getPacked();
break;
}
}
}
if (!result)
{
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
std::ostringstream css;
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
for (size_t renderAreaNdx = 0; renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
{
const int renderStart = m_renderStart[renderAreaNdx];
const int renderEnd = m_renderEnd[renderAreaNdx];
for (int y = renderStart; y < renderEnd; ++y)
for (int x = renderStart; x < renderEnd; ++x)
referenceImage.setPixel(x, y, foregroundColor);
}
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
css << std::endl;
for (size_t renderAreaNdx = 0; renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
{
const int renderStart = m_renderStart[renderAreaNdx];
const int renderEnd = m_renderEnd[renderAreaNdx];
css << "[" << renderStart << "," << renderEnd << ") x [" << renderStart << "," << renderEnd << ")" << std::endl;
}
log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Expected area(s) to be filled:" << css.str()
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
bool ConservativePointTestInstance::compareAndVerifyUnderestimated (std::vector<PointSceneSpec::ScenePoint>& points, tcu::Surface& resultImage)
{
DE_UNREF(points);
const char* iterationComments[] = { "Full coverage", "Full coverage with subpixel", "Exact coverage" };
const tcu::RGBA backgroundColor = tcu::RGBA(0, 0, 0, 255);
const tcu::RGBA foregroundColor = tcu::RGBA(255, 255, 255, 255);
const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
tcu::TestLog& log = m_context.getTestContext().getLog();
int errX = 0;
int errY = 0;
deUint32 errValue = 0;
bool result = true;
tcu::Surface referenceImage (resultImage.getWidth(), resultImage.getHeight());
log << tcu::TestLog::Message << "Points expected to be rasterized with white color" << tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Testing " << iterationComments[getIteration()] << tcu::TestLog::EndMessage;
for (int y = 0; y < resultImage.getHeight(); ++y)
for (int x = 0; x < resultImage.getWidth(); ++x)
referenceImage.setPixel(x, y, backgroundColor);
for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
{
const int renderStart = m_renderStart[renderAreaNdx];
const int renderEnd = m_renderEnd[renderAreaNdx];
for (int y = renderStart; y < renderEnd; ++y)
for (int x = renderStart; x < renderEnd; ++x)
referenceImage.setPixel(x, y, foregroundColor);
}
for (int y = 0; result && y < resultImage.getHeight(); ++y)
for (int x = 0; result && x < resultImage.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
{
result = false;
errX = x;
errY = y;
errValue = resultImage.getPixel(x, y).getPacked();
break;
}
}
if (!result)
{
tcu::Surface errorMask (resultImage.getWidth(), resultImage.getHeight());
std::ostringstream css;
for (int y = 0; y < errorMask.getHeight(); ++y)
for (int x = 0; x < errorMask.getWidth(); ++x)
{
if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
errorMask.setPixel(x, y, unexpectedPixelColor);
else
errorMask.setPixel(x, y, backgroundColor);
}
css << std::endl;
for (size_t renderAreaNdx = 0; renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
{
const int renderStart = m_renderStart[renderAreaNdx];
const int renderEnd = m_renderEnd[renderAreaNdx];
css << "[" << renderStart << "," << renderEnd << ") x [" << renderStart << "," << renderEnd << ")" << std::endl;
}
log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::Message << "Expected area(s) to be filled:" << css.str()
<< tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::Image("Reference", "Reference", referenceImage)
<< tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask)
<< tcu::TestLog::EndImageSet;
}
else
{
log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
<< tcu::TestLog::Image("Result", "Result", resultImage)
<< tcu::TestLog::EndImageSet;
}
return result;
}
const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativePointTestInstance::initRasterizationConservativeStateCreateInfo (void)
{
const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> result;
result.reserve(getIterationCount());
for (int iteration = 0; iteration < getIterationCount(); ++iteration)
{
const VkPipelineRasterizationConservativeStateCreateInfoEXT rasterizationConservativeStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineRasterizationConservativeStateCreateFlagsEXT)0, // VkPipelineRasterizationConservativeStateCreateFlagsEXT flags;
m_conservativeTestConfig.conservativeRasterizationMode, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
extraOverestimationSize // float extraPrimitiveOverestimationSize;
};
result.push_back(rasterizationConservativeStateCreateInfo);
}
return result;
}
const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativePointTestInstance::initRasterizationStateCreateInfo (void)
{
std::vector<VkPipelineRasterizationStateCreateInfo> result;
result.reserve(getIterationCount());
for (int iteration = 0; iteration < getIterationCount(); ++iteration)
{
const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
&m_rasterizationConservativeStateCreateInfo[iteration], // const void* pNext;
0, // VkPipelineRasterizationStateCreateFlags flags;
false, // VkBool32 depthClampEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
VK_FALSE, // VkBool32 depthBiasEnable;
0.0f, // float depthBiasConstantFactor;
0.0f, // float depthBiasClamp;
0.0f, // float depthBiasSlopeFactor;
0.0f, // float lineWidth;
};
result.push_back(rasterizationStateCreateInfo);
}
return result;
}
const VkPipelineRasterizationStateCreateInfo* ConservativePointTestInstance::getRasterizationStateCreateInfo (void) const
{
return &m_rasterizationStateCreateInfo[getIteration()];
}
const VkPipelineRasterizationLineStateCreateInfoEXT* ConservativePointTestInstance::getLineRasterizationStateCreateInfo (void)
{
return DE_NULL;
}
template <typename ConcreteTestInstance>
class WidenessTestCase : public BaseRenderingTestCase
{
public:
WidenessTestCase (tcu::TestContext& context,
const std::string& name,
const std::string& description,
PrimitiveWideness wideness,
PrimitiveStrictness strictness,
bool isLineTest,
VkSampleCountFlagBits sampleCount,
LineStipple stipple,
VkLineRasterizationModeEXT lineRasterizationMode,
LineStippleFactorCase stippleFactor = LineStippleFactorCase::DEFAULT,
deUint32 additionalRenderSize = 0)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_wideness (wideness)
, m_strictness (strictness)
, m_isLineTest (isLineTest)
, m_stipple (stipple)
, m_lineRasterizationMode (lineRasterizationMode)
, m_stippleFactor (stippleFactor)
, m_additionalRenderSize (additionalRenderSize)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new ConcreteTestInstance(context, m_wideness, m_strictness, m_sampleCount, m_stipple, m_lineRasterizationMode, m_stippleFactor, m_additionalRenderSize);
}
virtual void checkSupport (Context& context) const
{
if (m_isLineTest)
{
if (m_wideness == PRIMITIVEWIDENESS_WIDE)
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
switch (m_lineRasterizationMode)
{
default:
TCU_THROW(InternalError, "Unknown line rasterization mode");
case VK_LINE_RASTERIZATION_MODE_EXT_LAST:
{
if (m_strictness == PRIMITIVESTRICTNESS_STRICT)
if (!context.getDeviceProperties().limits.strictLines)
TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
if (m_strictness == PRIMITIVESTRICTNESS_NONSTRICT)
if (context.getDeviceProperties().limits.strictLines)
TCU_THROW(NotSupportedError, "Nonstrict rasterization is not supported");
break;
}
case VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT:
{
if (!context.getDeviceProperties().limits.strictLines)
TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
if (getLineStippleEnable() &&
!context.getLineRasterizationFeaturesEXT().stippledRectangularLines)
TCU_THROW(NotSupportedError, "Stippled rectangular lines not supported");
break;
}
case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT:
{
if (!context.getLineRasterizationFeaturesEXT().rectangularLines)
TCU_THROW(NotSupportedError, "Rectangular lines not supported");
if (getLineStippleEnable() &&
!context.getLineRasterizationFeaturesEXT().stippledRectangularLines)
TCU_THROW(NotSupportedError, "Stippled rectangular lines not supported");
break;
}
case VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT:
{
if (!context.getLineRasterizationFeaturesEXT().bresenhamLines)
TCU_THROW(NotSupportedError, "Bresenham lines not supported");
if (getLineStippleEnable() &&
!context.getLineRasterizationFeaturesEXT().stippledBresenhamLines)
TCU_THROW(NotSupportedError, "Stippled Bresenham lines not supported");
break;
}
case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT:
{
if (!context.getLineRasterizationFeaturesEXT().smoothLines)
TCU_THROW(NotSupportedError, "Smooth lines not supported");
if (getLineStippleEnable() &&
!context.getLineRasterizationFeaturesEXT().stippledSmoothLines)
TCU_THROW(NotSupportedError, "Stippled smooth lines not supported");
break;
}
}
}
else
{
if (m_wideness == PRIMITIVEWIDENESS_WIDE)
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
}
}
bool getLineStippleEnable (void) const { return m_stipple != LINESTIPPLE_DISABLED; }
virtual bool getLineStippleDynamic (void) const { return m_stipple == LINESTIPPLE_DYNAMIC; }
protected:
const PrimitiveWideness m_wideness;
const PrimitiveStrictness m_strictness;
const bool m_isLineTest;
const LineStipple m_stipple;
const VkLineRasterizationModeEXT m_lineRasterizationMode;
const LineStippleFactorCase m_stippleFactor;
const deUint32 m_additionalRenderSize;
};
class LinesTestInstance : public BaseLineTestInstance
{
public:
LinesTestInstance (Context& context, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount, LineStipple stipple, VkLineRasterizationModeEXT lineRasterizationMode, LineStippleFactorCase stippleFactor, deUint32 additionalRenderSize = 0)
: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, wideness, strictness, sampleCount, stipple, lineRasterizationMode, stippleFactor, additionalRenderSize)
{}
virtual void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
};
void LinesTestInstance::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
{
outData.resize(8);
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);
outData[6] = tcu::Vec4( 0.75f, -0.4f, 0.0f, 1.0f);
outData[7] = tcu::Vec4( 0.3f, 0.8f, 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);
outData[6] = tcu::Vec4( 0.0f, 1.0f, 0.0f, 1.0f);
outData[7] = tcu::Vec4( 0.0f, -1.0f, 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);
outData[6] = tcu::Vec4( 0.9f, 0.7f, 0.0f, 1.0f);
outData[7] = tcu::Vec4( -0.9f, 0.7f, 0.0f, 1.0f);
break;
}
outLines.resize(4);
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];
outLines[3].positions[0] = outData[6];
outLines[3].positions[1] = outData[7];
// 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, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount, LineStipple stipple, VkLineRasterizationModeEXT lineRasterizationMode, LineStippleFactorCase stippleFactor, deUint32)
: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, wideness, strictness, sampleCount, stipple, lineRasterizationMode, stippleFactor)
{}
virtual void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
};
void LineStripTestInstance::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& 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( 0.9f, -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<tcu::Vec4>& 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<tcu::Vec4> drawBuffer;
generateTriangles(m_iteration, drawBuffer);
// draw image
{
const std::vector<tcu::Vec4> 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 RESOLUTION_POT / 4;
else
return RESOLUTION_POT;
}
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<tcu::Vec4>& 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, VkPolygonMode polygonMode)
: BaseRenderingTestInstance (context, VK_SAMPLE_COUNT_1_BIT, RESOLUTION_POT)
, m_cullMode (cullMode)
, m_primitiveTopology (primitiveTopology)
, m_frontFace (frontFace)
, m_polygonMode (polygonMode)
, m_multisampling (true)
{}
virtual
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
tcu::TestStatus iterate (void);
private:
void generateVertices (std::vector<tcu::Vec4>& outData) const;
void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
void extractLines (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, std::vector<LineSceneSpec::SceneLine>& outLines) const;
void extractPoints (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, std::vector<PointSceneSpec::ScenePoint>& outPoints) 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;
const VkPolygonMode m_polygonMode;
const bool m_multisampling;
};
tcu::TestStatus CullingTestInstance::iterate (void)
{
DE_ASSERT(m_polygonMode <= VK_POLYGON_MODE_POINT);
tcu::Surface resultImage (m_renderSize, m_renderSize);
std::vector<tcu::Vec4> drawBuffer;
std::vector<TriangleSceneSpec::SceneTriangle> triangles;
std::vector<PointSceneSpec::ScenePoint> points;
std::vector<LineSceneSpec::SceneLine> lines;
const InstanceInterface& vk = m_context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice);
if (!(deviceFeatures.fillModeNonSolid) && (m_polygonMode == VK_POLYGON_MODE_LINE || m_polygonMode == VK_POLYGON_MODE_POINT))
TCU_THROW(NotSupportedError, "Wireframe fill modes are not supported");
// generate scene
generateVertices(drawBuffer);
extractTriangles(triangles, drawBuffer);
if (m_polygonMode == VK_POLYGON_MODE_LINE)
extractLines(triangles ,lines);
else if (m_polygonMode == VK_POLYGON_MODE_POINT)
extractPoints(triangles, points);
// 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;
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
bool isCompareOk = false;
args.numSamples = m_multisampling ? 1 : 0;
args.subpixelBits = m_subpixelBits;
args.redBits = colorBits[0];
args.greenBits = colorBits[1];
args.blueBits = colorBits[2];
switch (m_polygonMode)
{
case VK_POLYGON_MODE_LINE:
{
LineSceneSpec scene;
scene.lineWidth = 0;
scene.lines.swap(lines);
isCompareOk = verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
break;
}
case VK_POLYGON_MODE_POINT:
{
PointSceneSpec scene;
scene.points.swap(points);
isCompareOk = verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
break;
}
default:
{
TriangleSceneSpec scene;
scene.triangles.swap(triangles);
isCompareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), tcu::VERIFICATIONMODE_WEAK);
break;
}
}
if (isCompareOk)
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Incorrect rendering");
}
}
void CullingTestInstance::generateVertices (std::vector<tcu::Vec4>& 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<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& 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);
}
}
void CullingTestInstance::extractLines (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles,
std::vector<LineSceneSpec::SceneLine>& outLines) const
{
for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
{
for (int vrtxNdx = 0; vrtxNdx < 2; ++vrtxNdx)
{
LineSceneSpec::SceneLine line;
line.positions[0] = outTriangles.at(triNdx).positions[vrtxNdx];
line.positions[1] = outTriangles.at(triNdx).positions[vrtxNdx + 1];
outLines.push_back(line);
}
LineSceneSpec::SceneLine line;
line.positions[0] = outTriangles.at(triNdx).positions[2];
line.positions[1] = outTriangles.at(triNdx).positions[0];
outLines.push_back(line);
}
}
void CullingTestInstance::extractPoints (std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
std::vector<PointSceneSpec::ScenePoint> &outPoints) const
{
for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
{
for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
{
PointSceneSpec::ScenePoint point;
point.position = outTriangles.at(triNdx).positions[vrtxNdx];
point.pointSize = 1.0f;
outPoints.push_back(point);
}
}
}
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;
rasterizationStateCreateInfo.polygonMode = m_polygonMode;
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, VkPolygonMode polygonMode, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_cullMode (cullMode)
, m_primitiveTopology (primitiveTopology)
, m_frontFace (frontFace)
, m_polygonMode (polygonMode)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new CullingTestInstance(context, m_cullMode, m_primitiveTopology, m_frontFace, m_polygonMode);
}
void checkSupport (Context& context) const;
protected:
const VkCullModeFlags m_cullMode;
const VkPrimitiveTopology m_primitiveTopology;
const VkFrontFace m_frontFace;
const VkPolygonMode m_polygonMode;
};
void CullingTestCase::checkSupport (Context& context) const
{
#ifndef CTS_USES_VULKANSC
if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
{
const VkPhysicalDevicePortabilitySubsetFeaturesKHR& subsetFeatures = context.getPortabilitySubsetFeatures();
if (m_polygonMode == VK_POLYGON_MODE_POINT && !subsetFeatures.pointPolygons)
TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Point polygons are not supported by this implementation");
if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN && !subsetFeatures.triangleFans)
TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
}
#else
DE_UNREF(context);
#endif // CTS_USES_VULKANSC
}
class DiscardTestInstance : public BaseRenderingTestInstance
{
public:
DiscardTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, deBool queryFragmentShaderInvocations)
: BaseRenderingTestInstance (context, VK_SAMPLE_COUNT_1_BIT, RESOLUTION_POT)
, m_primitiveTopology (primitiveTopology)
, m_queryFragmentShaderInvocations (queryFragmentShaderInvocations)
{}
virtual const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
tcu::TestStatus iterate (void);
private:
void generateVertices (std::vector<tcu::Vec4>& outData) const;
void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
void extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices) const;
void extractPoints (std::vector<PointSceneSpec::ScenePoint>& outPoints, const std::vector<tcu::Vec4>& vertices) const;
void drawPrimitivesDiscard (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, VkPrimitiveTopology primitiveTopology, Move<VkQueryPool>& queryPool);
const VkPrimitiveTopology m_primitiveTopology;
const deBool m_queryFragmentShaderInvocations;
};
tcu::TestStatus DiscardTestInstance::iterate (void)
{
const DeviceInterface& vkd = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
deUint64 queryResult = 0u;
tcu::Surface resultImage (m_renderSize, m_renderSize);
std::vector<tcu::Vec4> drawBuffer;
std::vector<PointSceneSpec::ScenePoint> points;
std::vector<LineSceneSpec::SceneLine> lines;
std::vector<TriangleSceneSpec::SceneTriangle> triangles;
generateVertices(drawBuffer);
switch (m_primitiveTopology)
{
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
extractPoints(points, drawBuffer);
break;
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
extractLines(lines, drawBuffer);
break;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
extractTriangles(triangles, drawBuffer);
break;
default:
DE_ASSERT(false);
}
const VkQueryPoolCreateInfo queryPoolCreateInfo =
{
VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
(VkQueryPoolCreateFlags)0, // VkQueryPoolCreateFlags flags
VK_QUERY_TYPE_PIPELINE_STATISTICS , // VkQueryType queryType
1u, // deUint32 entryCount
VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT, // VkQueryPipelineStatisticFlags pipelineStatistics
};
if (m_queryFragmentShaderInvocations)
{
Move<VkQueryPool> queryPool = createQueryPool(vkd, vkDevice, &queryPoolCreateInfo);
drawPrimitivesDiscard(resultImage, drawBuffer, m_primitiveTopology, queryPool);
vkd.getQueryPoolResults(vkDevice, *queryPool, 0u, 1u, sizeof(deUint64), &queryResult, 0u, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
}
else
BaseRenderingTestInstance::drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
// compare
{
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
const RasterizationArguments args =
{
0, // int numSamples;
(int)m_subpixelBits, // int subpixelBits;
colorBits[0], // int redBits;
colorBits[1], // int greenBits;
colorBits[2] // int blueBits;
};
// Empty scene to compare to, primitives should be discarded before rasterization
TriangleSceneSpec scene;
const bool isCompareOk = verifyTriangleGroupRasterization(resultImage,
scene,
args,
m_context.getTestContext().getLog(),
tcu::VERIFICATIONMODE_STRICT);
if (isCompareOk)
{
if (m_queryFragmentShaderInvocations && queryResult > 0u)
return tcu::TestStatus::fail("Fragment shader invocations occured");
else
return tcu::TestStatus::pass("Pass");
}
else
return tcu::TestStatus::fail("Incorrect rendering");
}
}
void DiscardTestInstance::generateVertices (std::vector<tcu::Vec4>& outData) const
{
de::Random rnd(12345);
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 DiscardTestInstance::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
{
switch (m_primitiveTopology)
{
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
{
for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
{
TriangleSceneSpec::SceneTriangle tri;
const tcu::Vec4& v0 = vertices[vtxNdx + 0];
const tcu::Vec4& v1 = vertices[vtxNdx + 1];
const tcu::Vec4& v2 = vertices[vtxNdx + 2];
tri.positions[0] = v0;
tri.positions[1] = v1;
tri.positions[2] = v2;
outTriangles.push_back(tri);
}
break;
}
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
{
for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
{
TriangleSceneSpec::SceneTriangle tri;
const tcu::Vec4& v0 = vertices[vtxNdx + 0];
const tcu::Vec4& v1 = vertices[vtxNdx + 1];
const tcu::Vec4& v2 = vertices[vtxNdx + 2];
tri.positions[0] = v0;
tri.positions[1] = v1;
tri.positions[2] = v2;
outTriangles.push_back(tri);
}
break;
}
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
{
for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
{
TriangleSceneSpec::SceneTriangle tri;
const tcu::Vec4& v0 = vertices[0];
const tcu::Vec4& v1 = vertices[vtxNdx + 0];
const tcu::Vec4& v2 = vertices[vtxNdx + 1];
tri.positions[0] = v0;
tri.positions[1] = v1;
tri.positions[2] = v2;
outTriangles.push_back(tri);
}
break;
}
default:
DE_ASSERT(false);
}
}
void DiscardTestInstance::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices) 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];
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];
outLines.push_back(line);
}
break;
}
default:
DE_ASSERT(false);
}
}
void DiscardTestInstance::extractPoints (std::vector<PointSceneSpec::ScenePoint>& outPoints, const std::vector<tcu::Vec4>& vertices) const
{
for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
{
for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
{
PointSceneSpec::ScenePoint point;
point.position = vertices[vrtxNdx];
point.pointSize = 1.0f;
outPoints.push_back(point);
}
}
}
const VkPipelineRasterizationStateCreateInfo* DiscardTestInstance::getRasterizationStateCreateInfo (void) const
{
static const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
NULL, // const void* pNext;
0, // VkPipelineRasterizationStateCreateFlags flags;
VK_FALSE, // VkBool32 depthClipEnable;
VK_TRUE, // 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;
};
return &rasterizationStateCreateInfo;
}
void DiscardTestInstance::drawPrimitivesDiscard (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, VkPrimitiveTopology primitiveTopology, Move<VkQueryPool>& queryPool)
{
const DeviceInterface& vkd = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkPhysicalDeviceProperties properties = m_context.getDeviceProperties();
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);
const VkDeviceSize vertexBufferOffset = 0;
de::MovePtr<Allocation> vertexBufferMemory;
Move<VkBuffer> vertexBuffer;
Move<VkCommandBuffer> commandBuffer;
Move<VkPipeline> graphicsPipeline;
if (attributeBatchSize > properties.limits.maxVertexInputAttributeOffset)
{
std::stringstream message;
message << "Larger vertex input attribute offset is needed (" << attributeBatchSize << ") than the available maximum (" << properties.limits.maxVertexInputAttributeOffset << ").";
TCU_THROW(NotSupportedError, message.str().c_str());
}
// Create Graphics Pipeline
{
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 std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(m_renderSize)));
const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(m_renderSize)));
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;
};
graphicsPipeline = makeGraphicsPipeline(vkd, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayout, // const VkPipelineLayout pipelineLayout
*m_vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
*m_renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
primitiveTopology, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
getRasterizationStateCreateInfo(), // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
&multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo,
getColorBlendStateCreateInfo()); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
}
// 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;
};
const std::vector<tcu::Vec4> colorData (positionData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
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<deUint8*>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, colorData.data(), attributeBatchSize);
flushAlloc(vkd, vkDevice, *vertexBufferMemory);
}
// Create Command Buffer
commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
// Begin Command Buffer
beginCommandBuffer(vkd, *commandBuffer);
addImageTransitionBarrier(*commandBuffer, // VkCommandBuffer commandBuffer
*m_image, // VkImage 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, // VkCommandBuffer commandBuffer
*m_resolvedImage, // VkImage 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;
}
// Reset query pool
vkd.cmdResetQueryPool(*commandBuffer, *queryPool, 0u, 1u);
// Begin render pass and start query
beginRenderPass(vkd, *commandBuffer, *m_renderPass, *m_frameBuffer, vk::makeRect2D(0, 0, m_renderSize, m_renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
vkd.cmdBeginQuery(*commandBuffer, *queryPool, 0u, (VkQueryControlFlags)0u);
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);
endRenderPass(vkd, *commandBuffer);
vkd.cmdEndQuery(*commandBuffer, *queryPool, 0u);
// Copy Image
copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? *m_resolvedImage : *m_image, *m_resultBuffer, tcu::IVec2(m_renderSize, m_renderSize));
endCommandBuffer(vkd, *commandBuffer);
// Set Point Size
{
float pointSize = getPointSize();
deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
}
// Submit
submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1), m_resultBufferMemory->getHostPtr()));
}
class DiscardTestCase : public BaseRenderingTestCase
{
public:
DiscardTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, deBool queryFragmentShaderInvocations, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_primitiveTopology (primitiveTopology)
, m_queryFragmentShaderInvocations (queryFragmentShaderInvocations)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new DiscardTestInstance (context, m_primitiveTopology, m_queryFragmentShaderInvocations);
}
virtual void checkSupport (Context& context) const
{
if (m_queryFragmentShaderInvocations)
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_PIPELINE_STATISTICS_QUERY);
#ifndef CTS_USES_VULKANSC
if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
!context.getPortabilitySubsetFeatures().triangleFans)
TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
#endif // CTS_USES_VULKANSC
}
protected:
const VkPrimitiveTopology m_primitiveTopology;
const deBool m_queryFragmentShaderInvocations;
};
class TriangleInterpolationTestInstance : public BaseRenderingTestInstance
{
public:
TriangleInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, VkSampleCountFlagBits sampleCount)
: BaseRenderingTestInstance (context, sampleCount, RESOLUTION_POT)
, 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<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& 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<tcu::Vec4> drawBuffer;
std::vector<tcu::Vec4> colorBuffer;
std::vector<TriangleSceneSpec::SceneTriangle> 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<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& 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<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& 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);
}
virtual void checkSupport (Context& context) const
{
#ifndef CTS_USES_VULKANSC
if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
!context.getPortabilitySubsetFeatures().triangleFans)
{
TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
}
#else
DE_UNREF(context);
#endif // CTS_USES_VULKANSC
}
protected:
const VkPrimitiveTopology m_primitiveTopology;
const int m_flags;
};
class LineInterpolationTestInstance : public BaseRenderingTestInstance
{
public:
LineInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount);
virtual tcu::TestStatus iterate (void);
private:
void generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
void extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& 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<float> m_lineWidths;
bool m_flatshade;
PrimitiveStrictness m_strictness;
};
LineInterpolationTestInstance::LineInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, PrimitiveStrictness strictness, 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)
, m_strictness (strictness)
{
DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
// create line widths
if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
{
m_lineWidths.resize(m_iterationCount, 1.0f);
}
else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
{
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;
DE_ASSERT(range[1] > 1.0f);
// 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<tcu::Vec4> drawBuffer;
std::vector<tcu::Vec4> colorBuffer;
std::vector<LineSceneSpec::SceneLine> 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();
switch (m_strictness)
{
case PRIMITIVESTRICTNESS_STRICT:
{
if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog(), true))
m_allIterationsPassed = false;
break;
}
case PRIMITIVESTRICTNESS_NONSTRICT:
case PRIMITIVESTRICTNESS_IGNORE:
{
if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog(), false, true))
m_allIterationsPassed = false;
break;
}
default:
TCU_THROW(InternalError, "Not implemented");
}
}
}
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<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& 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<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& 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,
PrimitiveStrictness strictness,
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)
, m_strictness (strictness)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new LineInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_wideness, m_strictness, m_sampleCount);
}
virtual void checkSupport (Context& context) const
{
if (m_strictness == PRIMITIVESTRICTNESS_STRICT &&
!context.getDeviceProperties().limits.strictLines)
TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
if (m_wideness == PRIMITIVEWIDENESS_WIDE)
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
}
protected:
const VkPrimitiveTopology m_primitiveTopology;
const int m_flags;
const PrimitiveWideness m_wideness;
const PrimitiveStrictness m_strictness;
};
class StrideZeroCase : public vkt::TestCase
{
public:
struct Params
{
std::vector<tcu::Vec2> bufferData;
deUint32 drawVertexCount;
};
StrideZeroCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Params& params)
: vkt::TestCase (testCtx, name, description)
, m_params (params)
{}
virtual ~StrideZeroCase (void) {}
virtual void initPrograms (vk::SourceCollections& programCollection) const;
virtual TestInstance* createInstance (Context& context) const;
virtual void checkSupport (Context& context) const;
static constexpr vk::VkFormat kColorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
static constexpr vk::VkFormatFeatureFlags kColorFeatures = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
static constexpr vk::VkImageUsageFlags kColorUsage = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
// (-1,-1)
// +-----+-----+
// | | |
// | a | b | a = (-0.5, -0.5)
// | | | b = ( 0.5, -0.5)
// +-----------+ c = (-0.5, 0.5)
// | | | d = ( 0.5, 0.5)
// | c | d |
// | | |
// +-----+-----+
// (1,1)
static constexpr deUint32 kImageDim = 2u;
static const float kCornerDelta; // 0.5f;
static const tcu::Vec4 kClearColor;
static const tcu::Vec4 kDrawColor;
private:
Params m_params;
};
const float StrideZeroCase::kCornerDelta = 0.5f;
const tcu::Vec4 StrideZeroCase::kClearColor (0.0f, 0.0f, 0.0f, 1.0f);
const tcu::Vec4 StrideZeroCase::kDrawColor (1.0f, 1.0f, 1.0f, 1.0f);
class StrideZeroInstance : public vkt::TestInstance
{
public:
StrideZeroInstance (Context& context, const StrideZeroCase::Params& params)
: vkt::TestInstance (context)
, m_params (params)
{}
virtual ~StrideZeroInstance (void) {}
virtual tcu::TestStatus iterate (void);
private:
StrideZeroCase::Params m_params;
};
void StrideZeroCase::initPrograms (vk::SourceCollections& programCollection) const
{
std::ostringstream vert;
std::ostringstream frag;
std::ostringstream drawColor;
drawColor
<< std::setprecision(2) << std::fixed
<< "vec4(" << kDrawColor.x() << ", " << kDrawColor.y() << ", " << kDrawColor.z() << ", " << kDrawColor.w() << ")";
vert
<< "#version 450\n"
<< "layout (location=0) in vec2 inPos;\n"
<< "void main() {\n"
<< " gl_Position = vec4(inPos, 0.0, 1.0);\n"
<< " gl_PointSize = 1.0;\n"
<< "}\n"
;
frag
<< "#version 450\n"
<< "layout (location=0) out vec4 outColor;\n"
<< "void main() {\n"
<< " outColor = " << drawColor.str() << ";\n"
<< "}\n"
;
programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
}
TestInstance* StrideZeroCase::createInstance (Context& context) const
{
return new StrideZeroInstance(context, m_params);
}
void StrideZeroCase::checkSupport (Context& context) const
{
const auto properties = vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), kColorFormat);
if ((properties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
TCU_THROW(NotSupportedError, "Required image format not supported");
}
// Creates a vertex buffer with the given data but uses zero as the binding stride.
// Then, tries to draw the requested number of points. Only the first point should ever be used.
tcu::TestStatus StrideZeroInstance::iterate (void)
{
const auto& vkd = m_context.getDeviceInterface();
const auto device = m_context.getDevice();
auto& alloc = m_context.getDefaultAllocator();
const auto queue = m_context.getUniversalQueue();
const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
constexpr auto kImageDim = StrideZeroCase::kImageDim;
const auto colorExtent = vk::makeExtent3D(kImageDim, kImageDim, 1u);
// Prepare vertex buffer.
const auto vertexBufferSize = static_cast<vk::VkDeviceSize>(m_params.bufferData.size() * sizeof(decltype(m_params.bufferData)::value_type));
const auto vertexBufferInfo = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
const vk::BufferWithMemory vertexBuffer( vkd, device, alloc, vertexBufferInfo, vk::MemoryRequirement::HostVisible);
auto& vertexBufferAlloc = vertexBuffer.getAllocation();
const vk::VkDeviceSize vertexBufferOffset = 0ull;
deMemcpy(vertexBufferAlloc.getHostPtr(), m_params.bufferData.data(), static_cast<size_t>(vertexBufferSize));
flushAlloc(vkd, device, vertexBufferAlloc);
// Prepare render image.
const vk::VkImageCreateInfo colorAttachmentInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkImageCreateFlags flags;
vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
StrideZeroCase::kColorFormat, // VkFormat format;
colorExtent, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
StrideZeroCase::kColorUsage, // VkImageUsageFlags usage;
vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueIndex, // const deUint32* pQueueFamilyIndices;
vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
const vk::ImageWithMemory colorAttachment(vkd, device, alloc, colorAttachmentInfo, vk::MemoryRequirement::Any);
const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
const auto colorAttachmentView = vk::makeImageView(vkd, device, colorAttachment.get(), vk::VK_IMAGE_VIEW_TYPE_2D, StrideZeroCase::kColorFormat, colorSubresourceRange);
const vk::VkVertexInputBindingDescription vertexBinding =
{
0u, // deUint32 binding;
0u, // deUint32 stride; [IMPORTANT]
vk::VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
};
const vk::VkVertexInputAttributeDescription vertexAttribute =
{
0u, // deUint32 location;
0u, // deUint32 binding;
vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
0u, // deUint32 offset;
};
const vk::VkPipelineVertexInputStateCreateInfo vertexInput =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkPipelineVertexInputStateCreateFlags flags;
1u, // deUint32 vertexBindingDescriptionCount;
&vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1u, // deUint32 vertexAttributeDescriptionCount;
&vertexAttribute, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
};
const auto renderArea = vk::makeRect2D(kImageDim, kImageDim);
const auto viewports = std::vector<vk::VkViewport>(1, vk::makeViewport(kImageDim, kImageDim));
const auto scissors = std::vector<vk::VkRect2D>(1, renderArea);
const auto pipelineLayout = vk::makePipelineLayout(vkd, device);
const auto vertexShader = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
const auto fragmentShader = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
const auto renderPass = vk::makeRenderPass(vkd, device, StrideZeroCase::kColorFormat);
const auto graphicsPipeline = vk::makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
vertexShader.get(), DE_NULL, DE_NULL, DE_NULL, fragmentShader.get(), // Shaders.
renderPass.get(), viewports, scissors, vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0u, 0u, // Render pass, viewports, scissors, topology.
&vertexInput); // Vertex input state.
const auto framebuffer = vk::makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), kImageDim, kImageDim);
const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
const auto cmdBuffer = cmdBufferPtr.get();
// Buffer used to verify results.
const auto tcuFormat = vk::mapVkFormat(StrideZeroCase::kColorFormat);
const auto colorBufferSize = static_cast<vk::VkDeviceSize>(tcu::getPixelSize(tcuFormat)) * kImageDim * kImageDim;
const auto colorBufferInfo = vk::makeBufferCreateInfo(colorBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const vk::BufferWithMemory colorBuffer (vkd, device, alloc, colorBufferInfo, vk::MemoryRequirement::HostVisible);
auto& colorBufferAlloc = colorBuffer.getAllocation();
void* colorBufferPtr = colorBufferAlloc.getHostPtr();
const auto colorLayers = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
const auto copyRegion = vk::makeBufferImageCopy(colorExtent, colorLayers);
// Barriers from attachment to buffer and buffer to host.
const auto colorAttachmentBarrier = vk::makeImageMemoryBarrier (vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorAttachment.get(), colorSubresourceRange);
const auto colorBufferBarrier = vk::makeBufferMemoryBarrier (vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, colorBuffer.get(), 0ull, colorBufferSize);
vk::beginCommandBuffer(vkd, cmdBuffer);
vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea, StrideZeroCase::kClearColor);
vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
vkd.cmdDraw(cmdBuffer, m_params.drawVertexCount, 1u, 0u, 0u);
vk::endRenderPass(vkd, cmdBuffer);
vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorAttachmentBarrier);
vkd.cmdCopyImageToBuffer(cmdBuffer, colorAttachment.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.get(), 1u, &copyRegion);
vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &colorBufferBarrier, 0u, nullptr);
vk::endCommandBuffer(vkd, cmdBuffer);
vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
// Invalidate color buffer alloc.
vk::invalidateAlloc(vkd, device, colorBufferAlloc);
// Check buffer.
const int imageDimI = static_cast<int>(kImageDim);
const tcu::ConstPixelBufferAccess colorPixels (tcuFormat, imageDimI, imageDimI, 1, colorBufferPtr);
tcu::TestStatus testStatus = tcu::TestStatus::pass("Pass");
auto& log = m_context.getTestContext().getLog();
for (int x = 0; x < imageDimI; ++x)
for (int y = 0; y < imageDimI; ++y)
{
// Only the top-left corner should have draw data.
const auto expectedColor = ((x == 0 && y == 0) ? StrideZeroCase::kDrawColor : StrideZeroCase::kClearColor);
const auto imageColor = colorPixels.getPixel(x, y);
if (expectedColor != imageColor)
{
log
<< tcu::TestLog::Message
<< "Unexpected color found in pixel (" << x << ", " << y << "): "
<< "expected (" << expectedColor.x() << ", " << expectedColor.y() << ", " << expectedColor.z() << ", " << expectedColor.w() << ") "
<< "and found (" << imageColor.x() << ", " << imageColor.y() << ", " << imageColor.z() << ", " << imageColor.w() << ")"
<< tcu::TestLog::EndMessage;
testStatus = tcu::TestStatus::fail("Failed; Check log for details");
}
}
return testStatus;
}
void createRasterizationTests (tcu::TestCaseGroup* rasterizationTests)
{
tcu::TestContext& testCtx = rasterizationTests->getTestContext();
const struct
{
LineStippleFactorCase stippleFactor;
const std::string nameSuffix;
const std::string descSuffix;
} stippleFactorCases[] =
{
{ LineStippleFactorCase::DEFAULT, "", "" },
{ LineStippleFactorCase::ZERO, "_factor_0", " and use zero as the line stipple factor" },
{ LineStippleFactorCase::LARGE, "_factor_large", " and use a large number as the line stipple factor" },
};
// .primitives
{
tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(testCtx, "primitives", "Primitive rasterization");
rasterizationTests->addChild(primitives);
tcu::TestCaseGroup* const nostippleTests = new tcu::TestCaseGroup(testCtx, "no_stipple", "No stipple");
tcu::TestCaseGroup* const stippleStaticTests = new tcu::TestCaseGroup(testCtx, "static_stipple", "Line stipple static");
tcu::TestCaseGroup* const stippleDynamicTests = new tcu::TestCaseGroup(testCtx, "dynamic_stipple", "Line stipple dynamic");
tcu::TestCaseGroup* const strideZeroTests = new tcu::TestCaseGroup(testCtx, "stride_zero", "Test input assembly with stride zero");
primitives->addChild(nostippleTests);
primitives->addChild(stippleStaticTests);
primitives->addChild(stippleDynamicTests);
primitives->addChild(strideZeroTests);
// .stride_zero
{
{
StrideZeroCase::Params params;
params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
params.drawVertexCount = 1u;
strideZeroTests->addChild(new StrideZeroCase(testCtx, "single_point", "Attempt to draw 1 point with stride 0", params));
}
{
StrideZeroCase::Params params;
params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
params.bufferData.emplace_back( StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, StrideZeroCase::kCornerDelta);
params.bufferData.emplace_back( StrideZeroCase::kCornerDelta, StrideZeroCase::kCornerDelta);
params.drawVertexCount = static_cast<deUint32>(params.bufferData.size());
strideZeroTests->addChild(new StrideZeroCase(testCtx, "four_points", "Attempt to draw 4 points with stride 0 and 4 points in the buffer", params));
}
{
StrideZeroCase::Params params;
params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
params.drawVertexCount = 100000u;
strideZeroTests->addChild(new StrideZeroCase(testCtx, "many_points", "Attempt to draw many points with stride 0 with one point in the buffer", params));
}
}
nostippleTests->addChild(new BaseTestCase<TrianglesTestInstance> (testCtx, "triangles", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result"));
nostippleTests->addChild(new BaseTestCase<TriangleStripTestInstance> (testCtx, "triangle_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, verify rasterization result"));
nostippleTests->addChild(new BaseTestCase<TriangleFanTestInstance> (testCtx, "triangle_fan", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, verify rasterization result"));
nostippleTests->addChild(new WidenessTestCase<PointTestInstance> (testCtx, "points", "Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, false, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "strict_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "strict_line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in strict mode, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "strict_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "strict_line_strip_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in strict mode with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "non_strict_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "non_strict_line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "non_strict_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "non_strict_line_strip_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
for (int i = 0; i < 3; ++i) {
tcu::TestCaseGroup *g = i == 2 ? stippleDynamicTests : i == 1 ? stippleStaticTests : nostippleTests;
LineStipple stipple = (LineStipple)i;
for (const auto& sfCase : stippleFactorCases)
{
if (sfCase.stippleFactor != LineStippleFactorCase::DEFAULT && stipple != LINESTIPPLE_DISABLED)
continue;
const auto& factor = sfCase.stippleFactor;
const auto& suffix = sfCase.nameSuffix;
const auto& descSuffix = sfCase.descSuffix;
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "lines" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor, i == 0 ? RESOLUTION_NPOT : 0));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "line_strip" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "lines_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "line_strip_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "rectangular_lines" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "rectangular_line_strip" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "rectangular_lines_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "rectangular_line_strip_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "bresenham_lines" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "bresenham_line_strip" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "bresenham_lines_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "bresenham_line_strip_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "smooth_lines" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "smooth_line_strip" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "smooth_lines_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "smooth_line_strip_wide" + suffix, "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result" + descSuffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
}
}
}
// .primitive_size
{
tcu::TestCaseGroup* const primitiveSize = new tcu::TestCaseGroup(testCtx, "primitive_size", "Primitive size");
rasterizationTests->addChild(primitiveSize);
// .points
{
tcu::TestCaseGroup* const points = new tcu::TestCaseGroup(testCtx, "points", "Point size");
static const struct TestCombinations
{
const deUint32 renderSize;
const float pointSize;
} testCombinations[] =
{
{ 1024, 128.0f },
{ 1024, 256.0f },
{ 1024, 512.0f },
{ 2048, 1024.0f },
{ 4096, 2048.0f },
{ 8192, 4096.0f },
{ 9216, 8192.0f },
{ 10240, 10000.0f }
};
for (size_t testCombNdx = 0; testCombNdx < DE_LENGTH_OF_ARRAY(testCombinations); testCombNdx++)
{
std::string testCaseName = "point_size_" + de::toString(testCombinations[testCombNdx].pointSize);
deUint32 renderSize = testCombinations[testCombNdx].renderSize;
float pointSize = testCombinations[testCombNdx].pointSize;
points->addChild(new PointSizeTestCase<PointSizeTestInstance> (testCtx, testCaseName, testCaseName, renderSize, pointSize));
}
primitiveSize->addChild(points);
}
}
// .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" },
};
static const struct PolygonMode
{
VkPolygonMode mode;
const char* name;
} polygonModes[] =
{
{ VK_POLYGON_MODE_FILL, "" },
{ VK_POLYGON_MODE_LINE, "_line" },
{ VK_POLYGON_MODE_POINT, "_point" }
};
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)
for (int polygonModeNdx = 0; polygonModeNdx < DE_LENGTH_OF_ARRAY(polygonModes); ++polygonModeNdx)
{
if (!(cullModes[cullModeNdx].mode == VK_CULL_MODE_FRONT_AND_BACK && polygonModes[polygonModeNdx].mode != VK_POLYGON_MODE_FILL))
{
const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix + polygonModes[polygonModeNdx].name;
culling->addChild(new CullingTestCase(testCtx, name, "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode, polygonModes[polygonModeNdx].mode));
}
}
}
// .discard
{
static const struct PrimitiveType
{
VkPrimitiveTopology type;
const char* name;
} primitiveTypes[] =
{
{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangle_list" },
{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip" },
{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan" },
{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "line_list" },
{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, "line_strip" },
{ VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "point_list" }
};
static const struct queryPipeline
{
deBool useQuery;
const char* name;
} queryPipeline[] =
{
{ DE_FALSE, "query_pipeline_false" },
{ DE_TRUE, "query_pipeline_true" },
};
tcu::TestCaseGroup* const discard = new tcu::TestCaseGroup(testCtx, "discard", "Rasterizer discard");
for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
{
tcu::TestCaseGroup* const primitive = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveNdx].name, "Rasterizer discard");
for (int useQueryNdx = 0; useQueryNdx < DE_LENGTH_OF_ARRAY(queryPipeline); useQueryNdx++)
{
const std::string name = std::string(queryPipeline[useQueryNdx].name);
primitive->addChild(new DiscardTestCase(testCtx, name, "Test primitive discarding.", primitiveTypes[primitiveNdx].type, queryPipeline[useQueryNdx].useQuery));
}
discard->addChild(primitive);
}
rasterizationTests->addChild(discard);
}
// .conservative
{
typedef struct
{
float size;
const char* name;
} overestimateSizes;
const overestimateSizes overestimateNormalSizes[] =
{
{ 0.00f, "0_00" },
{ 0.25f, "0_25" },
{ 0.50f, "0_50" },
{ 0.75f, "0_75" },
{ 1.00f, "1_00" },
{ 2.00f, "2_00" },
{ 4.00f, "4_00" },
{ -TCU_INFINITY, "min" },
{ TCU_INFINITY, "max" },
};
const overestimateSizes overestimateDegenerate[] =
{
{ 0.00f, "0_00" },
{ 0.25f, "0_25" },
{ -TCU_INFINITY, "min" },
{ TCU_INFINITY, "max" },
};
const overestimateSizes underestimateLineWidths[] =
{
{ 0.50f, "0_50" },
{ 1.00f, "1_00" },
{ 1.50f, "1_50" },
};
const overestimateSizes underestimatePointSizes[] =
{
{ 1.00f, "1_00" },
{ 1.50f, "1_50" },
{ 2.00f, "2_00" },
{ 3.00f, "3_00" },
{ 4.00f, "4_00" },
{ 8.00f, "8_00" },
};
const struct PrimitiveType
{
VkPrimitiveTopology type;
const char* name;
}
primitiveTypes[] =
{
{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles" },
{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines" },
{ VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points" }
};
const VkSampleCountFlagBits samples[] =
{
VK_SAMPLE_COUNT_1_BIT,
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
};
tcu::TestCaseGroup* const conservative = new tcu::TestCaseGroup(testCtx, "conservative", "Conservative rasterization tests");
rasterizationTests->addChild(conservative);
{
tcu::TestCaseGroup* const overestimate = new tcu::TestCaseGroup(testCtx, "overestimate", "Overestimate tests");
conservative->addChild(overestimate);
for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
{
const std::string samplesGroupName = "samples_" + de::toString(samples[samplesNdx]);
tcu::TestCaseGroup* const samplesGroup = new tcu::TestCaseGroup(testCtx, samplesGroupName.c_str(), "Samples tests");
overestimate->addChild(samplesGroup);
for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
{
tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveTypeNdx].name, "Primitive tests");
samplesGroup->addChild(primitiveGroup);
{
tcu::TestCaseGroup* const normal = new tcu::TestCaseGroup(testCtx, "normal", "Normal conservative rasterization tests");
primitiveGroup->addChild(normal);
for (int overestimateSizesNdx = 0; overestimateSizesNdx < DE_LENGTH_OF_ARRAY(overestimateNormalSizes); ++overestimateSizesNdx)
{
const ConservativeTestConfig config =
{
VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
overestimateNormalSizes[overestimateSizesNdx].size, // float extraOverestimationSize;
primitiveTypes[primitiveTypeNdx].type, // VkPrimitiveTopology primitiveTopology;
false, // bool degeneratePrimitives;
1.0f, // float lineWidth;
RESOLUTION_POT, // deUint32 resolution;
};
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
normal->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance> (testCtx,
overestimateNormalSizes[overestimateSizesNdx].name,
"Overestimate test, verify rasterization result",
config,
samples[samplesNdx]));
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
normal->addChild(new ConservativeTestCase<ConservativeLineTestInstance> (testCtx,
overestimateNormalSizes[overestimateSizesNdx].name,
"Overestimate test, verify rasterization result",
config,
samples[samplesNdx]));
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
normal->addChild(new ConservativeTestCase<ConservativePointTestInstance> (testCtx,
overestimateNormalSizes[overestimateSizesNdx].name,
"Overestimate test, verify rasterization result",
config,
samples[samplesNdx]));
}
}
{
tcu::TestCaseGroup* const degenerate = new tcu::TestCaseGroup(testCtx, "degenerate", "Degenerate primitives conservative rasterization tests");
primitiveGroup->addChild(degenerate);
for (int overestimateSizesNdx = 0; overestimateSizesNdx < DE_LENGTH_OF_ARRAY(overestimateDegenerate); ++overestimateSizesNdx)
{
const ConservativeTestConfig config =
{
VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
overestimateDegenerate[overestimateSizesNdx].size, // float extraOverestimationSize;
primitiveTypes[primitiveTypeNdx].type, // VkPrimitiveTopology primitiveTopology;
true, // bool degeneratePrimitives;
1.0f, // float lineWidth;
64u, // deUint32 resolution;
};
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
degenerate->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance> (testCtx,
overestimateDegenerate[overestimateSizesNdx].name,
"Overestimate triangle test, verify rasterization result",
config,
samples[samplesNdx]));
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
degenerate->addChild(new ConservativeTestCase<ConservativeLineTestInstance> (testCtx,
overestimateDegenerate[overestimateSizesNdx].name,
"Overestimate line test, verify rasterization result",
config,
samples[samplesNdx]));
}
}
}
}
}
{
tcu::TestCaseGroup* const underestimate = new tcu::TestCaseGroup(testCtx, "underestimate", "Underestimate tests");
conservative->addChild(underestimate);
for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
{
const std::string samplesGroupName = "samples_" + de::toString(samples[samplesNdx]);
tcu::TestCaseGroup* const samplesGroup = new tcu::TestCaseGroup(testCtx, samplesGroupName.c_str(), "Samples tests");
underestimate->addChild(samplesGroup);
for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
{
tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveTypeNdx].name, "Primitive tests");
samplesGroup->addChild(primitiveGroup);
{
tcu::TestCaseGroup* const normal = new tcu::TestCaseGroup(testCtx, "normal", "Normal conservative rasterization tests");
primitiveGroup->addChild(normal);
ConservativeTestConfig config =
{
VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
0.0f, // float extraOverestimationSize;
primitiveTypes[primitiveTypeNdx].type, // VkPrimitiveTopology primitiveTopology;
false, // bool degeneratePrimitives;
1.0f, // float lineWidth;
64u, // deUint32 resolution;
};
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
normal->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance> (testCtx,
"test",
"Underestimate test, verify rasterization result",
config,
samples[samplesNdx]));
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
{
for (int underestimateWidthNdx = 0; underestimateWidthNdx < DE_LENGTH_OF_ARRAY(underestimateLineWidths); ++underestimateWidthNdx)
{
config.lineWidth = underestimateLineWidths[underestimateWidthNdx].size;
normal->addChild(new ConservativeTestCase<ConservativeLineTestInstance> (testCtx,
underestimateLineWidths[underestimateWidthNdx].name,
"Underestimate test, verify rasterization result",
config,
samples[samplesNdx]));
}
}
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
{
for (int underestimatePointSizeNdx = 0; underestimatePointSizeNdx < DE_LENGTH_OF_ARRAY(underestimatePointSizes); ++underestimatePointSizeNdx)
{
config.lineWidth = underestimatePointSizes[underestimatePointSizeNdx].size;
normal->addChild(new ConservativeTestCase<ConservativePointTestInstance> (testCtx,
underestimatePointSizes[underestimatePointSizeNdx].name,
"Underestimate test, verify rasterization result",
config,
samples[samplesNdx]));
}
}
}
{
tcu::TestCaseGroup* const degenerate = new tcu::TestCaseGroup(testCtx, "degenerate", "Degenerate primitives conservative rasterization tests");
primitiveGroup->addChild(degenerate);
ConservativeTestConfig config =
{
VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, // VkConservativeRasterizationModeEXT conservativeRasterizationMode;
0.0f, // float extraOverestimationSize;
primitiveTypes[primitiveTypeNdx].type, // VkPrimitiveTopology primitiveTopology;
true, // bool degeneratePrimitives;
1.0f, // float lineWidth;
64u, // deUint32 resolution;
};
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
degenerate->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance> (testCtx,
"test",
"Underestimate triangle test, verify rasterization result",
config,
samples[samplesNdx]));
if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
{
for (int underestimateWidthNdx = 0; underestimateWidthNdx < DE_LENGTH_OF_ARRAY(underestimateLineWidths); ++underestimateWidthNdx)
{
config.lineWidth = underestimateLineWidths[underestimateWidthNdx].size;
degenerate->addChild(new ConservativeTestCase<ConservativeLineTestInstance> (testCtx,
underestimateLineWidths[underestimateWidthNdx].name,
"Underestimate line test, verify rasterization result",
config,
samples[samplesNdx]));
}
}
}
}
}
}
}
// .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, PRIMITIVESTRICTNESS_IGNORE));
basic->addChild(new LineInterpolationTestCase (testCtx, "line_strip", "Verify line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE));
basic->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
basic->addChild(new LineInterpolationTestCase (testCtx, "line_strip_wide","Verify wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
basic->addChild(new LineInterpolationTestCase (testCtx, "strict_lines", "Verify strict line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "strict_line_strip", "Verify strict line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "strict_lines_wide", "Verify strict wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "strict_line_strip_wide", "Verify strict wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines", "Verify non-strict line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "non_strict_line_strip", "Verify non-strict line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines_wide", "Verify non-strict wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
basic->addChild(new LineInterpolationTestCase (testCtx, "non_strict_line_strip_wide", "Verify non-strict wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
}
// .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, PRIMITIVESTRICTNESS_IGNORE));
projected->addChild(new LineInterpolationTestCase (testCtx, "line_strip", "Verify line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE));
projected->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
projected->addChild(new LineInterpolationTestCase (testCtx, "line_strip_wide","Verify wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
projected->addChild(new LineInterpolationTestCase (testCtx, "strict_lines", "Verify strict line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "strict_line_strip", "Verify strict line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "strict_lines_wide", "Verify strict wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "strict_line_strip_wide", "Verify strict wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines", "Verify non-strict line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "non_strict_line_strip", "Verify non-strict line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines_wide", "Verify non-strict wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
projected->addChild(new LineInterpolationTestCase (testCtx, "non_strict_line_strip_wide", "Verify non-strict wide line strip interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
}
}
// .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, PRIMITIVESTRICTNESS_IGNORE));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "line_strip", "Verify line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "line_strip_wide","Verify wide line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "strict_lines", "Verify strict line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "strict_line_strip", "Verify strict line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "strict_lines_wide", "Verify strict wide line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "strict_line_strip_wide", "Verify strict wide line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines", "Verify non-strict line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "non_strict_line_strip", "Verify non-strict line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines_wide", "Verify non-strict wide line flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
flatshading->addChild(new LineInterpolationTestCase (testCtx, "non_strict_line_strip_wide", "Verify non-strict wide line strip flatshading", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
}
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);
tcu::TestCaseGroup* const nostippleTests = new tcu::TestCaseGroup(testCtx, "no_stipple", "No stipple");
tcu::TestCaseGroup* const stippleStaticTests = new tcu::TestCaseGroup(testCtx, "static_stipple", "Line stipple static");
tcu::TestCaseGroup* const stippleDynamicTests = new tcu::TestCaseGroup(testCtx, "dynamic_stipple", "Line stipple dynamic");
primitives->addChild(nostippleTests);
primitives->addChild(stippleStaticTests);
primitives->addChild(stippleDynamicTests);
nostippleTests->addChild(new BaseTestCase<TrianglesTestInstance> (testCtx, "triangles", "Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result", samples[samplesNdx]));
nostippleTests->addChild(new WidenessTestCase<PointTestInstance> (testCtx, "points", "Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, false, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "strict_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "strict_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "non_strict_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
nostippleTests->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "non_strict_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
for (int i = 0; i < 3; ++i) {
tcu::TestCaseGroup *g = i == 2 ? stippleDynamicTests : i == 1 ? stippleStaticTests : nostippleTests;
LineStipple stipple = (LineStipple)i;
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, LineStippleFactorCase::DEFAULT, i == 0 ? RESOLUTION_NPOT : 0));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "line_strip_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "rectangular_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "rectangular_line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "rectangular_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "rectangular_line_strip_wide","Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "bresenham_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "bresenham_line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "bresenham_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "bresenham_line_strip_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "smooth_lines", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "smooth_line_strip", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
g->addChild(new WidenessTestCase<LinesTestInstance> (testCtx, "smooth_lines_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
g->addChild(new WidenessTestCase<LineStripTestInstance> (testCtx, "smooth_line_strip_wide", "Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
}
}
// .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, PRIMITIVESTRICTNESS_IGNORE, samples[samplesNdx]));
interpolation->addChild(new LineInterpolationTestCase (testCtx, "lines_wide", "Verify wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, samples[samplesNdx]));
interpolation->addChild(new LineInterpolationTestCase (testCtx, "strict_lines", "Verify strict line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, samples[samplesNdx]));
interpolation->addChild(new LineInterpolationTestCase (testCtx, "strict_lines_wide", "Verify strict wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, samples[samplesNdx]));
interpolation->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines", "Verify non-strict line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, samples[samplesNdx]));
interpolation->addChild(new LineInterpolationTestCase (testCtx, "non_strict_lines_wide", "Verify non-strict wide line interpolation", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, samples[samplesNdx]));
}
}
// .provoking_vertex
#ifndef CTS_USES_VULKANSC
{
rasterizationTests->addChild(createProvokingVertexTests(testCtx));
}
#endif
// .line_continuity
#ifndef CTS_USES_VULKANSC
{
tcu::TestCaseGroup* const lineContinuity = new tcu::TestCaseGroup(testCtx, "line_continuity", "Test line continuity");
static const char dataDir[] = "rasterization/line_continuity";
struct Case
{
std::string name;
std::string desc;
bool requireFillModeNonSolid;
};
static const Case cases[] =
{
{ "line-strip", "Test line strip drawing produces continuous lines", false },
{ "polygon-mode-lines", "Test triangles drawn with lines are continuous", true }
};
rasterizationTests->addChild(lineContinuity);
for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
{
const std::string fileName = cases[i].name + ".amber";
cts_amber::AmberTestCase* testCase = cts_amber::createAmberTestCase(testCtx, cases[i].name.c_str(), cases[i].desc.c_str(), dataDir, fileName);
if (cases[i].requireFillModeNonSolid)
{
testCase->addRequirement("Features.fillModeNonSolid");
}
lineContinuity->addChild(testCase);
}
}
#endif
// .depth bias
#ifndef CTS_USES_VULKANSC
{
tcu::TestCaseGroup* const depthBias = new tcu::TestCaseGroup(testCtx, "depth_bias", "Test depth bias");
static const char dataDir[] = "rasterization/depth_bias";
static const struct
{
std::string name;
vk::VkFormat format;
std::string description;
} cases [] =
{
{"d16_unorm", vk::VK_FORMAT_D16_UNORM, "Test depth bias with format D16_UNORM"},
{"d32_sfloat", vk::VK_FORMAT_D32_SFLOAT, "Test depth bias with format D32_SFLOAT"},
{"d24_unorm", vk::VK_FORMAT_D24_UNORM_S8_UINT, "Test depth bias with format D24_UNORM_S8_UINT"}
};
for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
{
const VkImageCreateInfo vkImageCreateInfo = {
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
nullptr, // pNext
0, // flags
VK_IMAGE_TYPE_2D, // imageType
cases[i].format, // format
{250, 250, 1}, // extent
1, // mipLevels
1, // arrayLayers
VK_SAMPLE_COUNT_1_BIT, // samples
VK_IMAGE_TILING_OPTIMAL, // tiling
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, // usage
VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0, // queueFamilyIndexCount
nullptr, // pQueueFamilyIndices
VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
};
std::vector<std::string> requirements = std::vector<std::string>(0);
std::vector<VkImageCreateInfo> imageRequirements;
imageRequirements.push_back(vkImageCreateInfo);
const std::string fileName = cases[i].name + ".amber";
cts_amber::AmberTestCase* testCase = cts_amber::createAmberTestCase(testCtx, cases[i].name.c_str(), cases[i].description.c_str(), dataDir, fileName, requirements, imageRequirements);
depthBias->addChild(testCase);
}
rasterizationTests->addChild(depthBias);
}
#endif // CTS_USES_VULKANSC
// Fragment shader side effects.
{
rasterizationTests->addChild(createFragSideEffectsTests(testCtx));
}
}
} // anonymous
tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "rasterization", "Rasterization Tests", createRasterizationTests);
}
} // rasterization
} // vkt