1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Shader discard statement tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2fShaderDiscardTests.hpp" 25 #include "glsShaderRenderCase.hpp" 26 #include "tcuStringTemplate.hpp" 27 #include "gluTexture.hpp" 28 29 #include <map> 30 #include <sstream> 31 #include <string> 32 33 #include "glwEnums.hpp" 34 #include "glwFunctions.hpp" 35 36 using tcu::StringTemplate; 37 38 using std::map; 39 using std::string; 40 using std::ostringstream; 41 42 using namespace glu; 43 using namespace deqp::gls; 44 45 namespace deqp 46 { 47 namespace gles2 48 { 49 namespace Functional 50 { 51 52 enum CaseFlags 53 { 54 FLAG_USES_TEXTURES = (1<<0), 55 FLAG_REQUIRES_DYNAMIC_LOOPS = (1<<1), 56 }; 57 58 class ShaderDiscardCase : public ShaderRenderCase 59 { 60 public: 61 ShaderDiscardCase (Context& context, const char* name, const char* description, const char* shaderSource, ShaderEvalFunc evalFunc, deUint32 flags); 62 virtual ~ShaderDiscardCase (void); 63 64 void init (void); 65 void deinit (void); 66 67 void setupUniforms (int programID, const tcu::Vec4& constCoords); 68 69 private: 70 const deUint32 m_flags; 71 glu::Texture2D* m_brickTexture; 72 }; 73 74 ShaderDiscardCase::ShaderDiscardCase (Context& context, const char* name, const char* description, const char* shaderSource, ShaderEvalFunc evalFunc, deUint32 flags) 75 : ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, false, evalFunc) 76 , m_flags (flags) 77 , m_brickTexture (DE_NULL) 78 { 79 m_fragShaderSource = shaderSource; 80 m_vertShaderSource = 81 "attribute highp vec4 a_position;\n" 82 "attribute highp vec4 a_coords;\n" 83 "varying mediump vec4 v_color;\n" 84 "varying mediump vec4 v_coords;\n\n" 85 "void main (void)\n" 86 "{\n" 87 " gl_Position = a_position;\n" 88 " v_color = vec4(a_coords.xyz, 1.0);\n" 89 " v_coords = a_coords;\n" 90 "}\n"; 91 } 92 93 ShaderDiscardCase::~ShaderDiscardCase (void) 94 { 95 delete m_brickTexture; 96 } 97 98 void ShaderDiscardCase::init (void) 99 { 100 try 101 { 102 gls::ShaderRenderCase::init(); 103 } 104 catch (const CompileFailed&) 105 { 106 if (m_flags & FLAG_REQUIRES_DYNAMIC_LOOPS) 107 { 108 const bool isSupported = m_isVertexCase ? m_ctxInfo.isVertexDynamicLoopSupported() : m_ctxInfo.isFragmentDynamicLoopSupported(); 109 if (!isSupported) 110 throw tcu::NotSupportedError("Dynamic loops not supported"); 111 } 112 113 throw; 114 } 115 116 if (m_flags & FLAG_USES_TEXTURES) 117 { 118 m_brickTexture = glu::Texture2D::create(m_renderCtx, m_ctxInfo, m_testCtx.getArchive(), "data/brick.png"); 119 m_textures.push_back(TextureBinding(m_brickTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, 120 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR))); 121 } 122 } 123 124 void ShaderDiscardCase::deinit (void) 125 { 126 gls::ShaderRenderCase::deinit(); 127 delete m_brickTexture; 128 m_brickTexture = DE_NULL; 129 } 130 131 void ShaderDiscardCase::setupUniforms (int programID, const tcu::Vec4&) 132 { 133 const glw::Functions& gl = m_renderCtx.getFunctions(); 134 gl.uniform1i(gl.getUniformLocation(programID, "ut_brick"), 0); 135 } 136 137 ShaderDiscardTests::ShaderDiscardTests (Context& context) 138 : TestCaseGroup(context, "discard", "Discard statement tests") 139 { 140 } 141 142 ShaderDiscardTests::~ShaderDiscardTests (void) 143 { 144 } 145 146 enum DiscardMode 147 { 148 DISCARDMODE_ALWAYS = 0, 149 DISCARDMODE_NEVER, 150 DISCARDMODE_UNIFORM, 151 DISCARDMODE_DYNAMIC, 152 DISCARDMODE_TEXTURE, 153 154 DISCARDMODE_LAST 155 }; 156 157 enum DiscardTemplate 158 { 159 DISCARDTEMPLATE_MAIN_BASIC = 0, 160 DISCARDTEMPLATE_FUNCTION_BASIC, 161 DISCARDTEMPLATE_MAIN_STATIC_LOOP, 162 DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP, 163 DISCARDTEMPLATE_FUNCTION_STATIC_LOOP, 164 165 DISCARDTEMPLATE_LAST 166 }; 167 168 // Evaluation functions 169 inline void evalDiscardAlways (ShaderEvalContext& c) { c.discard(); } 170 inline void evalDiscardNever (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); } 171 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(); } 172 173 inline void evalDiscardTexture (ShaderEvalContext& c) 174 { 175 c.color.xyz() = c.coords.swizzle(0,1,2); 176 if (c.texture2D(0, c.coords.swizzle(0,1) * 0.25f + 0.5f).x() < 0.7f) 177 c.discard(); 178 } 179 180 static ShaderEvalFunc getEvalFunc (DiscardMode mode) 181 { 182 switch (mode) 183 { 184 case DISCARDMODE_ALWAYS: return evalDiscardAlways; 185 case DISCARDMODE_NEVER: return evalDiscardNever; 186 case DISCARDMODE_UNIFORM: return evalDiscardAlways; 187 case DISCARDMODE_DYNAMIC: return evalDiscardDynamic; 188 case DISCARDMODE_TEXTURE: return evalDiscardTexture; 189 default: 190 DE_ASSERT(DE_FALSE); 191 return evalDiscardAlways; 192 } 193 } 194 195 static const char* getTemplate (DiscardTemplate variant) 196 { 197 switch (variant) 198 { 199 case DISCARDTEMPLATE_MAIN_BASIC: 200 return "varying mediump vec4 v_color;\n" 201 "varying mediump vec4 v_coords;\n" 202 "uniform sampler2D ut_brick;\n" 203 "uniform mediump int ui_one;\n\n" 204 "void main (void)\n" 205 "{\n" 206 " gl_FragColor = v_color;\n" 207 " ${DISCARD};\n" 208 "}\n"; 209 210 case DISCARDTEMPLATE_FUNCTION_BASIC: 211 return "varying mediump vec4 v_color;\n" 212 "varying mediump vec4 v_coords;\n" 213 "uniform sampler2D ut_brick;\n" 214 "uniform mediump int ui_one;\n\n" 215 "void myfunc (void)\n" 216 "{\n" 217 " ${DISCARD};\n" 218 "}\n\n" 219 "void main (void)\n" 220 "{\n" 221 " gl_FragColor = v_color;\n" 222 " myfunc();\n" 223 "}\n"; 224 225 case DISCARDTEMPLATE_MAIN_STATIC_LOOP: 226 return "varying mediump vec4 v_color;\n" 227 "varying mediump vec4 v_coords;\n" 228 "uniform sampler2D ut_brick;\n" 229 "uniform mediump int ui_one;\n\n" 230 "void main (void)\n" 231 "{\n" 232 " gl_FragColor = v_color;\n" 233 " for (int i = 0; i < 2; i++)\n" 234 " {\n" 235 " if (i > 0)\n" 236 " ${DISCARD};\n" 237 " }\n" 238 "}\n"; 239 240 case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP: 241 return "varying mediump vec4 v_color;\n" 242 "varying mediump vec4 v_coords;\n" 243 "uniform sampler2D ut_brick;\n" 244 "uniform mediump int ui_one;\n" 245 "uniform mediump int ui_two;\n\n" 246 "void main (void)\n" 247 "{\n" 248 " gl_FragColor = v_color;\n" 249 " for (int i = 0; i < ui_two; i++)\n" 250 " {\n" 251 " if (i > 0)\n" 252 " ${DISCARD};\n" 253 " }\n" 254 "}\n"; 255 256 case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP: 257 return "varying mediump vec4 v_color;\n" 258 "varying mediump vec4 v_coords;\n" 259 "uniform sampler2D ut_brick;\n" 260 "uniform mediump int ui_one;\n\n" 261 "void myfunc (void)\n" 262 "{\n" 263 " for (int i = 0; i < 2; i++)\n" 264 " {\n" 265 " if (i > 0)\n" 266 " ${DISCARD};\n" 267 " }\n" 268 "}\n\n" 269 "void main (void)\n" 270 "{\n" 271 " gl_FragColor = v_color;\n" 272 " myfunc();\n" 273 "}\n"; 274 275 default: 276 DE_ASSERT(DE_FALSE); 277 return DE_NULL; 278 } 279 } 280 281 static const char* getTemplateName (DiscardTemplate variant) 282 { 283 switch (variant) 284 { 285 case DISCARDTEMPLATE_MAIN_BASIC: return "basic"; 286 case DISCARDTEMPLATE_FUNCTION_BASIC: return "function"; 287 case DISCARDTEMPLATE_MAIN_STATIC_LOOP: return "static_loop"; 288 case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP: return "dynamic_loop"; 289 case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP: return "function_static_loop"; 290 default: 291 DE_ASSERT(DE_FALSE); 292 return DE_NULL; 293 } 294 } 295 296 static const char* getModeName (DiscardMode mode) 297 { 298 switch (mode) 299 { 300 case DISCARDMODE_ALWAYS: return "always"; 301 case DISCARDMODE_NEVER: return "never"; 302 case DISCARDMODE_UNIFORM: return "uniform"; 303 case DISCARDMODE_DYNAMIC: return "dynamic"; 304 case DISCARDMODE_TEXTURE: return "texture"; 305 default: 306 DE_ASSERT(DE_FALSE); 307 return DE_NULL; 308 } 309 } 310 311 static const char* getTemplateDesc (DiscardTemplate variant) 312 { 313 switch (variant) 314 { 315 case DISCARDTEMPLATE_MAIN_BASIC: return "main"; 316 case DISCARDTEMPLATE_FUNCTION_BASIC: return "function"; 317 case DISCARDTEMPLATE_MAIN_STATIC_LOOP: return "static loop"; 318 case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP: return "dynamic loop"; 319 case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP: return "static loop in function"; 320 default: 321 DE_ASSERT(DE_FALSE); 322 return DE_NULL; 323 } 324 } 325 326 static const char* getModeDesc (DiscardMode mode) 327 { 328 switch (mode) 329 { 330 case DISCARDMODE_ALWAYS: return "Always discard"; 331 case DISCARDMODE_NEVER: return "Never discard"; 332 case DISCARDMODE_UNIFORM: return "Discard based on uniform value"; 333 case DISCARDMODE_DYNAMIC: return "Discard based on varying values"; 334 case DISCARDMODE_TEXTURE: return "Discard based on texture value"; 335 default: 336 DE_ASSERT(DE_FALSE); 337 return DE_NULL; 338 } 339 } 340 341 ShaderDiscardCase* makeDiscardCase (Context& context, DiscardTemplate tmpl, DiscardMode mode) 342 { 343 StringTemplate shaderTemplate(getTemplate(tmpl)); 344 345 map<string, string> params; 346 347 switch (mode) 348 { 349 case DISCARDMODE_ALWAYS: params["DISCARD"] = "discard"; break; 350 case DISCARDMODE_NEVER: params["DISCARD"] = "if (false) discard"; break; 351 case DISCARDMODE_UNIFORM: params["DISCARD"] = "if (ui_one > 0) discard"; break; 352 case DISCARDMODE_DYNAMIC: params["DISCARD"] = "if (v_coords.x+v_coords.y > 0.0) discard"; break; 353 case DISCARDMODE_TEXTURE: params["DISCARD"] = "if (texture2D(ut_brick, v_coords.xy*0.25+0.5).x < 0.7) discard"; break; 354 default: 355 DE_ASSERT(DE_FALSE); 356 break; 357 } 358 359 string name = string(getTemplateName(tmpl)) + "_" + getModeName(mode); 360 string description = string(getModeDesc(mode)) + " in " + getTemplateDesc(tmpl); 361 deUint32 flags = (mode == DISCARDMODE_TEXTURE ? FLAG_USES_TEXTURES : 0) 362 | (tmpl == DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP ? FLAG_REQUIRES_DYNAMIC_LOOPS : 0); 363 364 return new ShaderDiscardCase(context, name.c_str(), description.c_str(), shaderTemplate.specialize(params).c_str(), getEvalFunc(mode), flags); 365 } 366 367 void ShaderDiscardTests::init (void) 368 { 369 for (int tmpl = 0; tmpl < DISCARDTEMPLATE_LAST; tmpl++) 370 for (int mode = 0; mode < DISCARDMODE_LAST; mode++) 371 addChild(makeDiscardCase(m_context, (DiscardTemplate)tmpl, (DiscardMode)mode)); 372 } 373 374 } // Functional 375 } // gles2 376 } // deqp 377