/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 2.0 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 Algorithm implementation tests. *//*--------------------------------------------------------------------*/ #include "es2fShaderAlgorithmTests.hpp" #include "glsShaderRenderCase.hpp" #include "gluShaderUtil.hpp" #include "tcuStringTemplate.hpp" #include "deInt32.h" #include "deMemory.h" #include <map> #include <algorithm> using namespace std; using namespace tcu; using namespace glu; using namespace deqp::gls; namespace deqp { namespace gles2 { namespace Functional { // ShaderAlgorithmCase class ShaderAlgorithmCase : public ShaderRenderCase { public: ShaderAlgorithmCase (Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource); virtual ~ShaderAlgorithmCase (void); private: ShaderAlgorithmCase (const ShaderAlgorithmCase&); // not allowed! ShaderAlgorithmCase& operator= (const ShaderAlgorithmCase&); // not allowed! }; ShaderAlgorithmCase::ShaderAlgorithmCase (Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource) : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc) { m_vertShaderSource = vertShaderSource; m_fragShaderSource = fragShaderSource; } ShaderAlgorithmCase::~ShaderAlgorithmCase (void) { } // Helpers. static ShaderAlgorithmCase* createExpressionCase (Context& context, const char* caseName, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, LineStream& shaderBody) { std::ostringstream vtx; std::ostringstream frag; std::ostringstream& op = isVertexCase ? vtx : frag; vtx << "attribute highp vec4 a_position;\n"; vtx << "attribute highp vec4 a_unitCoords;\n"; if (isVertexCase) { vtx << "varying mediump vec3 v_color;\n"; frag << "varying mediump vec3 v_color;\n"; } else { vtx << "varying mediump vec4 v_coords;\n"; frag << "varying mediump vec4 v_coords;\n"; } // op << "uniform mediump sampler2D ut_brick;\n"; vtx << "\n"; vtx << "void main()\n"; vtx << "{\n"; vtx << " gl_Position = a_position;\n"; frag << "\n"; frag << "void main()\n"; frag << "{\n"; // Write matrix. if (isVertexCase) op << " ${PRECISION} vec4 coords = a_unitCoords;\n"; else op << " ${PRECISION} vec4 coords = v_coords;\n"; op << " ${PRECISION} vec3 res = vec3(0.0);\n"; op << shaderBody.str(); if (isVertexCase) { vtx << " v_color = res;\n"; frag << " gl_FragColor = vec4(v_color, 1.0);\n"; } else { vtx << " v_coords = a_unitCoords;\n"; frag << " gl_FragColor = vec4(res, 1.0);\n"; } vtx << "}\n"; frag << "}\n"; // Fill in shader templates. map<string, string> params; params.insert(pair<string, string>("PRECISION", "mediump")); StringTemplate vertTemplate(vtx.str().c_str()); StringTemplate fragTemplate(frag.str().c_str()); string vertexShaderSource = vertTemplate.specialize(params); string fragmentShaderSource = fragTemplate.specialize(params); return new ShaderAlgorithmCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(), fragmentShaderSource.c_str()); } // ShaderAlgorithmTests. ShaderAlgorithmTests::ShaderAlgorithmTests(Context& context) : TestCaseGroup(context, "algorithm", "Miscellaneous algorithm implementations using shaders.") { } ShaderAlgorithmTests::~ShaderAlgorithmTests (void) { } void ShaderAlgorithmTests::init (void) { // TestCaseGroup* colorGroup = new TestCaseGroup(m_testCtx, "color", "Miscellaneous color related algorithm tests."); // addChild(colorGroup); #define SHADER_OP_CASE(NAME, DESCRIPTION, SHADER_OP, EVAL_FUNC_BODY) \ do { \ struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY }; /* NOLINT(EVAL_FUNC_BODY) */ \ addChild(createExpressionCase(m_context, #NAME "_vertex", DESCRIPTION, true, &Eval_##NAME::eval, SHADER_OP)); \ addChild(createExpressionCase(m_context, #NAME "_fragment", DESCRIPTION, false, &Eval_##NAME::eval, SHADER_OP)); \ } while (deGetFalse()) SHADER_OP_CASE(hsl_to_rgb, "Conversion from HSL color space into RGB.", LineStream(1) << "mediump float H = coords.x, S = coords.y, L = coords.z;" << "mediump float v = (L <= 0.5) ? (L * (1.0 + S)) : (L + S - L * S);" << "res = vec3(L); // default to gray" << "if (v > 0.0)" << "{" << " mediump float m = L + L - v;" << " mediump float sv = (v - m) / v;" << " H *= 6.0;" << " mediump int sextant = int(H);" << " mediump float fract = H - float(sextant);" << " mediump float vsf = v * sv * fract;" << " mediump float mid1 = m + vsf;" << " mediump float mid2 = m - vsf;" << " if (sextant == 0) res = vec3(v, mid1, m);" << " else if (sextant == 1) res = vec3(mid2, v, m);" << " else if (sextant == 2) res = vec3(m, v, mid1);" << " else if (sextant == 3) res = vec3(m, mid2, v);" << " else if (sextant == 4) res = vec3(mid1, m, v);" << " else res = vec3(v, m, mid2);" << "}", { float H = c.unitCoords.x(); float S = c.unitCoords.y(); float L = c.unitCoords.z(); Vec3 rgb = Vec3(L); float v = (L <= 0.5f) ? (L * (1.0f + S)) : (L + S - L * S); if (v > 0.0f) { float m = L + L - v; float sv = (v - m) / v; H *= 6.0f; int sextant = int(H); float fract = H - float(sextant); float vsf = v * sv * fract; float mid1 = m + vsf; float mid2 = m - vsf; if (sextant == 0) rgb = Vec3(v, mid1, m); else if (sextant == 1) rgb = Vec3(mid2, v, m); else if (sextant == 2) rgb = Vec3(m, v, mid1); else if (sextant == 3) rgb = Vec3(m, mid2, v); else if (sextant == 4) rgb = Vec3(mid1, m, v); else rgb = Vec3(v, m, mid2); } c.color.xyz() = rgb; }); SHADER_OP_CASE(rgb_to_hsl, "Conversion from RGB color space into HSL.", LineStream(1) << "mediump float r = coords.x, g = coords.y, b = coords.z;" << "mediump float minVal = min(min(r, g), b);" << "mediump float maxVal = max(max(r, g), b);" << "mediump float L = (minVal + maxVal) * 0.5;" << "if (minVal == maxVal)" << " res = vec3(0.0, 0.0, L);" << "else" << "{" << " mediump float H;" << " mediump float S;" << " if (L < 0.5)" << " S = (maxVal - minVal) / (maxVal + minVal);" << " else" << " S = (maxVal - minVal) / (2.0 - maxVal - minVal);" << "" << " mediump float ooDiff = 1.0 / (maxVal - minVal);" << " if (r == maxVal) H = (g - b) * ooDiff;" << " else if (g == maxVal) H = 2.0 + (b - r) * ooDiff;" << " else H = 4.0 + (r - g) * ooDiff;" << " H /= 6.0;" << "" << " res = vec3(H, S, L);" << "}", { float r = c.unitCoords.x(); float g = c.unitCoords.y(); float b = c.unitCoords.z(); float minVal = min(min(r, g), b); float maxVal = max(max(r, g), b); float L = (minVal + maxVal) * 0.5f; Vec3 hsl; if (minVal == maxVal) hsl = Vec3(0.0f, 0.0f, L); else { float H; float S; if (L < 0.5f) S = (maxVal - minVal) / (maxVal + minVal); else S = (maxVal - minVal) / (2.0f - maxVal - minVal); float ooDiff = 1.0f / (maxVal - minVal); if (r == maxVal) H = (g - b) * ooDiff; else if (g == maxVal) H = 2.0f + (b - r) * ooDiff; else H = 4.0f + (r - g) * ooDiff; H /= 6.0f; hsl = Vec3(H, S, L); } c.color.xyz() = hsl; }); /* SHADER_OP_CASE(image_to_grayscale, "Convert image to grayscale.", LineStream(1) << "res = texture2D(ut_brick, coords.xy).rgb;", { c.color.xyz() = Vec3(0.5f); });*/ } } // Functional } // gles2 } // deqp