1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.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 GLSL ES 1.0 gl_FragData[] tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fShaderFragDataTests.hpp"
25
26 #include "glsShaderLibrary.hpp"
27
28 #include "gluRenderContext.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluDrawUtil.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluObjectWrapper.hpp"
33
34 #include "tcuRenderTarget.hpp"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuTestLog.hpp"
37 #include "tcuSurface.hpp"
38
39 #include "glwFunctions.hpp"
40 #include "glwEnums.hpp"
41
42 namespace deqp
43 {
44 namespace gles3
45 {
46 namespace Functional
47 {
48
49 using std::string;
50 using tcu::TestLog;
51
52 namespace
53 {
54
55 enum IndexExprType
56 {
57 INDEX_EXPR_STATIC = 0,
58 INDEX_EXPR_UNIFORM,
59 INDEX_EXPR_DYNAMIC,
60
61 INDEX_EXPR_TYPE_LAST
62 };
63
isExtensionSupported(const glu::RenderContext & renderCtx,const std::string & extension)64 static bool isExtensionSupported (const glu::RenderContext& renderCtx, const std::string& extension)
65 {
66 const glw::Functions& gl = renderCtx.getFunctions();
67 int numExts = 0;
68
69 gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts);
70
71 for (int ndx = 0; ndx < numExts; ndx++)
72 {
73 const char* curExt = (const char*)gl.getStringi(GL_EXTENSIONS, ndx);
74
75 if (extension == curExt)
76 return true;
77 }
78
79 return false;
80 }
81
compareSingleColor(tcu::TestLog & log,const tcu::Surface & surface,tcu::RGBA expectedColor,tcu::RGBA threshold)82 static bool compareSingleColor (tcu::TestLog& log, const tcu::Surface& surface, tcu::RGBA expectedColor, tcu::RGBA threshold)
83 {
84 const int maxPrints = 10;
85 int numFailedPixels = 0;
86
87 log << TestLog::Message << "Expecting " << expectedColor << " with threshold " << threshold << TestLog::EndMessage;
88
89 for (int y = 0; y < surface.getHeight(); y++)
90 {
91 for (int x = 0; x < surface.getWidth(); x++)
92 {
93 const tcu::RGBA resultColor = surface.getPixel(x, y);
94 const bool isOk = compareThreshold(resultColor, expectedColor, threshold);
95
96 if (!isOk)
97 {
98 if (numFailedPixels < maxPrints)
99 log << TestLog::Message << "ERROR: Got " << resultColor << " at (" << x << ", " << y << ")!" << TestLog::EndMessage;
100 else if (numFailedPixels == maxPrints)
101 log << TestLog::Message << "..." << TestLog::EndMessage;
102
103 numFailedPixels += 1;
104 }
105 }
106 }
107
108 if (numFailedPixels > 0)
109 {
110 log << TestLog::Message << "Found " << numFailedPixels << " invalid pixels, comparison FAILED!" << TestLog::EndMessage;
111 log << TestLog::Image("ResultImage", "Result Image", surface);
112 return false;
113 }
114 else
115 {
116 log << TestLog::Message << "Image comparison passed." << TestLog::EndMessage;
117 return true;
118 }
119 }
120
121 class FragDataIndexingCase : public TestCase
122 {
123 public:
FragDataIndexingCase(Context & context,const char * name,const char * description,IndexExprType indexExprType)124 FragDataIndexingCase (Context& context, const char* name, const char* description, IndexExprType indexExprType)
125 : TestCase (context, name, description)
126 , m_indexExprType (indexExprType)
127 {
128 }
129
genSources(const IndexExprType indexExprType)130 static glu::ProgramSources genSources (const IndexExprType indexExprType)
131 {
132 const char* const fragIndexExpr = indexExprType == INDEX_EXPR_STATIC ? "0" :
133 indexExprType == INDEX_EXPR_UNIFORM ? "u_index" :
134 indexExprType == INDEX_EXPR_DYNAMIC ? "int(v_index)" : DE_NULL;
135 glu::ProgramSources sources;
136
137 DE_ASSERT(fragIndexExpr);
138
139 sources << glu::VertexSource(
140 "attribute highp vec4 a_position;\n"
141 "attribute highp float a_index;\n"
142 "attribute highp vec4 a_color;\n"
143 "varying mediump float v_index;\n"
144 "varying mediump vec4 v_color;\n"
145 "void main (void)\n"
146 "{\n"
147 " gl_Position = a_position;\n"
148 " v_color = a_color;\n"
149 " v_index = a_index;\n"
150 "}\n");
151
152 sources << glu::FragmentSource(string(
153 "varying mediump vec4 v_color;\n"
154 "varying mediump float v_index;\n"
155 "uniform mediump int u_index;\n"
156 "void main (void)\n"
157 "{\n"
158 " gl_FragData[") + fragIndexExpr + "] = v_color;\n"
159 "}\n");
160
161 return sources;
162 }
163
iterate(void)164 IterateResult iterate (void)
165 {
166 const glu::RenderContext& renderCtx = m_context.getRenderContext();
167 const glw::Functions& gl = renderCtx.getFunctions();
168 const glu::ShaderProgram program (renderCtx, genSources(m_indexExprType));
169 const int viewportW = de::min(renderCtx.getRenderTarget().getWidth(), 128);
170 const int viewportH = de::min(renderCtx.getRenderTarget().getHeight(), 128);
171
172 const float positions[] =
173 {
174 -1.0f, -1.0f,
175 +1.0f, -1.0f,
176 -1.0f, +1.0f,
177 +1.0f, +1.0f
178 };
179 const float colors[] =
180 {
181 0.0f, 1.0f, 0.0f, 1.0f,
182 0.0f, 1.0f, 0.0f, 1.0f,
183 0.0f, 1.0f, 0.0f, 1.0f,
184 0.0f, 1.0f, 0.0f, 1.0f
185 };
186 const float indexValues[] = { 0.0f, 0.0f, 0.0f, 0.0f };
187 const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 };
188
189 const glu::VertexArrayBinding vertexArrays[] =
190 {
191 glu::va::Float("a_position", 2, 4, 0, &positions[0]),
192 glu::va::Float("a_color", 4, 4, 0, &colors[0]),
193 glu::va::Float("a_index", 1, 4, 0, &indexValues[0])
194 };
195
196 m_testCtx.getLog() << program;
197
198 if (!program.isOk())
199 {
200 if (m_indexExprType == INDEX_EXPR_STATIC)
201 TCU_FAIL("Compile failed");
202 else
203 throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
204 }
205
206 gl.clearColor (1.0f, 0.0f, 0.0f, 1.0f);
207 gl.clear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
208
209 gl.viewport (0, 0, viewportW, viewportH);
210 gl.useProgram (program.getProgram());
211 gl.uniform1i (gl.getUniformLocation(program.getProgram(), "u_index"), 0);
212
213 glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
214 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
215 GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
216
217 {
218 tcu::Surface result (viewportW, viewportH);
219 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
220 bool isOk;
221
222 glu::readPixels(renderCtx, 0, 0, result.getAccess());
223 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
224
225 isOk = compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold);
226
227 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
228 isOk ? "Pass" : "Image comparison failed");
229 }
230
231 return STOP;
232 }
233
234 private:
235 const IndexExprType m_indexExprType;
236 };
237
238 class FragDataDrawBuffersCase : public TestCase
239 {
240 public:
FragDataDrawBuffersCase(Context & context)241 FragDataDrawBuffersCase (Context& context)
242 : TestCase(context, "draw_buffers", "gl_FragData[] and glDrawBuffers() interaction")
243 {
244 }
245
iterate(void)246 IterateResult iterate (void)
247 {
248 const glu::RenderContext& renderCtx = m_context.getRenderContext();
249
250 int num_test_attachment = 2;
251 if(!isExtensionSupported(renderCtx, "GL_EXT_draw_buffers") && !isExtensionSupported(renderCtx, "GL_NV_draw_buffers"))
252 num_test_attachment = 1;
253
254 std::string extensionString;
255 if (isExtensionSupported(renderCtx, "GL_EXT_draw_buffers"))
256 extensionString = "#extension GL_EXT_draw_buffers : require\n";
257 else
258 if (isExtensionSupported(renderCtx, "GL_NV_draw_buffers"))
259 extensionString = "#extension GL_NV_draw_buffers : require\n";
260
261 const glu::ShaderProgram program (renderCtx, glu::ProgramSources()
262 << glu::VertexSource(
263 "attribute highp vec4 a_position;\n"
264 "attribute highp vec4 a_color;\n"
265 "varying mediump vec4 v_color;\n"
266 "void main (void)\n"
267 "{\n"
268 " gl_Position = a_position;\n"
269 " v_color = a_color;\n"
270 "}\n")
271 << glu::FragmentSource(
272 extensionString +
273 "varying mediump vec4 v_color;\n"
274 "uniform mediump int u_index;\n"
275 "void main (void)\n"
276 "{\n"
277 " gl_FragData[u_index] = v_color;\n"
278 "}\n"));
279 const glw::Functions& gl = renderCtx.getFunctions();
280 const int width = 128;
281 const int height = 128;
282 const int indexLoc = program.isOk() ? gl.getUniformLocation(program.getProgram(), "u_index") : -1;
283 const glu::Framebuffer fbo (renderCtx);
284 const glu::Renderbuffer colorBuf0 (renderCtx);
285 const glu::Renderbuffer colorBuf1 (renderCtx);
286
287 const float positions[] =
288 {
289 -1.0f, -1.0f,
290 +1.0f, -1.0f,
291 -1.0f, +1.0f,
292 +1.0f, +1.0f
293 };
294 const float colors[] =
295 {
296 0.0f, 1.0f, 0.0f, 1.0f,
297 0.0f, 1.0f, 0.0f, 1.0f,
298 0.0f, 1.0f, 0.0f, 1.0f,
299 0.0f, 1.0f, 0.0f, 1.0f
300 };
301 const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 };
302
303 const glu::VertexArrayBinding vertexArrays[] =
304 {
305 glu::va::Float("a_position", 2, 4, 0, &positions[0]),
306 glu::va::Float("a_color", 4, 4, 0, &colors[0])
307 };
308
309 m_testCtx.getLog() << program;
310
311 if (!program.isOk())
312 throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
313
314 gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
315 for (int ndx = 0; ndx < num_test_attachment; ndx++)
316 {
317 const deUint32 rbo = ndx == 0 ? *colorBuf0 : *colorBuf1;
318
319 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
320 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
321 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+ndx, GL_RENDERBUFFER, rbo);
322 }
323 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
324
325 {
326 const deUint32 drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
327 gl.drawBuffers(DE_LENGTH_OF_ARRAY(drawBuffers), &drawBuffers[0]);
328 }
329
330 gl.viewport (0, 0, width, height);
331 gl.useProgram (program.getProgram());
332
333 GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
334
335 bool allOk = true;
336 const tcu::RGBA threshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1);
337
338 for (int ndx = 0; ndx < num_test_attachment; ndx++)
339 {
340 gl.clearBufferfv(GL_COLOR, 0, tcu::RGBA::red().toVec().getPtr());
341 gl.clearBufferfv(GL_COLOR, 1, tcu::RGBA::red().toVec().getPtr());
342
343 m_testCtx.getLog() << TestLog::Message << "Drawing to attachments " << ndx << TestLog::EndMessage;
344
345 gl.uniform1i(indexLoc, ndx);
346 glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
347 glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
348
349 GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
350
351 {
352 tcu::Surface result(width, height);
353
354 m_testCtx.getLog() << TestLog::Message << "Verifying attachment " << ndx << "..." << TestLog::EndMessage;
355
356 gl.readBuffer(GL_COLOR_ATTACHMENT0+ndx);
357 glu::readPixels(renderCtx, 0, 0, result.getAccess());
358 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
359
360 if (!compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold))
361 allOk = false;
362 }
363 }
364
365 m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
366 allOk ? "Pass" : "Image comparison failed");
367
368 return STOP;
369 }
370 };
371
372 } // anonymous
373
ShaderFragDataTests(Context & context)374 ShaderFragDataTests::ShaderFragDataTests (Context& context)
375 : TestCaseGroup(context, "fragdata", "gl_FragData[] Tests")
376 {
377 }
378
~ShaderFragDataTests(void)379 ShaderFragDataTests::~ShaderFragDataTests (void)
380 {
381 }
382
init(void)383 void ShaderFragDataTests::init (void)
384 {
385 addChild(new FragDataIndexingCase (m_context, "valid_static_index", "Valid gl_FragData[] assignment using static index", INDEX_EXPR_STATIC));
386 addChild(new FragDataIndexingCase (m_context, "valid_uniform_index", "Valid gl_FragData[] assignment using uniform index", INDEX_EXPR_UNIFORM));
387 addChild(new FragDataIndexingCase (m_context, "valid_dynamic_index", "Valid gl_FragData[] assignment using dynamic index", INDEX_EXPR_DYNAMIC));
388 addChild(new FragDataDrawBuffersCase (m_context));
389
390 // Negative cases.
391 {
392 gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
393 std::vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/fragdata.test");
394
395 for (std::vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
396 addChild(*i);
397 }
398 }
399
400 } // Functional
401 } // gles3
402 } // deqp
403