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::ostringstream;
40 using std::string;
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,
62 ShaderEvalFunc evalFunc, uint32_t flags);
63 virtual ~ShaderDiscardCase(void);
64
65 void init(void);
66 void deinit(void);
67
68 void setupUniforms(int programID, const tcu::Vec4 &constCoords);
69
70 private:
71 const uint32_t m_flags;
72 glu::Texture2D *m_brickTexture;
73 };
74
ShaderDiscardCase(Context & context,const char * name,const char * description,const char * shaderSource,ShaderEvalFunc evalFunc,uint32_t flags)75 ShaderDiscardCase::ShaderDiscardCase(Context &context, const char *name, const char *description,
76 const char *shaderSource, ShaderEvalFunc evalFunc, uint32_t flags)
77 : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
78 description, false, evalFunc)
79 , m_flags(flags)
80 , m_brickTexture(DE_NULL)
81 {
82 m_fragShaderSource = shaderSource;
83 m_vertShaderSource = "attribute highp vec4 a_position;\n"
84 "attribute highp vec4 a_coords;\n"
85 "varying mediump vec4 v_color;\n"
86 "varying mediump vec4 v_coords;\n\n"
87 "void main (void)\n"
88 "{\n"
89 " gl_Position = a_position;\n"
90 " v_color = vec4(a_coords.xyz, 1.0);\n"
91 " v_coords = a_coords;\n"
92 "}\n";
93 }
94
~ShaderDiscardCase(void)95 ShaderDiscardCase::~ShaderDiscardCase(void)
96 {
97 delete m_brickTexture;
98 }
99
init(void)100 void ShaderDiscardCase::init(void)
101 {
102 try
103 {
104 gls::ShaderRenderCase::init();
105 }
106 catch (const CompileFailed &)
107 {
108 if (m_flags & FLAG_REQUIRES_DYNAMIC_LOOPS)
109 {
110 const bool isSupported =
111 m_isVertexCase ? m_ctxInfo.isVertexDynamicLoopSupported() : m_ctxInfo.isFragmentDynamicLoopSupported();
112 if (!isSupported)
113 throw tcu::NotSupportedError("Dynamic loops not supported");
114 }
115
116 throw;
117 }
118
119 if (m_flags & FLAG_USES_TEXTURES)
120 {
121 m_brickTexture = glu::Texture2D::create(m_renderCtx, m_ctxInfo, m_testCtx.getArchive(), "data/brick.png");
122 m_textures.push_back(TextureBinding(
123 m_brickTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
124 tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR)));
125 }
126 }
127
deinit(void)128 void ShaderDiscardCase::deinit(void)
129 {
130 gls::ShaderRenderCase::deinit();
131 delete m_brickTexture;
132 m_brickTexture = DE_NULL;
133 }
134
setupUniforms(int programID,const tcu::Vec4 &)135 void ShaderDiscardCase::setupUniforms(int programID, const tcu::Vec4 &)
136 {
137 const glw::Functions &gl = m_renderCtx.getFunctions();
138 gl.uniform1i(gl.getUniformLocation(programID, "ut_brick"), 0);
139 }
140
ShaderDiscardTests(Context & context)141 ShaderDiscardTests::ShaderDiscardTests(Context &context) : TestCaseGroup(context, "discard", "Discard statement tests")
142 {
143 }
144
~ShaderDiscardTests(void)145 ShaderDiscardTests::~ShaderDiscardTests(void)
146 {
147 }
148
149 enum DiscardMode
150 {
151 DISCARDMODE_ALWAYS = 0,
152 DISCARDMODE_NEVER,
153 DISCARDMODE_UNIFORM,
154 DISCARDMODE_DYNAMIC,
155 DISCARDMODE_TEXTURE,
156
157 DISCARDMODE_LAST
158 };
159
160 enum DiscardTemplate
161 {
162 DISCARDTEMPLATE_MAIN_BASIC = 0,
163 DISCARDTEMPLATE_FUNCTION_BASIC,
164 DISCARDTEMPLATE_MAIN_STATIC_LOOP,
165 DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP,
166 DISCARDTEMPLATE_FUNCTION_STATIC_LOOP,
167
168 DISCARDTEMPLATE_LAST
169 };
170
171 // Evaluation functions
evalDiscardAlways(ShaderEvalContext & c)172 inline void evalDiscardAlways(ShaderEvalContext &c)
173 {
174 c.discard();
175 }
evalDiscardNever(ShaderEvalContext & c)176 inline void evalDiscardNever(ShaderEvalContext &c)
177 {
178 c.color.xyz() = c.coords.swizzle(0, 1, 2);
179 }
evalDiscardDynamic(ShaderEvalContext & c)180 inline void evalDiscardDynamic(ShaderEvalContext &c)
181 {
182 c.color.xyz() = c.coords.swizzle(0, 1, 2);
183 if (c.coords.x() + c.coords.y() > 0.0f)
184 c.discard();
185 }
186
evalDiscardTexture(ShaderEvalContext & c)187 inline void evalDiscardTexture(ShaderEvalContext &c)
188 {
189 c.color.xyz() = c.coords.swizzle(0, 1, 2);
190 if (c.texture2D(0, c.coords.swizzle(0, 1) * 0.25f + 0.5f).x() < 0.7f)
191 c.discard();
192 }
193
getEvalFunc(DiscardMode mode)194 static ShaderEvalFunc getEvalFunc(DiscardMode mode)
195 {
196 switch (mode)
197 {
198 case DISCARDMODE_ALWAYS:
199 return evalDiscardAlways;
200 case DISCARDMODE_NEVER:
201 return evalDiscardNever;
202 case DISCARDMODE_UNIFORM:
203 return evalDiscardAlways;
204 case DISCARDMODE_DYNAMIC:
205 return evalDiscardDynamic;
206 case DISCARDMODE_TEXTURE:
207 return evalDiscardTexture;
208 default:
209 DE_ASSERT(false);
210 return evalDiscardAlways;
211 }
212 }
213
getTemplate(DiscardTemplate variant)214 static const char *getTemplate(DiscardTemplate variant)
215 {
216 switch (variant)
217 {
218 case DISCARDTEMPLATE_MAIN_BASIC:
219 return "varying mediump vec4 v_color;\n"
220 "varying mediump vec4 v_coords;\n"
221 "uniform sampler2D ut_brick;\n"
222 "uniform mediump int ui_one;\n\n"
223 "void main (void)\n"
224 "{\n"
225 " gl_FragColor = v_color;\n"
226 " ${DISCARD};\n"
227 "}\n";
228
229 case DISCARDTEMPLATE_FUNCTION_BASIC:
230 return "varying mediump vec4 v_color;\n"
231 "varying mediump vec4 v_coords;\n"
232 "uniform sampler2D ut_brick;\n"
233 "uniform mediump int ui_one;\n\n"
234 "void myfunc (void)\n"
235 "{\n"
236 " ${DISCARD};\n"
237 "}\n\n"
238 "void main (void)\n"
239 "{\n"
240 " gl_FragColor = v_color;\n"
241 " myfunc();\n"
242 "}\n";
243
244 case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
245 return "varying mediump vec4 v_color;\n"
246 "varying mediump vec4 v_coords;\n"
247 "uniform sampler2D ut_brick;\n"
248 "uniform mediump int ui_one;\n\n"
249 "void main (void)\n"
250 "{\n"
251 " gl_FragColor = v_color;\n"
252 " for (int i = 0; i < 2; i++)\n"
253 " {\n"
254 " if (i > 0)\n"
255 " ${DISCARD};\n"
256 " }\n"
257 "}\n";
258
259 case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
260 return "varying mediump vec4 v_color;\n"
261 "varying mediump vec4 v_coords;\n"
262 "uniform sampler2D ut_brick;\n"
263 "uniform mediump int ui_one;\n"
264 "uniform mediump int ui_two;\n\n"
265 "void main (void)\n"
266 "{\n"
267 " gl_FragColor = v_color;\n"
268 " for (int i = 0; i < ui_two; i++)\n"
269 " {\n"
270 " if (i > 0)\n"
271 " ${DISCARD};\n"
272 " }\n"
273 "}\n";
274
275 case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
276 return "varying mediump vec4 v_color;\n"
277 "varying mediump vec4 v_coords;\n"
278 "uniform sampler2D ut_brick;\n"
279 "uniform mediump int ui_one;\n\n"
280 "void myfunc (void)\n"
281 "{\n"
282 " for (int i = 0; i < 2; i++)\n"
283 " {\n"
284 " if (i > 0)\n"
285 " ${DISCARD};\n"
286 " }\n"
287 "}\n\n"
288 "void main (void)\n"
289 "{\n"
290 " gl_FragColor = v_color;\n"
291 " myfunc();\n"
292 "}\n";
293
294 default:
295 DE_ASSERT(false);
296 return DE_NULL;
297 }
298 }
299
getTemplateName(DiscardTemplate variant)300 static const char *getTemplateName(DiscardTemplate variant)
301 {
302 switch (variant)
303 {
304 case DISCARDTEMPLATE_MAIN_BASIC:
305 return "basic";
306 case DISCARDTEMPLATE_FUNCTION_BASIC:
307 return "function";
308 case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
309 return "static_loop";
310 case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
311 return "dynamic_loop";
312 case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
313 return "function_static_loop";
314 default:
315 DE_ASSERT(false);
316 return DE_NULL;
317 }
318 }
319
getModeName(DiscardMode mode)320 static const char *getModeName(DiscardMode mode)
321 {
322 switch (mode)
323 {
324 case DISCARDMODE_ALWAYS:
325 return "always";
326 case DISCARDMODE_NEVER:
327 return "never";
328 case DISCARDMODE_UNIFORM:
329 return "uniform";
330 case DISCARDMODE_DYNAMIC:
331 return "dynamic";
332 case DISCARDMODE_TEXTURE:
333 return "texture";
334 default:
335 DE_ASSERT(false);
336 return DE_NULL;
337 }
338 }
339
getTemplateDesc(DiscardTemplate variant)340 static const char *getTemplateDesc(DiscardTemplate variant)
341 {
342 switch (variant)
343 {
344 case DISCARDTEMPLATE_MAIN_BASIC:
345 return "main";
346 case DISCARDTEMPLATE_FUNCTION_BASIC:
347 return "function";
348 case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
349 return "static loop";
350 case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
351 return "dynamic loop";
352 case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
353 return "static loop in function";
354 default:
355 DE_ASSERT(false);
356 return DE_NULL;
357 }
358 }
359
getModeDesc(DiscardMode mode)360 static const char *getModeDesc(DiscardMode mode)
361 {
362 switch (mode)
363 {
364 case DISCARDMODE_ALWAYS:
365 return "Always discard";
366 case DISCARDMODE_NEVER:
367 return "Never discard";
368 case DISCARDMODE_UNIFORM:
369 return "Discard based on uniform value";
370 case DISCARDMODE_DYNAMIC:
371 return "Discard based on varying values";
372 case DISCARDMODE_TEXTURE:
373 return "Discard based on texture value";
374 default:
375 DE_ASSERT(false);
376 return DE_NULL;
377 }
378 }
379
makeDiscardCase(Context & context,DiscardTemplate tmpl,DiscardMode mode)380 ShaderDiscardCase *makeDiscardCase(Context &context, DiscardTemplate tmpl, DiscardMode mode)
381 {
382 StringTemplate shaderTemplate(getTemplate(tmpl));
383
384 map<string, string> params;
385
386 switch (mode)
387 {
388 case DISCARDMODE_ALWAYS:
389 params["DISCARD"] = "discard";
390 break;
391 case DISCARDMODE_NEVER:
392 params["DISCARD"] = "if (false) discard";
393 break;
394 case DISCARDMODE_UNIFORM:
395 params["DISCARD"] = "if (ui_one > 0) discard";
396 break;
397 case DISCARDMODE_DYNAMIC:
398 params["DISCARD"] = "if (v_coords.x+v_coords.y > 0.0) discard";
399 break;
400 case DISCARDMODE_TEXTURE:
401 params["DISCARD"] = "if (texture2D(ut_brick, v_coords.xy*0.25+0.5).x < 0.7) discard";
402 break;
403 default:
404 DE_ASSERT(false);
405 break;
406 }
407
408 string name = string(getTemplateName(tmpl)) + "_" + getModeName(mode);
409 string description = string(getModeDesc(mode)) + " in " + getTemplateDesc(tmpl);
410 uint32_t flags = (mode == DISCARDMODE_TEXTURE ? FLAG_USES_TEXTURES : 0) |
411 (tmpl == DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP ? FLAG_REQUIRES_DYNAMIC_LOOPS : 0);
412
413 return new ShaderDiscardCase(context, name.c_str(), description.c_str(), shaderTemplate.specialize(params).c_str(),
414 getEvalFunc(mode), flags);
415 }
416
init(void)417 void ShaderDiscardTests::init(void)
418 {
419 for (int tmpl = 0; tmpl < DISCARDTEMPLATE_LAST; tmpl++)
420 for (int mode = 0; mode < DISCARDMODE_LAST; mode++)
421 addChild(makeDiscardCase(m_context, (DiscardTemplate)tmpl, (DiscardMode)mode));
422 }
423
424 } // namespace Functional
425 } // namespace gles2
426 } // namespace deqp
427