/*------------------------------------------------------------------------- * 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::string; using std::ostringstream; 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(DE_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(DE_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(DE_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(DE_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(DE_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(DE_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(DE_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)); } } // Functional } // gles3 } // deqp