xref: /aosp_15_r20/external/deqp/modules/glshared/glsScissorTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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