You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
635 lines
22 KiB
635 lines
22 KiB
/*-------------------------------------------------------------------------
|
|
* 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 Tessellation and geometry shader interaction stress tests.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es31sTessellationGeometryInteractionTests.hpp"
|
|
|
|
#include "tcuTestLog.hpp"
|
|
#include "tcuRenderTarget.hpp"
|
|
#include "tcuSurface.hpp"
|
|
#include "tcuTextureUtil.hpp"
|
|
#include "gluRenderContext.hpp"
|
|
#include "gluShaderProgram.hpp"
|
|
#include "gluContextInfo.hpp"
|
|
#include "gluObjectWrapper.hpp"
|
|
#include "gluPixelTransfer.hpp"
|
|
#include "glwFunctions.hpp"
|
|
#include "glwEnums.hpp"
|
|
#include "deStringUtil.hpp"
|
|
#include "deUniquePtr.hpp"
|
|
|
|
#include <sstream>
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles31
|
|
{
|
|
namespace Stress
|
|
{
|
|
namespace
|
|
{
|
|
|
|
class AllowedRenderFailureException : public std::runtime_error
|
|
{
|
|
public:
|
|
AllowedRenderFailureException (const char* message) : std::runtime_error(message) { }
|
|
};
|
|
|
|
class GridRenderCase : public TestCase
|
|
{
|
|
public:
|
|
enum Flags
|
|
{
|
|
FLAG_TESSELLATION_MAX_SPEC = 0x0001,
|
|
FLAG_TESSELLATION_MAX_IMPLEMENTATION = 0x0002,
|
|
FLAG_GEOMETRY_MAX_SPEC = 0x0004,
|
|
FLAG_GEOMETRY_MAX_IMPLEMENTATION = 0x0008,
|
|
FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC = 0x0010,
|
|
FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION = 0x0020,
|
|
};
|
|
|
|
GridRenderCase (Context& context, const char* name, const char* description, int flags);
|
|
~GridRenderCase (void);
|
|
|
|
private:
|
|
void init (void);
|
|
void deinit (void);
|
|
IterateResult iterate (void);
|
|
|
|
void renderTo (std::vector<tcu::Surface>& dst);
|
|
bool verifyResultLayer (int layerNdx, const tcu::Surface& dst);
|
|
|
|
const char* getVertexSource (void);
|
|
const char* getFragmentSource (void);
|
|
std::string getTessellationControlSource (int tessLevel);
|
|
std::string getTessellationEvaluationSource (int tessLevel);
|
|
std::string getGeometryShaderSource (int numPrimitives, int numInstances);
|
|
|
|
enum
|
|
{
|
|
RENDER_SIZE = 256
|
|
};
|
|
|
|
const int m_flags;
|
|
|
|
glu::ShaderProgram* m_program;
|
|
int m_numLayers;
|
|
};
|
|
|
|
GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, int flags)
|
|
: TestCase (context, name, description)
|
|
, m_flags (flags)
|
|
, m_program (DE_NULL)
|
|
, m_numLayers (1)
|
|
{
|
|
DE_ASSERT(((m_flags & FLAG_TESSELLATION_MAX_SPEC) == 0) || ((m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) == 0));
|
|
DE_ASSERT(((m_flags & FLAG_GEOMETRY_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) == 0));
|
|
DE_ASSERT(((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) == 0) || ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) == 0));
|
|
}
|
|
|
|
GridRenderCase::~GridRenderCase (void)
|
|
{
|
|
deinit();
|
|
}
|
|
|
|
void GridRenderCase::init (void)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
|
|
// Requirements
|
|
|
|
if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
|
|
!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
|
|
throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
|
|
|
|
if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
|
|
m_context.getRenderTarget().getHeight() < RENDER_SIZE)
|
|
throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
|
|
|
|
// Log
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Testing tessellation and geometry shaders that output a large number of primitives.\n"
|
|
<< getDescription()
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
// Gen program
|
|
{
|
|
glu::ProgramSources sources;
|
|
int tessGenLevel = -1;
|
|
|
|
sources << glu::VertexSource(getVertexSource())
|
|
<< glu::FragmentSource(getFragmentSource());
|
|
|
|
// Tessellation limits
|
|
{
|
|
if (m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION)
|
|
{
|
|
gl.getIntegerv(GL_MAX_TESS_GEN_LEVEL, &tessGenLevel);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "query tessellation limits");
|
|
}
|
|
else if (m_flags & FLAG_TESSELLATION_MAX_SPEC)
|
|
{
|
|
tessGenLevel = 64;
|
|
}
|
|
else
|
|
{
|
|
tessGenLevel = 5;
|
|
}
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Tessellation level: " << tessGenLevel << ", mode = quad.\n"
|
|
<< "\tEach input patch produces " << (tessGenLevel*tessGenLevel) << " (" << (tessGenLevel*tessGenLevel*2) << " triangles)\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
sources << glu::TessellationControlSource(getTessellationControlSource(tessGenLevel))
|
|
<< glu::TessellationEvaluationSource(getTessellationEvaluationSource(tessGenLevel));
|
|
}
|
|
|
|
// Geometry limits
|
|
{
|
|
int geometryOutputComponents = -1;
|
|
int geometryOutputVertices = -1;
|
|
int geometryTotalOutputComponents = -1;
|
|
int geometryShaderInvocations = -1;
|
|
bool logGeometryLimits = false;
|
|
bool logInvocationLimits = false;
|
|
|
|
if (m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Using implementation maximum geometry shader output limits." << tcu::TestLog::EndMessage;
|
|
|
|
gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &geometryOutputComponents);
|
|
gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &geometryOutputVertices);
|
|
gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &geometryTotalOutputComponents);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry limits");
|
|
|
|
logGeometryLimits = true;
|
|
}
|
|
else if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader extension minimum maximum output limits." << tcu::TestLog::EndMessage;
|
|
|
|
geometryOutputComponents = 128;
|
|
geometryOutputVertices = 256;
|
|
geometryTotalOutputComponents = 1024;
|
|
logGeometryLimits = true;
|
|
}
|
|
else
|
|
{
|
|
geometryOutputComponents = 128;
|
|
geometryOutputVertices = 16;
|
|
geometryTotalOutputComponents = 1024;
|
|
}
|
|
|
|
if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION)
|
|
{
|
|
gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &geometryShaderInvocations);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry invocation limits");
|
|
|
|
logInvocationLimits = true;
|
|
}
|
|
else if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
|
|
{
|
|
geometryShaderInvocations = 32;
|
|
logInvocationLimits = true;
|
|
}
|
|
else
|
|
{
|
|
geometryShaderInvocations = 4;
|
|
}
|
|
|
|
if (logGeometryLimits || logInvocationLimits)
|
|
{
|
|
tcu::MessageBuilder msg(&m_testCtx.getLog());
|
|
|
|
msg << "Geometry shader, targeting following limits:\n";
|
|
|
|
if (logGeometryLimits)
|
|
msg << "\tGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = " << geometryOutputComponents << "\n"
|
|
<< "\tGL_MAX_GEOMETRY_OUTPUT_VERTICES = " << geometryOutputVertices << "\n"
|
|
<< "\tGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << geometryTotalOutputComponents << "\n";
|
|
|
|
if (logInvocationLimits)
|
|
msg << "\tGL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << geometryShaderInvocations;
|
|
|
|
msg << tcu::TestLog::EndMessage;
|
|
}
|
|
|
|
|
|
{
|
|
const int numComponentsPerVertex = 8; // vec4 pos, vec4 color
|
|
|
|
// If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
|
|
// Each slice is a triangle strip and is generated by a single shader invocation.
|
|
// One slice with 4 segment ends (nodes) and 3 segments:
|
|
// .__.__.__.
|
|
// |\ |\ |\ |
|
|
// |_\|_\|_\|
|
|
|
|
const int numSliceNodesComponentLimit = geometryTotalOutputComponents / (2 * numComponentsPerVertex); // each node 2 vertices
|
|
const int numSliceNodesOutputLimit = geometryOutputVertices / 2; // each node 2 vertices
|
|
const int numSliceNodes = de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
|
|
|
|
const int numVerticesPerInvocation = numSliceNodes * 2;
|
|
const int numPrimitivesPerInvocation = (numSliceNodes - 1) * 2;
|
|
|
|
const int geometryVerticesPerPrimitive = numVerticesPerInvocation * geometryShaderInvocations;
|
|
const int geometryPrimitivesOutPerPrimitive = numPrimitivesPerInvocation * geometryShaderInvocations;
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Geometry shader:\n"
|
|
<< "\tTotal output vertex count per invocation: " << (numVerticesPerInvocation) << "\n"
|
|
<< "\tTotal output primitive count per invocation: " << (numPrimitivesPerInvocation) << "\n"
|
|
<< "\tNumber of invocations per primitive: " << geometryShaderInvocations << "\n"
|
|
<< "\tTotal output vertex count per input primitive: " << (geometryVerticesPerPrimitive) << "\n"
|
|
<< "\tTotal output primitive count per input primitive: " << (geometryPrimitivesOutPerPrimitive) << "\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
sources << glu::GeometrySource(getGeometryShaderSource(numPrimitivesPerInvocation, geometryShaderInvocations));
|
|
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Program:\n"
|
|
<< "\tTotal program output vertices count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
|
|
<< "\tTotal program output primitive count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
|
|
m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
|
|
m_testCtx.getLog() << *m_program;
|
|
if (!m_program->isOk())
|
|
throw tcu::TestError("failed to build program");
|
|
}
|
|
}
|
|
|
|
void GridRenderCase::deinit (void)
|
|
{
|
|
delete m_program;
|
|
m_program = DE_NULL;
|
|
}
|
|
|
|
GridRenderCase::IterateResult GridRenderCase::iterate (void)
|
|
{
|
|
std::vector<tcu::Surface> renderedLayers (m_numLayers);
|
|
bool allLayersOk = true;
|
|
|
|
for (int ndx = 0; ndx < m_numLayers; ++ndx)
|
|
renderedLayers[ndx].setSize(RENDER_SIZE, RENDER_SIZE);
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)." << tcu::TestLog::EndMessage;
|
|
|
|
try
|
|
{
|
|
renderTo(renderedLayers);
|
|
}
|
|
catch (const AllowedRenderFailureException& ex)
|
|
{
|
|
// Got accepted failure
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message
|
|
<< "Could not render, reason: " << ex.what() << "\n"
|
|
<< "Failure is allowed."
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
return STOP;
|
|
}
|
|
|
|
for (int ndx = 0; ndx < m_numLayers; ++ndx)
|
|
allLayersOk &= verifyResultLayer(ndx, renderedLayers[ndx]);
|
|
|
|
if (allLayersOk)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
|
|
return STOP;
|
|
}
|
|
|
|
void GridRenderCase::renderTo (std::vector<tcu::Surface>& dst)
|
|
{
|
|
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
|
|
const int positionLocation = gl.getAttribLocation(m_program->getProgram(), "a_position");
|
|
const glu::VertexArray vao (m_context.getRenderContext());
|
|
|
|
if (positionLocation == -1)
|
|
throw tcu::TestError("Attribute a_position location was -1");
|
|
|
|
gl.viewport(0, 0, dst.front().getWidth(), dst.front().getHeight());
|
|
gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
|
|
|
|
gl.bindVertexArray(*vao);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
|
|
|
|
gl.useProgram(m_program->getProgram());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
|
|
|
|
gl.patchParameteri(GL_PATCH_VERTICES, 1);
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
|
|
|
|
gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
// clear viewport
|
|
gl.clear(GL_COLOR_BUFFER_BIT);
|
|
|
|
// draw
|
|
{
|
|
glw::GLenum glerror;
|
|
|
|
gl.drawArrays(GL_PATCHES, 0, 1);
|
|
|
|
// allow always OOM
|
|
glerror = gl.getError();
|
|
if (glerror == GL_OUT_OF_MEMORY)
|
|
throw AllowedRenderFailureException("got GL_OUT_OF_MEMORY while drawing");
|
|
|
|
GLU_EXPECT_NO_ERROR(glerror, "draw patches");
|
|
}
|
|
|
|
// Read layers
|
|
|
|
glu::readPixels(m_context.getRenderContext(), 0, 0, dst.front().getAccess());
|
|
GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
|
|
}
|
|
|
|
bool GridRenderCase::verifyResultLayer (int layerNdx, const tcu::Surface& image)
|
|
{
|
|
tcu::Surface errorMask (image.getWidth(), image.getHeight());
|
|
bool foundError = false;
|
|
|
|
tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output layer " << layerNdx << tcu::TestLog::EndMessage;
|
|
|
|
for (int y = 0; y < image.getHeight(); ++y)
|
|
for (int x = 0; x < image.getWidth(); ++x)
|
|
{
|
|
const int threshold = 8;
|
|
const tcu::RGBA color = image.getPixel(x, y);
|
|
|
|
// Color must be a linear combination of green and yellow
|
|
if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
|
|
{
|
|
errorMask.setPixel(x, y, tcu::RGBA::red());
|
|
foundError = true;
|
|
}
|
|
}
|
|
|
|
if (!foundError)
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("ImageVerification", "Image verification")
|
|
<< tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_testCtx.getLog()
|
|
<< tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
|
|
<< tcu::TestLog::ImageSet("ImageVerification", "Image verification")
|
|
<< tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
|
|
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
|
|
<< tcu::TestLog::EndImageSet;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const char* GridRenderCase::getVertexSource (void)
|
|
{
|
|
return "#version 310 es\n"
|
|
"in highp vec4 a_position;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" gl_Position = a_position;\n"
|
|
"}\n";
|
|
}
|
|
|
|
const char* GridRenderCase::getFragmentSource (void)
|
|
{
|
|
return "#version 310 es\n"
|
|
"flat in mediump vec4 v_color;\n"
|
|
"layout(location = 0) out mediump vec4 fragColor;\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" fragColor = v_color;\n"
|
|
"}\n";
|
|
}
|
|
|
|
std::string GridRenderCase::getTessellationControlSource (int tessLevel)
|
|
{
|
|
std::ostringstream buf;
|
|
|
|
buf << "#version 310 es\n"
|
|
"#extension GL_EXT_tessellation_shader : require\n"
|
|
"layout(vertices=1) out;\n"
|
|
"\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
|
|
" gl_TessLevelOuter[0] = " << tessLevel << ".0;\n"
|
|
" gl_TessLevelOuter[1] = " << tessLevel << ".0;\n"
|
|
" gl_TessLevelOuter[2] = " << tessLevel << ".0;\n"
|
|
" gl_TessLevelOuter[3] = " << tessLevel << ".0;\n"
|
|
" gl_TessLevelInner[0] = " << tessLevel << ".0;\n"
|
|
" gl_TessLevelInner[1] = " << tessLevel << ".0;\n"
|
|
"}\n";
|
|
|
|
return buf.str();
|
|
}
|
|
|
|
std::string GridRenderCase::getTessellationEvaluationSource (int tessLevel)
|
|
{
|
|
std::ostringstream buf;
|
|
|
|
buf << "#version 310 es\n"
|
|
"#extension GL_EXT_tessellation_shader : require\n"
|
|
"layout(quads) in;\n"
|
|
"\n"
|
|
"out mediump ivec2 v_tessellationGridPosition;\n"
|
|
"\n"
|
|
"// note: No need to use precise gl_Position since position does not depend on order\n"
|
|
"void main (void)\n"
|
|
"{\n"
|
|
" // Fill the whole viewport\n"
|
|
" gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n"
|
|
" // Calculate position in tessellation grid\n"
|
|
" v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << tessLevel << ")));\n"
|
|
"}\n";
|
|
|
|
return buf.str();
|
|
}
|
|
|
|
std::string GridRenderCase::getGeometryShaderSource (int numPrimitives, int numInstances)
|
|
{
|
|
std::ostringstream buf;
|
|
|
|
buf << "#version 310 es\n"
|
|
"#extension GL_EXT_geometry_shader : require\n"
|
|
"layout(triangles, invocations=" << numInstances << ") in;\n"
|
|
"layout(triangle_strip, max_vertices=" << (numPrimitives + 2) << ") out;\n"
|
|
"\n"
|
|
"in mediump ivec2 v_tessellationGridPosition[];\n"
|
|
"flat out highp vec4 v_color;\n"
|
|
"\n"
|
|
"void main ()\n"
|
|
"{\n"
|
|
" const float equalThreshold = 0.001;\n"
|
|
" const float gapOffset = 0.0001; // subdivision performed by the geometry shader might produce gaps. Fill potential gaps by enlarging the output slice a little.\n"
|
|
"\n"
|
|
" // Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
|
|
" // Original rectangle can be found by finding the bounding AABB of the triangle\n"
|
|
" vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
|
|
" min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
|
|
" max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
|
|
" max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
|
|
"\n"
|
|
" // Location in tessellation grid\n"
|
|
" ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
|
|
"\n"
|
|
" // Which triangle of the two that split the grid cell\n"
|
|
" int numVerticesOnBottomEdge = 0;\n"
|
|
" for (int ndx = 0; ndx < 3; ++ndx)\n"
|
|
" if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
|
|
" ++numVerticesOnBottomEdge;\n"
|
|
" bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
|
|
"\n"
|
|
" // Fill the input area with slices\n"
|
|
" // Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
|
|
" float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
|
|
" // Each slice is a invocation\n"
|
|
" float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInstances << ");\n"
|
|
" float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
|
|
"\n"
|
|
" vec4 outputSliceArea;\n"
|
|
" outputSliceArea.x = aabb.x - gapOffset;\n"
|
|
" outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
|
|
" outputSliceArea.z = aabb.z + gapOffset;\n"
|
|
" outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n""\n"
|
|
" // Draw slice\n"
|
|
" for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
|
|
" {\n"
|
|
" vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
|
" vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
|
|
" vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
|
|
" float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
|
|
"\n"
|
|
" gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
|
|
" v_color = outputColor;\n"
|
|
" EmitVertex();\n"
|
|
"\n"
|
|
" gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
|
|
" v_color = outputColor;\n"
|
|
" EmitVertex();\n"
|
|
" }\n"
|
|
"}\n";
|
|
|
|
return buf.str();
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
TessellationGeometryInteractionTests::TessellationGeometryInteractionTests (Context& context)
|
|
: TestCaseGroup(context, "tessellation_geometry_interaction", "Tessellation and geometry shader interaction stress tests")
|
|
{
|
|
}
|
|
|
|
TessellationGeometryInteractionTests::~TessellationGeometryInteractionTests (void)
|
|
{
|
|
}
|
|
|
|
void TessellationGeometryInteractionTests::init (void)
|
|
{
|
|
tcu::TestCaseGroup* const multilimitGroup = new tcu::TestCaseGroup(m_testCtx, "render_multiple_limits", "Various render tests");
|
|
|
|
addChild(multilimitGroup);
|
|
|
|
// .render_multiple_limits
|
|
{
|
|
static const struct LimitCaseDef
|
|
{
|
|
const char* name;
|
|
const char* desc;
|
|
int flags;
|
|
} cases[] =
|
|
{
|
|
// Test multiple limits at the same time
|
|
|
|
{
|
|
"output_required_max_tessellation_max_geometry",
|
|
"Minimum maximum tessellation level and geometry shader output vertices",
|
|
GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_MAX_SPEC
|
|
},
|
|
{
|
|
"output_implementation_max_tessellation_max_geometry",
|
|
"Maximum tessellation level and geometry shader output vertices supported by the implementation",
|
|
GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION
|
|
},
|
|
{
|
|
"output_required_max_tessellation_max_invocations",
|
|
"Minimum maximum tessellation level and geometry shader invocations",
|
|
GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
|
|
},
|
|
{
|
|
"output_implementation_max_tessellation_max_invocations",
|
|
"Maximum tessellation level and geometry shader invocations supported by the implementation",
|
|
GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
|
|
},
|
|
{
|
|
"output_required_max_geometry_max_invocations",
|
|
"Minimum maximum geometry shader output vertices and invocations",
|
|
GridRenderCase::FLAG_GEOMETRY_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
|
|
},
|
|
{
|
|
"output_implementation_max_geometry_max_invocations",
|
|
"Maximum geometry shader output vertices and invocations invocations supported by the implementation",
|
|
GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
|
|
},
|
|
|
|
// Test all limits simultaneously
|
|
{
|
|
"output_max_required",
|
|
"Output minimum maximum number of vertices",
|
|
GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
|
|
},
|
|
{
|
|
"output_max_implementation",
|
|
"Output maximum number of vertices supported by the implementation",
|
|
GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
|
|
},
|
|
};
|
|
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
|
|
multilimitGroup->addChild(new GridRenderCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
|
|
}
|
|
}
|
|
|
|
} // Stress
|
|
} // gles31
|
|
} // deqp
|