| /*------------------------------------------------------------------------- | 
 |  * drawElements Quality Program OpenGL ES 3.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 Shader discard statement tests. | 
 |  *//*--------------------------------------------------------------------*/ | 
 |  | 
 | #include "es3fShaderDiscardTests.hpp" | 
 | #include "glsShaderRenderCase.hpp" | 
 | #include "tcuStringTemplate.hpp" | 
 | #include "gluTexture.hpp" | 
 |  | 
 | #include <map> | 
 | #include <sstream> | 
 | #include <string> | 
 |  | 
 | #include "glwEnums.hpp" | 
 | #include "glwFunctions.hpp" | 
 |  | 
 | using tcu::StringTemplate; | 
 |  | 
 | using std::map; | 
 | using std::ostringstream; | 
 | using std::string; | 
 |  | 
 | using namespace glu; | 
 | using namespace deqp::gls; | 
 |  | 
 | namespace deqp | 
 | { | 
 | namespace gles3 | 
 | { | 
 | namespace Functional | 
 | { | 
 |  | 
 | class ShaderDiscardCase : public ShaderRenderCase | 
 | { | 
 | public: | 
 |     ShaderDiscardCase(Context &context, const char *name, const char *description, const char *shaderSource, | 
 |                       ShaderEvalFunc evalFunc, bool usesTexture); | 
 |     virtual ~ShaderDiscardCase(void); | 
 |  | 
 |     void init(void); | 
 |     void deinit(void); | 
 |  | 
 |     void setupUniforms(int programID, const tcu::Vec4 &constCoords); | 
 |  | 
 | private: | 
 |     bool m_usesTexture; | 
 |     glu::Texture2D *m_brickTexture; | 
 | }; | 
 |  | 
 | ShaderDiscardCase::ShaderDiscardCase(Context &context, const char *name, const char *description, | 
 |                                      const char *shaderSource, ShaderEvalFunc evalFunc, bool usesTexture) | 
 |     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, | 
 |                        description, false, evalFunc) | 
 |     , m_usesTexture(usesTexture) | 
 |     , m_brickTexture(DE_NULL) | 
 | { | 
 |     m_fragShaderSource = shaderSource; | 
 |     m_vertShaderSource = "#version 300 es\n" | 
 |                          "in  highp   vec4 a_position;\n" | 
 |                          "in  highp   vec4 a_coords;\n" | 
 |                          "out mediump vec4 v_color;\n" | 
 |                          "out mediump vec4 v_coords;\n\n" | 
 |                          "void main (void)\n" | 
 |                          "{\n" | 
 |                          "    gl_Position = a_position;\n" | 
 |                          "    v_color = vec4(a_coords.xyz, 1.0);\n" | 
 |                          "    v_coords = a_coords;\n" | 
 |                          "}\n"; | 
 | } | 
 |  | 
 | ShaderDiscardCase::~ShaderDiscardCase(void) | 
 | { | 
 |     delete m_brickTexture; | 
 | } | 
 |  | 
 | void ShaderDiscardCase::init(void) | 
 | { | 
 |     if (m_usesTexture) | 
 |     { | 
 |         m_brickTexture = glu::Texture2D::create(m_renderCtx, m_ctxInfo, m_testCtx.getArchive(), "data/brick.png"); | 
 |         m_textures.push_back(TextureBinding( | 
 |             m_brickTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, | 
 |                                          tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR))); | 
 |     } | 
 |     gls::ShaderRenderCase::init(); | 
 | } | 
 |  | 
 | void ShaderDiscardCase::deinit(void) | 
 | { | 
 |     gls::ShaderRenderCase::deinit(); | 
 |     delete m_brickTexture; | 
 |     m_brickTexture = DE_NULL; | 
 | } | 
 |  | 
 | void ShaderDiscardCase::setupUniforms(int programID, const tcu::Vec4 &) | 
 | { | 
 |     const glw::Functions &gl = m_renderCtx.getFunctions(); | 
 |     gl.uniform1i(gl.getUniformLocation(programID, "ut_brick"), 0); | 
 | } | 
 |  | 
 | ShaderDiscardTests::ShaderDiscardTests(Context &context) : TestCaseGroup(context, "discard", "Discard statement tests") | 
 | { | 
 | } | 
 |  | 
 | ShaderDiscardTests::~ShaderDiscardTests(void) | 
 | { | 
 | } | 
 |  | 
 | enum DiscardMode | 
 | { | 
 |     DISCARDMODE_ALWAYS = 0, | 
 |     DISCARDMODE_NEVER, | 
 |     DISCARDMODE_UNIFORM, | 
 |     DISCARDMODE_DYNAMIC, | 
 |     DISCARDMODE_TEXTURE, | 
 |  | 
 |     DISCARDMODE_LAST | 
 | }; | 
 |  | 
 | enum DiscardTemplate | 
 | { | 
 |     DISCARDTEMPLATE_MAIN_BASIC = 0, | 
 |     DISCARDTEMPLATE_FUNCTION_BASIC, | 
 |     DISCARDTEMPLATE_MAIN_STATIC_LOOP, | 
 |     DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP, | 
 |     DISCARDTEMPLATE_FUNCTION_STATIC_LOOP, | 
 |  | 
 |     DISCARDTEMPLATE_LAST | 
 | }; | 
 |  | 
 | // Evaluation functions | 
 | inline void evalDiscardAlways(ShaderEvalContext &c) | 
 | { | 
 |     c.discard(); | 
 | } | 
 | inline void evalDiscardNever(ShaderEvalContext &c) | 
 | { | 
 |     c.color.xyz() = c.coords.swizzle(0, 1, 2); | 
 | } | 
 | inline void evalDiscardDynamic(ShaderEvalContext &c) | 
 | { | 
 |     c.color.xyz() = c.coords.swizzle(0, 1, 2); | 
 |     if (c.coords.x() + c.coords.y() > 0.0f) | 
 |         c.discard(); | 
 | } | 
 |  | 
 | inline void evalDiscardTexture(ShaderEvalContext &c) | 
 | { | 
 |     c.color.xyz() = c.coords.swizzle(0, 1, 2); | 
 |     if (c.texture2D(0, c.coords.swizzle(0, 1) * 0.25f + 0.5f).x() < 0.7f) | 
 |         c.discard(); | 
 | } | 
 |  | 
 | static ShaderEvalFunc getEvalFunc(DiscardMode mode) | 
 | { | 
 |     switch (mode) | 
 |     { | 
 |     case DISCARDMODE_ALWAYS: | 
 |         return evalDiscardAlways; | 
 |     case DISCARDMODE_NEVER: | 
 |         return evalDiscardNever; | 
 |     case DISCARDMODE_UNIFORM: | 
 |         return evalDiscardAlways; | 
 |     case DISCARDMODE_DYNAMIC: | 
 |         return evalDiscardDynamic; | 
 |     case DISCARDMODE_TEXTURE: | 
 |         return evalDiscardTexture; | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         return evalDiscardAlways; | 
 |     } | 
 | } | 
 |  | 
 | static const char *getTemplate(DiscardTemplate variant) | 
 | { | 
 |     switch (variant) | 
 |     { | 
 |     case DISCARDTEMPLATE_MAIN_BASIC: | 
 |         return "#version 300 es\n" | 
 |                "in mediump vec4 v_color;\n" | 
 |                "in mediump vec4 v_coords;\n" | 
 |                "layout(location = 0) out mediump vec4 o_color;\n" | 
 |                "uniform sampler2D    ut_brick;\n" | 
 |                "uniform mediump int  ui_one;\n\n" | 
 |                "void main (void)\n" | 
 |                "{\n" | 
 |                "    o_color = v_color;\n" | 
 |                "    ${DISCARD};\n" | 
 |                "}\n"; | 
 |  | 
 |     case DISCARDTEMPLATE_FUNCTION_BASIC: | 
 |         return "#version 300 es\n" | 
 |                "in mediump vec4 v_color;\n" | 
 |                "in mediump vec4 v_coords;\n" | 
 |                "layout(location = 0) out mediump vec4 o_color;\n" | 
 |                "uniform sampler2D    ut_brick;\n" | 
 |                "uniform mediump int  ui_one;\n\n" | 
 |                "void myfunc (void)\n" | 
 |                "{\n" | 
 |                "    ${DISCARD};\n" | 
 |                "}\n\n" | 
 |                "void main (void)\n" | 
 |                "{\n" | 
 |                "    o_color = v_color;\n" | 
 |                "    myfunc();\n" | 
 |                "}\n"; | 
 |  | 
 |     case DISCARDTEMPLATE_MAIN_STATIC_LOOP: | 
 |         return "#version 300 es\n" | 
 |                "in mediump vec4 v_color;\n" | 
 |                "in mediump vec4 v_coords;\n" | 
 |                "layout(location = 0) out mediump vec4 o_color;\n" | 
 |                "uniform sampler2D    ut_brick;\n" | 
 |                "uniform mediump int  ui_one;\n\n" | 
 |                "void main (void)\n" | 
 |                "{\n" | 
 |                "    o_color = v_color;\n" | 
 |                "    for (int i = 0; i < 2; i++)\n" | 
 |                "    {\n" | 
 |                "        if (i > 0)\n" | 
 |                "            ${DISCARD};\n" | 
 |                "    }\n" | 
 |                "}\n"; | 
 |  | 
 |     case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP: | 
 |         return "#version 300 es\n" | 
 |                "in mediump vec4 v_color;\n" | 
 |                "in mediump vec4 v_coords;\n" | 
 |                "layout(location = 0) out mediump vec4 o_color;\n" | 
 |                "uniform sampler2D    ut_brick;\n" | 
 |                "uniform mediump int  ui_one;\n" | 
 |                "uniform mediump int  ui_two;\n\n" | 
 |                "void main (void)\n" | 
 |                "{\n" | 
 |                "    o_color = v_color;\n" | 
 |                "    for (int i = 0; i < ui_two; i++)\n" | 
 |                "    {\n" | 
 |                "        if (i > 0)\n" | 
 |                "            ${DISCARD};\n" | 
 |                "    }\n" | 
 |                "}\n"; | 
 |  | 
 |     case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP: | 
 |         return "#version 300 es\n" | 
 |                "in mediump vec4 v_color;\n" | 
 |                "in mediump vec4 v_coords;\n" | 
 |                "layout(location = 0) out mediump vec4 o_color;\n" | 
 |                "uniform sampler2D    ut_brick;\n" | 
 |                "uniform mediump int  ui_one;\n\n" | 
 |                "void myfunc (void)\n" | 
 |                "{\n" | 
 |                "    for (int i = 0; i < 2; i++)\n" | 
 |                "    {\n" | 
 |                "        if (i > 0)\n" | 
 |                "            ${DISCARD};\n" | 
 |                "    }\n" | 
 |                "}\n\n" | 
 |                "void main (void)\n" | 
 |                "{\n" | 
 |                "    o_color = v_color;\n" | 
 |                "    myfunc();\n" | 
 |                "}\n"; | 
 |  | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         return DE_NULL; | 
 |     } | 
 | } | 
 |  | 
 | static const char *getTemplateName(DiscardTemplate variant) | 
 | { | 
 |     switch (variant) | 
 |     { | 
 |     case DISCARDTEMPLATE_MAIN_BASIC: | 
 |         return "basic"; | 
 |     case DISCARDTEMPLATE_FUNCTION_BASIC: | 
 |         return "function"; | 
 |     case DISCARDTEMPLATE_MAIN_STATIC_LOOP: | 
 |         return "static_loop"; | 
 |     case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP: | 
 |         return "dynamic_loop"; | 
 |     case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP: | 
 |         return "function_static_loop"; | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         return DE_NULL; | 
 |     } | 
 | } | 
 |  | 
 | static const char *getModeName(DiscardMode mode) | 
 | { | 
 |     switch (mode) | 
 |     { | 
 |     case DISCARDMODE_ALWAYS: | 
 |         return "always"; | 
 |     case DISCARDMODE_NEVER: | 
 |         return "never"; | 
 |     case DISCARDMODE_UNIFORM: | 
 |         return "uniform"; | 
 |     case DISCARDMODE_DYNAMIC: | 
 |         return "dynamic"; | 
 |     case DISCARDMODE_TEXTURE: | 
 |         return "texture"; | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         return DE_NULL; | 
 |     } | 
 | } | 
 |  | 
 | static const char *getTemplateDesc(DiscardTemplate variant) | 
 | { | 
 |     switch (variant) | 
 |     { | 
 |     case DISCARDTEMPLATE_MAIN_BASIC: | 
 |         return "main"; | 
 |     case DISCARDTEMPLATE_FUNCTION_BASIC: | 
 |         return "function"; | 
 |     case DISCARDTEMPLATE_MAIN_STATIC_LOOP: | 
 |         return "static loop"; | 
 |     case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP: | 
 |         return "dynamic loop"; | 
 |     case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP: | 
 |         return "static loop in function"; | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         return DE_NULL; | 
 |     } | 
 | } | 
 |  | 
 | static const char *getModeDesc(DiscardMode mode) | 
 | { | 
 |     switch (mode) | 
 |     { | 
 |     case DISCARDMODE_ALWAYS: | 
 |         return "Always discard"; | 
 |     case DISCARDMODE_NEVER: | 
 |         return "Never discard"; | 
 |     case DISCARDMODE_UNIFORM: | 
 |         return "Discard based on uniform value"; | 
 |     case DISCARDMODE_DYNAMIC: | 
 |         return "Discard based on varying values"; | 
 |     case DISCARDMODE_TEXTURE: | 
 |         return "Discard based on texture value"; | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         return DE_NULL; | 
 |     } | 
 | } | 
 |  | 
 | ShaderDiscardCase *makeDiscardCase(Context &context, DiscardTemplate tmpl, DiscardMode mode) | 
 | { | 
 |     StringTemplate shaderTemplate(getTemplate(tmpl)); | 
 |  | 
 |     map<string, string> params; | 
 |  | 
 |     switch (mode) | 
 |     { | 
 |     case DISCARDMODE_ALWAYS: | 
 |         params["DISCARD"] = "discard"; | 
 |         break; | 
 |     case DISCARDMODE_NEVER: | 
 |         params["DISCARD"] = "if (false) discard"; | 
 |         break; | 
 |     case DISCARDMODE_UNIFORM: | 
 |         params["DISCARD"] = "if (ui_one > 0) discard"; | 
 |         break; | 
 |     case DISCARDMODE_DYNAMIC: | 
 |         params["DISCARD"] = "if (v_coords.x+v_coords.y > 0.0) discard"; | 
 |         break; | 
 |     case DISCARDMODE_TEXTURE: | 
 |         params["DISCARD"] = "if (texture(ut_brick, v_coords.xy*0.25+0.5).x < 0.7) discard"; | 
 |         break; | 
 |     default: | 
 |         DE_ASSERT(false); | 
 |         break; | 
 |     } | 
 |  | 
 |     string name        = string(getTemplateName(tmpl)) + "_" + getModeName(mode); | 
 |     string description = string(getModeDesc(mode)) + " in " + getTemplateDesc(tmpl); | 
 |  | 
 |     return new ShaderDiscardCase(context, name.c_str(), description.c_str(), shaderTemplate.specialize(params).c_str(), | 
 |                                  getEvalFunc(mode), mode == DISCARDMODE_TEXTURE); | 
 | } | 
 |  | 
 | void ShaderDiscardTests::init(void) | 
 | { | 
 |     for (int tmpl = 0; tmpl < DISCARDTEMPLATE_LAST; tmpl++) | 
 |         for (int mode = 0; mode < DISCARDMODE_LAST; mode++) | 
 |             addChild(makeDiscardCase(m_context, (DiscardTemplate)tmpl, (DiscardMode)mode)); | 
 | } | 
 |  | 
 | } // namespace Functional | 
 | } // namespace gles3 | 
 | } // namespace deqp |