blob: bc692993a77c61d5a3c6e8276a8949164cd134f3 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Copyright (c) 2016 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 Shader builtin variable tests.
*//*--------------------------------------------------------------------*/
#include "vktShaderRenderBuiltinVarTests.hpp"
#include "vkDefs.hpp"
#include "vktShaderRender.hpp"
#include "gluShaderUtil.hpp"
#include "tcuImageCompare.hpp"
#include "tcuStringTemplate.hpp"
#include "tcuTextureUtil.hpp"
#include "vktDrawUtil.hpp"
#include "tcuTestLog.hpp"
#include "deMath.h"
#include "deRandom.hpp"
#include <map>
using namespace std;
using namespace tcu;
using namespace vk;
namespace vkt
{
using namespace drawutil;
namespace sr
{
namespace
{
enum
{
FRONTFACE_RENDERWIDTH = 16,
FRONTFACE_RENDERHEIGHT = 16
};
class FrontFacingVertexShader : public rr::VertexShader
{
public:
FrontFacingVertexShader (void)
: rr::VertexShader(1, 0)
{
m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
}
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
packets[packetNdx]->instanceNdx,
packets[packetNdx]->vertexNdx);
}
}
};
class FrontFacingFragmentShader : public rr::FragmentShader
{
public:
FrontFacingFragmentShader (void)
: rr::FragmentShader(0, 1)
{
m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
}
void shadeFragments (rr::FragmentPacket* , const int numPackets, const rr::FragmentShadingContext& context) const
{
tcu::Vec4 color;
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
{
if (context.visibleFace == rr::FACETYPE_FRONT)
color = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
else
color = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
}
}
}
};
class BuiltinGlFrontFacingCaseInstance : public ShaderRenderCaseInstance
{
public:
BuiltinGlFrontFacingCaseInstance (Context& context, VkPrimitiveTopology topology);
TestStatus iterate (void);
private:
const VkPrimitiveTopology m_topology;
};
BuiltinGlFrontFacingCaseInstance::BuiltinGlFrontFacingCaseInstance (Context& context, VkPrimitiveTopology topology)
: ShaderRenderCaseInstance (context)
, m_topology (topology)
{
}
TestStatus BuiltinGlFrontFacingCaseInstance::iterate (void)
{
TestLog& log = m_context.getTestContext().getLog();
std::vector<Vec4> vertices;
std::vector<Shader> shaders;
FrontFacingVertexShader vertexShader;
FrontFacingFragmentShader fragmentShader;
std::string testDesc;
vertices.push_back(Vec4( -0.75f, -0.75f, 0.0f, 1.0f));
vertices.push_back(Vec4( 0.0f, -0.75f, 0.0f, 1.0f));
vertices.push_back(Vec4( -0.37f, 0.75f, 0.0f, 1.0f));
vertices.push_back(Vec4( 0.37f, 0.75f, 0.0f, 1.0f));
vertices.push_back(Vec4( 0.75f, -0.75f, 0.0f, 1.0f));
vertices.push_back(Vec4( 0.0f, -0.75f, 0.0f, 1.0f));
shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert")));
shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag")));
testDesc = "gl_FrontFacing " + getPrimitiveTopologyShortName(m_topology) + " ";
DrawState drawState (m_topology, FRONTFACE_RENDERWIDTH, FRONTFACE_RENDERHEIGHT);
DrawCallData drawCallData (vertices);
VulkanProgram vulkanProgram (shaders);
VulkanDrawContext dc(m_context, drawState, drawCallData, vulkanProgram);
dc.draw();
ReferenceDrawContext refDrawContext(drawState, drawCallData, vertexShader, fragmentShader);
refDrawContext.draw();
log << TestLog::Image( "reference",
"reference",
tcu::ConstPixelBufferAccess(tcu::TextureFormat(
refDrawContext.getColorPixels().getFormat()),
refDrawContext.getColorPixels().getWidth(),
refDrawContext.getColorPixels().getHeight(),
1,
refDrawContext.getColorPixels().getDataPtr()));
log << TestLog::Image( "result",
"result",
tcu::ConstPixelBufferAccess(tcu::TextureFormat(
dc.getColorPixels().getFormat()),
dc.getColorPixels().getWidth(),
dc.getColorPixels().getHeight(),
1,
dc.getColorPixels().getDataPtr()));
if (tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
"ComparisonResult",
"Image comparison result",
refDrawContext.getColorPixels(),
dc.getColorPixels(),
UVec4(0u),
IVec3(1,1,0),
false,
tcu::COMPARE_LOG_RESULT))
{
testDesc += "passed";
return tcu::TestStatus::pass(testDesc.c_str());
}
else
{
testDesc += "failed";
return tcu::TestStatus::fail(testDesc.c_str());
}
}
class BuiltinGlFrontFacingCase : public TestCase
{
public:
BuiltinGlFrontFacingCase (TestContext& testCtx, VkPrimitiveTopology topology, const char* name, const char* description);
virtual ~BuiltinGlFrontFacingCase (void);
void initPrograms (SourceCollections& dst) const;
TestInstance* createInstance (Context& context) const;
private:
BuiltinGlFrontFacingCase (const BuiltinGlFrontFacingCase&); // not allowed!
BuiltinGlFrontFacingCase& operator= (const BuiltinGlFrontFacingCase&); // not allowed!
const VkPrimitiveTopology m_topology;
};
BuiltinGlFrontFacingCase::BuiltinGlFrontFacingCase (TestContext& testCtx, VkPrimitiveTopology topology, const char* name, const char* description)
: TestCase (testCtx, name, description)
, m_topology (topology)
{
}
BuiltinGlFrontFacingCase::~BuiltinGlFrontFacingCase (void)
{
}
void BuiltinGlFrontFacingCase::initPrograms (SourceCollections& programCollection) const
{
{
std::ostringstream vertexSource;
vertexSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
<< "\n"
<< "layout(location = 0) in highp vec4 position;\n"
<< "void main()\n"
<< "{\n"
<< "gl_Position = position;\n"
<< "gl_PointSize = 1.0;\n"
<< "}\n";
programCollection.glslSources.add("vert") << glu::VertexSource(vertexSource.str());
}
{
std::ostringstream fragmentSource;
fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
<< "\n"
<< "layout(location = 0) out mediump vec4 color;\n"
<< "void main()\n"
<< "{\n"
<< "if (gl_FrontFacing)\n"
<< " color = vec4(1.0, 0.0, 0.0, 1.0);\n"
<< "else\n"
<< " color = vec4(0.0, 1.0, 0.0, 1.0);\n"
<< "}\n";
programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSource.str());
}
}
TestInstance* BuiltinGlFrontFacingCase::createInstance (Context& context) const
{
return new BuiltinGlFrontFacingCaseInstance(context, m_topology);
}
class BuiltinGlFragCoordXYZCaseInstance : public ShaderRenderCaseInstance
{
public:
BuiltinGlFragCoordXYZCaseInstance (Context& context);
TestStatus iterate (void);
virtual void setupDefaultInputs (void);
};
BuiltinGlFragCoordXYZCaseInstance::BuiltinGlFragCoordXYZCaseInstance (Context& context)
: ShaderRenderCaseInstance (context)
{
}
TestStatus BuiltinGlFragCoordXYZCaseInstance::iterate (void)
{
const UVec2 viewportSize = getViewportSize();
const int width = viewportSize.x();
const int height = viewportSize.y();
const tcu::Vec3 scale (1.f / float(width), 1.f / float(height), 1.0f);
const tcu::RGBA threshold (2, 2, 2, 2);
Surface resImage (width, height);
Surface refImage (width, height);
bool compareOk = false;
const deUint16 indices[6] =
{
2, 1, 3,
0, 1, 2,
};
setup();
addUniform(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, scale);
render(4, 2, indices);
copy(resImage.getAccess(), getResultImage().getAccess());
// Reference image
for (int y = 0; y < refImage.getHeight(); y++)
{
for (int x = 0; x < refImage.getWidth(); x++)
{
const float xf = (float(x)+.5f) / float(refImage.getWidth());
const float yf = (float(refImage.getHeight()-y-1)+.5f) / float(refImage.getHeight());
const float z = (xf + yf) / 2.0f;
const Vec3 fragCoord (float(x)+.5f, float(y)+.5f, z);
const Vec3 scaledFC = fragCoord*scale;
const Vec4 color (scaledFC.x(), scaledFC.y(), scaledFC.z(), 1.0f);
refImage.setPixel(x, y, RGBA(color));
}
}
compareOk = pixelThresholdCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT);
if (compareOk)
return TestStatus::pass("Result image matches reference");
else
return TestStatus::fail("Image mismatch");
}
void BuiltinGlFragCoordXYZCaseInstance::setupDefaultInputs (void)
{
const float vertices[] =
{
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.5f, 1.0f,
1.0f, 1.0f, 0.5f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f,
};
addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 4, vertices);
}
class BuiltinGlFragCoordXYZCase : public TestCase
{
public:
BuiltinGlFragCoordXYZCase (TestContext& testCtx, const string& name, const string& description);
virtual ~BuiltinGlFragCoordXYZCase (void);
void initPrograms (SourceCollections& dst) const;
TestInstance* createInstance (Context& context) const;
private:
BuiltinGlFragCoordXYZCase (const BuiltinGlFragCoordXYZCase&); // not allowed!
BuiltinGlFragCoordXYZCase& operator= (const BuiltinGlFragCoordXYZCase&); // not allowed!
};
BuiltinGlFragCoordXYZCase::BuiltinGlFragCoordXYZCase (TestContext& testCtx, const string& name, const string& description)
: TestCase(testCtx, name, description)
{
}
BuiltinGlFragCoordXYZCase::~BuiltinGlFragCoordXYZCase (void)
{
}
void BuiltinGlFragCoordXYZCase::initPrograms (SourceCollections& dst) const
{
dst.glslSources.add("vert") << glu::VertexSource(
"#version 310 es\n"
"layout(location = 0) in highp vec4 a_position;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
"}\n");
dst.glslSources.add("frag") << glu::FragmentSource(
"#version 310 es\n"
"layout(set=0, binding=0) uniform Scale { highp vec3 u_scale; };\n"
"layout(location = 0) out highp vec4 o_color;\n"
"void main (void)\n"
"{\n"
" o_color = vec4(gl_FragCoord.xyz * u_scale, 1.0);\n"
"}\n");
}
TestInstance* BuiltinGlFragCoordXYZCase::createInstance (Context& context) const
{
return new BuiltinGlFragCoordXYZCaseInstance(context);
}
inline float projectedTriInterpolate (const Vec3& s, const Vec3& w, float nx, float ny)
{
return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
}
class BuiltinGlFragCoordWCaseInstance : public ShaderRenderCaseInstance
{
public:
BuiltinGlFragCoordWCaseInstance (Context& context);
TestStatus iterate (void);
virtual void setupDefaultInputs (void);
private:
const Vec4 m_w;
};
BuiltinGlFragCoordWCaseInstance::BuiltinGlFragCoordWCaseInstance (Context& context)
: ShaderRenderCaseInstance (context)
, m_w (1.7f, 2.0f, 1.2f, 1.0f)
{
}
TestStatus BuiltinGlFragCoordWCaseInstance::iterate (void)
{
const UVec2 viewportSize = getViewportSize();
const int width = viewportSize.x();
const int height = viewportSize.y();
const tcu::RGBA threshold (2, 2, 2, 2);
Surface resImage (width, height);
Surface refImage (width, height);
bool compareOk = false;
const deUint16 indices[6] =
{
2, 1, 3,
0, 1, 2,
};
setup();
render(4, 2, indices);
copy(resImage.getAccess(), getResultImage().getAccess());
// Reference image
for (int y = 0; y < refImage.getHeight(); y++)
{
for (int x = 0; x < refImage.getWidth(); x++)
{
const float xf = (float(x)+.5f) / float(refImage.getWidth());
const float yf = (float(refImage.getHeight()-y-1)+.5f) / float(refImage.getHeight());
const float oow = ((xf + yf) < 1.0f)
? projectedTriInterpolate(Vec3(m_w[0], m_w[1], m_w[2]), Vec3(m_w[0], m_w[1], m_w[2]), xf, yf)
: projectedTriInterpolate(Vec3(m_w[3], m_w[2], m_w[1]), Vec3(m_w[3], m_w[2], m_w[1]), 1.0f-xf, 1.0f-yf);
const Vec4 color (0.0f, oow - 1.0f, 0.0f, 1.0f);
refImage.setPixel(x, y, RGBA(color));
}
}
compareOk = pixelThresholdCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT);
if (compareOk)
return TestStatus::pass("Result image matches reference");
else
return TestStatus::fail("Image mismatch");
}
void BuiltinGlFragCoordWCaseInstance::setupDefaultInputs (void)
{
const float vertices[] =
{
-m_w[0], m_w[0], 0.0f, m_w[0],
-m_w[1], -m_w[1], 0.0f, m_w[1],
m_w[2], m_w[2], 0.0f, m_w[2],
m_w[3], -m_w[3], 0.0f, m_w[3]
};
addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 4, vertices);
}
class BuiltinGlFragCoordWCase : public TestCase
{
public:
BuiltinGlFragCoordWCase (TestContext& testCtx, const string& name, const string& description);
virtual ~BuiltinGlFragCoordWCase (void);
void initPrograms (SourceCollections& dst) const;
TestInstance* createInstance (Context& context) const;
private:
BuiltinGlFragCoordWCase (const BuiltinGlFragCoordWCase&); // not allowed!
BuiltinGlFragCoordWCase& operator= (const BuiltinGlFragCoordWCase&); // not allowed!
};
BuiltinGlFragCoordWCase::BuiltinGlFragCoordWCase (TestContext& testCtx, const string& name, const string& description)
: TestCase(testCtx, name, description)
{
}
BuiltinGlFragCoordWCase::~BuiltinGlFragCoordWCase (void)
{
}
void BuiltinGlFragCoordWCase::initPrograms (SourceCollections& dst) const
{
dst.glslSources.add("vert") << glu::VertexSource(
"#version 310 es\n"
"layout(location = 0) in highp vec4 a_position;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
"}\n");
dst.glslSources.add("frag") << glu::FragmentSource(
"#version 310 es\n"
"layout(location = 0) out highp vec4 o_color;\n"
"void main (void)\n"
"{\n"
" o_color = vec4(0.0, 1.0 / gl_FragCoord.w - 1.0, 0.0, 1.0);\n"
"}\n");
}
TestInstance* BuiltinGlFragCoordWCase::createInstance (Context& context) const
{
return new BuiltinGlFragCoordWCaseInstance(context);
}
class BuiltinGlPointCoordCaseInstance : public ShaderRenderCaseInstance
{
public:
BuiltinGlPointCoordCaseInstance (Context& context);
TestStatus iterate (void);
virtual void setupDefaultInputs (void);
};
BuiltinGlPointCoordCaseInstance::BuiltinGlPointCoordCaseInstance (Context& context)
: ShaderRenderCaseInstance (context)
{
}
TestStatus BuiltinGlPointCoordCaseInstance::iterate (void)
{
const UVec2 viewportSize = getViewportSize();
const int width = viewportSize.x();
const int height = viewportSize.y();
const float threshold = 0.02f;
const int numPoints = 16;
vector<Vec3> coords (numPoints);
de::Random rnd (0x145fa);
Surface resImage (width, height);
Surface refImage (width, height);
bool compareOk = false;
// Compute coordinates.
{
const VkPhysicalDeviceLimits& limits = m_context.getDeviceProperties().limits;
const float minPointSize = limits.pointSizeRange[0];
const float maxPointSize = limits.pointSizeRange[1];
const int pointSizeDeltaMultiples = de::max(1, deCeilFloatToInt32((maxPointSize - minPointSize) / limits.pointSizeGranularity));
TCU_CHECK(minPointSize <= maxPointSize);
for (vector<Vec3>::iterator coord = coords.begin(); coord != coords.end(); ++coord)
{
coord->x() = rnd.getFloat(-0.9f, 0.9f);
coord->y() = rnd.getFloat(-0.9f, 0.9f);
coord->z() = de::min(maxPointSize, minPointSize + float(rnd.getInt(0, pointSizeDeltaMultiples)) * limits.pointSizeGranularity);
}
}
setup();
addAttribute(0u, VK_FORMAT_R32G32B32_SFLOAT, deUint32(sizeof(Vec3)), numPoints, &coords[0]);
render(numPoints, 0, DE_NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
copy(resImage.getAccess(), getResultImage().getAccess());
// Draw reference
clear(refImage.getAccess(), m_clearColor);
for (vector<Vec3>::const_iterator pointIter = coords.begin(); pointIter != coords.end(); ++pointIter)
{
const float centerX = float(width) *(pointIter->x()*0.5f + 0.5f);
const float centerY = float(height)*(pointIter->y()*0.5f + 0.5f);
const float size = pointIter->z();
const int x0 = deRoundFloatToInt32(centerX - size*0.5f);
const int y0 = deRoundFloatToInt32(centerY - size*0.5f);
const int x1 = deRoundFloatToInt32(centerX + size*0.5f);
const int y1 = deRoundFloatToInt32(centerY + size*0.5f);
const int w = x1-x0;
const int h = y1-y0;
for (int yo = 0; yo < h; yo++)
{
for (int xo = 0; xo < w; xo++)
{
const int dx = x0+xo;
const int dy = y0+yo;
const float fragX = float(dx) + 0.5f;
const float fragY = float(dy) + 0.5f;
const float s = 0.5f + (fragX - centerX) / size;
const float t = 0.5f + (fragY - centerY) / size;
const Vec4 color (s, t, 0.0f, 1.0f);
if (de::inBounds(dx, 0, refImage.getWidth()) && de::inBounds(dy, 0, refImage.getHeight()))
refImage.setPixel(dx, dy, RGBA(color));
}
}
}
compareOk = fuzzyCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT);
if (compareOk)
return TestStatus::pass("Result image matches reference");
else
return TestStatus::fail("Image mismatch");
}
void BuiltinGlPointCoordCaseInstance::setupDefaultInputs (void)
{
}
class BuiltinGlPointCoordCase : public TestCase
{
public:
BuiltinGlPointCoordCase (TestContext& testCtx, const string& name, const string& description);
virtual ~BuiltinGlPointCoordCase (void);
void initPrograms (SourceCollections& dst) const;
TestInstance* createInstance (Context& context) const;
private:
BuiltinGlPointCoordCase (const BuiltinGlPointCoordCase&); // not allowed!
BuiltinGlPointCoordCase& operator= (const BuiltinGlPointCoordCase&); // not allowed!
};
BuiltinGlPointCoordCase::BuiltinGlPointCoordCase (TestContext& testCtx, const string& name, const string& description)
: TestCase(testCtx, name, description)
{
}
BuiltinGlPointCoordCase::~BuiltinGlPointCoordCase (void)
{
}
void BuiltinGlPointCoordCase::initPrograms (SourceCollections& dst) const
{
dst.glslSources.add("vert") << glu::VertexSource(
"#version 310 es\n"
"layout(location = 0) in highp vec3 a_position;\n"
"void main (void)\n"
"{\n"
" gl_Position = vec4(a_position.xy, 0.0, 1.0);\n"
" gl_PointSize = a_position.z;\n"
"}\n");
dst.glslSources.add("frag") << glu::FragmentSource(
"#version 310 es\n"
"layout(location = 0) out lowp vec4 o_color;\n"
"void main (void)\n"
"{\n"
" o_color = vec4(gl_PointCoord, 0.0, 1.0);\n"
"}\n");
}
TestInstance* BuiltinGlPointCoordCase::createInstance (Context& context) const
{
return new BuiltinGlPointCoordCaseInstance(context);
}
enum ShaderInputTypeBits
{
SHADER_INPUT_BUILTIN_BIT = 0x01,
SHADER_INPUT_VARYING_BIT = 0x02,
SHADER_INPUT_CONSTANT_BIT = 0x04
};
typedef deUint16 ShaderInputTypes;
string shaderInputTypeToString (ShaderInputTypes type)
{
string typeString = "input";
if (type == 0)
return "input_none";
if (type & SHADER_INPUT_BUILTIN_BIT)
typeString += "_builtin";
if (type & SHADER_INPUT_VARYING_BIT)
typeString += "_varying";
if (type & SHADER_INPUT_CONSTANT_BIT)
typeString += "_constant";
return typeString;
}
class BuiltinInputVariationsCaseInstance : public ShaderRenderCaseInstance
{
public:
BuiltinInputVariationsCaseInstance (Context& context, const ShaderInputTypes shaderInputTypes);
TestStatus iterate (void);
virtual void setupDefaultInputs (void);
virtual void updatePushConstants (vk::VkCommandBuffer commandBuffer, vk::VkPipelineLayout pipelineLayout);
private:
const ShaderInputTypes m_shaderInputTypes;
const Vec4 m_constantColor;
};
BuiltinInputVariationsCaseInstance::BuiltinInputVariationsCaseInstance (Context& context, const ShaderInputTypes shaderInputTypes)
: ShaderRenderCaseInstance (context)
, m_shaderInputTypes (shaderInputTypes)
, m_constantColor (0.1f, 0.05f, 0.2f, 0.0f)
{
}
TestStatus BuiltinInputVariationsCaseInstance::iterate (void)
{
const UVec2 viewportSize = getViewportSize();
const int width = viewportSize.x();
const int height = viewportSize.y();
const tcu::RGBA threshold (2, 2, 2, 2);
Surface resImage (width, height);
Surface refImage (width, height);
bool compareOk = false;
const VkPushConstantRange pcRanges =
{
VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags;
0u, // deUint32 offset;
sizeof(Vec4) // deUint32 size;
};
const deUint16 indices[12] =
{
0, 4, 1,
0, 5, 4,
1, 2, 3,
1, 3, 4
};
setup();
if (m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT)
setPushConstantRanges(1, &pcRanges);
render(6, 4, indices);
copy(resImage.getAccess(), getResultImage().getAccess());
// Reference image
for (int y = 0; y < refImage.getHeight(); y++)
{
for (int x = 0; x < refImage.getWidth(); x++)
{
Vec4 color (0.1f, 0.2f, 0.3f, 1.0f);
if (((m_shaderInputTypes & SHADER_INPUT_BUILTIN_BIT) && (x < refImage.getWidth() / 2)) ||
!(m_shaderInputTypes & SHADER_INPUT_BUILTIN_BIT))
{
if (m_shaderInputTypes & SHADER_INPUT_VARYING_BIT)
{
const float xf = (float(x)+.5f) / float(refImage.getWidth());
color += Vec4(0.6f * (1 - xf), 0.6f * xf, 0.0f, 0.0f);
}
else
color += Vec4(0.3f, 0.2f, 0.1f, 0.0f);
}
if (m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT)
color += m_constantColor;
refImage.setPixel(x, y, RGBA(color));
}
}
compareOk = pixelThresholdCompare(m_context.getTestContext().getLog(), "Result", "Image comparison result", refImage, resImage, threshold, COMPARE_LOG_RESULT);
if (compareOk)
return TestStatus::pass("Result image matches reference");
else
return TestStatus::fail("Image mismatch");
}
void BuiltinInputVariationsCaseInstance::setupDefaultInputs (void)
{
const float vertices[] =
{
-1.0f, -1.0f, 0.0f, 1.0f,
0.0f, -1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 1.0f
};
addAttribute(0u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 6, vertices);
if (m_shaderInputTypes & SHADER_INPUT_VARYING_BIT)
{
const float colors[] =
{
0.6f, 0.0f, 0.0f, 1.0f,
0.3f, 0.3f, 0.0f, 1.0f,
0.0f, 0.6f, 0.0f, 1.0f,
0.0f, 0.6f, 0.0f, 1.0f,
0.3f, 0.3f, 0.0f, 1.0f,
0.6f, 0.0f, 0.0f, 1.0f
};
addAttribute(1u, VK_FORMAT_R32G32B32A32_SFLOAT, deUint32(sizeof(float) * 4), 6, colors);
}
}
void BuiltinInputVariationsCaseInstance::updatePushConstants (vk::VkCommandBuffer commandBuffer, vk::VkPipelineLayout pipelineLayout)
{
if (m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
vk.cmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(Vec4), &m_constantColor);
}
}
class BuiltinInputVariationsCase : public TestCase
{
public:
BuiltinInputVariationsCase (TestContext& testCtx, const string& name, const string& description, const ShaderInputTypes shaderInputTypes);
virtual ~BuiltinInputVariationsCase (void);
void initPrograms (SourceCollections& dst) const;
TestInstance* createInstance (Context& context) const;
private:
BuiltinInputVariationsCase (const BuiltinInputVariationsCase&); // not allowed!
BuiltinInputVariationsCase& operator= (const BuiltinInputVariationsCase&); // not allowed!
const ShaderInputTypes m_shaderInputTypes;
};
BuiltinInputVariationsCase::BuiltinInputVariationsCase (TestContext& testCtx, const string& name, const string& description, ShaderInputTypes shaderInputTypes)
: TestCase (testCtx, name, description)
, m_shaderInputTypes (shaderInputTypes)
{
}
BuiltinInputVariationsCase::~BuiltinInputVariationsCase (void)
{
}
void BuiltinInputVariationsCase::initPrograms (SourceCollections& dst) const
{
map<string, string> vertexParams;
map<string, string> fragmentParams;
const tcu::StringTemplate vertexCodeTemplate (
"#version 450\n"
"layout(location = 0) in highp vec4 a_position;\n"
"out gl_PerVertex {\n"
" vec4 gl_Position;\n"
"};\n"
"${VARYING_DECL}"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
" ${VARYING_USAGE}"
"}\n");
const tcu::StringTemplate fragmentCodeTemplate (
"#version 450\n"
"${VARYING_DECL}"
"${CONSTANT_DECL}"
"layout(location = 0) out highp vec4 o_color;\n"
"void main (void)\n"
"{\n"
" o_color = vec4(0.1, 0.2, 0.3, 1.0);\n"
" ${BUILTIN_USAGE}"
" ${VARYING_USAGE}"
" ${CONSTANT_USAGE}"
"}\n");
vertexParams["VARYING_DECL"] =
m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "layout(location = 1) in highp vec4 a_color;\n"
"layout(location = 0) out highp vec4 v_color;\n"
: "";
vertexParams["VARYING_USAGE"] =
m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "v_color = a_color;\n"
: "";
fragmentParams["VARYING_DECL"] =
m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "layout(location = 0) in highp vec4 a_color;\n"
: "";
fragmentParams["CONSTANT_DECL"] =
m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT ? "layout(push_constant) uniform PCBlock {\n"
" vec4 color;\n"
"} pc;\n"
: "";
fragmentParams["BUILTIN_USAGE"] =
m_shaderInputTypes & SHADER_INPUT_BUILTIN_BIT ? "if (gl_FrontFacing)\n"
: "";
fragmentParams["VARYING_USAGE"] =
m_shaderInputTypes & SHADER_INPUT_VARYING_BIT ? "o_color += vec4(a_color.xyz, 0.0);\n"
: "o_color += vec4(0.3, 0.2, 0.1, 0.0);\n";
fragmentParams["CONSTANT_USAGE"] =
m_shaderInputTypes & SHADER_INPUT_CONSTANT_BIT ? "o_color += pc.color;\n"
: "";
dst.glslSources.add("vert") << glu::VertexSource(vertexCodeTemplate.specialize(vertexParams));
dst.glslSources.add("frag") << glu::FragmentSource(fragmentCodeTemplate.specialize(fragmentParams));
}
TestInstance* BuiltinInputVariationsCase::createInstance (Context& context) const
{
return new BuiltinInputVariationsCaseInstance(context, m_shaderInputTypes);
}
} // anonymous
TestCaseGroup* createBuiltinVarTests (TestContext& testCtx)
{
de::MovePtr<TestCaseGroup> builtinGroup (new TestCaseGroup(testCtx, "builtin_var", "Shader builtin variable tests."));
de::MovePtr<TestCaseGroup> simpleGroup (new TestCaseGroup(testCtx, "simple", "Simple cases."));
de::MovePtr<TestCaseGroup> inputVariationsGroup (new TestCaseGroup(testCtx, "input_variations", "Input type variation tests."));
de::MovePtr<TestCaseGroup> frontFacingGroup (new TestCaseGroup(testCtx, "frontfacing", "Test gl_Frontfacing keyword."));
simpleGroup->addChild(new BuiltinGlFragCoordXYZCase(testCtx, "fragcoord_xyz", "FragCoord xyz test"));
simpleGroup->addChild(new BuiltinGlFragCoordWCase(testCtx, "fragcoord_w", "FragCoord w test"));
simpleGroup->addChild(new BuiltinGlPointCoordCase(testCtx, "pointcoord", "PointCoord test"));
// gl_FrontFacing tests
{
static const struct PrimitiveTable
{
const char* name;
const char* desc;
VkPrimitiveTopology primitive;
} frontfacingCases[] =
{
{ "point_list", "Test that points are frontfacing", VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
{ "line_list", "Test that lines are frontfacing", VK_PRIMITIVE_TOPOLOGY_LINE_LIST },
{ "triangle_list", "Test that triangles can be frontfacing or backfacing", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST },
{ "triangle_strip", "Test that traiangle strips can be front or back facing", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
{ "triangle_fan", "Test that triangle fans can be front or back facing", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN },
};
for (deUint32 ndx = 0; ndx < DE_LENGTH_OF_ARRAY(frontfacingCases); ndx++)
frontFacingGroup->addChild(new BuiltinGlFrontFacingCase(testCtx, frontfacingCases[ndx].primitive, frontfacingCases[ndx].name, frontfacingCases[ndx].desc));
}
builtinGroup->addChild(frontFacingGroup.release());
builtinGroup->addChild(simpleGroup.release());
for (deUint16 shaderType = 0; shaderType <= (SHADER_INPUT_BUILTIN_BIT | SHADER_INPUT_VARYING_BIT | SHADER_INPUT_CONSTANT_BIT); ++shaderType)
{
inputVariationsGroup->addChild(new BuiltinInputVariationsCase(testCtx, shaderInputTypeToString(shaderType), "Input variation test", shaderType));
}
builtinGroup->addChild(inputVariationsGroup.release());
return builtinGroup.release();
}
} // sr
} // vkt