blob: a97e4c8e85c81589b9fec35224ce674df1a0f77b [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2019 The Khronos Group Inc.
* Copyright (c) 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Tests for multiple interpolation decorations in a shader stage
*//*--------------------------------------------------------------------*/
#include "vktDrawMultipleInterpolationTests.hpp"
#include "tcuStringTemplate.hpp"
#include "vkCmdUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vktDrawBaseClass.hpp"
#include "vktTestGroupUtil.hpp"
namespace vkt
{
namespace Draw
{
namespace
{
enum Interpolation
{
SMOOTH = 0,
FLAT = 1,
NOPERSPECTIVE = 2,
CENTROID = 3,
SAMPLE = 4,
COUNT = 5,
};
struct DrawParams
{
vk::VkFormat format;
tcu::UVec2 size;
vk::VkSampleCountFlagBits samples;
// From the SPIR-V point of view, structured test variants will allow us to test interpolation decorations on struct members
// instead of plain ids.
bool useStructure;
bool includeSampleDecoration;
};
template<typename T>
inline de::SharedPtr<vk::Move<T> > makeSharedPtr(vk::Move<T> move)
{
return de::SharedPtr<vk::Move<T> >(new vk::Move<T>(move));
}
const char* interpolationToString (Interpolation interpolation)
{
switch (interpolation)
{
case SMOOTH:
return "smooth";
case FLAT:
return "flat";
case NOPERSPECTIVE:
return "noperspective";
case CENTROID:
return "centroid";
case SAMPLE:
return "sample";
default:
DE_FATAL("Invalid interpolation enum");
}
return "";
}
class DrawTestInstance : public TestInstance
{
public:
DrawTestInstance (Context& context, DrawParams params);
void render (de::SharedPtr<Image>& colorTargetImage,
tcu::ConstPixelBufferAccess* frame,
const char* vsName,
const char* fsName,
Interpolation interpolation,
bool sampleRateShading);
bool compare (const tcu::ConstPixelBufferAccess& result,
const tcu::ConstPixelBufferAccess& reference);
tcu::TestStatus iterate (void);
private:
DrawParams m_params;
};
DrawTestInstance::DrawTestInstance (Context& context, DrawParams params)
: TestInstance (context)
, m_params (params)
{
}
class DrawTestCase : public TestCase
{
public:
DrawTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const DrawParams params);
~DrawTestCase (void);
virtual void initPrograms (vk::SourceCollections& programCollection) const;
virtual void checkSupport (Context& context) const;
virtual TestInstance* createInstance (Context& context) const;
private:
const DrawParams m_params;
};
DrawTestCase::DrawTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const DrawParams params)
: TestCase (testCtx, name, description)
, m_params (params)
{
}
DrawTestCase::~DrawTestCase (void)
{
}
void DrawTestCase::initPrograms (vk::SourceCollections& programCollection) const
{
const std::string blockName = "ifb";
const std::map<std::string, std::string> replacements =
{
std::pair<std::string, std::string>{"blockOpeningOut" , (m_params.useStructure ? "layout(location = 0) out InterfaceBlock {\n" : "")},
std::pair<std::string, std::string>{"blockOpeningIn" , (m_params.useStructure ? "layout(location = 0) in InterfaceBlock {\n" : "")},
std::pair<std::string, std::string>{"blockClosure" , (m_params.useStructure ? "} " + blockName + ";\n" : "")},
std::pair<std::string, std::string>{"extensions" , (m_params.useStructure ? "#extension GL_ARB_enhanced_layouts : require\n" : "")},
std::pair<std::string, std::string>{"accessPrefix" , (m_params.useStructure ? blockName + "." : "")},
std::pair<std::string, std::string>{"outQual" , (m_params.useStructure ? "" : "out ")},
std::pair<std::string, std::string>{"inQual" , (m_params.useStructure ? "" : "in ")},
std::pair<std::string, std::string>{"indent" , (m_params.useStructure ? " " : "")},
};
std::ostringstream vertShaderMultiStream;
vertShaderMultiStream
<< "#version 430\n"
<< "${extensions}"
<< "\n"
<< "layout(location = 0) in vec4 in_position;\n"
<< "layout(location = 1) in vec4 in_color;\n"
<< "\n"
<< "${blockOpeningOut}"
<< "${indent}layout(location = 0) ${outQual}vec4 out_color_smooth;\n"
<< "${indent}layout(location = 1) ${outQual}flat vec4 out_color_flat;\n"
<< "${indent}layout(location = 2) ${outQual}noperspective vec4 out_color_noperspective;\n"
<< "${indent}layout(location = 3) ${outQual}centroid vec4 out_color_centroid;\n"
<< (m_params.includeSampleDecoration ? "${indent}layout(location = 4) ${outQual}sample vec4 out_color_sample;\n" : "")
<< "${blockClosure}"
<< "\n"
<< "void main()\n"
<< "{\n"
<< " ${accessPrefix}out_color_smooth = in_color;\n"
<< " ${accessPrefix}out_color_flat = in_color;\n"
<< " ${accessPrefix}out_color_noperspective = in_color;\n"
<< " ${accessPrefix}out_color_centroid = in_color;\n"
<< (m_params.includeSampleDecoration ? " ${accessPrefix}out_color_sample = in_color;\n" : "")
<< " gl_Position = in_position;\n"
<< "}\n"
;
const tcu::StringTemplate vertShaderMulti(vertShaderMultiStream.str());
const auto colorCount = (m_params.includeSampleDecoration ? COUNT : (COUNT - 1));
std::ostringstream fragShaderMultiStream;
fragShaderMultiStream
<< "#version 430\n"
<< "${extensions}"
<< "\n"
<< "${blockOpeningIn}"
<< "${indent}layout(location = 0) ${inQual}vec4 in_color_smooth;\n"
<< "${indent}layout(location = 1) ${inQual}flat vec4 in_color_flat;\n"
<< "${indent}layout(location = 2) ${inQual}noperspective vec4 in_color_noperspective;\n"
<< "${indent}layout(location = 3) ${inQual}centroid vec4 in_color_centroid;\n"
<< (m_params.includeSampleDecoration ? "${indent}layout(location = 4) ${inQual}sample vec4 in_color_sample;\n" : "")
<< "${blockClosure}"
<< "\n"
<< "layout(push_constant, std430) uniform PushConstants {\n"
<< " uint interpolationIndex;\n"
<< "} pc;\n"
<< "\n"
<< "layout(location=0) out vec4 out_color;\n"
<< "\n"
<< "void main()\n"
<< "{\n"
<< " const vec4 in_colors[" + de::toString(colorCount) + "] = vec4[](\n"
<< " ${accessPrefix}in_color_smooth,\n"
<< " ${accessPrefix}in_color_flat,\n"
<< " ${accessPrefix}in_color_noperspective,\n"
<< " ${accessPrefix}in_color_centroid" << (m_params.includeSampleDecoration ? "," : "") << "\n"
<< (m_params.includeSampleDecoration ? " ${accessPrefix}in_color_sample\n" : "")
<< " );\n"
<< " out_color = in_colors[pc.interpolationIndex];\n"
<< "}\n"
;
const tcu::StringTemplate fragShaderMulti(fragShaderMultiStream.str());
const tcu::StringTemplate vertShaderSingle
{
"#version 430\n"
"${extensions}"
"\n"
"layout(location = 0) in vec4 in_position;\n"
"layout(location = 1) in vec4 in_color;\n"
"\n"
"${blockOpeningOut}"
"${indent}layout(location = 0) ${outQual}${qualifier:opt}vec4 out_color;\n"
"${blockClosure}"
"\n"
"void main()\n"
"{\n"
" ${accessPrefix}out_color = in_color;\n"
" gl_Position = in_position;\n"
"}\n"
};
const tcu::StringTemplate fragShaderSingle
{
"#version 430\n"
"${extensions}"
"\n"
"${blockOpeningIn}"
"${indent}layout(location = 0) ${inQual}${qualifier:opt}vec4 in_color;\n"
"${blockClosure}"
"\n"
"layout(location = 0) out vec4 out_color;\n"
"\n"
"void main()\n"
"{\n"
" out_color = ${accessPrefix}in_color;\n"
"}\n"
};
std::map<std::string, std::string> smooth = replacements;
std::map<std::string, std::string> flat = replacements;
std::map<std::string, std::string> noperspective = replacements;
std::map<std::string, std::string> centroid = replacements;
std::map<std::string, std::string> sample = replacements;
flat["qualifier"] = "flat ";
noperspective["qualifier"] = "noperspective ";
centroid["qualifier"] = "centroid ";
sample["qualifier"] = "sample ";
programCollection.glslSources.add("vert_multi") << glu::VertexSource(vertShaderMulti.specialize(replacements));
programCollection.glslSources.add("frag_multi") << glu::FragmentSource(fragShaderMulti.specialize(replacements));
programCollection.glslSources.add("vert_smooth") << glu::VertexSource(vertShaderSingle.specialize(smooth));
programCollection.glslSources.add("frag_smooth") << glu::FragmentSource(fragShaderSingle.specialize(smooth));
programCollection.glslSources.add("vert_flat") << glu::VertexSource(vertShaderSingle.specialize(flat));
programCollection.glslSources.add("frag_flat") << glu::FragmentSource(fragShaderSingle.specialize(flat));
programCollection.glslSources.add("vert_noperspective") << glu::VertexSource(vertShaderSingle.specialize(noperspective));
programCollection.glslSources.add("frag_noperspective") << glu::FragmentSource(fragShaderSingle.specialize(noperspective));
programCollection.glslSources.add("vert_centroid") << glu::VertexSource(vertShaderSingle.specialize(centroid));
programCollection.glslSources.add("frag_centroid") << glu::FragmentSource(fragShaderSingle.specialize(centroid));
if (m_params.includeSampleDecoration)
{
programCollection.glslSources.add("vert_sample") << glu::VertexSource(vertShaderSingle.specialize(sample));
programCollection.glslSources.add("frag_sample") << glu::FragmentSource(fragShaderSingle.specialize(sample));
}
}
void DrawTestCase::checkSupport (Context& context) const
{
if (!(m_params.samples & context.getDeviceProperties().limits.framebufferColorSampleCounts))
TCU_THROW(NotSupportedError, "Multisampling with " + de::toString(m_params.samples) + " samples not supported");
if (m_params.includeSampleDecoration && !context.getDeviceFeatures().sampleRateShading)
TCU_THROW(NotSupportedError, "Sample rate shading not supported");
}
TestInstance* DrawTestCase::createInstance (Context& context) const
{
return new DrawTestInstance(context, m_params);
}
void DrawTestInstance::render (de::SharedPtr<Image>& colorTargetImage,
tcu::ConstPixelBufferAccess* frame,
const char* vsName,
const char* fsName,
Interpolation interpolation,
bool sampleRateShading)
{
const deUint32 pcData = static_cast<deUint32>(interpolation);
const deUint32 pcDataSize = static_cast<deUint32>(sizeof(pcData));
const bool useMultisampling = (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
const vk::VkBool32 sampleShadingEnable = (sampleRateShading ? VK_TRUE : VK_FALSE);
const vk::DeviceInterface& vk = m_context.getDeviceInterface();
const vk::VkDevice device = m_context.getDevice();
const vk::Unique<vk::VkShaderModule> vs (createShaderModule(vk, device, m_context.getBinaryCollection().get(vsName), 0));
const vk::Unique<vk::VkShaderModule> fs (createShaderModule(vk, device, m_context.getBinaryCollection().get(fsName), 0));
const CmdPoolCreateInfo cmdPoolCreateInfo = m_context.getUniversalQueueFamilyIndex();
vk::Move<vk::VkCommandPool> cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo);
vk::Move<vk::VkCommandBuffer> cmdBuffer = vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
de::SharedPtr<Image> multisampleImage;
std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > > colorTargetViews;
std::vector<de::SharedPtr<vk::Move<vk::VkImageView> > > multisampleViews;
de::SharedPtr<Buffer> vertexBuffer;
vk::Move<vk::VkRenderPass> renderPass;
vk::Move<vk::VkFramebuffer> framebuffer;
vk::Move<vk::VkPipelineLayout> pipelineLayout;
vk::Move<vk::VkPipeline> pipeline;
// Create color buffer images
{
const vk::VkExtent3D targetImageExtent = { m_params.size.x(), m_params.size.y(), 1 };
const vk::VkImageUsageFlags usage = vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT;
const ImageCreateInfo targetImageCreateInfo (vk::VK_IMAGE_TYPE_2D,
m_params.format,
targetImageExtent,
1,
1,
vk::VK_SAMPLE_COUNT_1_BIT,
vk::VK_IMAGE_TILING_OPTIMAL,
usage);
colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo,
m_context.getDefaultAllocator(),
m_context.getUniversalQueueFamilyIndex());
if (useMultisampling)
{
const ImageCreateInfo multisampleImageCreateInfo (vk::VK_IMAGE_TYPE_2D,
m_params.format,
targetImageExtent,
1,
1,
m_params.samples,
vk::VK_IMAGE_TILING_OPTIMAL,
usage);
multisampleImage = Image::createAndAlloc(vk, device, multisampleImageCreateInfo,
m_context.getDefaultAllocator(),
m_context.getUniversalQueueFamilyIndex());
}
}
// Create render pass and framebuffer
{
RenderPassCreateInfo renderPassCreateInfo;
std::vector<vk::VkImageView> attachments;
std::vector<vk::VkAttachmentReference> colorAttachmentRefs;
std::vector<vk::VkAttachmentReference> multisampleAttachmentRefs;
deUint32 attachmentNdx = 0;
{
const ImageViewCreateInfo colorTargetViewInfo (colorTargetImage->object(),
vk::VK_IMAGE_VIEW_TYPE_2D,
m_params.format);
const vk::VkAttachmentReference colorAttachmentReference =
{
attachmentNdx++,
vk::VK_IMAGE_LAYOUT_GENERAL
};
colorTargetViews.push_back(makeSharedPtr(createImageView(vk, device, &colorTargetViewInfo)));
colorAttachmentRefs.push_back(colorAttachmentReference);
renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
vk::VK_SAMPLE_COUNT_1_BIT,
vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
vk::VK_ATTACHMENT_STORE_OP_STORE,
vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
vk::VK_IMAGE_LAYOUT_UNDEFINED,
vk::VK_IMAGE_LAYOUT_GENERAL));
if (useMultisampling)
{
const ImageViewCreateInfo multisamplingTargetViewInfo (multisampleImage->object(),
vk::VK_IMAGE_VIEW_TYPE_2D,
m_params.format);
const vk::VkAttachmentReference multiSampleAttachmentReference =
{
attachmentNdx++,
vk::VK_IMAGE_LAYOUT_GENERAL
};
multisampleViews.push_back(makeSharedPtr(createImageView(vk, device, &multisamplingTargetViewInfo)));
multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
renderPassCreateInfo.addAttachment(AttachmentDescription(m_params.format,
m_params.samples,
vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
vk::VK_ATTACHMENT_STORE_OP_STORE,
vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
vk::VK_IMAGE_LAYOUT_UNDEFINED,
vk::VK_IMAGE_LAYOUT_GENERAL));
}
}
renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
0,
0,
DE_NULL,
(deUint32)colorAttachmentRefs.size(),
useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
useMultisampling ? &colorAttachmentRefs[0] : DE_NULL,
AttachmentReference(),
0,
DE_NULL));
renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
for (deUint32 frameNdx = 0; frameNdx < colorTargetViews.size(); frameNdx++)
{
attachments.push_back(**colorTargetViews[frameNdx]);
if (useMultisampling)
attachments.push_back(**multisampleViews[frameNdx]);
}
const vk::VkFramebufferCreateInfo framebufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
DE_NULL,
0u,
*renderPass,
(deUint32)attachments.size(),
&attachments[0],
m_params.size.x(),
m_params.size.y(),
1
};
framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
}
// Create vertex buffer.
{
const PositionColorVertex vertices[] =
{
PositionColorVertex(
tcu::Vec4(-1.5f, -0.4f, 1.0f, 2.0f), // Coord
tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)), // Color
PositionColorVertex(
tcu::Vec4(0.4f, -0.4f, 0.5f, 0.5f), // Coord
tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)), // Color
PositionColorVertex(
tcu::Vec4(0.3f, 0.8f, 0.0f, 1.0f), // Coord
tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f)) // Color
};
const vk::VkDeviceSize dataSize = DE_LENGTH_OF_ARRAY(vertices) * sizeof(PositionColorVertex);
vertexBuffer = Buffer::createAndAlloc(vk,
device,
BufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
m_context.getDefaultAllocator(),
vk::MemoryRequirement::HostVisible);
deUint8* ptr = reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
flushMappedMemoryRange(vk,
device,
vertexBuffer->getBoundMemory().getMemory(),
vertexBuffer->getBoundMemory().getOffset(),
VK_WHOLE_SIZE);
}
// Create pipeline
{
const vk::VkViewport viewport = vk::makeViewport(m_params.size.x(), m_params.size.y());
const vk::VkRect2D scissor = vk::makeRect2D(m_params.size.x(), m_params.size.y());
const auto pcRange = vk::makePushConstantRange(vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize);
const std::vector<vk::VkPushConstantRange> pcRanges (1u, pcRange);
const PipelineLayoutCreateInfo pipelineLayoutCreateInfo (0u, nullptr, static_cast<deUint32>(pcRanges.size()), pcRanges.data());
pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
PipelineCreateInfo pipelineCreateInfo (*pipelineLayout, *renderPass, 0, 0);
const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
{
0,
(deUint32)sizeof(tcu::Vec4) * 2,
vk::VK_VERTEX_INPUT_RATE_VERTEX
};
const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
{
{ 0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
{ 1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
};
std::vector<PipelineCreateInfo::ColorBlendState::Attachment> vkCbAttachmentStates (1u);
PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1,
&vertexInputBindingDescription,
2,
vertexInputAttributeDescriptions);
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState((deUint32)vkCbAttachmentStates.size(), &vkCbAttachmentStates[0]));
pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState(m_params.samples, sampleShadingEnable, 1.0f));
pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
}
// Queue draw and read results.
{
const vk::VkQueue queue = m_context.getUniversalQueue();
const vk::VkRect2D renderArea = vk::makeRect2D(m_params.size.x(), m_params.size.y());
const vk::VkDeviceSize vertexBufferOffset = 0;
const vk::VkBuffer buffer = vertexBuffer->object();
const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
const auto clearValueColor = vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
std::vector<vk::VkClearValue> clearValues;
clearValues.push_back(clearValueColor);
if (useMultisampling)
clearValues.push_back(clearValueColor);
beginCommandBuffer(vk, *cmdBuffer, 0u);
beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, (deUint32)clearValues.size(), &clearValues[0]);
vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &vertexBufferOffset);
vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize, &pcData);
vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);
endRenderPass(vk, *cmdBuffer);
endCommandBuffer(vk, *cmdBuffer);
submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
*frame = colorTargetImage->readSurface(queue,
m_context.getDefaultAllocator(),
vk::VK_IMAGE_LAYOUT_GENERAL,
zeroOffset,
(int)m_params.size.x(),
(int)m_params.size.y(),
vk::VK_IMAGE_ASPECT_COLOR_BIT);
}
}
bool DrawTestInstance::compare (const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& reference)
{
DE_ASSERT(result.getSize() == reference.getSize());
const size_t size = result.getWidth() * result.getHeight() * vk::mapVkFormat(m_params.format).getPixelSize();
const int res = deMemCmp(result.getDataPtr(), reference.getDataPtr(), size);
return (res == 0);
}
tcu::TestStatus DrawTestInstance::iterate (void)
{
tcu::TestLog& log = m_context.getTestContext().getLog();
const bool useMultisampling = (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
const deUint32 frameCount = static_cast<deUint32>(COUNT);
std::vector<de::SharedPtr<Image> > resImages (frameCount);
de::SharedPtr<Image> smoothImage[2];
de::SharedPtr<Image> flatImage[2];
de::SharedPtr<Image> noperspectiveImage[2];
de::SharedPtr<Image> centroidImage[2];
de::SharedPtr<Image> sampleImage[2];
tcu::ConstPixelBufferAccess resFrames[frameCount];
tcu::ConstPixelBufferAccess refFrames[frameCount];
tcu::ConstPixelBufferAccess refSRSFrames[frameCount]; // Using sample rate shading.
for (int interpolationType = 0; interpolationType < COUNT; ++interpolationType)
{
// Avoid generating a result image for the sample decoration if we're not using it.
if (!m_params.includeSampleDecoration && interpolationType == Interpolation::SAMPLE)
continue;
render(resImages[interpolationType], &resFrames[interpolationType], "vert_multi", "frag_multi", static_cast<Interpolation>(interpolationType), false);
}
for (int i = 0; i < 2; ++i)
{
const bool useSampleRateShading = (i > 0);
// Sample rate shading is an alternative good result for cases using the sample decoration.
if (useSampleRateShading && !m_params.includeSampleDecoration)
continue;
tcu::ConstPixelBufferAccess *framesArray = (useSampleRateShading ? refSRSFrames : refFrames);
render(smoothImage[i], &framesArray[SMOOTH], "vert_smooth", "frag_smooth", SMOOTH, useSampleRateShading);
render(flatImage[i], &framesArray[FLAT], "vert_flat", "frag_flat", FLAT, useSampleRateShading);
render(noperspectiveImage[i], &framesArray[NOPERSPECTIVE], "vert_noperspective", "frag_noperspective", NOPERSPECTIVE, useSampleRateShading);
render(centroidImage[i], &framesArray[CENTROID], "vert_centroid", "frag_centroid", CENTROID, useSampleRateShading);
// Avoid generating a reference image for the sample interpolation if we're not using it.
if (m_params.includeSampleDecoration)
render(sampleImage[i], &framesArray[SAMPLE], "vert_sample", "frag_sample", SAMPLE, useSampleRateShading);
}
for (deUint32 resNdx = 0; resNdx < frameCount; resNdx++)
{
if (!m_params.includeSampleDecoration && resNdx == SAMPLE)
continue;
const std::string resName = interpolationToString((Interpolation)resNdx);
log << tcu::TestLog::ImageSet(resName, resName)
<< tcu::TestLog::Image("Result", "Result", resFrames[resNdx])
<< tcu::TestLog::Image("Reference", "Reference", refFrames[resNdx]);
if (m_params.includeSampleDecoration)
log << tcu::TestLog::Image("ReferenceSRS", "Reference with sample shading", refSRSFrames[resNdx]);
log << tcu::TestLog::EndImageSet;
for (deUint32 refNdx = 0; refNdx < frameCount; refNdx++)
{
if (!m_params.includeSampleDecoration && refNdx == SAMPLE)
continue;
const std::string refName = interpolationToString((Interpolation)refNdx);
if (resNdx == refNdx)
{
if (!compare(resFrames[resNdx], refFrames[refNdx]) && (!m_params.includeSampleDecoration || !compare(resFrames[resNdx], refSRSFrames[refNdx])))
return tcu::TestStatus::fail(resName + " produced different results");
}
else if (!useMultisampling &&
((resNdx == SMOOTH && refNdx == CENTROID) ||
(resNdx == CENTROID && refNdx == SMOOTH) ||
(resNdx == SMOOTH && refNdx == SAMPLE) ||
(resNdx == SAMPLE && refNdx == SMOOTH) ||
(resNdx == CENTROID && refNdx == SAMPLE) ||
(resNdx == SAMPLE && refNdx == CENTROID)))
{
if (!compare(resFrames[resNdx], refFrames[refNdx]))
return tcu::TestStatus::fail(resName + " and " + refName + " produced different results without multisampling");
}
else
{
// "smooth" means lack of centroid and sample.
// Spec does not specify exactly what "smooth" should be, so it can match centroid or sample.
// "centroid" and "sample" may also produce the same results.
if (!((resNdx == SMOOTH && refNdx == CENTROID) ||
(resNdx == CENTROID && refNdx == SMOOTH) ||
(resNdx == SMOOTH && refNdx == SAMPLE) ||
(resNdx == SAMPLE && refNdx == SMOOTH) ||
(resNdx == CENTROID && refNdx == SAMPLE) ||
(resNdx == SAMPLE && refNdx == CENTROID) ))
{
if (compare(resFrames[resNdx], refFrames[refNdx]))
return tcu::TestStatus::fail(resName + " and " + refName + " produced same result");
}
}
}
}
return tcu::TestStatus::pass("Results differ and references match");
}
void createTests (tcu::TestCaseGroup* testGroup)
{
tcu::TestContext& testCtx = testGroup->getTestContext();
const vk::VkFormat format = vk::VK_FORMAT_R8G8B8A8_UNORM;
const tcu::UVec2 size (128, 128);
struct TestVariant
{
const std::string name;
const std::string desc;
const vk::VkSampleCountFlagBits samples;
};
static const std::vector<TestVariant> testVariants =
{
{ "1_sample", "Without multisampling", vk::VK_SAMPLE_COUNT_1_BIT },
{ "2_samples", "2 samples", vk::VK_SAMPLE_COUNT_2_BIT },
{ "4_samples", "4 samples", vk::VK_SAMPLE_COUNT_4_BIT },
{ "8_samples", "8 samples", vk::VK_SAMPLE_COUNT_8_BIT },
{ "16_samples", "16 samples", vk::VK_SAMPLE_COUNT_16_BIT },
{ "32_samples", "32 samples", vk::VK_SAMPLE_COUNT_32_BIT },
{ "64_samples", "64 samples", vk::VK_SAMPLE_COUNT_64_BIT },
};
struct GroupVariant
{
const bool useStructure;
const std::string groupName;
};
static const std::vector<GroupVariant> groupVariants =
{
{ false, "separate" },
{ true, "structured" },
};
const struct
{
const bool includeSampleDecoration;
const std::string groupName;
} sampleVariants[] =
{
{ false, "no_sample_decoration" },
{ true, "with_sample_decoration" },
};
for (const auto& grpVariant : groupVariants)
{
de::MovePtr<tcu::TestCaseGroup> group {new tcu::TestCaseGroup{testCtx, grpVariant.groupName.c_str(), ""}};
for (const auto& sampleVariant : sampleVariants)
{
de::MovePtr<tcu::TestCaseGroup> sampleGroup {new tcu::TestCaseGroup{testCtx, sampleVariant.groupName.c_str(), ""}};
for (const auto& testVariant : testVariants)
{
const DrawParams params {format, size, testVariant.samples, grpVariant.useStructure, sampleVariant.includeSampleDecoration};
sampleGroup->addChild(new DrawTestCase(testCtx, testVariant.name, testVariant.desc, params));
}
group->addChild(sampleGroup.release());
}
testGroup->addChild(group.release());
}
}
} // anonymous
tcu::TestCaseGroup* createMultipleInterpolationTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx,
"multiple_interpolation",
"Tests for multiple interpolation decorations in a shader stage.",
createTests);
}
} // Draw
} // vkt