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