blob: 3b3f9d79dbc8c260b232928d4040a8d16bdf10a1 [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 "tcuRasterizationVerifier.hpp"
#include "tcuSurface.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuResultCollector.hpp"
#include "vkImageUtil.hpp"
#include "deStringUtil.hpp"
#include "deRandom.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include <vector>
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 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;
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* 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;
};
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())
{
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;
deMemset(&m_lineRasterizationStateInfo, 0, sizeof(m_lineRasterizationStateInfo));
// 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();
rasterizationStateInfo.pNext = getLineRasterizationStateCreateInfo();
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::getLineRasterizationStateCreateInfo (void)
{
m_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 &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);
virtual tcu::TestStatus iterate (void);
private:
virtual void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) = DE_NULL;
int m_iteration;
const int m_iterationCount;
VkPrimitiveTopology m_primitiveTopology;
bool m_allIterationsPassed;
};
BaseTriangleTestInstance::BaseTriangleTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount)
: BaseRenderingTestInstance (context, sampleCount)
, m_iteration (0)
, m_iterationCount (3)
, m_primitiveTopology (primitiveTopology)
, m_allIterationsPassed (true)
{
}
tcu::TestStatus BaseTriangleTestInstance::iterate (void)
{
const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), iterationDescription, iterationDescription);
tcu::Surface resultImage (m_renderSize, m_renderSize);
std::vector<tcu::Vec4> drawBuffer;
std::vector<TriangleSceneSpec::SceneTriangle> triangles;
generateTriangles(m_iteration, drawBuffer, triangles);
// draw image
drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
// compare
{
bool compareOk;
RasterizationArguments args;
TriangleSceneSpec scene;
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
args.numSamples = m_multisampling ? 1 : 0;
args.subpixelBits = m_subpixelBits;
args.redBits = colorBits[0];
args.greenBits = colorBits[1];
args.blueBits = colorBits[2];
scene.triangles.swap(triangles);
compareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
if (!compareOk)
m_allIterationsPassed = false;
}
// result
if (++m_iteration == m_iterationCount)
{
if (m_allIterationsPassed)
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Incorrect rasterization");
}
else
return tcu::TestStatus::incomplete();
}
class BaseLineTestInstance : public BaseRenderingTestInstance
{
public:
BaseLineTestInstance (Context& context,
VkPrimitiveTopology primitiveTopology,
PrimitiveWideness wideness,
PrimitiveStrictness strictness,
VkSampleCountFlagBits sampleCount,
LineStipple stipple,
VkLineRasterizationModeEXT lineRasterizationMode,
const deUint32 additionalRenderSize = 0);
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* getLineRasterizationStateCreateInfo (void);
private:
virtual void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) = DE_NULL;
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;
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,
const deUint32 additionalRenderSize)
: BaseRenderingTestInstance (context, sampleCount, RESOLUTION_POT, 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)
{
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, 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);
// 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);
tcu::Surface additionalResultImage (m_additionalRenderSize, m_additionalRenderSize);
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
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;
// 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()))
m_allIterationsPassed = 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;
m_allIterationsPassed = 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))
m_allIterationsPassed = 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)
{
m_allIterationsPassed = 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))
m_allIterationsPassed = false;
else
m_qualityWarning = true;
}
}
}
}
}
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();
}
float BaseLineTestInstance::getLineWidth (void) const
{
return m_lineWidths[m_iteration];
}
VkPipelineRasterizationLineStateCreateInfoEXT* BaseLineTestInstance::getLineRasterizationStateCreateInfo (void)
{
if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_EXT_LAST)
return DE_NULL;
m_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)
{
m_lineRasterizationStateInfo.lineStippleFactor = lineStippleFactor;
m_lineRasterizationStateInfo.lineStipplePattern = lineStipplePattern;
}
return &m_lineRasterizationStateInfo;
}
class PointTestInstance : public BaseRenderingTestInstance
{
public:
PointTestInstance (Context& context,
PrimitiveWideness wideness,
PrimitiveStrictness strictness, // ignored
VkSampleCountFlagBits sampleCount,
LineStipple stipple, // ignored
VkLineRasterizationModeEXT lineRasterizationMode, // ignored
deUint32 renderSize); // ignored
virtual tcu::TestStatus iterate (void);
virtual float getPointSize (void) const;
private:
virtual void generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints);
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,
deUint32 renderSize)
: BaseRenderingTestInstance (context, sampleCount)
, m_iteration (0)
, m_iterationCount (3)
, m_primitiveWideness (wideness)
, m_allIterationsPassed (true)
, m_maxPointSize (1.0f)
{
DE_UNREF(strictness);
DE_UNREF(stipple);
DE_UNREF(lineRasterizationMode);
DE_UNREF(renderSize);
// create point sizes
if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
{
m_pointSizes.resize(m_iterationCount, 1.0f);
}
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
{
bool compareOk;
RasterizationArguments args;
PointSceneSpec scene;
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
args.numSamples = m_multisampling ? 1 : 0;
args.subpixelBits = m_subpixelBits;
args.redBits = colorBits[0];
args.greenBits = colorBits[1];
args.blueBits = colorBits[2];
scene.points.swap(points);
compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
if (!compareOk)
m_allIterationsPassed = false;
}
}
else
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point size " << pointSize << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
// result
if (++m_iteration == m_iterationCount)
{
if (m_allIterationsPassed)
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Incorrect rasterization");
}
else
return tcu::TestStatus::incomplete();
}
float PointTestInstance::getPointSize (void) const
{
return m_pointSizes[m_iteration];
}
void PointTestInstance::generatePoints (int iteration, std::vector<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
{
// 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");
}
}
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);
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)
: BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, sampleCount)
{}
void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
};
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;
}
}
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,
deUint32 additionalRenderSize = 0)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_wideness(wideness)
, m_strictness (strictness)
, m_isLineTest (isLineTest)
, m_stipple (stipple)
, m_lineRasterizationMode (lineRasterizationMode)
, m_additionalRenderSize (additionalRenderSize)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new ConcreteTestInstance(context, m_wideness, m_strictness, m_sampleCount, m_stipple, m_lineRasterizationMode, 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 deUint32 m_additionalRenderSize;
};
class LinesTestInstance : public BaseLineTestInstance
{
public:
LinesTestInstance (Context& context, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount, LineStipple stipple, VkLineRasterizationModeEXT lineRasterizationMode, deUint32 additionalRenderSize = 0)
: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, wideness, strictness, sampleCount, stipple, lineRasterizationMode, 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, deUint32)
: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, wideness, strictness, sampleCount, stipple, lineRasterizationMode)
{}
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()