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