| /*------------------------------------------------------------------------- |
| * 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 Multisample interpolation tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es31fShaderMultisampleInterpolationTests.hpp" |
| #include "es31fMultisampleShaderRenderCase.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuRGBA.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuStringTemplate.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "gluContextInfo.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluRenderContext.hpp" |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| #include "deArrayUtil.hpp" |
| #include "deStringUtil.hpp" |
| #include "deMath.h" |
| |
| #include <map> |
| |
| namespace deqp |
| { |
| namespace gles31 |
| { |
| namespace Functional |
| { |
| namespace |
| { |
| |
| 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_SHADER_MULTISAMPLE_INTERPOLATION"] = supportsES32 ? "" : "#extension GL_OES_shader_multisample_interpolation : require\n"; |
| args["GLSL_EXT_SAMPLE_VARIABLES"] = supportsES32 ? "" : "#extension GL_OES_sample_variables : require\n"; |
| |
| return tcu::StringTemplate(shaderSource).specialize(args); |
| } |
| |
| static bool verifyGreenImage (const tcu::Surface& image, tcu::TestLog& log) |
| { |
| bool error = false; |
| |
| log << tcu::TestLog::Message << "Verifying result image, expecting green." << tcu::TestLog::EndMessage; |
| |
| // all pixels must be green |
| |
| for (int y = 0; y < image.getHeight(); ++y) |
| for (int x = 0; x < image.getWidth(); ++x) |
| { |
| const tcu::RGBA color = image.getPixel(x, y); |
| const int greenThreshold = 8; |
| |
| if (color.getRed() > 0 || color.getGreen() < 255-greenThreshold || color.getBlue() > 0) |
| error = true; |
| } |
| |
| if (error) |
| log << tcu::TestLog::Image("ResultImage", "Result Image", image.getAccess()) |
| << tcu::TestLog::Message |
| << "Image verification failed." |
| << tcu::TestLog::EndMessage; |
| else |
| log << tcu::TestLog::Image("ResultImage", "Result Image", image.getAccess()) |
| << tcu::TestLog::Message |
| << "Image verification passed." |
| << tcu::TestLog::EndMessage; |
| |
| return !error; |
| } |
| |
| class MultisampleShadeCountRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase |
| { |
| public: |
| MultisampleShadeCountRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); |
| virtual ~MultisampleShadeCountRenderCase (void); |
| |
| void init (void); |
| |
| private: |
| enum |
| { |
| RENDER_SIZE = 128 |
| }; |
| |
| virtual std::string getIterationDescription (int iteration) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| }; |
| |
| MultisampleShadeCountRenderCase::MultisampleShadeCountRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) |
| : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_PER_ITERATION_SHADER) |
| { |
| m_numIterations = -1; // must be set by deriving class |
| } |
| |
| MultisampleShadeCountRenderCase::~MultisampleShadeCountRenderCase (void) |
| { |
| } |
| |
| void MultisampleShadeCountRenderCase::init (void) |
| { |
| // requirements |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| |
| MultisampleShaderRenderUtil::MultisampleRenderCase::init(); |
| } |
| |
| std::string MultisampleShadeCountRenderCase::getIterationDescription (int iteration) const |
| { |
| // must be overriden |
| DE_UNREF(iteration); |
| DE_ASSERT(false); |
| return ""; |
| } |
| |
| bool MultisampleShadeCountRenderCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1); |
| const int numShadesRequired = (isSingleSampleTarget) ? (2) : (m_numTargetSamples + 1); |
| const int rareThreshold = 100; |
| int rareCount = 0; |
| std::map<deUint32, int> shadeFrequency; |
| |
| m_testCtx.getLog() |
| << tcu::TestLog::Image("ResultImage", "Result Image", resultImage.getAccess()) |
| << tcu::TestLog::Message |
| << "Verifying image has (at least) " << numShadesRequired << " different shades.\n" |
| << "Excluding pixels with no full coverage (pixels on the shared edge of the triangle pair)." |
| << tcu::TestLog::EndMessage; |
| |
| for (int y = 0; y < RENDER_SIZE; ++y) |
| for (int x = 0; x < RENDER_SIZE; ++x) |
| { |
| const tcu::RGBA color = resultImage.getPixel(x, y); |
| const deUint32 packed = ((deUint32)color.getRed()) + ((deUint32)color.getGreen() << 8) + ((deUint32)color.getGreen() << 16); |
| |
| // on the triangle edge, skip |
| if (x == y) |
| continue; |
| |
| if (shadeFrequency.find(packed) == shadeFrequency.end()) |
| shadeFrequency[packed] = 1; |
| else |
| shadeFrequency[packed] = shadeFrequency[packed] + 1; |
| } |
| |
| for (std::map<deUint32, int>::const_iterator it = shadeFrequency.begin(); it != shadeFrequency.end(); ++it) |
| if (it->second < rareThreshold) |
| rareCount++; |
| |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Found " << (int)shadeFrequency.size() << " different shades.\n" |
| << "\tRare (less than " << rareThreshold << " pixels): " << rareCount << "\n" |
| << "\tCommon: " << (int)shadeFrequency.size() - rareCount << "\n" |
| << tcu::TestLog::EndMessage; |
| |
| if ((int)shadeFrequency.size() < numShadesRequired) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage; |
| return false; |
| } |
| return true; |
| } |
| |
| class SampleQualifierRenderCase : public MultisampleShadeCountRenderCase |
| { |
| public: |
| SampleQualifierRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); |
| ~SampleQualifierRenderCase (void); |
| |
| void init (void); |
| |
| private: |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| std::string getIterationDescription (int iteration) const; |
| }; |
| |
| SampleQualifierRenderCase::SampleQualifierRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) |
| : MultisampleShadeCountRenderCase(context, name, description, numSamples, target) |
| { |
| m_numIterations = 6; // float, vec2, .3, .4, array, struct |
| } |
| |
| SampleQualifierRenderCase::~SampleQualifierRenderCase (void) |
| { |
| } |
| |
| void SampleQualifierRenderCase::init (void) |
| { |
| const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1); |
| |
| // test purpose and expectations |
| if (isSingleSampleTarget) |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that a sample-qualified varying is given different values for different samples.\n" |
| << " Render high-frequency function, map result to black/white.\n" |
| << " => Resulting image image should contain both black and white pixels.\n" |
| << tcu::TestLog::EndMessage; |
| } |
| else |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that a sample-qualified varying is given different values for different samples.\n" |
| << " Render high-frequency function, map result to black/white.\n" |
| << " => Resulting image should contain n+1 shades of gray, n = sample count.\n" |
| << tcu::TestLog::EndMessage; |
| } |
| |
| MultisampleShadeCountRenderCase::init(); |
| } |
| |
| std::string SampleQualifierRenderCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec4 a_position;\n"; |
| |
| if (m_iteration == 0) |
| buf << "sample out highp float v_input;\n"; |
| else if (m_iteration == 1) |
| buf << "sample out highp vec2 v_input;\n"; |
| else if (m_iteration == 2) |
| buf << "sample out highp vec3 v_input;\n"; |
| else if (m_iteration == 3) |
| buf << "sample out highp vec4 v_input;\n"; |
| else if (m_iteration == 4) |
| buf << "sample out highp float[2] v_input;\n"; |
| else if (m_iteration == 5) |
| buf << "struct VaryingStruct { highp float a; highp float b; };\n" |
| "sample out VaryingStruct v_input;\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n"; |
| |
| if (m_iteration == 0) |
| buf << " v_input = a_position.x + exp(a_position.y) + step(0.9, a_position.x)*step(a_position.y, -0.9)*8.0;\n"; |
| else if (m_iteration == 1) |
| buf << " v_input = a_position.xy;\n"; |
| else if (m_iteration == 2) |
| buf << " v_input = vec3(a_position.xy, a_position.x * 2.0 - a_position.y);\n"; |
| else if (m_iteration == 3) |
| buf << " v_input = vec4(a_position.xy, a_position.x * 2.0 - a_position.y, a_position.x*a_position.y);\n"; |
| else if (m_iteration == 4) |
| buf << " v_input[0] = a_position.x;\n" |
| " v_input[1] = a_position.y;\n"; |
| else if (m_iteration == 5) |
| buf << " v_input.a = a_position.x;\n" |
| " v_input.b = a_position.y;\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << "}"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string SampleQualifierRenderCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}"; |
| |
| if (m_iteration == 0) |
| buf << "sample in highp float v_input;\n"; |
| else if (m_iteration == 1) |
| buf << "sample in highp vec2 v_input;\n"; |
| else if (m_iteration == 2) |
| buf << "sample in highp vec3 v_input;\n"; |
| else if (m_iteration == 3) |
| buf << "sample in highp vec4 v_input;\n"; |
| else if (m_iteration == 4) |
| buf << "sample in highp float[2] v_input;\n"; |
| else if (m_iteration == 5) |
| buf << "struct VaryingStruct { highp float a; highp float b; };\n" |
| "sample in VaryingStruct v_input;\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n"; |
| |
| if (m_iteration == 0) |
| buf << " highp float field = exp(v_input) + v_input*v_input;\n"; |
| else if (m_iteration == 1) |
| buf << " highp float field = dot(v_input.xy, v_input.xy) + dot(21.0 * v_input.xx, sin(3.1 * v_input.xy));\n"; |
| else if (m_iteration == 2) |
| buf << " highp float field = dot(v_input.xy, v_input.xy) + dot(21.0 * v_input.zx, sin(3.1 * v_input.zy));\n"; |
| else if (m_iteration == 3) |
| buf << " highp float field = dot(v_input.xy, v_input.zw) + dot(21.0 * v_input.zy, sin(3.1 * v_input.zw));\n"; |
| else if (m_iteration == 4) |
| buf << " highp float field = dot(vec2(v_input[0], v_input[1]), vec2(v_input[0], v_input[1])) + dot(21.0 * vec2(v_input[0]), sin(3.1 * vec2(v_input[0], v_input[1])));\n"; |
| else if (m_iteration == 5) |
| buf << " highp float field = dot(vec2(v_input.a, v_input.b), vec2(v_input.a, v_input.b)) + dot(21.0 * vec2(v_input.a), sin(3.1 * vec2(v_input.a, v_input.b)));\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << " fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" |
| "\n" |
| " if (fract(field) > 0.5)\n" |
| " fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n" |
| "}"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string SampleQualifierRenderCase::getIterationDescription (int iteration) const |
| { |
| if (iteration == 0) |
| return "Test with float varying"; |
| else if (iteration == 1) |
| return "Test with vec2 varying"; |
| else if (iteration == 2) |
| return "Test with vec3 varying"; |
| else if (iteration == 3) |
| return "Test with vec4 varying"; |
| else if (iteration == 4) |
| return "Test with array varying"; |
| else if (iteration == 5) |
| return "Test with struct varying"; |
| |
| DE_ASSERT(false); |
| return ""; |
| } |
| |
| class InterpolateAtSampleRenderCase : public MultisampleShadeCountRenderCase |
| { |
| public: |
| enum IndexingMode |
| { |
| INDEXING_STATIC, |
| INDEXING_DYNAMIC, |
| |
| INDEXING_LAST |
| }; |
| InterpolateAtSampleRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, IndexingMode mode); |
| ~InterpolateAtSampleRenderCase (void); |
| |
| void init (void); |
| void preDraw (void); |
| |
| private: |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| std::string getIterationDescription (int iteration) const; |
| |
| const IndexingMode m_indexMode; |
| }; |
| |
| InterpolateAtSampleRenderCase::InterpolateAtSampleRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, IndexingMode mode) |
| : MultisampleShadeCountRenderCase (context, name, description, numSamples, target) |
| , m_indexMode (mode) |
| { |
| DE_ASSERT(mode < INDEXING_LAST); |
| |
| m_numIterations = 5; // float, vec2, .3, .4, array |
| } |
| |
| InterpolateAtSampleRenderCase::~InterpolateAtSampleRenderCase (void) |
| { |
| } |
| |
| void InterpolateAtSampleRenderCase::init (void) |
| { |
| const bool isSingleSampleTarget = (m_renderTarget != TARGET_DEFAULT && m_numRequestedSamples == 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1); |
| |
| // test purpose and expectations |
| if (isSingleSampleTarget) |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that a interpolateAtSample returns different values for different samples.\n" |
| << " Render high-frequency function, map result to black/white.\n" |
| << " => Resulting image image should contain both black and white pixels.\n" |
| << tcu::TestLog::EndMessage; |
| } |
| else |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that a interpolateAtSample returns different values for different samples.\n" |
| << " Render high-frequency function, map result to black/white.\n" |
| << " => Resulting image should contain n+1 shades of gray, n = sample count.\n" |
| << tcu::TestLog::EndMessage; |
| } |
| |
| MultisampleShadeCountRenderCase::init(); |
| } |
| |
| void InterpolateAtSampleRenderCase::preDraw (void) |
| { |
| if (m_indexMode == INDEXING_DYNAMIC) |
| { |
| const deInt32 range = m_numTargetSamples; |
| const deInt32 offset = 1; |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| const deInt32 offsetLoc = gl.getUniformLocation(m_program->getProgram(), "u_offset"); |
| const deInt32 rangeLoc = gl.getUniformLocation(m_program->getProgram(), "u_range"); |
| |
| if (offsetLoc == -1) |
| throw tcu::TestError("Location of u_offset was -1"); |
| if (rangeLoc == -1) |
| throw tcu::TestError("Location of u_range was -1"); |
| |
| gl.uniform1i(offsetLoc, 0); |
| gl.uniform1i(rangeLoc, m_numTargetSamples); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "set uniforms"); |
| |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Set u_offset = " << offset << "\n" |
| << "Set u_range = " << range |
| << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| std::string InterpolateAtSampleRenderCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "in highp vec4 a_position;\n"; |
| |
| if (m_iteration == 0) |
| buf << "out highp float v_input;\n"; |
| else if (m_iteration == 1) |
| buf << "out highp vec2 v_input;\n"; |
| else if (m_iteration == 2) |
| buf << "out highp vec3 v_input;\n"; |
| else if (m_iteration == 3) |
| buf << "out highp vec4 v_input;\n"; |
| else if (m_iteration == 4) |
| buf << "out highp vec2[2] v_input;\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n"; |
| |
| if (m_iteration == 0) |
| buf << " v_input = a_position.x + exp(a_position.y) + step(0.9, a_position.x)*step(a_position.y, -0.9)*8.0;\n"; |
| else if (m_iteration == 1) |
| buf << " v_input = a_position.xy;\n"; |
| else if (m_iteration == 2) |
| buf << " v_input = vec3(a_position.xy, a_position.x * 2.0 - a_position.y);\n"; |
| else if (m_iteration == 3) |
| buf << " v_input = vec4(a_position.xy, a_position.x * 2.0 - a_position.y, a_position.x*a_position.y);\n"; |
| else if (m_iteration == 4) |
| buf << " v_input[0] = a_position.yx + vec2(0.5, 0.5);\n" |
| " v_input[1] = a_position.xy;\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << "}"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string InterpolateAtSampleRenderCase::genFragmentSource (int numTargetSamples) const |
| { |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}"; |
| |
| if (m_iteration == 0) |
| buf << "in highp float v_input;\n"; |
| else if (m_iteration == 1) |
| buf << "in highp vec2 v_input;\n"; |
| else if (m_iteration == 2) |
| buf << "in highp vec3 v_input;\n"; |
| else if (m_iteration == 3) |
| buf << "in highp vec4 v_input;\n"; |
| else if (m_iteration == 4) |
| buf << "in highp vec2[2] v_input;\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << "layout(location = 0) out mediump vec4 fragColor;\n"; |
| |
| if (m_indexMode == INDEXING_DYNAMIC) |
| buf << "uniform highp int u_offset;\n" |
| "uniform highp int u_range;\n"; |
| |
| buf << "void main (void)\n" |
| "{\n" |
| " mediump int coverage = 0;\n" |
| "\n"; |
| |
| if (m_indexMode == INDEXING_STATIC) |
| { |
| for (int ndx = 0; ndx < numTargetSamples; ++ndx) |
| { |
| if (m_iteration == 0) |
| buf << " highp float sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; |
| else if (m_iteration == 1) |
| buf << " highp vec2 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; |
| else if (m_iteration == 2) |
| buf << " highp vec3 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; |
| else if (m_iteration == 3) |
| buf << " highp vec4 sampleInput" << ndx << " = interpolateAtSample(v_input, " << ndx << ");\n"; |
| else if (m_iteration == 4) |
| buf << " highp vec2 sampleInput" << ndx << " = interpolateAtSample(v_input[1], " << ndx << ");\n"; |
| else |
| DE_ASSERT(false); |
| } |
| buf << "\n"; |
| |
| for (int ndx = 0; ndx < numTargetSamples; ++ndx) |
| { |
| if (m_iteration == 0) |
| buf << " highp float field" << ndx << " = exp(sampleInput" << ndx << ") + sampleInput" << ndx << "*sampleInput" << ndx << ";\n"; |
| else if (m_iteration == 1 || m_iteration == 4) |
| buf << " highp float field" << ndx << " = dot(sampleInput" << ndx << ", sampleInput" << ndx << ") + dot(21.0 * sampleInput" << ndx << ".xx, sin(3.1 * sampleInput" << ndx << "));\n"; |
| else if (m_iteration == 2) |
| buf << " highp float field" << ndx << " = dot(sampleInput" << ndx << ".xy, sampleInput" << ndx << ".xy) + dot(21.0 * sampleInput" << ndx << ".zx, sin(3.1 * sampleInput" << ndx << ".zy));\n"; |
| else if (m_iteration == 3) |
| buf << " highp float field" << ndx << " = dot(sampleInput" << ndx << ".xy, sampleInput" << ndx << ".zw) + dot(21.0 * sampleInput" << ndx << ".zy, sin(3.1 * sampleInput" << ndx << ".zw));\n"; |
| else |
| DE_ASSERT(false); |
| } |
| buf << "\n"; |
| |
| for (int ndx = 0; ndx < numTargetSamples; ++ndx) |
| buf << " if (fract(field" << ndx << ") <= 0.5)\n" |
| " ++coverage;\n"; |
| } |
| else if (m_indexMode == INDEXING_DYNAMIC) |
| { |
| buf << " for (int ndx = 0; ndx < " << numTargetSamples << "; ++ndx)\n" |
| " {\n"; |
| |
| if (m_iteration == 0) |
| buf << " highp float sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; |
| else if (m_iteration == 1) |
| buf << " highp vec2 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; |
| else if (m_iteration == 2) |
| buf << " highp vec3 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; |
| else if (m_iteration == 3) |
| buf << " highp vec4 sampleInput = interpolateAtSample(v_input, (u_offset + ndx) % u_range);\n"; |
| else if (m_iteration == 4) |
| buf << " highp vec2 sampleInput = interpolateAtSample(v_input[1], (u_offset + ndx) % u_range);\n"; |
| else |
| DE_ASSERT(false); |
| |
| if (m_iteration == 0) |
| buf << " highp float field = exp(sampleInput) + sampleInput*sampleInput;\n"; |
| else if (m_iteration == 1 || m_iteration == 4) |
| buf << " highp float field = dot(sampleInput, sampleInput) + dot(21.0 * sampleInput.xx, sin(3.1 * sampleInput));\n"; |
| else if (m_iteration == 2) |
| buf << " highp float field = dot(sampleInput.xy, sampleInput.xy) + dot(21.0 * sampleInput.zx, sin(3.1 * sampleInput.zy));\n"; |
| else if (m_iteration == 3) |
| buf << " highp float field = dot(sampleInput.xy, sampleInput.zw) + dot(21.0 * sampleInput.zy, sin(3.1 * sampleInput.zw));\n"; |
| else |
| DE_ASSERT(false); |
| |
| buf << " if (fract(field) <= 0.5)\n" |
| " ++coverage;\n" |
| " }\n"; |
| } |
| |
| buf << " fragColor = vec4(vec3(float(coverage) / float(" << numTargetSamples << ")), 1.0);\n" |
| "}"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string InterpolateAtSampleRenderCase::getIterationDescription (int iteration) const |
| { |
| if (iteration == 0) |
| return "Test with float varying"; |
| else if (iteration < 4) |
| return "Test with vec" + de::toString(iteration+1) + " varying"; |
| else if (iteration == 4) |
| return "Test with array varying"; |
| |
| DE_ASSERT(false); |
| return ""; |
| } |
| |
| class SingleSampleInterpolateAtSampleCase : public MultisampleShaderRenderUtil::MultisampleRenderCase |
| { |
| public: |
| enum SampleCase |
| { |
| SAMPLE_0 = 0, |
| SAMPLE_N, |
| |
| SAMPLE_LAST |
| }; |
| |
| SingleSampleInterpolateAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, SampleCase sampleCase); |
| virtual ~SingleSampleInterpolateAtSampleCase (void); |
| |
| void init (void); |
| |
| private: |
| enum |
| { |
| RENDER_SIZE = 32 |
| }; |
| |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| |
| const SampleCase m_sampleCase; |
| }; |
| |
| SingleSampleInterpolateAtSampleCase::SingleSampleInterpolateAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, SampleCase sampleCase) |
| : MultisampleShaderRenderUtil::MultisampleRenderCase (context, name, description, numSamples, target, RENDER_SIZE) |
| , m_sampleCase (sampleCase) |
| { |
| DE_ASSERT(numSamples == 0); |
| DE_ASSERT(sampleCase < SAMPLE_LAST); |
| } |
| |
| SingleSampleInterpolateAtSampleCase::~SingleSampleInterpolateAtSampleCase (void) |
| { |
| } |
| |
| void SingleSampleInterpolateAtSampleCase::init (void) |
| { |
| // requirements |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| if (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1) |
| TCU_THROW(NotSupportedError, "Non-multisample framebuffer required"); |
| |
| // test purpose and expectations |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n" |
| << " Interpolate varying containing screen space location.\n" |
| << " => fract(screen space location) should be (about) (0.5, 0.5)\n" |
| << tcu::TestLog::EndMessage; |
| |
| MultisampleShaderRenderUtil::MultisampleRenderCase::init(); |
| } |
| |
| std::string SingleSampleInterpolateAtSampleCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "in highp vec4 a_position;\n" |
| "out highp vec2 v_position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_position = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string SingleSampleInterpolateAtSampleCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec2 v_position;\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n"; // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) |
| |
| if (m_sampleCase == SAMPLE_0) |
| { |
| buf << " highp vec2 samplePosition = interpolateAtSample(v_position, 0);\n" |
| " highp vec2 positionInsideAPixel = fract(samplePosition);\n" |
| "\n" |
| " if (abs(positionInsideAPixel.x - 0.5) <= threshold && abs(positionInsideAPixel.y - 0.5) <= threshold)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| } |
| else if (m_sampleCase == SAMPLE_N) |
| { |
| buf << " bool allOk = true;\n" |
| " for (int sampleNdx = 159; sampleNdx < 163; ++sampleNdx)\n" |
| " {\n" |
| " highp vec2 samplePosition = interpolateAtSample(v_position, sampleNdx);\n" |
| " highp vec2 positionInsideAPixel = fract(samplePosition);\n" |
| " if (abs(positionInsideAPixel.x - 0.5) > threshold || abs(positionInsideAPixel.y - 0.5) > threshold)\n" |
| " allOk = false;\n" |
| " }\n" |
| "\n" |
| " if (allOk)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| } |
| else |
| DE_ASSERT(false); |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| bool SingleSampleInterpolateAtSampleCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| return verifyGreenImage(resultImage, m_testCtx.getLog()); |
| } |
| |
| class CentroidRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase |
| { |
| public: |
| CentroidRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, int renderSize); |
| virtual ~CentroidRenderCase (void); |
| |
| void init (void); |
| |
| private: |
| void setupRenderData (void); |
| }; |
| |
| CentroidRenderCase::CentroidRenderCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, int renderSize) |
| : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, renderSize) |
| { |
| } |
| |
| CentroidRenderCase::~CentroidRenderCase (void) |
| { |
| } |
| |
| void CentroidRenderCase::init (void) |
| { |
| // requirements |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| |
| MultisampleShaderRenderUtil::MultisampleRenderCase::init(); |
| } |
| |
| void CentroidRenderCase::setupRenderData (void) |
| { |
| const int numTriangles = 200; |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| std::vector<tcu::Vec4> data (numTriangles * 3 * 3); |
| |
| m_renderMode = GL_TRIANGLES; |
| m_renderCount = numTriangles * 3; |
| m_renderSceneDescription = "triangle fan of narrow triangles"; |
| |
| m_renderAttribs["a_position"].offset = 0; |
| m_renderAttribs["a_position"].stride = (int)sizeof(float[4]) * 3; |
| m_renderAttribs["a_barycentricsA"].offset = (int)sizeof(float[4]); |
| m_renderAttribs["a_barycentricsA"].stride = (int)sizeof(float[4]) * 3; |
| m_renderAttribs["a_barycentricsB"].offset = (int)sizeof(float[4]) * 2; |
| m_renderAttribs["a_barycentricsB"].stride = (int)sizeof(float[4]) * 3; |
| |
| for (int triangleNdx = 0; triangleNdx < numTriangles; ++triangleNdx) |
| { |
| const float angle = ((float)triangleNdx) / (float)numTriangles * 2.0f * DE_PI; |
| const float nextAngle = ((float)triangleNdx + 1.0f) / (float)numTriangles * 2.0f * DE_PI; |
| |
| data[(triangleNdx * 3 + 0) * 3 + 0] = tcu::Vec4(0.2f, -0.3f, 0.0f, 1.0f); |
| data[(triangleNdx * 3 + 0) * 3 + 1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f); |
| data[(triangleNdx * 3 + 0) * 3 + 2] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f); |
| |
| data[(triangleNdx * 3 + 1) * 3 + 0] = tcu::Vec4(2.0f * deFloatCos(angle), 2.0f * deFloatSin(angle), 0.0f, 1.0f); |
| data[(triangleNdx * 3 + 1) * 3 + 1] = tcu::Vec4(0.0f, 1.0f, 0.0f, 0.0f); |
| data[(triangleNdx * 3 + 1) * 3 + 2] = tcu::Vec4(0.0f, 1.0f, 0.0f, 0.0f); |
| |
| data[(triangleNdx * 3 + 2) * 3 + 0] = tcu::Vec4(2.0f * deFloatCos(nextAngle), 2.0f * deFloatSin(nextAngle), 0.0f, 1.0f); |
| data[(triangleNdx * 3 + 2) * 3 + 1] = tcu::Vec4(0.0f, 0.0f, 1.0f, 0.0f); |
| data[(triangleNdx * 3 + 2) * 3 + 2] = tcu::Vec4(0.0f, 0.0f, 1.0f, 0.0f); |
| } |
| |
| gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer); |
| gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(data.size() * sizeof(tcu::Vec4)), data[0].getPtr(), GL_STATIC_DRAW); |
| } |
| |
| class CentroidQualifierAtSampleCase : public CentroidRenderCase |
| { |
| public: |
| CentroidQualifierAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); |
| virtual ~CentroidQualifierAtSampleCase (void); |
| |
| void init (void); |
| |
| private: |
| enum |
| { |
| RENDER_SIZE = 128 |
| }; |
| |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| }; |
| |
| CentroidQualifierAtSampleCase::CentroidQualifierAtSampleCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) |
| : CentroidRenderCase(context, name, description, numSamples, target, RENDER_SIZE) |
| { |
| } |
| |
| CentroidQualifierAtSampleCase::~CentroidQualifierAtSampleCase (void) |
| { |
| } |
| |
| void CentroidQualifierAtSampleCase::init (void) |
| { |
| // test purpose and expectations |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that interpolateAtSample ignores the centroid-qualifier.\n" |
| << " Draw a fan of narrow triangles (large number of pixels on the edges).\n" |
| << " Set varyings 'barycentricsA' and 'barycentricsB' to contain barycentric coordinates.\n" |
| << " Add centroid-qualifier for barycentricsB.\n" |
| << " => interpolateAtSample(barycentricsB, N) ~= interpolateAtSample(barycentricsA, N)\n" |
| << tcu::TestLog::EndMessage; |
| |
| CentroidRenderCase::init(); |
| } |
| |
| std::string CentroidQualifierAtSampleCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "in highp vec4 a_position;\n" |
| "in highp vec4 a_barycentricsA;\n" |
| "in highp vec4 a_barycentricsB;\n" |
| "out highp vec3 v_barycentricsA;\n" |
| "centroid out highp vec3 v_barycentricsB;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_barycentricsA = a_barycentricsA.xyz;\n" |
| " v_barycentricsB = a_barycentricsB.xyz;\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string CentroidQualifierAtSampleCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec3 v_barycentricsA;\n" |
| "centroid in highp vec3 v_barycentricsB;\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.0005;\n" |
| " bool allOk = true;\n" |
| "\n" |
| " for (int sampleNdx = 0; sampleNdx < " << numTargetSamples << "; ++sampleNdx)\n" |
| " {\n" |
| " highp vec3 sampleA = interpolateAtSample(v_barycentricsA, sampleNdx);\n" |
| " highp vec3 sampleB = interpolateAtSample(v_barycentricsB, sampleNdx);\n" |
| " bool valuesEqual = all(lessThan(abs(sampleA - sampleB), vec3(threshold)));\n" |
| " if (!valuesEqual)\n" |
| " allOk = false;\n" |
| " }\n" |
| "\n" |
| " if (allOk)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| bool CentroidQualifierAtSampleCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| return verifyGreenImage(resultImage, m_testCtx.getLog()); |
| } |
| |
| class InterpolateAtSampleIDCase : public MultisampleShaderRenderUtil::MultisampleRenderCase |
| { |
| public: |
| InterpolateAtSampleIDCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); |
| virtual ~InterpolateAtSampleIDCase (void); |
| |
| void init (void); |
| private: |
| enum |
| { |
| RENDER_SIZE = 32 |
| }; |
| |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| }; |
| |
| InterpolateAtSampleIDCase::InterpolateAtSampleIDCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) |
| : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE) |
| { |
| } |
| |
| InterpolateAtSampleIDCase::~InterpolateAtSampleIDCase (void) |
| { |
| } |
| |
| void InterpolateAtSampleIDCase::init (void) |
| { |
| // requirements |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_variables extension"); |
| |
| // test purpose and expectations |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n" |
| << " Interpolate varying containing screen space location.\n" |
| << " => interpolateAtSample(varying, sampleID) = varying" |
| << tcu::TestLog::EndMessage; |
| |
| MultisampleShaderRenderUtil::MultisampleRenderCase::init(); |
| } |
| |
| std::string InterpolateAtSampleIDCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec4 a_position;\n" |
| "sample out highp vec2 v_screenPosition;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string InterpolateAtSampleIDCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SAMPLE_VARIABLES}" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "sample in highp vec2 v_screenPosition;\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) |
| "\n" |
| " highp vec2 offsetValue = interpolateAtSample(v_screenPosition, gl_SampleID);\n" |
| " highp vec2 refValue = v_screenPosition;\n" |
| "\n" |
| " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" |
| " if (valuesEqual)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| bool InterpolateAtSampleIDCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| return verifyGreenImage(resultImage, m_testCtx.getLog()); |
| } |
| |
| class InterpolateAtCentroidCase : public CentroidRenderCase |
| { |
| public: |
| enum TestType |
| { |
| TEST_CONSISTENCY = 0, |
| TEST_ARRAY_ELEMENT, |
| |
| TEST_LAST |
| }; |
| |
| InterpolateAtCentroidCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType type); |
| virtual ~InterpolateAtCentroidCase (void); |
| |
| void init (void); |
| |
| private: |
| enum |
| { |
| RENDER_SIZE = 128 |
| }; |
| |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| |
| const TestType m_type; |
| }; |
| |
| InterpolateAtCentroidCase::InterpolateAtCentroidCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType type) |
| : CentroidRenderCase (context, name, description, numSamples, target, RENDER_SIZE) |
| , m_type (type) |
| { |
| } |
| |
| InterpolateAtCentroidCase::~InterpolateAtCentroidCase (void) |
| { |
| } |
| |
| void InterpolateAtCentroidCase::init (void) |
| { |
| // test purpose and expectations |
| if (m_type == TEST_CONSISTENCY) |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid-qualified varying.\n" |
| << " Draw a fan of narrow triangles (large number of pixels on the edges).\n" |
| << " Set varyings 'barycentricsA' and 'barycentricsB' to contain barycentric coordinates.\n" |
| << " Add centroid-qualifier for barycentricsB.\n" |
| << " => interpolateAtCentroid(barycentricsA) ~= barycentricsB\n" |
| << tcu::TestLog::EndMessage; |
| } |
| else if (m_type == TEST_ARRAY_ELEMENT) |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Testing interpolateAtCentroid with element of array as an argument." |
| << tcu::TestLog::EndMessage; |
| } |
| else |
| DE_ASSERT(false); |
| |
| CentroidRenderCase::init(); |
| } |
| |
| std::string InterpolateAtCentroidCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| if (m_type == TEST_CONSISTENCY) |
| buf << "${GLSL_VERSION_DECL}\n" |
| "in highp vec4 a_position;\n" |
| "in highp vec4 a_barycentricsA;\n" |
| "in highp vec4 a_barycentricsB;\n" |
| "out highp vec3 v_barycentricsA;\n" |
| "centroid out highp vec3 v_barycentricsB;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_barycentricsA = a_barycentricsA.xyz;\n" |
| " v_barycentricsB = a_barycentricsB.xyz;\n" |
| "}\n"; |
| else if (m_type == TEST_ARRAY_ELEMENT) |
| buf << "${GLSL_VERSION_DECL}\n" |
| "in highp vec4 a_position;\n" |
| "in highp vec4 a_barycentricsA;\n" |
| "in highp vec4 a_barycentricsB;\n" |
| "out highp vec3[2] v_barycentrics;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_barycentrics[0] = a_barycentricsA.xyz;\n" |
| " v_barycentrics[1] = a_barycentricsB.xyz;\n" |
| "}\n"; |
| else |
| DE_ASSERT(false); |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string InterpolateAtCentroidCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| if (m_type == TEST_CONSISTENCY) |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec3 v_barycentricsA;\n" |
| "centroid in highp vec3 v_barycentricsB;\n" |
| "layout(location = 0) out highp vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.0005;\n" |
| "\n" |
| " highp vec3 centroidASampled = interpolateAtCentroid(v_barycentricsA);\n" |
| " bool valuesEqual = all(lessThan(abs(centroidASampled - v_barycentricsB), vec3(threshold)));\n" |
| " bool centroidAIsInvalid = any(greaterThan(centroidASampled, vec3(1.0))) ||\n" |
| " any(lessThan(centroidASampled, vec3(0.0)));\n" |
| " bool centroidBIsInvalid = any(greaterThan(v_barycentricsB, vec3(1.0))) ||\n" |
| " any(lessThan(v_barycentricsB, vec3(0.0)));\n" |
| "\n" |
| " if (valuesEqual && !centroidAIsInvalid && !centroidBIsInvalid)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else if (centroidAIsInvalid || centroidBIsInvalid)\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n" |
| "}\n"; |
| else if (m_type == TEST_ARRAY_ELEMENT) |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec3[2] v_barycentrics;\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.0005;\n" |
| "\n" |
| " highp vec3 centroidInterpolated = interpolateAtCentroid(v_barycentrics[1]);\n" |
| " bool centroidIsInvalid = any(greaterThan(centroidInterpolated, vec3(1.0))) ||\n" |
| " any(lessThan(centroidInterpolated, vec3(0.0)));\n" |
| "\n" |
| " if (!centroidIsInvalid)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| else |
| DE_ASSERT(false); |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| bool InterpolateAtCentroidCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| return verifyGreenImage(resultImage, m_testCtx.getLog()); |
| } |
| |
| class InterpolateAtOffsetCase : public MultisampleShaderRenderUtil::MultisampleRenderCase |
| { |
| public: |
| enum TestType |
| { |
| TEST_QUALIFIER_NONE = 0, |
| TEST_QUALIFIER_CENTROID, |
| TEST_QUALIFIER_SAMPLE, |
| TEST_ARRAY_ELEMENT, |
| |
| TEST_LAST |
| }; |
| InterpolateAtOffsetCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType testType); |
| virtual ~InterpolateAtOffsetCase (void); |
| |
| void init (void); |
| private: |
| enum |
| { |
| RENDER_SIZE = 32 |
| }; |
| |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| |
| const TestType m_testType; |
| }; |
| |
| InterpolateAtOffsetCase::InterpolateAtOffsetCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target, TestType testType) |
| : MultisampleShaderRenderUtil::MultisampleRenderCase (context, name, description, numSamples, target, RENDER_SIZE) |
| , m_testType (testType) |
| { |
| DE_ASSERT(testType < TEST_LAST); |
| } |
| |
| InterpolateAtOffsetCase::~InterpolateAtOffsetCase (void) |
| { |
| } |
| |
| void InterpolateAtOffsetCase::init (void) |
| { |
| // requirements |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| |
| // test purpose and expectations |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that interpolateAtOffset returns correct values.\n" |
| << " Interpolate varying containing screen space location.\n" |
| << " => interpolateAtOffset(varying, offset) should be \"varying value at the pixel center\" + offset" |
| << tcu::TestLog::EndMessage; |
| |
| MultisampleShaderRenderUtil::MultisampleRenderCase::init(); |
| } |
| |
| std::string InterpolateAtOffsetCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| buf << "${GLSL_VERSION_DECL}\n" |
| << "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| << "in highp vec4 a_position;\n"; |
| |
| if (m_testType == TEST_QUALIFIER_NONE || m_testType == TEST_QUALIFIER_CENTROID || m_testType == TEST_QUALIFIER_SAMPLE) |
| { |
| const char* const qualifier = (m_testType == TEST_QUALIFIER_CENTROID) ? ("centroid ") : (m_testType == TEST_QUALIFIER_SAMPLE) ? ("sample ") : (""); |
| buf << qualifier << "out highp vec2 v_screenPosition;\n" |
| << qualifier << "out highp vec2 v_offset;\n"; |
| } |
| else if (m_testType == TEST_ARRAY_ELEMENT) |
| { |
| buf << "out highp vec2[2] v_screenPosition;\n" |
| << "out highp vec2 v_offset;\n"; |
| } |
| else |
| DE_ASSERT(false); |
| |
| buf << "void main (void)\n" |
| << "{\n" |
| << " gl_Position = a_position;\n"; |
| |
| if (m_testType != TEST_ARRAY_ELEMENT) |
| buf << " v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"; |
| else |
| buf << " v_screenPosition[0] = a_position.xy; // not used\n" |
| " v_screenPosition[1] = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n"; |
| |
| buf << " v_offset = a_position.xy * 0.5f;\n" |
| << "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string InterpolateAtOffsetCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| const char* const arrayIndexing = (m_testType == TEST_ARRAY_ELEMENT) ? ("[1]") : (""); |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}"; |
| |
| if (m_testType == TEST_QUALIFIER_NONE || m_testType == TEST_QUALIFIER_CENTROID || m_testType == TEST_QUALIFIER_SAMPLE) |
| { |
| const char* const qualifier = (m_testType == TEST_QUALIFIER_CENTROID) ? ("centroid ") : (m_testType == TEST_QUALIFIER_SAMPLE) ? ("sample ") : (""); |
| buf << qualifier << "in highp vec2 v_screenPosition;\n" |
| << qualifier << "in highp vec2 v_offset;\n"; |
| } |
| else if (m_testType == TEST_ARRAY_ELEMENT) |
| { |
| buf << "in highp vec2[2] v_screenPosition;\n" |
| << "in highp vec2 v_offset;\n"; |
| } |
| else |
| DE_ASSERT(false); |
| |
| buf << "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) |
| "\n" |
| " highp vec2 pixelCenter = floor(v_screenPosition" << arrayIndexing << ") + vec2(0.5, 0.5);\n" |
| " highp vec2 offsetValue = interpolateAtOffset(v_screenPosition" << arrayIndexing << ", v_offset);\n" |
| " highp vec2 refValue = pixelCenter + v_offset;\n" |
| "\n" |
| " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" |
| " if (valuesEqual)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| bool InterpolateAtOffsetCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| return verifyGreenImage(resultImage, m_testCtx.getLog()); |
| } |
| |
| class InterpolateAtSamplePositionCase : public MultisampleShaderRenderUtil::MultisampleRenderCase |
| { |
| public: |
| InterpolateAtSamplePositionCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target); |
| virtual ~InterpolateAtSamplePositionCase (void); |
| |
| void init (void); |
| private: |
| enum |
| { |
| RENDER_SIZE = 32 |
| }; |
| |
| std::string genVertexSource (int numTargetSamples) const; |
| std::string genFragmentSource (int numTargetSamples) const; |
| bool verifyImage (const tcu::Surface& resultImage); |
| }; |
| |
| InterpolateAtSamplePositionCase::InterpolateAtSamplePositionCase (Context& context, const char* name, const char* description, int numSamples, RenderTarget target) |
| : MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, description, numSamples, target, RENDER_SIZE) |
| { |
| } |
| |
| InterpolateAtSamplePositionCase::~InterpolateAtSamplePositionCase (void) |
| { |
| } |
| |
| void InterpolateAtSamplePositionCase::init (void) |
| { |
| // requirements |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_sample_variables extension"); |
| |
| // test purpose and expectations |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying that interpolateAtOffset with the offset of current sample position returns consistent values.\n" |
| << " Interpolate varying containing screen space location.\n" |
| << " => interpolateAtOffset(varying, currentOffset) = varying" |
| << tcu::TestLog::EndMessage; |
| |
| MultisampleShaderRenderUtil::MultisampleRenderCase::init(); |
| } |
| |
| std::string InterpolateAtSamplePositionCase::genVertexSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "in highp vec4 a_position;\n" |
| "sample out highp vec2 v_screenPosition;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_screenPosition = (a_position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(" << (int)RENDER_SIZE << ".0, " << (int)RENDER_SIZE << ".0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| std::string InterpolateAtSamplePositionCase::genFragmentSource (int numTargetSamples) const |
| { |
| DE_UNREF(numTargetSamples); |
| |
| std::ostringstream buf; |
| |
| buf << "${GLSL_VERSION_DECL}\n" |
| "${GLSL_EXT_SAMPLE_VARIABLES}" |
| "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| "sample in highp vec2 v_screenPosition;\n" |
| "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE) |
| "\n" |
| " highp vec2 offset = gl_SamplePosition - vec2(0.5, 0.5);\n" |
| " highp vec2 offsetValue = interpolateAtOffset(v_screenPosition, offset);\n" |
| " highp vec2 refValue = v_screenPosition;\n" |
| "\n" |
| " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" |
| " if (valuesEqual)\n" |
| " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else\n" |
| " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| bool InterpolateAtSamplePositionCase::verifyImage (const tcu::Surface& resultImage) |
| { |
| return verifyGreenImage(resultImage, m_testCtx.getLog()); |
| } |
| |
| class NegativeCompileInterpolationCase : public TestCase |
| { |
| public: |
| enum CaseType |
| { |
| CASE_VEC4_IDENTITY_SWIZZLE = 0, |
| CASE_VEC4_CROP_SWIZZLE, |
| CASE_VEC4_MIXED_SWIZZLE, |
| CASE_INTERPOLATE_IVEC4, |
| CASE_INTERPOLATE_UVEC4, |
| CASE_INTERPOLATE_ARRAY, |
| CASE_INTERPOLATE_STRUCT, |
| CASE_INTERPOLATE_STRUCT_MEMBER, |
| CASE_INTERPOLATE_LOCAL, |
| CASE_INTERPOLATE_GLOBAL, |
| CASE_INTERPOLATE_CONSTANT, |
| |
| CASE_LAST |
| }; |
| enum InterpolatorType |
| { |
| INTERPOLATE_AT_SAMPLE = 0, |
| INTERPOLATE_AT_CENTROID, |
| INTERPOLATE_AT_OFFSET, |
| |
| INTERPOLATE_LAST |
| }; |
| |
| NegativeCompileInterpolationCase (Context& context, const char* name, const char* description, CaseType caseType, InterpolatorType interpolator); |
| |
| private: |
| void init (void); |
| IterateResult iterate (void); |
| |
| std::string genShaderSource (void) const; |
| |
| const CaseType m_caseType; |
| const InterpolatorType m_interpolation; |
| }; |
| |
| NegativeCompileInterpolationCase::NegativeCompileInterpolationCase (Context& context, const char* name, const char* description, CaseType caseType, InterpolatorType interpolator) |
| : TestCase (context, name, description) |
| , m_caseType (caseType) |
| , m_interpolation (interpolator) |
| { |
| DE_ASSERT(m_caseType < CASE_LAST); |
| DE_ASSERT(m_interpolation < INTERPOLATE_LAST); |
| } |
| |
| void NegativeCompileInterpolationCase::init (void) |
| { |
| if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) |
| TCU_THROW(NotSupportedError, "Test requires GL_OES_shader_multisample_interpolation extension"); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "Trying to compile illegal shader, expecting compile to fail." << tcu::TestLog::EndMessage; |
| } |
| |
| NegativeCompileInterpolationCase::IterateResult NegativeCompileInterpolationCase::iterate (void) |
| { |
| const std::string source = genShaderSource(); |
| glu::Shader shader (m_context.getRenderContext(), glu::SHADERTYPE_FRAGMENT); |
| const char* const sourceStrPtr = source.c_str(); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Fragment shader source:" |
| << tcu::TestLog::EndMessage |
| << tcu::TestLog::KernelSource(source); |
| |
| shader.setSources(1, &sourceStrPtr, DE_NULL); |
| shader.compile(); |
| |
| m_testCtx.getLog() << tcu::TestLog::Message |
| << "Info log:" |
| << tcu::TestLog::EndMessage |
| << tcu::TestLog::KernelSource(shader.getInfoLog()); |
| |
| if (shader.getCompileStatus()) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "ERROR: Illegal shader compiled successfully." << tcu::TestLog::EndMessage; |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected compile status"); |
| } |
| else |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Compile failed as expected." << tcu::TestLog::EndMessage; |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| return STOP; |
| } |
| |
| std::string NegativeCompileInterpolationCase::genShaderSource (void) const |
| { |
| std::ostringstream buf; |
| std::string interpolation; |
| const char* interpolationTemplate; |
| const char* description; |
| const char* globalDeclarations = ""; |
| const char* localDeclarations = ""; |
| const char* interpolationTarget = ""; |
| const char* postSelector = ""; |
| |
| switch (m_caseType) |
| { |
| case CASE_VEC4_IDENTITY_SWIZZLE: |
| globalDeclarations = "in highp vec4 v_var;\n"; |
| interpolationTarget = "v_var.xyzw"; |
| description = "component selection is illegal"; |
| break; |
| |
| case CASE_VEC4_CROP_SWIZZLE: |
| globalDeclarations = "in highp vec4 v_var;\n"; |
| interpolationTarget = "v_var.xy"; |
| postSelector = ".x"; |
| description = "component selection is illegal"; |
| break; |
| |
| case CASE_VEC4_MIXED_SWIZZLE: |
| globalDeclarations = "in highp vec4 v_var;\n"; |
| interpolationTarget = "v_var.yzxw"; |
| description = "component selection is illegal"; |
| break; |
| |
| case CASE_INTERPOLATE_IVEC4: |
| globalDeclarations = "flat in highp ivec4 v_var;\n"; |
| interpolationTarget = "v_var"; |
| description = "no overload for ivec"; |
| break; |
| |
| case CASE_INTERPOLATE_UVEC4: |
| globalDeclarations = "flat in highp uvec4 v_var;\n"; |
| interpolationTarget = "v_var"; |
| description = "no overload for uvec"; |
| break; |
| |
| case CASE_INTERPOLATE_ARRAY: |
| globalDeclarations = "in highp float v_var[2];\n"; |
| interpolationTarget = "v_var"; |
| postSelector = "[1]"; |
| description = "no overload for arrays"; |
| break; |
| |
| case CASE_INTERPOLATE_STRUCT: |
| case CASE_INTERPOLATE_STRUCT_MEMBER: |
| globalDeclarations = "struct S\n" |
| "{\n" |
| " highp float a;\n" |
| " highp float b;\n" |
| "};\n" |
| "in S v_var;\n"; |
| |
| interpolationTarget = (m_caseType == CASE_INTERPOLATE_STRUCT) ? ("v_var") : ("v_var.a"); |
| postSelector = (m_caseType == CASE_INTERPOLATE_STRUCT) ? (".a") : (""); |
| description = (m_caseType == CASE_INTERPOLATE_STRUCT) ? ("no overload for this type") : ("<interpolant> is not an input variable (just a member of)"); |
| break; |
| |
| case CASE_INTERPOLATE_LOCAL: |
| localDeclarations = " highp vec4 local_var = gl_FragCoord;\n"; |
| interpolationTarget = "local_var"; |
| description = "<interpolant> is not an input variable"; |
| break; |
| |
| case CASE_INTERPOLATE_GLOBAL: |
| globalDeclarations = "highp vec4 global_var;\n"; |
| localDeclarations = " global_var = gl_FragCoord;\n"; |
| interpolationTarget = "global_var"; |
| description = "<interpolant> is not an input variable"; |
| break; |
| |
| case CASE_INTERPOLATE_CONSTANT: |
| globalDeclarations = "const highp vec4 const_var = vec4(0.2);\n"; |
| interpolationTarget = "const_var"; |
| description = "<interpolant> is not an input variable"; |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| return ""; |
| } |
| |
| switch (m_interpolation) |
| { |
| case INTERPOLATE_AT_SAMPLE: |
| interpolationTemplate = "interpolateAtSample(${TARGET}, 0)${POST_SELECTOR}"; |
| break; |
| |
| case INTERPOLATE_AT_CENTROID: |
| interpolationTemplate = "interpolateAtCentroid(${TARGET})${POST_SELECTOR}"; |
| break; |
| |
| case INTERPOLATE_AT_OFFSET: |
| interpolationTemplate = "interpolateAtOffset(${TARGET}, vec2(0.2, 0.2))${POST_SELECTOR}"; |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| return ""; |
| } |
| |
| { |
| std::map<std::string, std::string> args; |
| args["TARGET"] = interpolationTarget; |
| args["POST_SELECTOR"] = postSelector; |
| |
| interpolation = tcu::StringTemplate(interpolationTemplate).specialize(args); |
| } |
| |
| buf << glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType())) << "\n" |
| << "${GLSL_EXT_SHADER_MULTISAMPLE_INTERPOLATION}" |
| << globalDeclarations |
| << "layout(location = 0) out mediump vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| << localDeclarations |
| << " fragColor = vec4(" << interpolation << "); // " << description << "\n" |
| "}\n"; |
| |
| return specializeShader(buf.str(), m_context.getRenderContext().getType()); |
| } |
| |
| } // anonymous |
| |
| ShaderMultisampleInterpolationTests::ShaderMultisampleInterpolationTests (Context& context) |
| : TestCaseGroup(context, "multisample_interpolation", "Test multisample interpolation") |
| { |
| } |
| |
| ShaderMultisampleInterpolationTests::~ShaderMultisampleInterpolationTests (void) |
| { |
| } |
| |
| void ShaderMultisampleInterpolationTests::init (void) |
| { |
| using namespace MultisampleShaderRenderUtil; |
| |
| static const struct RenderTarget |
| { |
| const char* name; |
| const char* desc; |
| int numSamples; |
| MultisampleRenderCase::RenderTarget target; |
| } targets[] = |
| { |
| { "default_framebuffer", "Test with default framebuffer", 0, MultisampleRenderCase::TARGET_DEFAULT }, |
| { "singlesample_texture", "Test with singlesample texture", 0, MultisampleRenderCase::TARGET_TEXTURE }, |
| { "multisample_texture_1", "Test with multisample texture", 1, MultisampleRenderCase::TARGET_TEXTURE }, |
| { "multisample_texture_2", "Test with multisample texture", 2, MultisampleRenderCase::TARGET_TEXTURE }, |
| { "multisample_texture_4", "Test with multisample texture", 4, MultisampleRenderCase::TARGET_TEXTURE }, |
| { "multisample_texture_8", "Test with multisample texture", 8, MultisampleRenderCase::TARGET_TEXTURE }, |
| { "multisample_texture_16", "Test with multisample texture", 16, MultisampleRenderCase::TARGET_TEXTURE }, |
| { "singlesample_rbo", "Test with singlesample rbo", 0, MultisampleRenderCase::TARGET_RENDERBUFFER }, |
| { "multisample_rbo_1", "Test with multisample rbo", 1, MultisampleRenderCase::TARGET_RENDERBUFFER }, |
| { "multisample_rbo_2", "Test with multisample rbo", 2, MultisampleRenderCase::TARGET_RENDERBUFFER }, |
| { "multisample_rbo_4", "Test with multisample rbo", 4, MultisampleRenderCase::TARGET_RENDERBUFFER }, |
| { "multisample_rbo_8", "Test with multisample rbo", 8, MultisampleRenderCase::TARGET_RENDERBUFFER }, |
| { "multisample_rbo_16", "Test with multisample rbo", 16, MultisampleRenderCase::TARGET_RENDERBUFFER }, |
| }; |
| |
| static const struct |
| { |
| const char* name; |
| const char* description; |
| NegativeCompileInterpolationCase::CaseType caseType; |
| } negativeCompileCases[] = |
| { |
| { "vec4_identity_swizzle", "use identity swizzle", NegativeCompileInterpolationCase::CASE_VEC4_IDENTITY_SWIZZLE }, |
| { "vec4_crop_swizzle", "use cropped identity swizzle", NegativeCompileInterpolationCase::CASE_VEC4_CROP_SWIZZLE }, |
| { "vec4_mixed_swizzle", "use swizzle", NegativeCompileInterpolationCase::CASE_VEC4_MIXED_SWIZZLE }, |
| { "interpolate_ivec4", "interpolate integer variable", NegativeCompileInterpolationCase::CASE_INTERPOLATE_IVEC4 }, |
| { "interpolate_uvec4", "interpolate integer variable", NegativeCompileInterpolationCase::CASE_INTERPOLATE_UVEC4 }, |
| { "interpolate_array", "interpolate whole array", NegativeCompileInterpolationCase::CASE_INTERPOLATE_ARRAY }, |
| { "interpolate_struct", "interpolate whole struct", NegativeCompileInterpolationCase::CASE_INTERPOLATE_STRUCT }, |
| { "interpolate_struct_member", "interpolate struct member", NegativeCompileInterpolationCase::CASE_INTERPOLATE_STRUCT_MEMBER }, |
| { "interpolate_local", "interpolate local variable", NegativeCompileInterpolationCase::CASE_INTERPOLATE_LOCAL }, |
| { "interpolate_global", "interpolate global variable", NegativeCompileInterpolationCase::CASE_INTERPOLATE_GLOBAL }, |
| { "interpolate_constant", "interpolate constant variable", NegativeCompileInterpolationCase::CASE_INTERPOLATE_CONSTANT }, |
| }; |
| |
| // .sample_qualifier |
| { |
| tcu::TestCaseGroup* const sampleQualifierGroup = new tcu::TestCaseGroup(m_testCtx, "sample_qualifier", "Test sample qualifier"); |
| addChild(sampleQualifierGroup); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| sampleQualifierGroup->addChild(new SampleQualifierRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); |
| } |
| |
| // .interpolate_at_sample |
| { |
| tcu::TestCaseGroup* const interpolateAtSampleGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_sample", "Test interpolateAtSample"); |
| addChild(interpolateAtSampleGroup); |
| |
| // .static_sample_number |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "static_sample_number", "Test interpolateAtSample sample number"); |
| interpolateAtSampleGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtSampleRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtSampleRenderCase::INDEXING_STATIC)); |
| } |
| |
| // .dynamic_sample_number |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "dynamic_sample_number", "Test interpolateAtSample sample number"); |
| interpolateAtSampleGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtSampleRenderCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtSampleRenderCase::INDEXING_DYNAMIC)); |
| } |
| |
| // .non_multisample_buffer |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "non_multisample_buffer", "Test interpolateAtSample with non-multisample buffers"); |
| interpolateAtSampleGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| if (targets[targetNdx].numSamples == 0) |
| group->addChild(new SingleSampleInterpolateAtSampleCase(m_context, std::string("sample_0_").append(targets[targetNdx].name).c_str(), targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SingleSampleInterpolateAtSampleCase::SAMPLE_0)); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| if (targets[targetNdx].numSamples == 0) |
| group->addChild(new SingleSampleInterpolateAtSampleCase(m_context, std::string("sample_n_").append(targets[targetNdx].name).c_str(), targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SingleSampleInterpolateAtSampleCase::SAMPLE_N)); |
| } |
| |
| // .centroid_qualifier |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "centroid_qualified", "Test interpolateAtSample with centroid qualified varying"); |
| interpolateAtSampleGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new CentroidQualifierAtSampleCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); |
| } |
| |
| // .at_sample_id |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "at_sample_id", "Test interpolateAtSample at current sample id"); |
| interpolateAtSampleGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtSampleIDCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); |
| } |
| |
| // .negative |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "negative", "interpolateAtSample negative tests"); |
| interpolateAtSampleGroup->addChild(group); |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(negativeCompileCases); ++ndx) |
| group->addChild(new NegativeCompileInterpolationCase(m_context, |
| negativeCompileCases[ndx].name, |
| negativeCompileCases[ndx].description, |
| negativeCompileCases[ndx].caseType, |
| NegativeCompileInterpolationCase::INTERPOLATE_AT_SAMPLE)); |
| } |
| } |
| |
| // .interpolate_at_centroid |
| { |
| tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_centroid", "Test interpolateAtCentroid"); |
| addChild(methodGroup); |
| |
| // .consistency |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "consistency", "Test interpolateAtCentroid return value is consistent to centroid qualified value"); |
| methodGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtCentroidCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtCentroidCase::TEST_CONSISTENCY)); |
| } |
| |
| // .array_element |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array_element", "Test interpolateAtCentroid with array element"); |
| methodGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtCentroidCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtCentroidCase::TEST_ARRAY_ELEMENT)); |
| } |
| |
| // .negative |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "negative", "interpolateAtCentroid negative tests"); |
| methodGroup->addChild(group); |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(negativeCompileCases); ++ndx) |
| group->addChild(new NegativeCompileInterpolationCase(m_context, |
| negativeCompileCases[ndx].name, |
| negativeCompileCases[ndx].description, |
| negativeCompileCases[ndx].caseType, |
| NegativeCompileInterpolationCase::INTERPOLATE_AT_CENTROID)); |
| } |
| } |
| |
| // .interpolate_at_offset |
| { |
| static const struct TestConfig |
| { |
| const char* name; |
| InterpolateAtOffsetCase::TestType type; |
| } configs[] = |
| { |
| { "no_qualifiers", InterpolateAtOffsetCase::TEST_QUALIFIER_NONE }, |
| { "centroid_qualifier", InterpolateAtOffsetCase::TEST_QUALIFIER_CENTROID }, |
| { "sample_qualifier", InterpolateAtOffsetCase::TEST_QUALIFIER_SAMPLE }, |
| }; |
| |
| tcu::TestCaseGroup* const methodGroup = new tcu::TestCaseGroup(m_testCtx, "interpolate_at_offset", "Test interpolateAtOffset"); |
| addChild(methodGroup); |
| |
| // .no_qualifiers |
| // .centroid_qualifier |
| // .sample_qualifier |
| for (int configNdx = 0; configNdx < DE_LENGTH_OF_ARRAY(configs); ++configNdx) |
| { |
| tcu::TestCaseGroup* const qualifierGroup = new tcu::TestCaseGroup(m_testCtx, configs[configNdx].name, "Test interpolateAtOffset with qualified/non-qualified varying"); |
| methodGroup->addChild(qualifierGroup); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| qualifierGroup->addChild(new InterpolateAtOffsetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, configs[configNdx].type)); |
| } |
| |
| // .at_sample_position |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "at_sample_position", "Test interpolateAtOffset at sample position"); |
| methodGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtSamplePositionCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target)); |
| } |
| |
| // .array_element |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "array_element", "Test interpolateAtOffset with array element"); |
| methodGroup->addChild(group); |
| |
| for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx) |
| group->addChild(new InterpolateAtOffsetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, InterpolateAtOffsetCase::TEST_ARRAY_ELEMENT)); |
| } |
| |
| // .negative |
| { |
| tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "negative", "interpolateAtOffset negative tests"); |
| methodGroup->addChild(group); |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(negativeCompileCases); ++ndx) |
| group->addChild(new NegativeCompileInterpolationCase(m_context, |
| negativeCompileCases[ndx].name, |
| negativeCompileCases[ndx].description, |
| negativeCompileCases[ndx].caseType, |
| NegativeCompileInterpolationCase::INTERPOLATE_AT_OFFSET)); |
| } |
| } |
| } |
| |
| } // Functional |
| } // gles31 |
| } // deqp |