blob: 007f452536379d17c9b81aabafca1149d88ffa2d [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 PrimitiveWideness
{
PRIMITIVEWIDENESS_NARROW = 0,
PRIMITIVEWIDENESS_WIDE,
PRIMITIVEWIDENESS_LAST
};
class BaseRenderingTestCase : public TestCase
{
public:
BaseRenderingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deBool flatshade = DE_FALSE);
virtual ~BaseRenderingTestCase (void);
virtual void initPrograms (vk::SourceCollections& programCollection) const;
protected:
const VkSampleCountFlagBits m_sampleCount;
const deBool m_flatshade;
};
BaseRenderingTestCase::BaseRenderingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount, deBool flatshade)
: TestCase(context, name, description)
, m_sampleCount (sampleCount)
, m_flatshade (flatshade)
{
}
void BaseRenderingTestCase::initPrograms (vk::SourceCollections& programCollection) const
{
tcu::StringTemplate vertexSource (s_shaderVertexTemplate);
tcu::StringTemplate fragmentSource (s_shaderFragmentTemplate);
std::map<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:
enum {
DEFAULT_RENDER_SIZE = 256
};
BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deUint32 renderSize = DEFAULT_RENDER_SIZE, VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM);
~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);
virtual float getLineWidth (void) const;
virtual float getPointSize (void) const;
virtual
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
virtual
const VkPipelineColorBlendStateCreateInfo* getColorBlendStateCreateInfo (void) const;
const tcu::TextureFormat& getTextureFormat (void) const;
const deUint32 m_renderSize;
const VkSampleCountFlagBits m_sampleCount;
const deUint32 m_subpixelBits;
const deBool m_multisampling;
const VkFormat m_imageFormat;
const tcu::TextureFormat m_textureFormat;
Move<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;
};
BaseRenderingTestInstance::BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount, deUint32 renderSize, VkFormat imageFormat)
: 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())
{
const DeviceInterface& vkd = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
Allocator& allocator = m_context.getDefaultAllocator();
DescriptorPoolBuilder descriptorPoolBuilder;
DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
// Command Pool
m_commandPool = createCommandPool(vkd, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
// Image
{
const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
VkImageFormatProperties properties;
if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(),
m_imageFormat,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL,
imageUsage,
0,
&properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
{
TCU_THROW(NotSupportedError, "Format not supported");
}
if ((properties.sampleCounts & m_sampleCount) != m_sampleCount)
{
TCU_THROW(NotSupportedError, "Format not supported");
}
const VkImageCreateInfo imageCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_imageFormat, // VkFormat format;
{ m_renderSize, m_renderSize, 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
m_sampleCount, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
imageUsage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_image = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
m_imageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_image), MemoryRequirement::Any);
VK_CHECK(vkd.bindImageMemory(vkDevice, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset()));
}
// Image View
{
const VkImageViewCreateInfo imageViewCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_image, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_imageFormat, // VkFormat format;
makeComponentMappingRGBA(), // VkComponentMapping components;
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
m_imageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
}
if (m_multisampling)
{
{
// Resolved Image
const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkImageFormatProperties properties;
if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(),
m_imageFormat,
VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL,
imageUsage,
0,
&properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
{
TCU_THROW(NotSupportedError, "Format not supported");
}
const VkImageCreateInfo imageCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_imageFormat, // VkFormat format;
{ m_renderSize, m_renderSize, 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
imageUsage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_resolvedImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
m_resolvedImageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_resolvedImage), MemoryRequirement::Any);
VK_CHECK(vkd.bindImageMemory(vkDevice, *m_resolvedImage, m_resolvedImageMemory->getMemory(), m_resolvedImageMemory->getOffset()));
}
// Resolved Image View
{
const VkImageViewCreateInfo imageViewCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_resolvedImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_imageFormat, // VkFormat format;
makeComponentMappingRGBA(), // VkComponentMapping components;
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArrayLayer;
1u, // deUint32 arraySize;
}, // VkImageSubresourceRange subresourceRange;
};
m_resolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
}
}
// Render Pass
{
const VkImageLayout imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
const VkAttachmentDescription attachmentDesc[] =
{
{
0u, // VkAttachmentDescriptionFlags flags;
m_imageFormat, // VkFormat format;
m_sampleCount, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
imageLayout, // VkImageLayout initialLayout;
imageLayout, // VkImageLayout finalLayout;
},
{
0u, // VkAttachmentDescriptionFlags flags;
m_imageFormat, // VkFormat format;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
imageLayout, // VkImageLayout initialLayout;
imageLayout, // VkImageLayout finalLayout;
}
};
const VkAttachmentReference attachmentRef =
{
0u, // deUint32 attachment;
imageLayout, // VkImageLayout layout;
};
const VkAttachmentReference resolveAttachmentRef =
{
1u, // deUint32 attachment;
imageLayout, // VkImageLayout layout;
};
const VkSubpassDescription subpassDesc =
{
0u, // VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // deUint32 inputAttachmentCount;
DE_NULL, // const VkAttachmentReference* pInputAttachments;
1u, // deUint32 colorAttachmentCount;
&attachmentRef, // const VkAttachmentReference* pColorAttachments;
m_multisampling ? &resolveAttachmentRef : DE_NULL, // const VkAttachmentReference* pResolveAttachments;
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
0u, // deUint32 preserveAttachmentCount;
DE_NULL, // const VkAttachmentReference* pPreserveAttachments;
};
const VkRenderPassCreateInfo renderPassCreateInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkRenderPassCreateFlags flags;
m_multisampling ? 2u : 1u, // deUint32 attachmentCount;
attachmentDesc, // const VkAttachmentDescription* pAttachments;
1u, // deUint32 subpassCount;
&subpassDesc, // const VkSubpassDescription* pSubpasses;
0u, // deUint32 dependencyCount;
DE_NULL, // const VkSubpassDependency* pDependencies;
};
m_renderPass = createRenderPass(vkd, vkDevice, &renderPassCreateInfo, DE_NULL);
}
// FrameBuffer
{
const VkImageView attachments[] =
{
*m_imageView,
*m_resolvedImageView
};
const VkFramebufferCreateInfo framebufferCreateInfo =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkFramebufferCreateFlags flags;
*m_renderPass, // VkRenderPass renderPass;
m_multisampling ? 2u : 1u, // deUint32 attachmentCount;
attachments, // const VkImageView* pAttachments;
m_renderSize, // deUint32 width;
m_renderSize, // deUint32 height;
1u, // deUint32 layers;
};
m_frameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL);
}
// Uniform Buffer
{
const VkBufferCreateInfo bufferCreateInfo =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_uniformBufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
m_uniformBuffer = createBuffer(vkd, vkDevice, &bufferCreateInfo);
m_uniformBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_uniformBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_uniformBuffer, m_uniformBufferMemory->getMemory(), m_uniformBufferMemory->getOffset()));
}
// Descriptors
{
descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
m_descriptorPool = descriptorPoolBuilder.build(vkd, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
m_descriptorSetLayout = descriptorSetLayoutBuilder.build(vkd, vkDevice);
const VkDescriptorSetAllocateInfo descriptorSetParams =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
*m_descriptorPool,
1u,
&m_descriptorSetLayout.get(),
};
m_descriptorSet = allocateDescriptorSet(vkd, vkDevice, &descriptorSetParams);
const VkDescriptorBufferInfo descriptorBufferInfo =
{
*m_uniformBuffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
VK_WHOLE_SIZE // VkDeviceSize range;
};
const VkWriteDescriptorSet writeDescritporSet =
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_descriptorSet, // VkDescriptorSet destSet;
0, // deUint32 destBinding;
0, // deUint32 destArrayElement;
1u, // deUint32 count;
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType descriptorType;
DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
&descriptorBufferInfo, // const VkDescriptorBufferInfo* pBufferInfo;
DE_NULL // const VkBufferView* pTexelBufferView;
};
vkd.updateDescriptorSets(vkDevice, 1u, &writeDescritporSet, 0u, DE_NULL);
}
// Pipeline Layout
{
const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineLayoutCreateFlags flags;
1u, // deUint32 descriptorSetCount;
&m_descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
m_pipelineLayout = createPipelineLayout(vkd, vkDevice, &pipelineLayoutCreateInfo);
}
// Shaders
{
m_vertexShaderModule = createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("vertext_shader"), 0);
m_fragmentShaderModule = createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("fragment_shader"), 0);
}
// Result Buffer
{
const VkBufferCreateInfo bufferCreateInfo =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_resultBufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
m_resultBuffer = createBuffer(vkd, vkDevice, &bufferCreateInfo);
m_resultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_resultBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_resultBuffer, m_resultBufferMemory->getMemory(), m_resultBufferMemory->getOffset()));
}
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Sample count = " << getSampleCountFlagsStr(m_sampleCount) << tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
}
BaseRenderingTestInstance::~BaseRenderingTestInstance (void)
{
}
void BaseRenderingTestInstance::addImageTransitionBarrier(VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const
{
const DeviceInterface& vkd = m_context.getDeviceInterface();
const VkImageSubresourceRange subResourcerange =
{
VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
0, // deUint32 baseMipLevel;
1, // deUint32 levelCount;
0, // deUint32 baseArrayLayer;
1 // deUint32 layerCount;
};
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
srcAccessMask, // VkAccessFlags srcAccessMask;
dstAccessMask, // VkAccessFlags dstAccessMask;
oldLayout, // VkImageLayout oldLayout;
newLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex;
image, // VkImage image;
subResourcerange // VkImageSubresourceRange subresourceRange;
};
vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &imageBarrier);
}
void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
{
// default to color white
const std::vector<tcu::Vec4> colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
drawPrimitives(result, vertexData, colorData, primitiveTopology);
}
void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology)
{
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(m_renderSize)));
const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(m_renderSize)));
const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineMultisampleStateCreateFlags flags;
m_sampleCount, // VkSampleCountFlagBits rasterizationSamples;
VK_FALSE, // VkBool32 sampleShadingEnable;
0.0f, // float minSampleShading;
DE_NULL, // const VkSampleMask* pSampleMask;
VK_FALSE, // VkBool32 alphaToCoverageEnable;
VK_FALSE // VkBool32 alphaToOneEnable;
};
graphicsPipeline = makeGraphicsPipeline(vkd, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayout, // const VkPipelineLayout pipelineLayout
*m_vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule
*m_renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
primitiveTopology, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
getRasterizationStateCreateInfo(), // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
&multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo,
getColorBlendStateCreateInfo()); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
}
// Create Vertex Buffer
{
const VkBufferCreateInfo vertexBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
attributeBatchSize * 2, // VkDeviceSize size;
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
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, *m_image,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags srcStageMask
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VkPipelineStageFlags dstStageMask
0, // VkAccessFlags srcAccessMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
if (m_multisampling) {
addImageTransitionBarrier(*commandBuffer, *m_resolvedImage,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // VkPipelineStageFlags srcStageMask
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, // VkPipelineStageFlags dstStageMask
0, // VkAccessFlags srcAccessMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
}
// Begin Render Pass
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, (deUint32)positionData.size(), 1, 0, 0);
endRenderPass(vkd, *commandBuffer);
// Copy Image
copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? *m_resolvedImage : *m_image, *m_resultBuffer, tcu::IVec2(m_renderSize, m_renderSize));
endCommandBuffer(vkd, *commandBuffer);
// Set Point Size
{
float pointSize = getPointSize();
deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
}
// Submit
submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1), m_resultBufferMemory->getHostPtr()));
}
float BaseRenderingTestInstance::getLineWidth (void) const
{
return 1.0f;
}
float BaseRenderingTestInstance::getPointSize (void) const
{
return 1.0f;
}
const VkPipelineRasterizationStateCreateInfo* BaseRenderingTestInstance::getRasterizationStateCreateInfo (void) const
{
static VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkPipelineRasterizationStateCreateFlags flags;
false, // VkBool32 depthClipEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkFillMode fillMode;
VK_CULL_MODE_NONE, // VkCullMode cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
VK_FALSE, // VkBool32 depthBiasEnable;
0.0f, // float depthBias;
0.0f, // float depthBiasClamp;
0.0f, // float slopeScaledDepthBias;
getLineWidth(), // float lineWidth;
};
rasterizationStateCreateInfo.lineWidth = getLineWidth();
return &rasterizationStateCreateInfo;
}
const VkPipelineColorBlendStateCreateInfo* BaseRenderingTestInstance::getColorBlendStateCreateInfo (void) const
{
static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
{
false, // VkBool32 blendEnable;
VK_BLEND_FACTOR_ONE, // VkBlend srcBlendColor;
VK_BLEND_FACTOR_ZERO, // VkBlend destBlendColor;
VK_BLEND_OP_ADD, // VkBlendOp blendOpColor;
VK_BLEND_FACTOR_ONE, // VkBlend srcBlendAlpha;
VK_BLEND_FACTOR_ZERO, // VkBlend destBlendAlpha;
VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha;
(VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT) // VkChannelFlags channelWriteMask;
};
static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkPipelineColorBlendStateCreateFlags flags;
false, // VkBool32 logicOpEnable;
VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
1u, // deUint32 attachmentCount;
&colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
{ 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4];
};
return &colorBlendStateParams;
}
const tcu::TextureFormat& BaseRenderingTestInstance::getTextureFormat (void) const
{
return m_textureFormat;
}
class BaseTriangleTestInstance : public BaseRenderingTestInstance
{
public:
BaseTriangleTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount);
virtual tcu::TestStatus iterate (void);
private:
virtual void generateTriangles (int iteration, std::vector<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, VkSampleCountFlagBits sampleCount);
virtual tcu::TestStatus iterate (void);
virtual float getLineWidth (void) const;
private:
virtual void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) = DE_NULL;
int m_iteration;
const int m_iterationCount;
VkPrimitiveTopology m_primitiveTopology;
const PrimitiveWideness m_primitiveWideness;
bool m_allIterationsPassed;
float m_maxLineWidth;
std::vector<float> m_lineWidths;
};
BaseLineTestInstance::BaseLineTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount)
: BaseRenderingTestInstance (context, sampleCount)
, m_iteration (0)
, m_iterationCount (3)
, m_primitiveTopology (primitiveTopology)
, m_primitiveWideness (wideness)
, m_allIterationsPassed (true)
, m_maxLineWidth (1.0f)
{
DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
// create line widths
if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
{
m_lineWidths.resize(m_iterationCount, 1.0f);
}
else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
{
const float* range = context.getDeviceProperties().limits.lineWidthRange;
m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
DE_ASSERT(range[1] > 1.0f);
// set hand picked sizes
m_lineWidths.push_back(5.0f);
m_lineWidths.push_back(10.0f);
m_lineWidths.push_back(range[1]);
DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
m_maxLineWidth = range[1];
}
else
DE_ASSERT(false);
}
tcu::TestStatus BaseLineTestInstance::iterate (void)
{
const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
const tcu::ScopedLogSection section (m_context.getTestContext().getLog(), iterationDescription, iterationDescription);
const float lineWidth = getLineWidth();
tcu::Surface resultImage (m_renderSize, m_renderSize);
std::vector<tcu::Vec4> drawBuffer;
std::vector<LineSceneSpec::SceneLine> lines;
// supported?
if (lineWidth <= m_maxLineWidth)
{
// gen data
generateLines(m_iteration, drawBuffer, lines);
// draw image
drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
// compare
{
RasterizationArguments args;
LineSceneSpec scene;
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
args.numSamples = m_multisampling ? 1 : 0;
args.subpixelBits = m_subpixelBits;
args.redBits = colorBits[0];
args.greenBits = colorBits[1];
args.blueBits = colorBits[2];
scene.lines.swap(lines);
scene.lineWidth = lineWidth;
if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog()))
m_allIterationsPassed = false;
}
}
else
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
// result
if (++m_iteration == m_iterationCount)
{
if (m_allIterationsPassed)
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Incorrect rasterization");
}
else
return tcu::TestStatus::incomplete();
}
float BaseLineTestInstance::getLineWidth (void) const
{
return m_lineWidths[m_iteration];
}
class PointTestInstance : public BaseRenderingTestInstance
{
public:
PointTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount);
virtual tcu::TestStatus iterate (void);
virtual float getPointSize (void) const;
private:
virtual void generatePoints (int iteration, std::vector<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, VkSampleCountFlagBits sampleCount)
: BaseRenderingTestInstance (context, sampleCount)
, m_iteration (0)
, m_iterationCount (3)
, m_primitiveWideness (wideness)
, m_allIterationsPassed (true)
, m_maxPointSize (1.0f)
{
// create point sizes
if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
{
m_pointSizes.resize(m_iterationCount, 1.0f);
}
else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
{
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, bool isLineTest, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase(context, name, description, sampleCount)
, m_wideness (wideness)
, m_isLineTest (isLineTest)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new ConcreteTestInstance(context, m_wideness, m_sampleCount);
}
virtual void checkSupport (Context& context) const
{
if (m_isLineTest)
{
if (!context.getDeviceProperties().limits.strictLines)
TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
if (m_wideness == PRIMITIVEWIDENESS_WIDE)
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
}
else
{
if (m_wideness == PRIMITIVEWIDENESS_WIDE)
context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
}
}
protected:
const PrimitiveWideness m_wideness;
const bool m_isLineTest;
};
class LinesTestInstance : public BaseLineTestInstance
{
public:
LinesTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount)
: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, wideness, sampleCount)
{}
virtual void generateLines (int iteration, std::vector<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(6);
switch (iteration)
{
case 0:
// \note: these values are chosen arbitrarily
outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f);
outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f);
outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f);
outData[3] = tcu::Vec4(-0.3f, 0.2f, 0.0f, 1.0f);
outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
outData[5] = tcu::Vec4( 0.1f, 0.5f, 0.0f, 1.0f);
break;
case 1:
outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f);
outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f);
outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f);
outData[5] = tcu::Vec4( 0.18f, -0.2f, 0.0f, 1.0f);
break;
case 2:
outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f);
outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f);
outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f);
outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f);
outData[5] = tcu::Vec4( 0.8f, -0.7f, 0.0f, 1.0f);
break;
}
outLines.resize(3);
outLines[0].positions[0] = outData[0];
outLines[0].positions[1] = outData[1];
outLines[1].positions[0] = outData[2];
outLines[1].positions[1] = outData[3];
outLines[2].positions[0] = outData[4];
outLines[2].positions[1] = outData[5];
// log
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << getLineWidth() << ")" << tcu::TestLog::EndMessage;
for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Line " << (lineNdx+1) << ":"
<< "\n\t" << outLines[lineNdx].positions[0]
<< "\n\t" << outLines[lineNdx].positions[1]
<< tcu::TestLog::EndMessage;
}
}
class LineStripTestInstance : public BaseLineTestInstance
{
public:
LineStripTestInstance (Context& context, PrimitiveWideness wideness, VkSampleCountFlagBits sampleCount)
: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, wideness, sampleCount)
{}
virtual void generateLines (int iteration, std::vector<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( 1.1f, -0.9f, 0.0f, 1.0f);
outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f);
outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f);
break;
}
outLines.resize(3);
outLines[0].positions[0] = outData[0];
outLines[0].positions[1] = outData[1];
outLines[1].positions[0] = outData[1];
outLines[1].positions[1] = outData[2];
outLines[2].positions[0] = outData[2];
outLines[2].positions[1] = outData[3];
// log
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "\t" << outData[vtxNdx]
<< tcu::TestLog::EndMessage;
}
}
class FillRuleTestInstance : public BaseRenderingTestInstance
{
public:
enum FillRuleCaseType
{
FILLRULECASE_BASIC = 0,
FILLRULECASE_REVERSED,
FILLRULECASE_CLIPPED_FULL,
FILLRULECASE_CLIPPED_PARTIAL,
FILLRULECASE_PROJECTED,
FILLRULECASE_LAST
};
FillRuleTestInstance (Context& context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount);
virtual tcu::TestStatus iterate (void);
private:
virtual const VkPipelineColorBlendStateCreateInfo* getColorBlendStateCreateInfo (void) const;
int getRenderSize (FillRuleCaseType type) const;
int getNumIterations (FillRuleCaseType type) const;
void generateTriangles (int iteration, std::vector<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 DEFAULT_RENDER_SIZE / 4;
else
return DEFAULT_RENDER_SIZE;
}
int FillRuleTestInstance::getNumIterations (FillRuleCaseType type) const
{
if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
return 15;
else
return 2;
}
void FillRuleTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const
{
switch (m_caseType)
{
case FILLRULECASE_BASIC:
case FILLRULECASE_REVERSED:
case FILLRULECASE_PROJECTED:
{
const int numRows = 4;
const int numColumns = 4;
const float quadSide = 0.15f;
de::Random rnd (0xabcd);
outData.resize(6 * numRows * numColumns);
for (int col = 0; col < numColumns; ++col)
for (int row = 0; row < numRows; ++row)
{
const tcu::Vec2 center = tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f, ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f);
const float rotation = (float)(iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x());
const tcu::Vec2 quad[4] =
{
center + sideH + sideV,
center + sideH - sideV,
center - sideH - sideV,
center - sideH + sideV,
};
if (m_caseType == FILLRULECASE_BASIC)
{
outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
}
else if (m_caseType == FILLRULECASE_REVERSED)
{
outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
}
else if (m_caseType == FILLRULECASE_PROJECTED)
{
const float w0 = rnd.getFloat(0.1f, 4.0f);
const float w1 = rnd.getFloat(0.1f, 4.0f);
const float w2 = rnd.getFloat(0.1f, 4.0f);
const float w3 = rnd.getFloat(0.1f, 4.0f);
outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
}
else
DE_ASSERT(DE_FALSE);
}
break;
}
case FILLRULECASE_CLIPPED_PARTIAL:
case FILLRULECASE_CLIPPED_FULL:
{
const float quadSide = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
const tcu::Vec2 center = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
const float rotation = (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x());
const tcu::Vec2 quad[4] =
{
center + sideH + sideV,
center + sideH - sideV,
center - sideH - sideV,
center - sideH + sideV,
};
outData.resize(6);
outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
break;
}
default:
DE_ASSERT(DE_FALSE);
}
}
const VkPipelineColorBlendStateCreateInfo* FillRuleTestInstance::getColorBlendStateCreateInfo (void) const
{
static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
{
true, // VkBool32 blendEnable;
VK_BLEND_FACTOR_ONE, // VkBlend srcBlendColor;
VK_BLEND_FACTOR_ONE, // VkBlend destBlendColor;
VK_BLEND_OP_ADD, // VkBlendOp blendOpColor;
VK_BLEND_FACTOR_ONE, // VkBlend srcBlendAlpha;
VK_BLEND_FACTOR_ONE, // VkBlend destBlendAlpha;
VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha;
(VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT) // VkChannelFlags channelWriteMask;
};
static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkPipelineColorBlendStateCreateFlags flags;
false, // VkBool32 logicOpEnable;
VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
1u, // deUint32 attachmentCount;
&colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
{ 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConst[4];
};
return &colorBlendStateParams;
}
class FillRuleTestCase : public BaseRenderingTestCase
{
public:
FillRuleTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, FillRuleTestInstance::FillRuleCaseType type, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_type (type)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new FillRuleTestInstance(context, m_type, m_sampleCount);
}
protected:
const FillRuleTestInstance::FillRuleCaseType m_type;
};
class CullingTestInstance : public BaseRenderingTestInstance
{
public:
CullingTestInstance (Context& context, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace, VkPolygonMode polygonMode)
: BaseRenderingTestInstance (context, VK_SAMPLE_COUNT_1_BIT, DEFAULT_RENDER_SIZE)
, m_cullMode (cullMode)
, m_primitiveTopology (primitiveTopology)
, m_frontFace (frontFace)
, m_polygonMode (polygonMode)
, m_multisampling (true)
{}
virtual
const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
tcu::TestStatus iterate (void);
private:
void generateVertices (std::vector<tcu::Vec4>& outData) const;
void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
void extractLines (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, std::vector<LineSceneSpec::SceneLine>& outLines) const;
void extractPoints (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, std::vector<PointSceneSpec::ScenePoint>& outPoints) const;
bool triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const;
const VkCullModeFlags m_cullMode;
const VkPrimitiveTopology m_primitiveTopology;
const VkFrontFace m_frontFace;
const VkPolygonMode m_polygonMode;
const bool m_multisampling;
};
tcu::TestStatus CullingTestInstance::iterate (void)
{
DE_ASSERT(m_polygonMode <= VK_POLYGON_MODE_POINT);
tcu::Surface resultImage (m_renderSize, m_renderSize);
std::vector<tcu::Vec4> drawBuffer;
std::vector<TriangleSceneSpec::SceneTriangle> triangles;
std::vector<PointSceneSpec::ScenePoint> points;
std::vector<LineSceneSpec::SceneLine> lines;
const InstanceInterface& vk = m_context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice);
if (!(deviceFeatures.fillModeNonSolid) && (m_polygonMode == VK_POLYGON_MODE_LINE || m_polygonMode == VK_POLYGON_MODE_POINT))
TCU_THROW(NotSupportedError, "Wireframe fill modes are not supported");
// generate scene
generateVertices(drawBuffer);
extractTriangles(triangles, drawBuffer);
if (m_polygonMode == VK_POLYGON_MODE_LINE)
extractLines(triangles ,lines);
else if (m_polygonMode == VK_POLYGON_MODE_POINT)
extractPoints(triangles, points);
// draw image
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Setting front face to " << m_frontFace << tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Setting cull face to " << m_cullMode << tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Drawing test pattern (" << m_primitiveTopology << ")" << tcu::TestLog::EndMessage;
drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
}
// compare
{
RasterizationArguments args;
tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
bool isCompareOk = false;
args.numSamples = m_multisampling ? 1 : 0;
args.subpixelBits = m_subpixelBits;
args.redBits = colorBits[0];
args.greenBits = colorBits[1];
args.blueBits = colorBits[2];
switch (m_polygonMode)
{
case VK_POLYGON_MODE_LINE:
{
LineSceneSpec scene;
scene.lineWidth = 0;
scene.lines.swap(lines);
isCompareOk = verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
break;
}
case VK_POLYGON_MODE_POINT:
{
PointSceneSpec scene;
scene.points.swap(points);
isCompareOk = verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
break;
}
default:
{
TriangleSceneSpec scene;
scene.triangles.swap(triangles);
isCompareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), tcu::VERIFICATIONMODE_WEAK);
break;
}
}
if (isCompareOk)
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Incorrect rendering");
}
}
void CullingTestInstance::generateVertices (std::vector<tcu::Vec4>& outData) const
{
de::Random rnd(543210);
outData.resize(6);
for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
{
outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
outData[vtxNdx].z() = 0.0f;
outData[vtxNdx].w() = 1.0f;
}
}
void CullingTestInstance::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
{
const bool cullDirection = (m_cullMode == VK_CULL_MODE_FRONT_BIT) ^ (m_frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE);
// No triangles
if (m_cullMode == VK_CULL_MODE_FRONT_AND_BACK)
return;
switch (m_primitiveTopology)
{
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
{
for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
{
const tcu::Vec4& v0 = vertices[vtxNdx + 0];
const tcu::Vec4& v1 = vertices[vtxNdx + 1];
const tcu::Vec4& v2 = vertices[vtxNdx + 2];
if (triangleOrder(v0, v1, v2) != cullDirection)
{
TriangleSceneSpec::SceneTriangle tri;
tri.positions[0] = v0; tri.sharedEdge[0] = false;
tri.positions[1] = v1; tri.sharedEdge[1] = false;
tri.positions[2] = v2; tri.sharedEdge[2] = false;
outTriangles.push_back(tri);
}
}
break;
}
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
{
for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
{
const tcu::Vec4& v0 = vertices[vtxNdx + 0];
const tcu::Vec4& v1 = vertices[vtxNdx + 1];
const tcu::Vec4& v2 = vertices[vtxNdx + 2];
if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
{
TriangleSceneSpec::SceneTriangle tri;
tri.positions[0] = v0; tri.sharedEdge[0] = false;
tri.positions[1] = v1; tri.sharedEdge[1] = false;
tri.positions[2] = v2; tri.sharedEdge[2] = false;
outTriangles.push_back(tri);
}
}
break;
}
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
{
for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
{
const tcu::Vec4& v0 = vertices[0];
const tcu::Vec4& v1 = vertices[vtxNdx + 0];
const tcu::Vec4& v2 = vertices[vtxNdx + 1];
if (triangleOrder(v0, v1, v2) != cullDirection)
{
TriangleSceneSpec::SceneTriangle tri;
tri.positions[0] = v0; tri.sharedEdge[0] = false;
tri.positions[1] = v1; tri.sharedEdge[1] = false;
tri.positions[2] = v2; tri.sharedEdge[2] = false;
outTriangles.push_back(tri);
}
}
break;
}
default:
DE_ASSERT(false);
}
}
void CullingTestInstance::extractLines (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles,
std::vector<LineSceneSpec::SceneLine>& outLines) const
{
for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
{
for (int vrtxNdx = 0; vrtxNdx < 2; ++vrtxNdx)
{
LineSceneSpec::SceneLine line;
line.positions[0] = outTriangles.at(triNdx).positions[vrtxNdx];
line.positions[1] = outTriangles.at(triNdx).positions[vrtxNdx + 1];
outLines.push_back(line);
}
LineSceneSpec::SceneLine line;
line.positions[0] = outTriangles.at(triNdx).positions[2];
line.positions[1] = outTriangles.at(triNdx).positions[0];
outLines.push_back(line);
}
}
void CullingTestInstance::extractPoints (std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
std::vector<PointSceneSpec::ScenePoint> &outPoints) const
{
for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
{
for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
{
PointSceneSpec::ScenePoint point;
point.position = outTriangles.at(triNdx).positions[vrtxNdx];
point.pointSize = 1.0f;
outPoints.push_back(point);
}
}
}
bool CullingTestInstance::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const
{
const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
// cross
return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) > 0;
}
const VkPipelineRasterizationStateCreateInfo* CullingTestInstance::getRasterizationStateCreateInfo (void) const
{
static VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkPipelineRasterizationStateCreateFlags flags;
false, // VkBool32 depthClipEnable;
false, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkFillMode fillMode;
VK_CULL_MODE_NONE, // VkCullMode cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
VK_FALSE, // VkBool32 depthBiasEnable;
0.0f, // float depthBias;
0.0f, // float depthBiasClamp;
0.0f, // float slopeScaledDepthBias;
getLineWidth(), // float lineWidth;
};
rasterizationStateCreateInfo.lineWidth = getLineWidth();
rasterizationStateCreateInfo.cullMode = m_cullMode;
rasterizationStateCreateInfo.frontFace = m_frontFace;
rasterizationStateCreateInfo.polygonMode = m_polygonMode;
return &rasterizationStateCreateInfo;
}
class CullingTestCase : public BaseRenderingTestCase
{
public:
CullingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace, VkPolygonMode polygonMode, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
: BaseRenderingTestCase (context, name, description, sampleCount)
, m_cullMode (cullMode)
, m_primitiveTopology (primitiveTopology)
, m_frontFace (frontFace)
, m_polygonMode (polygonMode)
{}
virtual TestInstance* createInstance (Context& context) const
{
return new CullingTestInstance(context, m_cullMode, m_primitiveTopology, m_frontFace, m_polygonMode);
}
protected:
const VkCullModeFlags m_cullMode;
const VkPrimitiveTopology m_primitiveTopology;
const VkFrontFace m_frontFace;
const VkPolygonMode m_polygonMode;
};
class DiscardTestInstance : public BaseRenderingTestInstance
{
public:
DiscardTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, deBool queryFragmentShaderInvocations)
: BaseRenderingTestInstance (context, VK_SAMPLE_COUNT_1_BIT, DEFAULT_RENDER_SIZE)
, m_primitiveTopology (primitiveTopology)
, m_queryFragmentShaderInvocations (queryFragmentShaderInvocations)
{}
virtual const VkPipelineRasterizationStateCreateInfo* getRasterizationStateCreateInfo (void) const;
tcu::TestStatus iterate (void);
private:
void generateVertices (std::vector<tcu::Vec4>& outData) const;
void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
void extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices) const;
void extractPoints (std::vector<PointSceneSpec::ScenePoint>& outPoints, const std::vector<tcu::Vec4>& vertices) const;
void drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, VkPrimitiveTopology primitiveTopology, Move<VkQueryPool>& queryPool);
const VkPrimitiveTopology m_primitiveTopology;
const deBool m_queryFragmentShaderInvocations;
};
tcu::TestStatus DiscardTestInstance::iterate (void)
{
const DeviceInterface& vkd = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
deUint64 queryResult = 0u;
tcu::Surface resultImage (m_renderSize, m_renderSize);
std::vector<tcu::Vec4> drawBuffer;
std::vector<PointSceneSpec::ScenePoint> points;
std::vector<LineSceneSpec::SceneLine> lines;
std::vector<TriangleSceneSpec::SceneTriangle> triangles;
generateVertices(drawBuffer);
switch (m_primitiveTopology)
{
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
extractPoints(points, drawBuffer);
break;
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
extractLines(lines, drawBuffer);
break;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
extractTriangles(triangles, drawBuffer);
break;
default:
DE_ASSERT(false);
}
const VkQueryPoolCreateInfo queryPoolCreateInfo =
{
VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
(VkQueryPoolCreateFlags)0, // VkQueryPoolCreateFlags flags
VK_QUERY_TYPE_PIPELINE_STATISTICS , // VkQueryType queryType
1u, // deUint32 entryCount
VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT, // VkQueryPipelineStatisticFlags pipelineStatistics
};
if (m_queryFragmentShaderInvocations)
{
Move<VkQueryPool> queryPool = createQueryPool