blob: 7ceba8b5c7bf35ed1e7b324940a223f59063ba4c [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES 3.1 Module
* -------------------------------------------------
*
* Copyright 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 Geometry shader tests.
*//*--------------------------------------------------------------------*/
#include "es31fGeometryShaderTests.hpp"
#include "gluRenderContext.hpp"
#include "gluTextureUtil.hpp"
#include "gluObjectWrapper.hpp"
#include "gluPixelTransfer.hpp"
#include "gluContextInfo.hpp"
#include "gluCallLogWrapper.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuTestLog.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuStringTemplate.hpp"
#include "glsStateQueryUtil.hpp"
#include "gluStrUtil.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include "deMemory.h"
#include "sglrContext.hpp"
#include "sglrReferenceContext.hpp"
#include "sglrGLContext.hpp"
#include "sglrReferenceUtils.hpp"
#include "glwDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include <algorithm>
using namespace glw;
namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{
using namespace gls::StateQueryUtil;
const int TEST_CANVAS_SIZE = 256;
static const char* const s_commonShaderSourceVertex = "${GLSL_VERSION_DECL}\n"
"in highp vec4 a_position;\n"
"in highp vec4 a_color;\n"
"out highp vec4 v_geom_FragColor;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
" gl_PointSize = 1.0;\n"
" v_geom_FragColor = a_color;\n"
"}\n";
static const char* const s_commonShaderSourceFragment = "${GLSL_VERSION_DECL}\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"in mediump vec4 v_frag_FragColor;\n"
"void main (void)\n"
"{\n"
" fragColor = v_frag_FragColor;\n"
"}\n";
static const char* const s_expandShaderSourceGeometryBody = "in highp vec4 v_geom_FragColor[];\n"
"out highp vec4 v_frag_FragColor;\n"
"\n"
"void main (void)\n"
"{\n"
" const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
" const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
" const highp vec4 offset2 = vec4(-0.01, 0.08, 0.0, 0.0);\n"
" highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
"\n"
" for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
" {\n"
" gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
" gl_PrimitiveID = gl_PrimitiveIDIn;\n"
" v_frag_FragColor = v_geom_FragColor[ndx];\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
" gl_PrimitiveID = gl_PrimitiveIDIn;\n"
" v_frag_FragColor = v_geom_FragColor[ndx];\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
" gl_PrimitiveID = gl_PrimitiveIDIn;\n"
" v_frag_FragColor = v_geom_FragColor[ndx];\n"
" EmitVertex();\n"
" EndPrimitive();\n"
" }\n"
"}\n";
static std::string specializeShader (const std::string& shaderSource, const glu::ContextType& contextType)
{
const bool supportsES32 = glu::contextSupports(contextType, glu::ApiType::es(3, 2));
std::map<std::string, std::string> args;
args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(contextType));
args["GLSL_EXT_GEOMETRY_SHADER"] = supportsES32 ? "" : "#extension GL_EXT_geometry_shader : require\n";
args["GLSL_OES_TEXTURE_STORAGE_MULTISAMPLE"]= supportsES32 ? "" : "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
return tcu::StringTemplate(shaderSource).specialize(args);
}
std::string inputTypeToGLString (rr::GeometryShaderInputType inputType)
{
switch (inputType)
{
case rr::GEOMETRYSHADERINPUTTYPE_POINTS: return "points";
case rr::GEOMETRYSHADERINPUTTYPE_LINES: return "lines";
case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY: return "lines_adjacency";
case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES: return "triangles";
case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY: return "triangles_adjacency";
default:
DE_ASSERT(DE_FALSE);
return "error";
}
}
std::string outputTypeToGLString (rr::GeometryShaderOutputType outputType)
{
switch (outputType)
{
case rr::GEOMETRYSHADEROUTPUTTYPE_POINTS: return "points";
case rr::GEOMETRYSHADEROUTPUTTYPE_LINE_STRIP: return "line_strip";
case rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP: return "triangle_strip";
default:
DE_ASSERT(DE_FALSE);
return "error";
}
}
std::string primitiveTypeToString (GLenum primitive)
{
switch (primitive)
{
case GL_POINTS: return "points";
case GL_LINES: return "lines";
case GL_LINE_LOOP: return "line_loop";
case GL_LINE_STRIP: return "line_strip";
case GL_LINES_ADJACENCY: return "lines_adjacency";
case GL_LINE_STRIP_ADJACENCY: return "line_strip_adjacency";
case GL_TRIANGLES: return "triangles";
case GL_TRIANGLE_STRIP: return "triangle_strip";
case GL_TRIANGLE_FAN: return "triangle_fan";
case GL_TRIANGLES_ADJACENCY: return "triangles_adjacency";
case GL_TRIANGLE_STRIP_ADJACENCY: return "triangle_strip_adjacency";
default:
DE_ASSERT(DE_FALSE);
return "error";
}
}
struct OutputCountPatternSpec
{
OutputCountPatternSpec (int count);
OutputCountPatternSpec (int count0, int count1);
std::vector<int> pattern;
};
OutputCountPatternSpec::OutputCountPatternSpec (int count)
{
pattern.push_back(count);
}
OutputCountPatternSpec::OutputCountPatternSpec (int count0, int count1)
{
pattern.push_back(count0);
pattern.push_back(count1);
}
class VertexExpanderShader : public sglr::ShaderProgram
{
public:
VertexExpanderShader (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType);
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
private:
size_t calcOutputVertices (rr::GeometryShaderInputType inputType) const;
std::string genGeometrySource (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType) const;
};
VertexExpanderShader::VertexExpanderShader (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType)
: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
<< sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
<< sglr::pdec::GeometryShaderDeclaration(inputType, outputType, calcOutputVertices(inputType))
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, inputType, outputType)))
{
}
void VertexExpanderShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->pointSize = 1.0f;
packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void VertexExpanderShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
}
void VertexExpanderShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(invocationID);
for (int ndx = 0; ndx < numPackets; ++ndx)
for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
{
const tcu::Vec4 offsets[] =
{
tcu::Vec4(-0.07f, -0.01f, 0.0f, 0.0f),
tcu::Vec4( 0.03f, -0.03f, 0.0f, 0.0f),
tcu::Vec4(-0.01f, 0.08f, 0.0f, 0.0f)
};
const tcu::Vec4 yoffset = float(packets[ndx].primitiveIDIn) * tcu::Vec4(0.02f, 0.1f, 0, 0);
// Create new primitive at every input vertice
const rr::VertexPacket* vertex = packets[ndx].vertices[verticeNdx];
output.EmitVertex(vertex->position + offsets[0] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
output.EmitVertex(vertex->position + offsets[1] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
output.EmitVertex(vertex->position + offsets[2] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
output.EndPrimitive();
}
}
size_t VertexExpanderShader::calcOutputVertices (rr::GeometryShaderInputType inputType) const
{
switch (inputType)
{
case rr::GEOMETRYSHADERINPUTTYPE_POINTS: return 1 * 3;
case rr::GEOMETRYSHADERINPUTTYPE_LINES: return 2 * 3;
case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY: return 4 * 3;
case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES: return 3 * 3;
case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY: return 6 * 3;
default:
DE_ASSERT(DE_FALSE);
return 0;
}
}
std::string VertexExpanderShader::genGeometrySource (const glu::ContextType& contextType, rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType) const
{
std::ostringstream str;
str << "${GLSL_VERSION_DECL}\n";
str << "${GLSL_EXT_GEOMETRY_SHADER}";
str << "layout(" << inputTypeToGLString(inputType) << ") in;\n";
str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << calcOutputVertices(inputType) << ") out;";
str << "\n";
str << s_expandShaderSourceGeometryBody;
return specializeShader(str.str(), contextType);
}
class VertexEmitterShader : public sglr::ShaderProgram
{
public:
VertexEmitterShader (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType);
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
private:
std::string genGeometrySource (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType) const;
int m_emitCountA;
int m_endCountA;
int m_emitCountB;
int m_endCountB;
};
VertexEmitterShader::VertexEmitterShader (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType)
: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
<< sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, outputType, emitCountA + emitCountB)
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, emitCountA, endCountA, emitCountB, endCountB, outputType)))
, m_emitCountA (emitCountA)
, m_endCountA (endCountA)
, m_emitCountB (emitCountB)
, m_endCountB (endCountB)
{
}
void VertexEmitterShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->pointSize = 1.0f;
packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void VertexEmitterShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
}
void VertexEmitterShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(verticesIn);
DE_UNREF(invocationID);
for (int ndx = 0; ndx < numPackets; ++ndx)
{
const tcu::Vec4 positions[] =
{
tcu::Vec4(-0.5f, 0.5f, 0.0f, 0.0f),
tcu::Vec4( 0.0f, 0.1f, 0.0f, 0.0f),
tcu::Vec4( 0.5f, 0.5f, 0.0f, 0.0f),
tcu::Vec4( 0.7f, -0.2f, 0.0f, 0.0f),
tcu::Vec4( 0.2f, 0.2f, 0.0f, 0.0f),
tcu::Vec4( 0.4f, -0.3f, 0.0f, 0.0f),
};
// Create new primitive at this point
const rr::VertexPacket* vertex = packets[ndx].vertices[0];
for (int i = 0; i < m_emitCountA; ++i)
output.EmitVertex(vertex->position + positions[i], vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
for (int i = 0; i < m_endCountA; ++i)
output.EndPrimitive();
for (int i = 0; i < m_emitCountB; ++i)
output.EmitVertex(vertex->position + positions[m_emitCountA + i], vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
for (int i = 0; i < m_endCountB; ++i)
output.EndPrimitive();
}
}
std::string VertexEmitterShader::genGeometrySource (const glu::ContextType& contextType, int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType) const
{
std::ostringstream str;
str << "${GLSL_VERSION_DECL}\n";
str << "${GLSL_EXT_GEOMETRY_SHADER}";
str << "layout(points) in;\n";
str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << (emitCountA+emitCountB) << ") out;";
str << "\n";
str << "in highp vec4 v_geom_FragColor[];\n"
"out highp vec4 v_frag_FragColor;\n"
"\n"
"void main (void)\n"
"{\n"
" const highp vec4 position0 = vec4(-0.5, 0.5, 0.0, 0.0);\n"
" const highp vec4 position1 = vec4( 0.0, 0.1, 0.0, 0.0);\n"
" const highp vec4 position2 = vec4( 0.5, 0.5, 0.0, 0.0);\n"
" const highp vec4 position3 = vec4( 0.7, -0.2, 0.0, 0.0);\n"
" const highp vec4 position4 = vec4( 0.2, 0.2, 0.0, 0.0);\n"
" const highp vec4 position5 = vec4( 0.4, -0.3, 0.0, 0.0);\n"
"\n";
for (int i = 0; i < emitCountA; ++i)
str << " gl_Position = gl_in[0].gl_Position + position" << i << ";\n"
" gl_PrimitiveID = gl_PrimitiveIDIn;\n"
" v_frag_FragColor = v_geom_FragColor[0];\n"
" EmitVertex();\n"
"\n";
for (int i = 0; i < endCountA; ++i)
str << " EndPrimitive();\n";
for (int i = 0; i < emitCountB; ++i)
str << " gl_Position = gl_in[0].gl_Position + position" << (emitCountA + i) << ";\n"
" gl_PrimitiveID = gl_PrimitiveIDIn;\n"
" v_frag_FragColor = v_geom_FragColor[0];\n"
" EmitVertex();\n"
"\n";
for (int i = 0; i < endCountB; ++i)
str << " EndPrimitive();\n";
str << "}\n";
return specializeShader(str.str(), contextType);
}
class VertexVaryingShader : public sglr::ShaderProgram
{
public:
VertexVaryingShader (const glu::ContextType& contextType, int vertexOut, int geometryOut);
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
private:
static sglr::pdec::ShaderProgramDeclaration genProgramDeclaration (const glu::ContextType& contextType, int vertexOut, int geometryOut);
const int m_vertexOut;
const int m_geometryOut;
};
VertexVaryingShader::VertexVaryingShader (const glu::ContextType& contextType, int vertexOut, int geometryOut)
: sglr::ShaderProgram (genProgramDeclaration(contextType, vertexOut, geometryOut))
, m_vertexOut (vertexOut)
, m_geometryOut (geometryOut)
{
}
void VertexVaryingShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
// vertex shader is no-op
if (m_vertexOut == -1)
return;
for (int ndx = 0; ndx < numPackets; ++ndx)
{
const tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->pointSize = 1.0f;
switch (m_vertexOut)
{
case 0:
break;
case 1:
packets[ndx]->outputs[0] = color;
break;
case 2:
packets[ndx]->outputs[0] = color * 0.5f;
packets[ndx]->outputs[1] = color.swizzle(2,1,0,3) * 0.5f;
break;
default:
DE_ASSERT(DE_FALSE);
}
}
}
void VertexVaryingShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
switch (m_geometryOut)
{
case 0:
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
break;
case 1:
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
break;
case 2:
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx)
+ rr::readTriangleVarying<float>(packets[packetNdx], context, 1, fragNdx).swizzle(1, 0, 2, 3));
break;
default:
DE_ASSERT(DE_FALSE);
}
}
}
void VertexVaryingShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(invocationID);
const tcu::Vec4 vertexOffset(-0.2f, -0.2f, 0, 0);
if (m_vertexOut == -1)
{
// vertex is a no-op
const tcu::Vec4 inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
rr::GenericVec4 outputs[2];
// output color
switch (m_geometryOut)
{
case 0:
break;
case 1:
outputs[0] = inputColor;
break;
case 2:
outputs[0] = inputColor * 0.5f;
outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
break;
default:
DE_ASSERT(DE_FALSE);
}
for (int ndx = 0; ndx < numPackets; ++ndx)
{
output.EmitVertex(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
output.EmitVertex(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
output.EmitVertex(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
output.EndPrimitive();
}
}
else
{
// vertex is not a no-op
for (int ndx = 0; ndx < numPackets; ++ndx)
{
for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
{
tcu::Vec4 inputColor;
rr::GenericVec4 outputs[2];
// input color
switch (m_vertexOut)
{
case 0:
inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
break;
case 1:
inputColor = packets[ndx].vertices[verticeNdx]->outputs[0].get<float>();
break;
case 2:
inputColor = (packets[ndx].vertices[verticeNdx]->outputs[0].get<float>() * 0.5f)
+ (packets[ndx].vertices[verticeNdx]->outputs[1].get<float>().swizzle(2, 1, 0, 3) * 0.5f);
break;
default:
DE_ASSERT(DE_FALSE);
}
// output color
switch (m_geometryOut)
{
case 0:
break;
case 1:
outputs[0] = inputColor;
break;
case 2:
outputs[0] = inputColor * 0.5f;
outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
break;
default:
DE_ASSERT(DE_FALSE);
}
output.EmitVertex(packets[ndx].vertices[verticeNdx]->position + vertexOffset, packets[ndx].vertices[verticeNdx]->pointSize, outputs, packets[ndx].primitiveIDIn);
}
output.EndPrimitive();
}
}
}
sglr::pdec::ShaderProgramDeclaration VertexVaryingShader::genProgramDeclaration (const glu::ContextType& contextType, int vertexOut, int geometryOut)
{
sglr::pdec::ShaderProgramDeclaration decl;
std::ostringstream vertexSource;
std::ostringstream fragmentSource;
std::ostringstream geometrySource;
decl
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT);
for (int i = 0; i < vertexOut; ++i)
decl << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT);
for (int i = 0; i < geometryOut; ++i)
decl << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
decl
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, 3);
// vertexSource
vertexSource << "${GLSL_VERSION_DECL}\n"
"in highp vec4 a_position;\n"
"in highp vec4 a_color;\n";
// no-op case?
if (vertexOut == -1)
{
vertexSource << "void main (void)\n"
"{\n"
"}\n";
}
else
{
for (int i = 0; i < vertexOut; ++i)
vertexSource << "out highp vec4 v_geom_" << i << ";\n";
vertexSource << "void main (void)\n"
"{\n"
"\tgl_Position = a_position;\n"
"\tgl_PointSize = 1.0;\n";
switch (vertexOut)
{
case 0:
break;
case 1:
vertexSource << "\tv_geom_0 = a_color;\n";
break;
case 2:
vertexSource << "\tv_geom_0 = a_color * 0.5;\n";
vertexSource << "\tv_geom_1 = a_color.zyxw * 0.5;\n";
break;
default:
DE_ASSERT(DE_FALSE);
}
vertexSource << "}\n";
}
// fragmentSource
fragmentSource << "${GLSL_VERSION_DECL}\n"
"layout(location = 0) out mediump vec4 fragColor;\n";
for (int i = 0; i < geometryOut; ++i)
fragmentSource << "in mediump vec4 v_frag_" << i << ";\n";
fragmentSource << "void main (void)\n"
"{\n";
switch (geometryOut)
{
case 0:
fragmentSource << "\tfragColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
break;
case 1:
fragmentSource << "\tfragColor = v_frag_0;\n";
break;
case 2:
fragmentSource << "\tfragColor = v_frag_0 + v_frag_1.yxzw;\n";
break;
default:
DE_ASSERT(DE_FALSE);
}
fragmentSource << "}\n";
// geometrySource
geometrySource << "${GLSL_VERSION_DECL}\n"
"${GLSL_EXT_GEOMETRY_SHADER}"
"layout(triangles) in;\n"
"layout(triangle_strip, max_vertices = 3) out;\n";
for (int i = 0; i < vertexOut; ++i)
geometrySource << "in highp vec4 v_geom_" << i << "[];\n";
for (int i = 0; i < geometryOut; ++i)
geometrySource << "out highp vec4 v_frag_" << i << ";\n";
geometrySource << "void main (void)\n"
"{\n"
"\thighp vec4 offset = vec4(-0.2, -0.2, 0.0, 0.0);\n"
"\thighp vec4 inputColor;\n\n";
for (int vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
{
if (vertexOut == -1)
{
// vertex is a no-op
geometrySource << "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"\tgl_Position = vec4(" << ((vertexNdx==0) ? ("0.0, 0.0") : ((vertexNdx==1) ? ("1.0, 0.0") : ("1.0, 1.0"))) << ", 0.0, 1.0) + offset;\n"
"\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
}
else
{
switch (vertexOut)
{
case 0:
geometrySource << "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
break;
case 1:
geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "];\n";
break;
case 2:
geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "] * 0.5 + v_geom_1[" << vertexNdx << "].zyxw * 0.5;\n";
break;
default:
DE_ASSERT(DE_FALSE);
}
geometrySource << "\tgl_Position = gl_in[" << vertexNdx << "].gl_Position + offset;\n"
"\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
}
switch (geometryOut)
{
case 0:
break;
case 1:
geometrySource << "\tv_frag_0 = inputColor;\n";
break;
case 2:
geometrySource << "\tv_frag_0 = inputColor * 0.5;\n";
geometrySource << "\tv_frag_1 = inputColor.yxzw * 0.5;\n";
break;
default:
DE_ASSERT(DE_FALSE);
}
geometrySource << "\tEmitVertex();\n\n";
}
geometrySource << "\tEndPrimitive();\n"
"}\n";
decl
<< sglr::pdec::VertexSource(specializeShader(vertexSource.str(), contextType))
<< sglr::pdec::FragmentSource(specializeShader(fragmentSource.str(), contextType))
<< sglr::pdec::GeometrySource(specializeShader(geometrySource.str(), contextType));
return decl;
}
class OutputCountShader : public sglr::ShaderProgram
{
public:
OutputCountShader (const glu::ContextType& contextType, const OutputCountPatternSpec& spec);
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
private:
std::string genGeometrySource (const glu::ContextType& contextType, const OutputCountPatternSpec& spec) const;
size_t getPatternEmitCount (const OutputCountPatternSpec& spec) const;
const int m_patternLength;
const int m_patternMaxEmitCount;
const OutputCountPatternSpec m_spec;
};
OutputCountShader::OutputCountShader (const glu::ContextType& contextType, const OutputCountPatternSpec& spec)
: sglr::ShaderProgram (sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
<< sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, getPatternEmitCount(spec))
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, spec)))
, m_patternLength ((int)spec.pattern.size())
, m_patternMaxEmitCount ((int)getPatternEmitCount(spec))
, m_spec (spec)
{
}
void OutputCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->pointSize = 1.0f;
packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void OutputCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
}
void OutputCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(verticesIn);
DE_UNREF(invocationID);
const float rowHeight = 2.0f / (float)m_patternLength;
const float colWidth = 2.0f / (float)m_patternMaxEmitCount;
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
// Create triangle strip at this point
const rr::VertexPacket* vertex = packets[packetNdx].vertices[0];
const int emitCount = m_spec.pattern[packets[packetNdx].primitiveIDIn];
for (int ndx = 0; ndx < emitCount / 2; ++ndx)
{
output.EmitVertex(vertex->position + tcu::Vec4(2 * (float)ndx * colWidth, 0.0, 0.0, 0.0), vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
output.EmitVertex(vertex->position + tcu::Vec4(2 * (float)ndx * colWidth, rowHeight, 0.0, 0.0), vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
}
output.EndPrimitive();
}
}
std::string OutputCountShader::genGeometrySource (const glu::ContextType& contextType, const OutputCountPatternSpec& spec) const
{
std::ostringstream str;
// draw row with a triangle strip, always make rectangles
for (int ndx = 0; ndx < (int)spec.pattern.size(); ++ndx)
DE_ASSERT(spec.pattern[ndx] % 2 == 0);
str << "${GLSL_VERSION_DECL}\n";
str << "${GLSL_EXT_GEOMETRY_SHADER}";
str << "layout(points) in;\n";
str << "layout(triangle_strip, max_vertices = " << getPatternEmitCount(spec) << ") out;";
str << "\n";
str << "in highp vec4 v_geom_FragColor[];\n"
"out highp vec4 v_frag_FragColor;\n"
"\n"
"void main (void)\n"
"{\n"
" const highp float rowHeight = 2.0 / float(" << spec.pattern.size() << ");\n"
" const highp float colWidth = 2.0 / float(" << getPatternEmitCount(spec) << ");\n"
"\n";
str << " highp int emitCount = ";
for (int ndx = 0; ndx < (int)spec.pattern.size() - 1; ++ndx)
str << "(gl_PrimitiveIDIn == " << ndx << ") ? (" << spec.pattern[ndx] << ") : (";
str << spec.pattern[(int)spec.pattern.size() - 1]
<< ((spec.pattern.size() == 1) ? ("") : (")"))
<< ";\n";
str << " for (highp int ndx = 0; ndx < emitCount / 2; ndx++)\n"
" {\n"
" gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, 0.0, 0.0, 0.0);\n"
" v_frag_FragColor = v_geom_FragColor[0];\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, rowHeight, 0.0, 0.0);\n"
" v_frag_FragColor = v_geom_FragColor[0];\n"
" EmitVertex();\n"
" }\n"
"}\n";
return specializeShader(str.str(), contextType);
}
size_t OutputCountShader::getPatternEmitCount (const OutputCountPatternSpec& spec) const
{
return *std::max_element(spec.pattern.begin(), spec.pattern.end());
}
class BuiltinVariableShader : public sglr::ShaderProgram
{
public:
enum VariableTest
{
TEST_POINT_SIZE = 0,
TEST_PRIMITIVE_ID_IN,
TEST_PRIMITIVE_ID,
TEST_LAST
};
BuiltinVariableShader (const glu::ContextType& contextType, VariableTest test);
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
static const char* getTestAttributeName (VariableTest test);
private:
std::string genGeometrySource (const glu::ContextType& contextType, VariableTest test) const;
std::string genVertexSource (const glu::ContextType& contextType, VariableTest test) const;
std::string genFragmentSource (const glu::ContextType& contextType, VariableTest test) const;
const VariableTest m_test;
};
BuiltinVariableShader::BuiltinVariableShader (const glu::ContextType& contextType, VariableTest test)
: sglr::ShaderProgram (sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute(getTestAttributeName(test), rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(genVertexSource(contextType, test))
<< sglr::pdec::FragmentSource(genFragmentSource(contextType, test))
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
((test == TEST_POINT_SIZE) ? (rr::GEOMETRYSHADEROUTPUTTYPE_POINTS) : (rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP)),
((test == TEST_POINT_SIZE) ? (1) : (3)))
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, test)))
, m_test (test)
{
}
void BuiltinVariableShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->pointSize = 1.0f;
packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void BuiltinVariableShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 blue = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 colors[4] = { yellow, red, green, blue };
if (m_test == TEST_POINT_SIZE || m_test == TEST_PRIMITIVE_ID_IN)
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
}
else if (m_test == TEST_PRIMITIVE_ID)
{
const tcu::Vec4 color = colors[context.primitiveID % 4];
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
}
else
DE_ASSERT(DE_FALSE);
}
void BuiltinVariableShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(verticesIn);
DE_UNREF(invocationID);
const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 blue = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 colors[4] = { red, green, blue, yellow };
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
const rr::VertexPacket* vertex = packets[packetNdx].vertices[0];
if (m_test == TEST_POINT_SIZE)
{
rr::GenericVec4 fragColor;
const float pointSize = vertex->outputs[0].get<float>().x() + 1.0f;
fragColor = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
output.EmitVertex(vertex->position, pointSize, &fragColor, packets[packetNdx].primitiveIDIn);
}
else if (m_test == TEST_PRIMITIVE_ID_IN)
{
rr::GenericVec4 fragColor;
fragColor = colors[packets[packetNdx].primitiveIDIn % 4];
output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
output.EmitVertex(vertex->position + tcu::Vec4(0.0f, 0.05f, 0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
}
else if (m_test == TEST_PRIMITIVE_ID)
{
const int primitiveID = (int)deFloatFloor(vertex->outputs[0].get<float>().x()) + 3;
output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f, 0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
output.EmitVertex(vertex->position + tcu::Vec4(0.0f, 0.05f, 0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
}
else
DE_ASSERT(DE_FALSE);
output.EndPrimitive();
}
}
const char* BuiltinVariableShader::getTestAttributeName (VariableTest test)
{
switch (test)
{
case TEST_POINT_SIZE: return "a_pointSize";
case TEST_PRIMITIVE_ID_IN: return "";
case TEST_PRIMITIVE_ID: return "a_primitiveID";
default:
DE_ASSERT(DE_FALSE);
return "";
}
}
std::string BuiltinVariableShader::genGeometrySource (const glu::ContextType& contextType, VariableTest test) const
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"${GLSL_EXT_GEOMETRY_SHADER}";
if (test == TEST_POINT_SIZE)
buf << "#extension GL_EXT_geometry_point_size : require\n";
buf << "layout(points) in;\n";
if (test == TEST_POINT_SIZE)
buf << "layout(points, max_vertices = 1) out;\n";
else
buf << "layout(triangle_strip, max_vertices = 3) out;\n";
if (test == TEST_POINT_SIZE)
buf << "in highp vec4 v_geom_pointSize[];\n";
else if (test == TEST_PRIMITIVE_ID)
buf << "in highp vec4 v_geom_primitiveID[];\n";
if (test != TEST_PRIMITIVE_ID)
buf << "out highp vec4 v_frag_FragColor;\n";
buf << "\n"
"void main (void)\n"
"{\n";
if (test == TEST_POINT_SIZE)
{
buf << " gl_Position = gl_in[0].gl_Position;\n"
" gl_PointSize = v_geom_pointSize[0].x + 1.0;\n"
" v_frag_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
" EmitVertex();\n";
}
else if (test == TEST_PRIMITIVE_ID_IN)
{
buf << " const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
" const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
" const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
" const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
" const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
"\n"
" gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
" v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
" v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
" v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
" EmitVertex();\n";
}
else if (test == TEST_PRIMITIVE_ID)
{
buf << " gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
" gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
" gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
" EmitVertex();\n"
"\n"
" gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
" gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
" EmitVertex();\n"
"\n";
}
else
DE_ASSERT(DE_FALSE);
buf << "}\n";
return specializeShader(buf.str(), contextType);
}
std::string BuiltinVariableShader::genVertexSource (const glu::ContextType& contextType, VariableTest test) const
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"in highp vec4 a_position;\n";
if (test == TEST_POINT_SIZE)
buf << "in highp vec4 a_pointSize;\n";
else if (test == TEST_PRIMITIVE_ID)
buf << "in highp vec4 a_primitiveID;\n";
if (test == TEST_POINT_SIZE)
buf << "out highp vec4 v_geom_pointSize;\n";
else if (test == TEST_PRIMITIVE_ID)
buf << "out highp vec4 v_geom_primitiveID;\n";
buf << "void main (void)\n"
"{\n"
" gl_Position = a_position;\n"
" gl_PointSize = 1.0;\n";
if (test == TEST_POINT_SIZE)
buf << " v_geom_pointSize = a_pointSize;\n";
else if (test == TEST_PRIMITIVE_ID)
buf << " v_geom_primitiveID = a_primitiveID;\n";
buf << "}\n";
return specializeShader(buf.str(), contextType);
}
std::string BuiltinVariableShader::genFragmentSource (const glu::ContextType& contextType, VariableTest test) const
{
std::ostringstream buf;
if (test == TEST_POINT_SIZE || test == TEST_PRIMITIVE_ID_IN)
return specializeShader(s_commonShaderSourceFragment, contextType);
else if (test == TEST_PRIMITIVE_ID)
{
buf << "${GLSL_VERSION_DECL}\n"
"${GLSL_EXT_GEOMETRY_SHADER}"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main (void)\n"
"{\n"
" const mediump vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
" const mediump vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
" const mediump vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
" const mediump vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
" const mediump vec4 colors[4] = vec4[4](yellow, red, green, blue);\n"
" fragColor = colors[gl_PrimitiveID % 4];\n"
"}\n";
return specializeShader(buf.str(), contextType);
}
else
{
DE_ASSERT(DE_FALSE);
return "";
}
}
class VaryingOutputCountShader : public sglr::ShaderProgram
{
public:
enum VaryingSource
{
READ_ATTRIBUTE = 0,
READ_UNIFORM,
READ_TEXTURE,
READ_LAST
};
enum
{
EMIT_COUNT_VERTEX_0 = 6,
EMIT_COUNT_VERTEX_1 = 0,
EMIT_COUNT_VERTEX_2 = -1,
EMIT_COUNT_VERTEX_3 = 10,
};
VaryingOutputCountShader (const glu::ContextType& contextType, VaryingSource source, int maxEmitCount, bool instanced);
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
static const char* getAttributeName (VaryingSource test);
private:
static std::string genGeometrySource (const glu::ContextType& contextType, VaryingSource test, int maxEmitCount, bool instanced);
static std::string genVertexSource (const glu::ContextType& contextType, VaryingSource test);
const VaryingSource m_test;
const sglr::UniformSlot& m_sampler;
const sglr::UniformSlot& m_emitCount;
const int m_maxEmitCount;
const bool m_instanced;
};
VaryingOutputCountShader::VaryingOutputCountShader (const glu::ContextType& contextType, VaryingSource source, int maxEmitCount, bool instanced)
: sglr::ShaderProgram (sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::Uniform("u_sampler", glu::TYPE_SAMPLER_2D)
<< sglr::pdec::Uniform("u_emitCount", glu::TYPE_INT_VEC4)
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute(getAttributeName(source), rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(genVertexSource(contextType, source))
<< sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
maxEmitCount,
(instanced) ? (4) : (1))
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, source, maxEmitCount, instanced)))
, m_test (source)
, m_sampler (getUniformByName("u_sampler"))
, m_emitCount (getUniformByName("u_emitCount"))
, m_maxEmitCount (maxEmitCount)
, m_instanced (instanced)
{
}
void VaryingOutputCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void VaryingOutputCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
}
void VaryingOutputCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(verticesIn);
const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 blue = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 colors[4] = { red, green, blue, yellow };
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
const rr::VertexPacket* vertex = packets[packetNdx].vertices[0];
int emitCount = 0;
tcu::Vec4 color = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
if (m_test == READ_ATTRIBUTE)
{
emitCount = (int)vertex->outputs[0].get<float>()[(m_instanced) ? (invocationID) : (0)];
color = tcu::Vec4((emitCount < 10) ? (0.0f) : (1.0f), (emitCount > 10) ? (0.0f) : (1.0f), 1.0f, 1.0f);
}
else if (m_test == READ_UNIFORM)
{
const int primitiveNdx = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
DE_ASSERT(primitiveNdx >= 0);
DE_ASSERT(primitiveNdx < 4);
emitCount = m_emitCount.value.i4[primitiveNdx];
color = colors[primitiveNdx];
}
else if (m_test == READ_TEXTURE)
{
const int primitiveNdx = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
const tcu::Vec2 texCoord = tcu::Vec2(1.0f / 8.0f + (float)primitiveNdx / 4.0f, 0.5f);
const tcu::Vec4 texColor = m_sampler.sampler.tex2D->sample(texCoord.x(), texCoord.y(), 0.0f);
DE_ASSERT(primitiveNdx >= 0);
DE_ASSERT(primitiveNdx < 4);
color = colors[primitiveNdx];
emitCount = 0;
if (texColor.x() > 0.0f)
emitCount += (EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_0);
if (texColor.y() > 0.0f)
emitCount += (EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_1);
if (texColor.z() > 0.0f)
emitCount += (EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_2);
if (texColor.w() > 0.0f)
emitCount += (EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_3);
}
else
DE_ASSERT(DE_FALSE);
for (int ndx = 0; ndx < (int)emitCount / 2; ++ndx)
{
const float angle = (float(ndx) + 0.5f) / float(emitCount / 2) * 3.142f;
const tcu::Vec4 basePosition = (m_instanced) ?
(vertex->position + tcu::Vec4(deFloatCos(float(invocationID)), deFloatSin(float(invocationID)), 0.0f, 0.0f) * 0.5f) :
(vertex->position);
const tcu::Vec4 position0 = basePosition + tcu::Vec4(deFloatCos(angle), deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
const tcu::Vec4 position1 = basePosition + tcu::Vec4(deFloatCos(angle), -deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
rr::GenericVec4 fragColor;
fragColor = color;
output.EmitVertex(position0, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
output.EmitVertex(position1, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
}
output.EndPrimitive();
}
}
const char* VaryingOutputCountShader::getAttributeName (VaryingSource test)
{
switch (test)
{
case READ_ATTRIBUTE: return "a_emitCount";
case READ_UNIFORM: return "a_vertexNdx";
case READ_TEXTURE: return "a_vertexNdx";
default:
DE_ASSERT(DE_FALSE);
return "";
}
}
std::string VaryingOutputCountShader::genGeometrySource (const glu::ContextType& contextType, VaryingSource test, int maxEmitCount, bool instanced)
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"${GLSL_EXT_GEOMETRY_SHADER}"
"layout(points" << ((instanced) ? (",invocations=4") : ("")) << ") in;\n"
"layout(triangle_strip, max_vertices = " << maxEmitCount << ") out;\n";
if (test == READ_ATTRIBUTE)
buf << "in highp vec4 v_geom_emitCount[];\n";
else if (test == READ_UNIFORM)
buf << "in highp vec4 v_geom_vertexNdx[];\n"
"uniform highp ivec4 u_emitCount;\n";
else
buf << "in highp vec4 v_geom_vertexNdx[];\n"
"uniform highp sampler2D u_sampler;\n";
buf << "out highp vec4 v_frag_FragColor;\n"
"\n"
"void main (void)\n"
"{\n";
// emit count
if (test == READ_ATTRIBUTE)
{
buf << " highp vec4 attrEmitCounts = v_geom_emitCount[0];\n"
" mediump int emitCount = int(attrEmitCounts[" << ((instanced) ? ("gl_InvocationID") : ("0")) << "]);\n";
}
else if (test == READ_UNIFORM)
{
buf << " mediump int primitiveNdx = " << ((instanced) ? ("gl_InvocationID") : ("int(v_geom_vertexNdx[0].x)")) << ";\n"
" mediump int emitCount = u_emitCount[primitiveNdx];\n";
}
else if (test == READ_TEXTURE)
{
buf << " highp float primitiveNdx = " << ((instanced) ? ("float(gl_InvocationID)") : ("v_geom_vertexNdx[0].x")) << ";\n"
" highp vec2 texCoord = vec2(1.0 / 8.0 + primitiveNdx / 4.0, 0.5);\n"
" highp vec4 texColor = texture(u_sampler, texCoord);\n"
" mediump int emitCount = 0;\n"
" if (texColor.x > 0.0)\n"
" emitCount += " << ((EMIT_COUNT_VERTEX_0 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_0)) << ";\n"
" if (texColor.y > 0.0)\n"
" emitCount += " << ((EMIT_COUNT_VERTEX_1 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_1)) << ";\n"
" if (texColor.z > 0.0)\n"
" emitCount += " << ((EMIT_COUNT_VERTEX_2 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_2)) << ";\n"
" if (texColor.w > 0.0)\n"
" emitCount += " << ((EMIT_COUNT_VERTEX_3 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_3)) << ";\n";
}
else
DE_ASSERT(DE_FALSE);
// color
if (test == READ_ATTRIBUTE)
{
// We don't want color to be compile time constant
buf << " highp vec4 color = vec4((emitCount < 10) ? (0.0) : (1.0), (emitCount > 10) ? (0.0) : (1.0), 1.0, 1.0);\n";
}
else if (test == READ_UNIFORM || test == READ_TEXTURE)
{
buf << "\n"
" const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
" const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
" const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
" const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
" const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
" highp vec4 color = colors[int(primitiveNdx)];\n";
}
else
DE_ASSERT(DE_FALSE);
buf << "\n"
" highp vec4 basePos = " << ((instanced) ? ("gl_in[0].gl_Position + 0.5 * vec4(cos(float(gl_InvocationID)), sin(float(gl_InvocationID)), 0.0, 0.0)") : ("gl_in[0].gl_Position")) << ";\n"
" for (mediump int i = 0; i < emitCount / 2; i++)\n"
" {\n"
" highp float angle = (float(i) + 0.5) / float(emitCount / 2) * 3.142;\n"
" gl_Position = basePos + vec4(cos(angle), sin(angle), 0.0, 0.0) * 0.15;\n"
" v_frag_FragColor = color;\n"
" EmitVertex();\n"
" gl_Position = basePos + vec4(cos(angle), -sin(angle), 0.0, 0.0) * 0.15;\n"
" v_frag_FragColor = color;\n"
" EmitVertex();\n"
" }"
"}\n";
return specializeShader(buf.str(), contextType);
}
std::string VaryingOutputCountShader::genVertexSource (const glu::ContextType& contextType, VaryingSource test)
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"in highp vec4 a_position;\n";
if (test == READ_ATTRIBUTE)
{
buf << "in highp vec4 a_emitCount;\n";
buf << "out highp vec4 v_geom_emitCount;\n";
}
else if (test == READ_UNIFORM || test == READ_TEXTURE)
{
buf << "in highp vec4 a_vertexNdx;\n";
buf << "out highp vec4 v_geom_vertexNdx;\n";
}
buf << "void main (void)\n"
"{\n"
" gl_Position = a_position;\n";
if (test == READ_ATTRIBUTE)
buf << " v_geom_emitCount = a_emitCount;\n";
else if (test == READ_UNIFORM || test == READ_TEXTURE)
buf << " v_geom_vertexNdx = a_vertexNdx;\n";
buf << "}\n";
return specializeShader(buf.str(), contextType);
}
class InvocationCountShader : public sglr::ShaderProgram
{
public:
enum OutputCase
{
CASE_FIXED_OUTPUT_COUNTS = 0,
CASE_DIFFERENT_OUTPUT_COUNTS,
CASE_LAST
};
InvocationCountShader (const glu::ContextType& contextType, int numInvocations, OutputCase testCase);
private:
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
static std::string genGeometrySource (const glu::ContextType& contextType, int numInvocations, OutputCase testCase);
static size_t getNumVertices (int numInvocations, OutputCase testCase);
const int m_numInvocations;
const OutputCase m_testCase;
};
InvocationCountShader::InvocationCountShader (const glu::ContextType& contextType, int numInvocations, OutputCase testCase)
: sglr::ShaderProgram (sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(specializeShader(s_commonShaderSourceVertex, contextType))
<< sglr::pdec::FragmentSource(specializeShader(s_commonShaderSourceFragment, contextType))
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
getNumVertices(numInvocations, testCase),
numInvocations)
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, numInvocations, testCase)))
, m_numInvocations (numInvocations)
, m_testCase (testCase)
{
}
void InvocationCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void InvocationCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
}
void InvocationCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(verticesIn);
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
const float l_angle = float(invocationID) / float(m_numInvocations) * 5.5f;
const float l_radius = 0.6f;
const rr::VertexPacket* vertex = packets[packetNdx].vertices[0];
if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
{
const tcu::Vec4 position0 = vertex->position + tcu::Vec4(deFloatCos(l_angle) * (l_radius - 0.1f), deFloatSin(l_angle) * (l_radius - 0.1f), 0.0f, 0.0f);
const tcu::Vec4 position1 = vertex->position + tcu::Vec4(deFloatCos(l_angle+0.1f) * l_radius, deFloatSin(l_angle+0.1f) * l_radius, 0.0f, 0.0f);
const tcu::Vec4 position2 = vertex->position + tcu::Vec4(deFloatCos(l_angle-0.1f) * l_radius, deFloatSin(l_angle-0.1f) * l_radius, 0.0f, 0.0f);
rr::GenericVec4 tipColor;
rr::GenericVec4 baseColor;
tipColor = tcu::Vec4(1.0, 1.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
baseColor = tcu::Vec4(1.0, 0.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
output.EmitVertex(position0, 0.0f, &tipColor, packets[packetNdx].primitiveIDIn);
output.EmitVertex(position1, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
output.EmitVertex(position2, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
output.EndPrimitive();
}
else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
{
const tcu::Vec4 color = tcu::Vec4(float(invocationID % 2), (((invocationID / 2) % 2) == 0) ? (1.0f) : (0.0f), 1.0f, 1.0f);
const tcu::Vec4 basePosition = vertex->position + tcu::Vec4(deFloatCos(l_angle) * l_radius, deFloatSin(l_angle) * l_radius, 0.0f, 0.0f);
const int numNgonVtx = invocationID + 3;
rr::GenericVec4 outColor;
outColor = color;
for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)
{
const float subAngle = (float(ndx) + 1.0f) / float(numNgonVtx) * 3.141f;
output.EmitVertex(basePosition + tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) * 0.1f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
output.EmitVertex(basePosition + tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) * -0.1f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
}
if ((numNgonVtx % 2) == 1)
output.EmitVertex(basePosition + tcu::Vec4(-0.1f, 0.0f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
output.EndPrimitive();
}
}
}
std::string InvocationCountShader::genGeometrySource (const glu::ContextType& contextType, int numInvocations, OutputCase testCase)
{
const int maxVertices = (int)getNumVertices(numInvocations, testCase);
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"${GLSL_EXT_GEOMETRY_SHADER}"
"layout(points, invocations = " << numInvocations << ") in;\n"
"layout(triangle_strip, max_vertices = " << maxVertices << ") out;\n"
"\n"
"in highp vec4 v_geom_FragColor[];\n"
"out highp vec4 v_frag_FragColor;\n"
"\n"
"void main ()\n"
"{\n"
" highp float l_angle = float(gl_InvocationID) / float(" << numInvocations << ") * 5.5;\n"
" highp float l_radius = 0.6;\n"
"\n";
if (testCase == CASE_FIXED_OUTPUT_COUNTS)
{
buf << " v_frag_FragColor = vec4(1.0, 1.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
" gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle) * (l_radius - 0.1), sin(l_angle) * (l_radius - 0.1), 0.0, 0.0);\n"
" EmitVertex();\n"
"\n"
" v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
" gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle+0.1) * l_radius, sin(l_angle+0.1) * l_radius, 0.0, 0.0);\n"
" EmitVertex();\n"
"\n"
" v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
" gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle-0.1) * l_radius, sin(l_angle-0.1) * l_radius, 0.0, 0.0);\n"
" EmitVertex();\n";
}
else if (testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
{
buf << " highp vec4 l_color = vec4(float(gl_InvocationID % 2), (((gl_InvocationID / 2) % 2) == 0) ? (1.0) : (0.0), 1.0, 1.0);\n"
" highp vec4 basePosition = gl_in[0].gl_Position + vec4(cos(l_angle) * l_radius, sin(l_angle) * l_radius, 0.0, 0.0);\n"
" mediump int numNgonVtx = gl_InvocationID + 3;\n"
"\n"
" for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)\n"
" {\n"
" highp float sub_angle = (float(ndx) + 1.0) / float(numNgonVtx) * 3.141;\n"
"\n"
" v_frag_FragColor = l_color;\n"
" gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * 0.1, 0.0, 0.0);\n"
" EmitVertex();\n"
"\n"
" v_frag_FragColor = l_color;\n"
" gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * -0.1, 0.0, 0.0);\n"
" EmitVertex();\n"
" }\n"
" if ((numNgonVtx % 2) == 1)\n"
" {\n"
" v_frag_FragColor = l_color;\n"
" gl_Position = basePosition + vec4(-0.1, 0.0, 0.0, 0.0);\n"
" EmitVertex();\n"
" }\n";
}
else
DE_ASSERT(false);
buf << "}\n";
return specializeShader(buf.str(), contextType);
}
size_t InvocationCountShader::getNumVertices (int numInvocations, OutputCase testCase)
{
switch (testCase)
{
case CASE_FIXED_OUTPUT_COUNTS: return 3;
case CASE_DIFFERENT_OUTPUT_COUNTS: return (size_t)(2 + numInvocations);
default:
DE_ASSERT(false);
return 0;
}
}
class InstancedExpansionShader : public sglr::ShaderProgram
{
public:
InstancedExpansionShader (const glu::ContextType& contextType, int numInvocations);
private:
void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
void shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
static std::string genVertexSource (const glu::ContextType& contextType);
static std::string genFragmentSource (const glu::ContextType& contextType);
static std::string genGeometrySource (const glu::ContextType& contextType, int numInvocations);
const int m_numInvocations;
};
InstancedExpansionShader::InstancedExpansionShader (const glu::ContextType& contextType, int numInvocations)
: sglr::ShaderProgram (sglr::pdec::ShaderProgramDeclaration()
<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
<< sglr::pdec::VertexSource(genVertexSource(contextType))
<< sglr::pdec::FragmentSource(genFragmentSource(contextType))
<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
4,
numInvocations)
<< sglr::pdec::GeometrySource(genGeometrySource(contextType, numInvocations)))
, m_numInvocations (numInvocations)
{
}
void InstancedExpansionShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
{
for (int ndx = 0; ndx < numPackets; ++ndx)
{
packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) +
rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
}
}
void InstancedExpansionShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
{
DE_UNREF(packets);
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
}
void InstancedExpansionShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
{
DE_UNREF(verticesIn);
for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
{
const rr::VertexPacket* vertex = packets[packetNdx].vertices[0];
const tcu::Vec4 basePosition = vertex->position;
const float phase = float(invocationID) / float(m_numInvocations) * 6.3f;
const tcu::Vec4 centerPosition = basePosition + tcu::Vec4(deFloatCos(phase), deFloatSin(phase), 0.0f, 0.0f) * 0.1f;
output.EmitVertex(centerPosition + tcu::Vec4( 0.0f, -0.1f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
output.EmitVertex(centerPosition + tcu::Vec4(-0.05f, 0.0f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
output.EmitVertex(centerPosition + tcu::Vec4( 0.05f, 0.0f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
output.EndPrimitive();
}
}
std::string InstancedExpansionShader::genVertexSource (const glu::ContextType& contextType)
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"in highp vec4 a_position;\n"
"in highp vec4 a_offset;\n"
"void main (void)\n"
"{\n"
" gl_Position = a_position + a_offset;\n"
"}\n";
return specializeShader(buf.str(), contextType);
}
std::string InstancedExpansionShader::genFragmentSource (const glu::ContextType& contextType)
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main (void)\n"
"{\n"
" fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
"}\n";
return specializeShader(buf.str(), contextType);
}
std::string InstancedExpansionShader::genGeometrySource (const glu::ContextType& contextType, int numInvocations)
{
std::ostringstream buf;
buf << "${GLSL_VERSION_DECL}\n"
"${GLSL_EXT_GEOMETRY_SHADER}"
"layout(points,invocations=" << numInvocations << ") in;\n"
"layout(triangle_strip, max_vertices = 3) out;\n"
"\n"
"void main (void)\n"
"{\n"
" highp vec4 basePosition = gl_in[0].gl_Position;\n"
" highp float phase = float(gl_InvocationID) / float(" << numInvocations << ") * 6.3;\n"
" highp vec4 centerPosition = basePosition + 0.1 * vec4(cos(phase), sin(phase), 0.0, 0.0);\n"
"\n"
" gl_Position = centerPosition + vec4( 0.00, -0.1, 0.0, 0.0);\n"
" EmitVertex();\n"
" gl_Position = centerPosition + vec4(-0.05, 0.0, 0.0, 0.0);\n"
" EmitVertex();\n"
" gl_Position = centerPosition + vec4( 0.05, 0.0, 0.0, 0.0);\n"
" EmitVertex();\n"
"}\n";
return specializeShader(buf.str(), contextType);
}
class GeometryShaderRenderTest : public TestCase
{
public:
enum Flag
{
FLAG_DRAW_INSTANCED = 1,
FLAG_USE_INDICES = 2,
FLAG_USE_RESTART_INDEX = 4,
};
GeometryShaderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives, const char* dataAttributeName, int flags = 0);
virtual ~GeometryShaderRenderTest (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
bool compare (void);
virtual sglr::ShaderProgram& getProgram (void) = 0;
protected:
virtual void genVertexAttribData (void);
void renderWithContext (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dstSurface);
virtual void preRender (sglr::Context& ctx, GLuint programID);
virtual void postRender (sglr::Context& ctx, GLuint programID);
int m_numDrawVertices;
int m_numDrawInstances;
int m_vertexAttrDivisor;
const GLenum m_inputPrimitives;
const GLenum m_outputPrimitives;
const char* const m_dataAttributeName;
const int m_flags;
tcu::IVec2 m_viewportSize;
int m_interationCount;
tcu::Surface* m_glResult;
tcu::Surface* m_refResult;
sglr::ReferenceContextBuffers* m_refBuffers;
sglr::ReferenceContext* m_refContext;
sglr::Context* m_glContext;
std::vector<tcu::Vec4> m_vertexPosData;
std::vector<tcu::Vec4> m_vertexAttrData;
std::vector<deUint16> m_indices;
};
GeometryShaderRenderTest::GeometryShaderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives, const char* dataAttributeName, int flags)
: TestCase (context, name, desc)
, m_numDrawVertices (0)
, m_numDrawInstances (0)
, m_vertexAttrDivisor (0)
, m_inputPrimitives (inputPrimitives)
, m_outputPrimitives (outputPrimitives)
, m_dataAttributeName (dataAttributeName)
, m_flags (flags)
, m_viewportSize (TEST_CANVAS_SIZE, TEST_CANVAS_SIZE)
, m_interationCount (0)
, m_glResult (DE_NULL)
, m_refResult (DE_NULL)
, m_refBuffers (DE_NULL)
, m_refContext (DE_NULL)
, m_glContext (DE_NULL)
{
// Disallow instanced drawElements
DE_ASSERT(((m_flags & FLAG_DRAW_INSTANCED) == 0) || ((m_flags & FLAG_USE_INDICES) == 0));
// Disallow restart without indices
DE_ASSERT(!(((m_flags & FLAG_USE_RESTART_INDEX) != 0) && ((m_flags & FLAG_USE_INDICES) == 0)));
}
GeometryShaderRenderTest::~GeometryShaderRenderTest (void)
{
deinit();
}
void GeometryShaderRenderTest::init (void)
{
// requirements
if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
// gen resources
{
sglr::ReferenceContextLimits limits;
m_glResult = new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
m_refResult = new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
m_refBuffers = new sglr::ReferenceContextBuffers(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, m_viewportSize.x(), m_viewportSize.y());
m_refContext = new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
m_glContext = new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, m_viewportSize.x(), m_viewportSize.y()));
}
}
void GeometryShaderRenderTest::deinit (void)
{
delete m_glResult;
delete m_refResult;
m_glResult = DE_NULL;
m_refResult = DE_NULL;
delete m_refContext;
delete m_glContext;
delete m_refBuffers;
m_refBuffers = DE_NULL;
m_refContext = DE_NULL;
m_glContext = DE_NULL;
}
tcu::TestCase::IterateResult GeometryShaderRenderTest::iterate (void)
{
// init() must be called
DE_ASSERT(m_glContext);
DE_ASSERT(m_refContext);
const int iteration = m_interationCount++;
if (iteration == 0)
{
// Check requirements
const int width = m_context.getRenderTarget().getWidth();
const int height = m_context.getRenderTarget().getHeight();
if (width < m_viewportSize.x() || height < m_viewportSize.y())
throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_viewportSize.x()) + "x" + de::toString(m_viewportSize.y()));
// Gen data
genVertexAttribData();
return CONTINUE;
}
else if (iteration == 1)
{
// Render
sglr::ShaderProgram& program = getProgram();
renderWithContext(*m_glContext, program, *m_glResult);
renderWithContext(*m_refContext, program, *m_refResult);
return CONTINUE;
}
else
{
if (compare())
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
return STOP;
}
}
bool GeometryShaderRenderTest::compare (void)
{
using tcu::TestLog;
if (m_context.getRenderTarget().getNumSamples() > 1)
{
return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", m_refResult->getAccess(), m_glResult->getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
}
else
{
tcu::Surface errorMask (m_viewportSize.x(), m_viewportSize.y());
const tcu::RGBA green (0, 255, 0, 255);
const tcu::RGBA red (255, 0, 0, 255);
const int colorComponentThreshold = 20;
bool testResult = true;
for (int x = 0; x < m_viewportSize.x(); ++x)
for (int y = 0; y < m_viewportSize.y(); ++y)
{
if (x == 0 || y == 0 || x + 1 == m_viewportSize.x() || y + 1 == m_viewportSize.y())
{
// Mark edge pixels as correct since their neighbourhood is undefined
errorMask.setPixel(x, y, green);
}
else
{
const tcu::RGBA refcolor = m_refResult->getPixel(x, y);
bool found = false;
// Got to find similar pixel near this pixel (3x3 kernel)
for (int dx = -1; dx <= 1; ++dx)
for (int dy = -1; dy <= 1; ++dy)
{
const tcu::RGBA testColor = m_glResult->getPixel(x + dx, y + dy);
const tcu::IVec4 colDiff = tcu::abs(testColor.toIVec() - refcolor.toIVec());
const int maxColDiff = de::max(de::max(colDiff.x(), colDiff.y()), colDiff.z()); // check RGB channels
if (maxColDiff <= colorComponentThreshold)
found = true;
}
if (!found)
testResult = false;
errorMask.setPixel(x, y, (found) ? (green) : (red));
}
}
if (testResult)
{
m_testCtx.getLog() << TestLog::ImageSet("Compare result", "Result of rendering")
<< TestLog::Image("Result", "Result", *m_glResult)
<< TestLog::EndImageSet;
m_testCtx.getLog() << TestLog::Message << "Image compare ok." << TestLog::EndMessage;
}
else
{
m_testCtx.getLog() << TestLog::ImageSet("Compare result", "Result of rendering")
<< TestLog::Image("Result", "Result", *m_glResult)
<< TestLog::Image("Reference", "Reference", *m_refResult)
<< TestLog::Image("ErrorMask", "Error mask", errorMask)
<< TestLog::EndImageSet;
m_testCtx.getLog() << TestLog::Message << "Image compare failed." << TestLog::EndMessage;
}
return testResult;
}
}
void GeometryShaderRenderTest::genVertexAttribData (void)
{
// Create 1 X 2 grid in triangle strip adjacent - order
const float scale = 0.3f;
const tcu::Vec4 offset(-0.5f, -0.2f, 0.0f, 1.0f);
m_vertexPosData.resize(12);
m_vertexPosData[ 0] = tcu::Vec4( 0, 0, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 1] = tcu::Vec4(-1, -1, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 2] = tcu::Vec4( 0, -1, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 3] = tcu::Vec4( 1, 1, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 4] = tcu::Vec4( 1, 0, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 5] = tcu::Vec4( 0, -2, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 6] = tcu::Vec4( 1, -1, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 7] = tcu::Vec4( 2, 1, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 8] = tcu::Vec4( 2, 0, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[ 9] = tcu::Vec4( 1, -2, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[10] = tcu::Vec4( 2, -1, 0.0f, 0.0f) * scale + offset;
m_vertexPosData[11] = tcu::Vec4( 3, 0, 0.0f, 0.0f) * scale + offset;
// Red and white
m_vertexAttrData.resize(12);
for (int i = 0; i < 12; ++i)
m_vertexAttrData[i] = (i % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
m_numDrawVertices = 12;
}
void GeometryShaderRenderTest::renderWithContext (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dstSurface)
{
#define CHECK_GL_CTX_ERRORS() glu::checkError(ctx.getError(), DE_NULL, __FILE__, __LINE__)
const GLuint programId = ctx.createProgram(&program);
const GLint attrPosLoc = ctx.getAttribLocation(programId, "a_position");
const GLint attrColLoc = ctx.getAttribLocation(programId, m_dataAttributeName);
GLuint vaoId = 0;
GLuint vertexPosBuf = 0;
GLuint vertexAttrBuf = 0;
GLuint elementArrayBuf = 0;
ctx.genVertexArrays(1, &vaoId);
ctx.bindVertexArray(vaoId);
if (attrPosLoc != -1)
{
ctx.genBuffers(1, &vertexPosBuf);
ctx.bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
ctx.bufferData(GL_ARRAY_BUFFER, m_vertexPosData.size() * sizeof(tcu::Vec4), &m_vertexPosData[0], GL_STATIC_DRAW);
ctx.vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
ctx.enableVertexAttribArray(attrPosLoc);
}
if (attrColLoc != -1)
{
ctx.genBuffers(1, &vertexAttrBuf);
ctx.bindBuffer(GL_ARRAY_BUFFER, vertexAttrBuf);
ctx.bufferData(GL_ARRAY_BUFFER, m_vertexAttrData.size() * sizeof(tcu::Vec4), &m_vertexAttrData[0], GL_STATIC_DRAW);
ctx.vertexAttribPointer(attrColLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
ctx.enableVertexAttribArray(attrColLoc);
if (m_vertexAttrDivisor)
ctx.vertexAttribDivisor(attrColLoc, m_vertexAttrDivisor);
}
if (m_flags & FLAG_USE_INDICES)
{
ctx.genBuffers(1, &elementArrayBuf);
ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBuf);
ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(deUint16), &m_indices[0], GL_STATIC_DRAW);
}
ctx.clearColor(0, 0, 0, 1);
ctx.clear(GL_COLOR_BUFFER_BIT);
ctx.viewport(0, 0, m_viewportSize.x(), m_viewportSize.y());
CHECK_GL_CTX_ERRORS();
ctx.useProgram(programId);
CHECK_GL_CTX_ERRORS();
preRender(ctx, programId);
CHECK_GL_CTX_ERRORS();
if (m_flags & FLAG_USE_RESTART_INDEX)
{
ctx.enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
CHECK_GL_CTX_ERRORS();
}
if (m_flags & FLAG_USE_INDICES)
ctx.drawElements(m_inputPrimitives, m_numDrawVertices, GL_UNSIGNED_SHORT, DE_NULL);
else if (m_flags & FLAG_DRAW_INSTANCED)
ctx.drawArraysInstanced(m_inputPrimitives, 0, m_numDrawVertices, m_numDrawInstances);
else
ctx.drawArrays(m_inputPrimitives, 0, m_numDrawVertices);
CHECK_GL_CTX_ERRORS();
if (m_flags & FLAG_USE_RESTART_INDEX)
{
ctx.disable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
CHECK_GL_CTX_ERRORS();
}
postRender(ctx, programId);
CHECK_GL_CTX_ERRORS();
ctx.useProgram(0);
if (attrPosLoc != -1)
ctx.disableVertexAttribArray(attrPosLoc);
if (attrColLoc != -1)
ctx.disableVertexAttribArray(attrColLoc);
if (vertexPosBuf)
ctx.deleteBuffers(1, &vertexPosBuf);
if (vertexAttrBuf)
ctx.deleteBuffers(1, &vertexAttrBuf);
if (elementArrayBuf)
ctx.deleteBuffers(1, &elementArrayBuf);
ctx.deleteVertexArrays(1, &vaoId);
CHECK_GL_CTX_ERRORS();
ctx.finish();
ctx.readPixels(dstSurface, 0, 0, m_viewportSize.x(), m_viewportSize.y());
#undef CHECK_GL_CTX_ERRORS
}
void GeometryShaderRenderTest::preRender (sglr::Context& ctx, GLuint programID)
{
DE_UNREF(ctx);
DE_UNREF(programID);
}
void GeometryShaderRenderTest::postRender (sglr::Context& ctx, GLuint programID)
{
DE_UNREF(ctx);
DE_UNREF(programID);
}
class GeometryExpanderRenderTest : public GeometryShaderRenderTest
{
public:
GeometryExpanderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives);
virtual ~GeometryExpanderRenderTest (void);
sglr::ShaderProgram& getProgram (void);
private:
void init (void);
void deinit (void);
VertexExpanderShader* m_program;
};
GeometryExpanderRenderTest::GeometryExpanderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives)
: GeometryShaderRenderTest (context, name, desc, inputPrimitives, outputPrimitives, "a_color")
, m_program (DE_NULL)
{
}
GeometryExpanderRenderTest::~GeometryExpanderRenderTest (void)
{
}
void GeometryExpanderRenderTest::init (void)
{
m_program = new VertexExpanderShader(m_context.getRenderContext().getType(), sglr::rr_util::mapGLGeometryShaderInputType(m_inputPrimitives), sglr::rr_util::mapGLGeometryShaderOutputType(m_outputPrimitives));
GeometryShaderRenderTest::init();
}
void GeometryExpanderRenderTest::deinit (void)
{
if (m_program)
{
delete m_program;
m_program = DE_NULL;
}
GeometryShaderRenderTest::deinit();
}
sglr::ShaderProgram& GeometryExpanderRenderTest::getProgram (void)
{
return *m_program;
}
class EmitTest : public GeometryShaderRenderTest
{
public:
EmitTest (Context& context, const char* name, const char* desc, int emitCountA, int endCountA, int emitCountB, int endCountB, GLenum outputType);
sglr::ShaderProgram& getProgram (void);
private:
void init (void);
void deinit (void);
void genVertexAttribData (void);
VertexEmitterShader* m_program;
int m_emitCountA;
int m_endCountA;
int m_emitCountB;
int m_endCountB;
GLenum m_outputType;
};
EmitTest::EmitTest (Context& context, const char* name, const char* desc, int emitCountA, int endCountA, int emitCountB, int endCountB, GLenum outputType)
: GeometryShaderRenderTest (context, name, desc, GL_POINTS, outputType, "a_color")
, m_program (DE_NULL)
, m_emitCountA (emitCountA)
, m_endCountA (endCountA)
, m_emitCountB (emitCountB)
, m_endCountB (endCountB)
, m_outputType (outputType)
{
}
void EmitTest::init(void)
{
m_program = new VertexEmitterShader(m_context.getRenderContext().getType(), m_emitCountA, m_endCountA, m_emitCountB, m_endCountB, sglr::rr_util::mapGLGeometryShaderOutputType(m_outputType));
GeometryShaderRenderTest::init();
}
void EmitTest::deinit (void)
{
if (m_program)
{
delete m_program;
m_program = DE_NULL;
}
GeometryShaderRenderTest::deinit();
}
sglr::ShaderProgram& EmitTest::getProgram (void)
{
return *m_program;
}
void EmitTest::genVertexAttribData (void)
{
m_vertexPosData.resize(1);
m_vertexPosData[0] = tcu::Vec4(0, 0, 0, 1);
m_vertexAttrData.resize(1);
m_vertexAttrData[0] = tcu::Vec4(1, 1, 1, 1);
m_numDrawVertices = 1;
}
class VaryingTest : public GeometryShaderRenderTest
{
public:
VaryingTest (Context& context, const char* name, const char* desc, int vertexOut, int geometryOut);
sglr::ShaderProgram& getProgram (void);
private:
void init (void);
void deinit (void);
void genVertexAttribData (void);
VertexVaryingShader* m_program;
int m_vertexOut;
int m_geometryOut;
};
VaryingTest::VaryingTest (Context& context, const char* name, const char* desc, int vertexOut, int geometryOut)
: GeometryShaderRenderTest (context, name, desc, GL_TRIANGLES, GL_TRIANGLE_STRIP, "a_color")
, m_program (DE_NULL)
, m_vertexOut (vertexOut)
, m_geometryOut (geometryOut)
{
}
void VaryingTest::init (void)
{
m_program = new VertexVaryingShader(m_context.getRenderContext().getType(), m_vertexOut, m_geometryOut);
GeometryShaderRenderTest::init();
}
void VaryingTest::deinit (void)
{
if (m_program)
{
delete m_program;
m_program = DE_NULL;
}
GeometryShaderRenderTest::deinit();
}
sglr::ShaderProgram& VaryingTest::getProgram (void)
{
return *m_program;
}
void VaryingTest::genVertexAttribData (void)
{
m_vertexPosData.resize(3);
m_vertexPosData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
m_vertexPosData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
m_vertexPosData[2] = tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f);
m_vertexAttrData.resize(3);
m_vertexAttrData[0] = tcu::Vec4(0.7f, 0.4f, 0.6f, 1.0f);
m_vertexAttrData[1] = tcu::Vec4(0.9f, 0.2f, 0.5f, 1.0f);
m_vertexAttrData[2] = tcu::Vec4(0.1f, 0.8f, 0.3f, 1.0f);
m_numDrawVertices = 3;
}
class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
{
public:
TriangleStripAdjacencyVertexCountTest (Context& context, const char* name, const char* desc, int numInputVertices);
private:
void genVertexAttribData (void);
int m_numInputVertices;
};
TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest (Context& context, const char* name, const char* desc, int numInputVertices)
: GeometryExpanderRenderTest (context, name, desc, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLE_STRIP)
, m_numInputVertices (numInputVertices)
{
}
void TriangleStripAdjacencyVertexCountTest::genVertexAttribData (void)
{
this->GeometryShaderRenderTest::genVertexAttribData();
m_numDrawVertices = m_numInputVertices;
}
class NegativeDrawCase : public TestCase
{
public:
NegativeDrawCase (Context& context, const char* name, const char* desc, GLenum inputType, GLenum inputPrimitives);
~NegativeDrawCase (void);
void init (void);
void deinit (void);
IterateResult iterate (void);
private:
sglr::Context* m_ctx;
VertexExpanderShader* m_program;
GLenum m_inputType;
GLenum m_inputPrimitives;
};
NegativeDrawCase::NegativeDrawCase (Context& context, const char* name, const char* desc, GLenum inputType, GLenum inputPrimitives)
: TestCase (context, name, desc)
, m_ctx (DE_NULL)
, m_program (DE_NULL)
, m_inputType (inputType)
, m_inputPrimitives (inputPrimitives)
{
}
NegativeDrawCase::~NegativeDrawCase (void)
{
deinit();
}
void NegativeDrawCase::init (void)
{
if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
m_ctx = new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, 1, 1));
m_program = new VertexExpanderShader(m_context.getRenderContext().getType() , sglr::rr_util::mapGLGeometryShaderInputType(m_inputType), rr::GEOMETRYSHADEROUTPUTTYPE_POINTS);
}
void NegativeDrawCase::deinit (void)
{
delete m_ctx;
delete m_program;
m_ctx = NULL;
m_program = DE_NULL;
}
NegativeDrawCase::IterateResult NegativeDrawCase::iterate (void)
{
const GLuint programId = m_ctx->createProgram(m_program);
const GLint attrPosLoc = m_ctx->getAttribLocation(programId, "a_position");
const tcu::Vec4 vertexPosData (0, 0, 0, 1);
GLuint vaoId = 0;
GLuint vertexPosBuf = 0;
GLenum errorCode = 0;
m_ctx->genVertexArrays(1, &vaoId);
m_ctx->bindVertexArray(vaoId);
m_ctx->genBuffers(1, &vertexPosBuf);
m_ctx->bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
m_ctx->bufferData(GL_ARRAY_BUFFER, sizeof(tcu::Vec4), vertexPosData.m_data, GL_STATIC_DRAW);
m_ctx->vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
m_ctx->enableVertexAttribArray(attrPosLoc);
m_ctx->clearColor(0, 0, 0, 1);
m_ctx->clear(GL_COLOR_BUFFER_BIT);
m_ctx->viewport(0, 0, 1, 1);
m_ctx->useProgram(programId);
// no errors before
glu::checkError(m_ctx->getError(), "", __FILE__, __LINE__);
m_ctx->drawArrays(m_inputPrimitives, 0, 1);
errorCode = m_ctx->getError();
if (errorCode != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
m_ctx->useProgram(0);
m_ctx->disableVertexAttribArray(attrPosLoc);
m_ctx->deleteBuffers(1, &vertexPosBuf);
m_ctx->deleteVertexArrays(1, &vaoId);
return STOP;
}
class OutputCountCase : public GeometryShaderRenderTest
{
public:
OutputCountCase (Context& context, const char* name, const char* desc, const OutputCountPatternSpec&);
private:
void init (void);
void deinit (void);
sglr::ShaderProgram& getProgram (void);
void genVertexAttribData (void);
const int m_primitiveCount;
OutputCountShader* m_program;
OutputCountPatternSpec m_spec;
};
OutputCountCase::OutputCountCase (Context& context, const char* name, const char* desc, const OutputCountPatternSpec& spec)
: GeometryShaderRenderTest (context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
, m_primitiveCount ((int)spec.pattern.size())
, m_program (DE_NULL)
, m_spec (spec)
{
}
void OutputCountCase::init (void)
{
// Check requirements and adapt to them
{
const int componentsPerVertex = 4 + 4; // vec4 pos, vec4 color
const int testVertices = *std::max_element(m_spec.pattern.begin(), m_spec.pattern.end());
glw::GLint maxVertices = 0;
glw::GLint maxComponents = 0;
// check the extension before querying anything
if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
TCU_THROW(NotSupportedError, "Tests require GL_EXT_geometry_shader extension or higher context version.");
m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex << tcu::TestLog::EndMessage;
if (testVertices == -1)
{
// "max vertices"-case
DE_ASSERT((int)m_spec.pattern.size() == 1);
m_spec.pattern[0] = de::min(maxVertices, maxComponents / componentsPerVertex);
// make sure size is dividable by 2, as OutputShader requires
m_spec.pattern[0] = m_spec.pattern[0] & ~0x00000001;
if (m_spec.pattern[0] == 0)
throw tcu::InternalError("Pattern size is invalid.");
}
else
{
// normal case
if (testVertices > maxVertices)
throw tcu::NotSupportedError(de::toString(testVertices) + " output vertices required.");
if (testVertices * componentsPerVertex > maxComponents)
throw tcu::NotSupportedError(de::toString(testVertices * componentsPerVertex) + " output components required.");
}
}
// Log what the test tries to do
m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)m_spec.pattern.size() << " row(s).\nOne geometry shader invocation generates one row.\nRow sizes:" << tcu::TestLog::EndMessage;
for (int ndx = 0; ndx < (int)m_spec.pattern.size(); ++ndx)
m_testCtx.getLog() << tcu::TestLog::Message << "Row " << ndx << ": " << m_spec.pattern[ndx] << " vertices." << tcu::TestLog::EndMessage;
// Gen shader
DE_ASSERT(!m_program);
m_program = new OutputCountShader(m_context.getRenderContext().getType(), m_spec);
// Case init
GeometryShaderRenderTest::init();
}
void OutputCountCase::deinit (void)
{
if (m_program)
{
delete m_program;
m_program = DE_NULL;
}
GeometryShaderRenderTest::deinit();
}
sglr::ShaderProgram& OutputCountCase::getProgram (void)
{
return *m_program;
}
void OutputCountCase::genVertexAttribData (void)
{
m_vertexPosData.resize(m_primitiveCount);
m_vertexAttrData.resize(m_primitiveCount);
for (int ndx = 0; ndx < m_primitiveCount; ++ndx)
{
m_vertexPosData[ndx] = tcu::Vec4(-1.0f, ((float)ndx) / (float)m_primitiveCount * 2.0f - 1.0f, 0.0f, 1.0f);
m_vertexAttrData[ndx] = (ndx % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
}
m_numDrawVertices = m_primitiveCount;
}
class BuiltinVariableRenderTest : public GeometryShaderRenderTest
{
public:
BuiltinVariableRenderTest (Context& context, const char* name, const char* desc, BuiltinVariableShader::VariableTest test, int flags = 0);
private:
void init (void);
void deinit (void);