1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) 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 GLES Scissor tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "glsScissorTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26
27 #include "deMath.h"
28 #include "deRandom.hpp"
29 #include "deUniquePtr.hpp"
30
31 #include "tcuTestCase.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "tcuVector.hpp"
34 #include "tcuVectorUtil.hpp"
35 #include "tcuTexture.hpp"
36 #include "tcuStringTemplate.hpp"
37
38 #include "gluStrUtil.hpp"
39 #include "gluDrawUtil.hpp"
40 #include "gluPixelTransfer.hpp"
41 #include "gluObjectWrapper.hpp"
42
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
45
46 #include <map>
47
48 namespace deqp
49 {
50 namespace gls
51 {
52 namespace Functional
53 {
54 namespace
55 {
56
57 using namespace ScissorTestInternal;
58 using namespace glw; // GL types
59
60 using tcu::ConstPixelBufferAccess;
61 using tcu::PixelBufferAccess;
62 using tcu::TestLog;
63
64 using std::vector;
65 using std::string;
66 using std::map;
67 using tcu::Vec3;
68 using tcu::Vec4;
69 using tcu::IVec4;
70 using tcu::UVec4;
71
drawQuad(const glw::Functions & gl,deUint32 program,const Vec3 & p0,const Vec3 & p1)72 void drawQuad (const glw::Functions& gl, deUint32 program, const Vec3& p0, const Vec3& p1)
73 {
74 // Vertex data.
75 const float hz = (p0.z() + p1.z()) * 0.5f;
76 const float position[] =
77 {
78 p0.x(), p0.y(), p0.z(), 1.0f,
79 p0.x(), p1.y(), hz, 1.0f,
80 p1.x(), p0.y(), hz, 1.0f,
81 p1.x(), p1.y(), p1.z(), 1.0f
82 };
83
84 const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 };
85
86 const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
87
88 gl.useProgram(program);
89 gl.enableVertexAttribArray(posLoc);
90 gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
91
92 gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
93
94 gl.disableVertexAttribArray(posLoc);
95
96 }
97
drawPrimitives(const glw::Functions & gl,deUint32 program,const deUint32 type,const vector<float> & vertices,const vector<deUint16> & indices)98 void drawPrimitives (const glw::Functions& gl, deUint32 program, const deUint32 type, const vector<float>& vertices, const vector<deUint16>& indices)
99 {
100 const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
101
102 TCU_CHECK(posLoc >= 0);
103
104 gl.useProgram(program);
105 gl.enableVertexAttribArray(posLoc);
106 gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]);
107
108 gl.drawElements(type, GLsizei(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
109
110 gl.disableVertexAttribArray(posLoc);
111 }
112
113 template<typename T>
clearEdges(const tcu::PixelBufferAccess & access,const T & color,const IVec4 & scissorArea)114 void clearEdges(const tcu::PixelBufferAccess& access, const T& color, const IVec4& scissorArea)
115 {
116 for (int y = 0; y < access.getHeight(); y++)
117 for (int x = 0; x < access.getWidth(); x++)
118 {
119 if (y < scissorArea.y() ||
120 y >= scissorArea.y() + scissorArea.w() ||
121 x < scissorArea.x() ||
122 x >= scissorArea.x()+ scissorArea.z())
123 access.setPixel(color, x, y);
124 }
125 }
126
genShaders(glu::GLSLVersion version)127 glu::ProgramSources genShaders(glu::GLSLVersion version)
128 {
129 const string vtxSource = "${VERSION}\n"
130 "${IN} highp vec4 a_position;\n"
131 "void main(){\n"
132 " gl_Position = a_position;\n"
133 "}\n";
134
135 const string frgSource = "${VERSION}\n"
136 "${OUT_DECL}"
137 "uniform highp vec4 u_color;\n"
138 "void main(){\n"
139 " ${OUTPUT} = u_color;\n"
140 "}\n";
141
142 map<string, string> params;
143
144 switch(version)
145 {
146 case glu::GLSL_VERSION_100_ES:
147 params["VERSION"] = "#version 100";
148 params["IN"] = "attribute";
149 params["OUT_DECL"] = "";
150 params["OUTPUT"] = "gl_FragColor";
151 break;
152
153 case glu::GLSL_VERSION_300_ES:
154 case glu::GLSL_VERSION_310_ES: // Assumed to support 3.0
155 params["VERSION"] = "#version 300 es";
156 params["IN"] = "in";
157 params["OUT_DECL"] = "out mediump vec4 f_color;\n";
158 params["OUTPUT"] = "f_color";
159 break;
160
161 default:
162 DE_ASSERT(!"Unsupported version");
163 }
164
165 return glu::makeVtxFragSources(tcu::StringTemplate(vtxSource).specialize(params), tcu::StringTemplate(frgSource).specialize(params));
166 }
167
168 // Wrapper class, provides iterator & reporting logic
169 class ScissorCase : public tcu::TestCase
170 {
171 public:
172 ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea);
~ScissorCase(void)173 virtual ~ScissorCase (void) {}
174
175 virtual IterateResult iterate (void);
176
177 protected:
178 virtual void render (GLuint program, const IVec4& viewport) const = 0;
179
180 glu::RenderContext& m_renderCtx;
181 const Vec4 m_scissorArea;
182 };
183
ScissorCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea)184 ScissorCase::ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea)
185 : TestCase (testCtx, name, desc)
186 , m_renderCtx (renderCtx)
187 , m_scissorArea (scissorArea)
188 {
189 }
190
iterate(void)191 ScissorCase::IterateResult ScissorCase::iterate (void)
192 {
193 using TextureTestUtil::RandomViewport;
194
195 const glw::Functions& gl = m_renderCtx.getFunctions();
196 TestLog& log = m_testCtx.getLog();
197 const glu::ShaderProgram shader (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
198
199 const RandomViewport viewport (m_renderCtx.getRenderTarget(), 256, 256, deStringHash(getName()));
200 const IVec4 relScissorArea (int(m_scissorArea.x()*viewport.width),
201 int(m_scissorArea.y()*viewport.height),
202 int(m_scissorArea.z()*viewport.width),
203 int(m_scissorArea.w()*viewport.height));
204 const IVec4 absScissorArea (relScissorArea.x() + viewport.x,
205 relScissorArea.y() + viewport.y,
206 relScissorArea.z(),
207 relScissorArea.w());
208
209 tcu::Surface refImage (viewport.width, viewport.height);
210 tcu::Surface resImage (viewport.width, viewport.height);
211
212 if (!shader.isOk())
213 {
214 log << shader;
215 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
216 return STOP;
217 }
218
219 log << TestLog::Message << "Viewport area is " << IVec4(viewport.x, viewport.y, viewport.width, viewport.height) << TestLog::EndMessage;
220 log << TestLog::Message << "Scissor area is " << absScissorArea << TestLog::EndMessage;
221
222 // Render reference (no scissors)
223 {
224 log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
225
226 gl.useProgram(shader.getProgram());
227 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
228
229 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
230 gl.clearDepthf(1.0f);
231 gl.clearStencil(0);
232 gl.disable(GL_DEPTH_TEST);
233 gl.disable(GL_STENCIL_TEST);
234 gl.disable(GL_SCISSOR_TEST);
235 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
236
237 render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
238
239 glu::readPixels(m_renderCtx, viewport.x, viewport.y, refImage.getAccess());
240 GLU_CHECK_ERROR(gl.getError());
241 }
242
243 // Render result (scissors)
244 {
245 log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
246
247 gl.useProgram(shader.getProgram());
248 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
249
250 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
251 gl.clearDepthf(1.0f);
252 gl.clearStencil(0);
253 gl.disable(GL_DEPTH_TEST);
254 gl.disable(GL_STENCIL_TEST);
255 gl.disable(GL_SCISSOR_TEST);
256 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
257
258 gl.scissor(absScissorArea.x(), absScissorArea.y(), absScissorArea.z(), absScissorArea.w());
259 gl.enable(GL_SCISSOR_TEST);
260
261 render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
262
263 glu::readPixels(m_renderCtx, viewport.x, viewport.y, resImage.getAccess());
264 GLU_CHECK_ERROR(gl.getError());
265 }
266
267 // Manual 'scissors' for reference image
268 log << TestLog::Message << "Clearing area outside scissor area from reference" << TestLog::EndMessage;
269 clearEdges(refImage.getAccess(), IVec4(32, 64, 128, 255), relScissorArea);
270
271 if (tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT))
272 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
273 else
274 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
275
276 return STOP;
277 }
278
279 // Tests scissoring with multiple primitive types
280 class ScissorPrimitiveCase : public ScissorCase
281 {
282 public:
283 ScissorPrimitiveCase (tcu::TestContext& testCtx,
284 glu::RenderContext& renderCtx,
285 const char* name,
286 const char* desc,
287 const Vec4& scissorArea,
288 const Vec4& renderArea,
289 PrimitiveType type,
290 int primitiveCount);
~ScissorPrimitiveCase(void)291 virtual ~ScissorPrimitiveCase (void){}
292
293 protected:
294 virtual void render (GLuint program, const IVec4& viewport) const;
295
296 private:
297 const Vec4 m_renderArea;
298 const PrimitiveType m_primitiveType;
299 const int m_primitiveCount;
300 };
301
ScissorPrimitiveCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,const Vec4 & renderArea,PrimitiveType type,int primitiveCount)302 ScissorPrimitiveCase::ScissorPrimitiveCase (tcu::TestContext& testCtx,
303 glu::RenderContext& renderCtx,
304 const char* name,
305 const char* desc,
306 const Vec4& scissorArea,
307 const Vec4& renderArea,
308 PrimitiveType type,
309 int primitiveCount)
310 : ScissorCase (testCtx, renderCtx, name, desc, scissorArea)
311 , m_renderArea (renderArea)
312 , m_primitiveType (type)
313 , m_primitiveCount (primitiveCount)
314 {
315 }
316
render(GLuint program,const IVec4 &) const317 void ScissorPrimitiveCase::render (GLuint program, const IVec4&) const
318 {
319 const glw::Functions& gl = m_renderCtx.getFunctions();
320 const Vec4 white (1.0f, 1.0f, 1.0f, 1.0);
321 const Vec4 primitiveArea (m_renderArea.x()*2.0f-1.0f,
322 m_renderArea.x()*2.0f-1.0f,
323 m_renderArea.z()*2.0f,
324 m_renderArea.w()*2.0f);
325
326 static const float quadPositions[] =
327 {
328 0.0f, 1.0f,
329 0.0f, 0.0f,
330 1.0f, 1.0f,
331 1.0f, 0.0f
332 };
333 static const float triPositions[] =
334 {
335 0.0f, 0.0f,
336 1.0f, 0.0f,
337 0.5f, 1.0f,
338 };
339 static const float linePositions[] =
340 {
341 0.0f, 0.0f,
342 1.0f, 1.0f
343 };
344 static const float pointPosition[] =
345 {
346 0.5f, 0.5f
347 };
348
349 const float* positionSet[] = { pointPosition, linePositions, triPositions, quadPositions };
350 const int vertexCountSet[]= { 1, 2, 3, 4 };
351 const int indexCountSet[] = { 1, 2, 3, 6 };
352
353 const deUint16 baseIndices[] = { 0, 1, 2, 2, 1, 3 };
354 const float* basePositions = positionSet[m_primitiveType];
355 const int vertexCount = vertexCountSet[m_primitiveType];
356 const int indexCount = indexCountSet[m_primitiveType];
357
358 const float scale = 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f); // Magic value to roughly fill the render area with primitives at a readable density
359 vector<float> positions (4*vertexCount*m_primitiveCount);
360 vector<deUint16> indices (indexCount*m_primitiveCount);
361 de::Random rng (1234);
362
363 for (int primNdx = 0; primNdx < m_primitiveCount; primNdx++)
364 {
365 const float dx = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
366 const float dy = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
367
368 for (int vertNdx = 0; vertNdx < vertexCount; vertNdx++)
369 {
370 const int ndx = primNdx*4*vertexCount + vertNdx*4;
371 positions[ndx+0] = (basePositions[vertNdx*2 + 0]*scale + dx)*primitiveArea.z() + primitiveArea.x();
372 positions[ndx+1] = (basePositions[vertNdx*2 + 1]*scale + dy)*primitiveArea.w() + primitiveArea.y();
373 positions[ndx+2] = 0.2f;
374 positions[ndx+3] = 1.0f;
375 }
376
377 for (int ndx = 0; ndx < indexCount; ndx++)
378 indices[primNdx*indexCount + ndx] = baseIndices[ndx] + primNdx*vertexCount;
379 }
380
381 gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.m_data);
382
383 switch (m_primitiveType)
384 {
385 case TRIANGLE: drawPrimitives(gl, program, GL_TRIANGLES, positions, indices); break;
386 case LINE: drawPrimitives(gl, program, GL_LINES, positions, indices); break;
387 case POINT: drawPrimitives(gl, program, GL_POINTS, positions, indices); break;
388 default: DE_ASSERT(false); break;
389 }
390 }
391
392 // Test effect of scissor on default framebuffer clears
393 class ScissorClearCase : public ScissorCase
394 {
395 public:
396 ScissorClearCase (tcu::TestContext& testCtx,
397 glu::RenderContext& renderCtx,
398 const char* name,
399 const char* desc,
400 const Vec4& scissorArea,
401 deUint32 clearMode);
~ScissorClearCase(void)402 virtual ~ScissorClearCase (void) {}
403
404 virtual void init (void);
405
406 protected:
407 virtual void render (GLuint program, const IVec4& viewport) const;
408
409 private:
410 const deUint32 m_clearMode; //!< Combination of the flags accepted by glClear
411 };
412
ScissorClearCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,deUint32 clearMode)413 ScissorClearCase::ScissorClearCase (tcu::TestContext& testCtx,
414 glu::RenderContext& renderCtx,
415 const char* name,
416 const char* desc,
417 const Vec4& scissorArea,
418 deUint32 clearMode)
419 : ScissorCase (testCtx, renderCtx, name, desc, scissorArea)
420 , m_clearMode (clearMode)
421 {
422 }
423
init(void)424 void ScissorClearCase::init (void)
425 {
426 if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderCtx.getRenderTarget().getDepthBits() == 0)
427 throw tcu::NotSupportedError("Cannot clear depth; no depth buffer present", "", __FILE__, __LINE__);
428 else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderCtx.getRenderTarget().getStencilBits() == 0)
429 throw tcu::NotSupportedError("Cannot clear stencil; no stencil buffer present", "", __FILE__, __LINE__);
430 }
431
render(GLuint program,const IVec4 &) const432 void ScissorClearCase::render (GLuint program, const IVec4&) const
433 {
434 const glw::Functions& gl = m_renderCtx.getFunctions();
435 const Vec4 white (1.0f, 1.0f, 1.0f, 1.0);
436
437 gl.clearColor(0.6f, 0.1f, 0.1f, 1.0);
438 gl.clearDepthf(0.0f);
439
440 if (m_clearMode & GL_DEPTH_BUFFER_BIT)
441 {
442 gl.enable(GL_DEPTH_TEST);
443 gl.depthFunc(GL_GREATER);
444 }
445
446 if (m_clearMode & GL_STENCIL_BUFFER_BIT)
447 {
448 gl.clearStencil(123);
449 gl.enable(GL_STENCIL_TEST);
450 gl.stencilFunc(GL_EQUAL, 123, ~0u);
451 }
452
453 if (m_clearMode & GL_COLOR_BUFFER_BIT)
454 gl.clearColor(0.1f, 0.6f, 0.1f, 1.0);
455
456 gl.clear(m_clearMode);
457 gl.disable(GL_SCISSOR_TEST);
458
459 gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.getPtr());
460
461 if (!(m_clearMode & GL_COLOR_BUFFER_BIT))
462 drawQuad(gl, program, Vec3(-1.0f, -1.0f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
463
464 gl.disable(GL_DEPTH_TEST);
465 gl.disable(GL_STENCIL_TEST);
466 }
467
468 class FramebufferBlitCase : public ScissorCase
469 {
470 public:
471 FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea);
~FramebufferBlitCase(void)472 virtual ~FramebufferBlitCase (void) {}
473
474 virtual void init (void);
475 virtual void deinit (void);
476
477 protected:
478 typedef de::MovePtr<glu::Framebuffer> FramebufferP;
479
480 enum {SIZE = 64};
481
482 virtual void render (GLuint program, const IVec4& viewport) const;
483
484 FramebufferP m_fbo;
485 };
486
FramebufferBlitCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea)487 FramebufferBlitCase::FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea)
488 : ScissorCase(testCtx, renderCtx, name, desc, scissorArea)
489 {
490 }
491
init(void)492 void FramebufferBlitCase::init (void)
493 {
494 if (m_renderCtx.getRenderTarget().getNumSamples())
495 throw tcu::NotSupportedError("Cannot blit to multisampled framebuffer", "", __FILE__, __LINE__);
496
497 const glw::Functions& gl = m_renderCtx.getFunctions();
498 const glu::Renderbuffer colorbuf (gl);
499 const tcu::Vec4 clearColor (1.0f, 0.5, 0.125f, 1.0f);
500
501 m_fbo = FramebufferP(new glu::Framebuffer(gl));
502
503 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
504
505 gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
506 gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SIZE, SIZE);
507 gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
508
509 gl.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());
510 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_renderCtx.getDefaultFramebuffer());
511 }
512
deinit(void)513 void FramebufferBlitCase::deinit (void)
514 {
515 m_fbo.clear();
516 }
517
render(GLuint program,const IVec4 & viewport) const518 void FramebufferBlitCase::render(GLuint program, const IVec4& viewport) const
519 {
520 const glw::Functions& gl = m_renderCtx.getFunctions();
521
522 const int width = viewport.z();
523 const int height = viewport.w();
524 const deInt32 defaultFramebuffer = m_renderCtx.getDefaultFramebuffer();
525
526 DE_UNREF(program);
527
528 // blit to default framebuffer
529 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
530 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
531
532 gl.blitFramebuffer(0, 0, SIZE, SIZE, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
533
534 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer);
535 }
536
537 struct BufferFmtDesc
538 {
539 tcu::TextureFormat texFmt;
540 GLenum colorFmt;
541 };
542
543 struct Color
544 {
545 enum Type {FLOAT, INT, UINT};
546
547 Type type;
548
549 union
550 {
551 float f[4];
552 deInt32 i[4];
553 deUint32 u[4];
554 };
555
Colordeqp::gls::Functional::__anonf0c93c320111::Color556 Color(const float f_[4]) : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; }
Colordeqp::gls::Functional::__anonf0c93c320111::Color557 Color(const deInt32 i_[4]) : type(INT) { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; }
Colordeqp::gls::Functional::__anonf0c93c320111::Color558 Color(const deUint32 u_[4]) : type(UINT) { u[0] = u_[0]; u[1] = u_[1]; u[2] = u_[2]; u[3] = u_[3]; }
559 };
560
561 class FramebufferClearCase : public tcu::TestCase
562 {
563 public:
564 FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType);
~FramebufferClearCase(void)565 virtual ~FramebufferClearCase (void) {}
566
567 virtual IterateResult iterate (void);
568
569 private:
570 static void clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil);
571 static Color getBaseColor (const BufferFmtDesc& bufferFmt);
572 static Color getMainColor (const BufferFmtDesc& bufferFmt);
573 static BufferFmtDesc getBufferFormat (ClearType type);
574
575 virtual void render (GLuint program) const;
576
577 glu::RenderContext& m_renderCtx;
578 const ClearType m_clearType;
579 };
580
FramebufferClearCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,ClearType clearType)581 FramebufferClearCase::FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType)
582 : tcu::TestCase (testCtx, name, desc)
583 , m_renderCtx (renderCtx)
584 , m_clearType (clearType)
585 {
586 }
587
clearBuffers(const glw::Functions & gl,Color color,float depth,int stencil)588 void FramebufferClearCase::clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil)
589 {
590 switch(color.type)
591 {
592 case Color::FLOAT: gl.clearBufferfv (GL_COLOR, 0, color.f); break;
593 case Color::INT: gl.clearBufferiv (GL_COLOR, 0, color.i); break;
594 case Color::UINT: gl.clearBufferuiv(GL_COLOR, 0, color.u); break;
595 default:
596 DE_ASSERT(false);
597 }
598
599 gl.clearBufferfv(GL_DEPTH, 0, &depth);
600 gl.clearBufferiv(GL_STENCIL, 0, &stencil);
601 }
602
iterate(void)603 FramebufferClearCase::IterateResult FramebufferClearCase::iterate (void)
604 {
605 TestLog& log = m_testCtx.getLog();
606 const glw::Functions& gl = m_renderCtx.getFunctions();
607 const glu::ShaderProgram shader (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
608
609 const glu::Framebuffer fbo (gl);
610 const glu::Renderbuffer colorbuf (gl);
611 const glu::Renderbuffer depthbuf (gl);
612
613 const BufferFmtDesc bufferFmt = getBufferFormat(m_clearType);
614 const Color baseColor = getBaseColor(bufferFmt);
615
616 const int width = 64;
617 const int height = 64;
618
619 const IVec4 scissorArea (8, 8, 48, 48);
620
621 vector<deUint8> refData (width*height*bufferFmt.texFmt.getPixelSize());
622 vector<deUint8> resData (width*height*bufferFmt.texFmt.getPixelSize());
623
624 tcu::PixelBufferAccess refAccess (bufferFmt.texFmt, width, height, 1, &refData[0]);
625 tcu::PixelBufferAccess resAccess (bufferFmt.texFmt, width, height, 1, &resData[0]);
626
627 if (!shader.isOk())
628 {
629 log << shader;
630 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
631 return STOP;
632 }
633
634 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
635 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *fbo);
636
637 // Color
638 gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
639 gl.renderbufferStorage(GL_RENDERBUFFER, bufferFmt.colorFmt, width, height);
640 gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
641
642 // Depth/stencil
643 gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuf);
644 gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
645 gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *depthbuf);
646
647 log << TestLog::Message << "Scissor area is " << scissorArea << TestLog::EndMessage;
648
649 // Render reference
650 {
651 log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
652
653 gl.useProgram(shader.getProgram());
654 gl.viewport(0, 0, width, height);
655
656 gl.disable(GL_DEPTH_TEST);
657 gl.disable(GL_STENCIL_TEST);
658 gl.disable(GL_SCISSOR_TEST);
659
660 clearBuffers(gl, baseColor, 1.0f, 0);
661
662 render(shader.getProgram());
663
664 glu::readPixels(m_renderCtx, 0, 0, refAccess);
665 GLU_CHECK_ERROR(gl.getError());
666 }
667
668 // Render result
669 {
670 log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
671
672 gl.useProgram(shader.getProgram());
673 gl.viewport(0, 0, width, height);
674
675 gl.disable(GL_DEPTH_TEST);
676 gl.disable(GL_STENCIL_TEST);
677 gl.disable(GL_SCISSOR_TEST);
678
679 clearBuffers(gl, baseColor, 1.0f, 0);
680
681 gl.enable(GL_SCISSOR_TEST);
682 gl.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
683
684 render(shader.getProgram());
685
686 glu::readPixels(m_renderCtx, 0, 0, resAccess);
687 GLU_CHECK_ERROR(gl.getError());
688 }
689
690 {
691 bool resultOk = false;
692
693 switch (baseColor.type)
694 {
695 case Color::FLOAT:
696 clearEdges(refAccess, Vec4(baseColor.f[0], baseColor.f[1], baseColor.f[2], baseColor.f[3]), scissorArea);
697 resultOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT);
698 break;
699
700 case Color::INT:
701 clearEdges(refAccess, IVec4(baseColor.i[0], baseColor.i[1], baseColor.i[2], baseColor.i[3]), scissorArea);
702 resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
703 break;
704
705 case Color::UINT:
706 clearEdges(refAccess, UVec4(baseColor.u[0], baseColor.u[1], baseColor.u[2], baseColor.u[3]), scissorArea);
707 resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
708 break;
709 }
710
711 if (resultOk)
712 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
713 else
714 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
715 }
716
717 return STOP;
718 }
719
getBaseColor(const BufferFmtDesc & bufferFmt)720 Color FramebufferClearCase::getBaseColor (const BufferFmtDesc& bufferFmt)
721 {
722 const float f[4] = {0.125f, 0.25f, 0.5f, 1.0f};
723 const deInt32 i[4] = {0, 0, 0, 0};
724 const deUint32 u[4] = {0, 0, 0, 0};
725
726 switch(bufferFmt.colorFmt)
727 {
728 case GL_RGBA8: return Color(f);
729 case GL_RGBA8I: return Color(i);
730 case GL_RGBA8UI: return Color(u);
731 default:
732 DE_ASSERT(false);
733 }
734
735 return Color(f);
736 }
737
getMainColor(const BufferFmtDesc & bufferFmt)738 Color FramebufferClearCase::getMainColor (const BufferFmtDesc& bufferFmt)
739 {
740 const float f[4] = {1.0f, 1.0f, 0.5f, 1.0f};
741 const deInt32 i[4] = {127, -127, 0, 127};
742 const deUint32 u[4] = {255, 255, 0, 255};
743
744 switch(bufferFmt.colorFmt)
745 {
746 case GL_RGBA8: return Color(f);
747 case GL_RGBA8I: return Color(i);
748 case GL_RGBA8UI: return Color(u);
749 default:
750 DE_ASSERT(false);
751 }
752
753 return Color(f);
754 }
755
getBufferFormat(ClearType type)756 BufferFmtDesc FramebufferClearCase::getBufferFormat (ClearType type)
757 {
758 BufferFmtDesc retval;
759
760 switch (type)
761 {
762 case CLEAR_COLOR_FLOAT:
763 retval.colorFmt = GL_RGBA16F;
764 retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT);
765 DE_ASSERT(!"Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension...
766 break;
767
768 case CLEAR_COLOR_INT:
769 retval.colorFmt = GL_RGBA8I;
770 retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
771 break;
772
773 case CLEAR_COLOR_UINT:
774 retval.colorFmt = GL_RGBA8UI;
775 retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
776 break;
777
778 default:
779 retval.colorFmt = GL_RGBA8;
780 retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
781 break;
782 }
783
784 return retval;
785 }
786
render(GLuint program) const787 void FramebufferClearCase::render (GLuint program) const
788 {
789 const glw::Functions& gl = m_renderCtx.getFunctions();
790
791 const BufferFmtDesc bufferFmt = getBufferFormat(m_clearType);
792 const Color clearColor = getMainColor(bufferFmt);
793
794 const int clearStencil = 123;
795 const float clearDepth = 0.5f;
796
797 switch (m_clearType)
798 {
799 case CLEAR_COLOR_FIXED: gl.clearBufferfv (GL_COLOR, 0, clearColor.f); break;
800 case CLEAR_COLOR_FLOAT: gl.clearBufferfv (GL_COLOR, 0, clearColor.f); break;
801 case CLEAR_COLOR_INT: gl.clearBufferiv (GL_COLOR, 0, clearColor.i); break;
802 case CLEAR_COLOR_UINT: gl.clearBufferuiv(GL_COLOR, 0, clearColor.u); break;
803 case CLEAR_DEPTH: gl.clearBufferfv (GL_DEPTH, 0, &clearDepth); break;
804 case CLEAR_STENCIL: gl.clearBufferiv (GL_STENCIL, 0, &clearStencil); break;
805 case CLEAR_DEPTH_STENCIL: gl.clearBufferfi (GL_DEPTH_STENCIL, 0, clearDepth, clearStencil); break;
806
807 default:
808 DE_ASSERT(false);
809 }
810
811 const bool useDepth = (m_clearType == CLEAR_DEPTH || m_clearType == CLEAR_DEPTH_STENCIL);
812 const bool useStencil = (m_clearType == CLEAR_STENCIL || m_clearType == CLEAR_DEPTH_STENCIL);
813
814 // Render something to expose changes to depth/stencil buffer
815 if (useDepth || useStencil)
816 {
817 if (useDepth)
818 gl.enable(GL_DEPTH_TEST);
819
820 if (useStencil)
821 gl.enable(GL_STENCIL_TEST);
822
823 gl.stencilFunc(GL_EQUAL, clearStencil, ~0u);
824 gl.depthFunc(GL_GREATER);
825 gl.disable(GL_SCISSOR_TEST);
826
827 gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, clearColor.f);
828 drawQuad(gl, program, tcu::Vec3(-1.0f, -1.0f, 0.6f), tcu::Vec3(1.0f, 1.0f, 0.6f));
829 }
830 }
831
832 } // Anonymous
833
834 namespace ScissorTestInternal
835 {
836
createPrimitiveTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,const Vec4 & renderArea,PrimitiveType type,int primitiveCount)837 tcu::TestNode* createPrimitiveTest (tcu::TestContext& testCtx,
838 glu::RenderContext& renderCtx,
839 const char* name,
840 const char* desc,
841 const Vec4& scissorArea,
842 const Vec4& renderArea,
843 PrimitiveType type,
844 int primitiveCount)
845 {
846 return new ScissorPrimitiveCase(testCtx, renderCtx, name, desc, scissorArea, renderArea, type, primitiveCount);
847 }
848
createClearTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea,deUint32 clearMode)849 tcu::TestNode* createClearTest (tcu::TestContext& testCtx,
850 glu::RenderContext& renderCtx,
851 const char* name,
852 const char* desc,
853 const Vec4& scissorArea,
854 deUint32 clearMode)
855 {
856 return new ScissorClearCase(testCtx, renderCtx, name, desc, scissorArea, clearMode);
857 }
858
createFramebufferClearTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,ClearType clearType)859 tcu::TestNode* createFramebufferClearTest (tcu::TestContext& testCtx,
860 glu::RenderContext& renderCtx,
861 const char* name,
862 const char* desc,
863 ClearType clearType)
864 {
865 return new FramebufferClearCase(testCtx, renderCtx, name, desc, clearType);
866 }
867
createFramebufferBlitTest(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * desc,const Vec4 & scissorArea)868 tcu::TestNode* createFramebufferBlitTest (tcu::TestContext& testCtx,
869 glu::RenderContext& renderCtx,
870 const char* name,
871 const char* desc,
872 const Vec4& scissorArea)
873 {
874 return new FramebufferBlitCase(testCtx, renderCtx, name, desc, scissorArea);
875 }
876
877 } // ScissorTestInternal
878 } // Functional
879 } // gls
880 } // deqp
881