xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fClipControlTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2019 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 /**
25  * \file  gl2fClipControlTests.cpp
26  * \brief Implements conformance tests for "EXT_clip_control" functionality.
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "es2fClipControlTests.hpp"
30 
31 #include "deSharedPtr.hpp"
32 
33 #include "gluContextInfo.hpp"
34 #include "gluDrawUtil.hpp"
35 #include "gluDefs.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluShaderProgram.hpp"
38 
39 #include "tcuFuzzyImageCompare.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuRenderTarget.hpp"
42 #include "tcuSurface.hpp"
43 #include "tcuTestLog.hpp"
44 
45 #include "glw.h"
46 #include "glwFunctions.hpp"
47 
48 #include <cmath>
49 
50 namespace deqp
51 {
52 namespace gles2
53 {
54 namespace Functional
55 {
56 
57 class ClipControlApi
58 {
59 public:
ClipControlApi(Context & context)60     ClipControlApi(Context &context) : m_context(context)
61     {
62         if (!Supported(m_context))
63         {
64             throw tcu::NotSupportedError("Required extension EXT_clip_control is not supported");
65         }
66         clipControl = context.getRenderContext().getFunctions().clipControl;
67     }
68 
Supported(Context & context)69     static bool Supported(Context &context)
70     {
71         return context.getContextInfo().isExtensionSupported("GL_EXT_clip_control");
72     }
73 
74     glw::glClipControlFunc clipControl;
75 
76 private:
77     Context &m_context;
78 };
79 
80 class ClipControlBaseTest : public TestCase
81 {
82 protected:
ClipControlBaseTest(Context & context,const char * name,const char * description)83     ClipControlBaseTest(Context &context, const char *name, const char *description)
84         : TestCase(context, name, description)
85     {
86     }
87 
init()88     void init() override
89     {
90         ClipControlApi api(m_context);
91     }
92 
verifyState(glw::GLenum origin,glw::GLenum depth)93     bool verifyState(glw::GLenum origin, glw::GLenum depth)
94     {
95         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
96 
97         bool ret = true;
98 
99         glw::GLint retI;
100         gl.getIntegerv(GL_CLIP_ORIGIN, &retI);
101         GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_CLIP_ORIGIN");
102 
103         ret &= (static_cast<glw::GLenum>(retI) == origin);
104 
105         gl.getIntegerv(GL_CLIP_DEPTH_MODE, &retI);
106         GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_CLIP_DEPTH_MODE");
107 
108         ret &= (static_cast<glw::GLenum>(retI) == depth);
109 
110         return ret;
111     }
112 };
113 
114 class ClipControlRenderBaseTest : public ClipControlBaseTest
115 {
116 protected:
ClipControlRenderBaseTest(Context & context,const char * name,const char * description)117     ClipControlRenderBaseTest(Context &context, const char *name, const char *description)
118         : ClipControlBaseTest(context, name, description)
119         , m_fbo(0)
120         , m_rboC(0)
121         , m_depthTexure(0)
122     {
123     }
124 
fsh()125     const char *fsh()
126     {
127         return "void main() {"
128                "\n"
129                "    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);"
130                "\n"
131                "}";
132     }
133 
fuzzyDepthCompare(tcu::TestLog & log,const char * imageSetName,const char * imageSetDesc,const tcu::TextureLevel & reference,const tcu::TextureLevel & result,float threshold,const tcu::TextureLevel * importanceMask=NULL)134     bool fuzzyDepthCompare(tcu::TestLog &log, const char *imageSetName, const char *imageSetDesc,
135                            const tcu::TextureLevel &reference, const tcu::TextureLevel &result, float threshold,
136                            const tcu::TextureLevel *importanceMask = NULL)
137     {
138         (void)imageSetName;
139         (void)imageSetDesc;
140         bool depthOk     = true;
141         float difference = 0.0f;
142 
143         for (int y = 0; y < result.getHeight() && depthOk; y++)
144         {
145             for (int x = 0; x < result.getWidth() && depthOk; x++)
146             {
147                 float ref  = reference.getAccess().getPixDepth(x, y);
148                 float res  = result.getAccess().getPixel(x, y).x();
149                 difference = std::abs(ref - res);
150                 if (importanceMask)
151                 {
152                     difference *= importanceMask->getAccess().getPixDepth(x, y);
153                 }
154                 depthOk &= (difference < threshold);
155             }
156         }
157 
158         if (!depthOk)
159             log << tcu::TestLog::Message << "Image comparison failed: difference = " << difference
160                 << ", threshold = " << threshold << tcu::TestLog::EndMessage;
161         tcu::Vec4 pixelBias(0.0f, 0.0f, 0.0f, 0.0f);
162         tcu::Vec4 pixelScale(1.0f, 1.0f, 1.0f, 1.0f);
163         log << tcu::TestLog::ImageSet("Result", "Depth image comparison result")
164             << tcu::TestLog::Image("Result", "Result", result.getAccess(), pixelScale, pixelBias)
165             << tcu::TestLog::Image("Reference", "Reference", reference.getAccess(), pixelScale, pixelBias);
166         if (importanceMask)
167         {
168             log << tcu::TestLog::Image("Importance mask", "mask", importanceMask->getAccess(), pixelScale, pixelBias);
169         }
170         log << tcu::TestLog::EndImageSet;
171 
172         return depthOk;
173     }
174 
init(void)175     virtual void init(void)
176     {
177         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
178         glw::GLuint viewportW                 = renderTarget.getWidth();
179         glw::GLuint viewportH                 = renderTarget.getHeight();
180         const glw::Functions &gl              = m_context.getRenderContext().getFunctions();
181 
182         gl.genFramebuffers(1, &m_fbo);
183         gl.genRenderbuffers(1, &m_rboC);
184         gl.genTextures(1, &m_depthTexure);
185 
186         gl.bindRenderbuffer(GL_RENDERBUFFER, m_rboC);
187         gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, viewportW, viewportH);
188 
189         gl.bindTexture(GL_TEXTURE_2D, m_depthTexure);
190         gl.texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewportW, viewportH, 0, GL_DEPTH_COMPONENT,
191                       GL_UNSIGNED_SHORT, DE_NULL);
192 
193         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
194         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rboC);
195         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexure, 0);
196     }
197 
deinit(void)198     virtual void deinit(void)
199     {
200         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
201         gl.deleteFramebuffers(1, &m_fbo);
202         gl.deleteRenderbuffers(1, &m_rboC);
203         gl.deleteTextures(1, &m_depthTexure);
204         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
205     }
206 
getDepthTexture()207     GLuint getDepthTexture()
208     {
209         return m_depthTexure;
210     }
211 
212 private:
213     GLuint m_fbo, m_rboC, m_depthTexure;
214 };
215 
216 /*
217  Verify the following state values are implemented and return a valid
218  initial value by calling GetIntegerv:
219 
220  Get Value                                 Initial Value
221  -------------------------------------------------------
222  CLIP_ORIGIN                                  LOWER_LEFT
223  CLIP_DEPTH_MODE                     NEGATIVE_ONE_TO_ONE
224 
225  Verify no GL error is generated.
226  */
227 class ClipControlInitialState : public ClipControlBaseTest
228 {
229 public:
ClipControlInitialState(Context & context,const char * name)230     ClipControlInitialState(Context &context, const char *name)
231         : ClipControlBaseTest(context, name, "Verify initial state")
232     {
233     }
234 
iterate()235     IterateResult iterate() override
236     {
237         if (!verifyState(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE))
238         {
239             TCU_FAIL("Wrong intitial state: GL_CLIP_ORIGIN should be GL_LOWER_LEFT,"
240                      " GL_CLIP_ORIGIN should be NEGATIVE_ONE_TO_ONE");
241         }
242 
243         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
244         return STOP;
245     }
246 };
247 
248 /*
249  Modify the state to each of the following combinations and after each
250  state change verify the state values:
251 
252  ClipControl(UPPER_LEFT, ZERO_TO_ONE)
253  ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
254  ClipControl(LOWER_LEFT, ZERO_TO_ONE)
255  ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE)
256 
257  Verify no GL error is generated.
258 
259  */
260 class ClipControlModifyGetState : public ClipControlBaseTest
261 {
262 public:
ClipControlModifyGetState(Context & context,const char * name)263     ClipControlModifyGetState(Context &context, const char *name)
264         : ClipControlBaseTest(context, name, "Verify initial state")
265     {
266     }
267 
deinit()268     void deinit() override
269     {
270         if (ClipControlApi::Supported(m_context))
271         {
272             ClipControlApi cc(m_context);
273             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
274         }
275     }
276 
iterate()277     IterateResult iterate() override
278     {
279         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
280         ClipControlApi cc(m_context);
281 
282         GLenum cases[4][2] = {
283             {GL_UPPER_LEFT, GL_ZERO_TO_ONE},
284             {GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE},
285             {GL_LOWER_LEFT, GL_ZERO_TO_ONE},
286             {GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE},
287         };
288 
289         for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(cases); i++)
290         {
291             cc.clipControl(cases[i][0], cases[i][1]);
292             GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
293             if (!verifyState(cases[i][0], cases[i][1]))
294             {
295                 TCU_FAIL("Wrong ClipControl state after ClipControl() call");
296             }
297         }
298 
299         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
300         return STOP;
301     }
302 };
303 
304 /*
305  Check that ClipControl generate an GL_INVALID_ENUM error if origin is
306  not GL_LOWER_LEFT or GL_UPPER_LEFT.
307 
308  Check that ClipControl generate an GL_INVALID_ENUM error if depth is
309  not GL_NEGATIVE_ONE_TO_ONE or GL_ZERO_TO_ONE.
310 
311  Test is based on OpenGL 4.5 Core Profile Specification May 28th Section
312  13.5 Primitive Clipping:
313  "An INVALID_ENUM error is generated if origin is not LOWER_LEFT or
314  UPPER_LEFT.
315  An INVALID_ENUM error is generated if depth is not NEGATIVE_ONE_-
316  TO_ONE or ZERO_TO_ONE."
317  */
318 class ClipControlErrors : public ClipControlBaseTest
319 {
320 public:
ClipControlErrors(Context & context,const char * name)321     ClipControlErrors(Context &context, const char *name)
322         : ClipControlBaseTest(context, name, "Verify that proper errors are generated when using ClipControl.")
323     {
324     }
325 
deinit()326     void deinit() override
327     {
328         if (ClipControlApi::Supported(m_context))
329         {
330             ClipControlApi cc(m_context);
331             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
332         }
333     }
334 
iterate()335     IterateResult iterate() override
336     {
337         /* API query */
338         tcu::TestLog &log        = m_testCtx.getLog();
339         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
340         ClipControlApi cc(m_context);
341 
342         /* Finding improper value. */
343         GLenum improper_value = GL_NONE;
344 
345         while ((GL_UPPER_LEFT == improper_value) || (GL_LOWER_LEFT == improper_value) ||
346                (GL_ZERO_TO_ONE == improper_value) || (GL_NEGATIVE_ONE_TO_ONE == improper_value))
347         {
348             ++improper_value;
349         }
350 
351         /* Test setup. */
352         GLenum cases[5][2] = {{GL_UPPER_LEFT, improper_value},
353                               {GL_LOWER_LEFT, improper_value},
354                               {improper_value, GL_ZERO_TO_ONE},
355                               {improper_value, GL_NEGATIVE_ONE_TO_ONE},
356                               {improper_value, improper_value}};
357 
358         /* Test iterations. */
359         for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(cases); i++)
360         {
361             cc.clipControl(cases[i][0], cases[i][1]);
362 
363             if (GL_INVALID_ENUM != gl.getError())
364             {
365                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
366 
367                 log << tcu::TestLog::Message
368                     << "ClipControl have not generated GL_INVALID_ENUM error when called with invalid value ("
369                     << cases[i][0] << ", " << cases[i][1] << ")." << tcu::TestLog::EndMessage;
370             }
371         }
372 
373         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
374         return STOP;
375     }
376 };
377 
378 /*
379  Clip Control Origin Test
380 
381  * Basic <origin> behavior can be tested by rendering to a viewport with
382  clip coordinates where -1.0 <= x_c <= 0.0 and -1.0 <= y_c <= 0.0.
383  When <origin> is LOWER_LEFT the "bottom left" portion of the window
384  is rendered and when UPPER_LEFT is used the "top left" portion of the
385  window is rendered. The default framebuffer should be bound. Here is the
386  basic outline of the test:
387 
388  - Clear the default framebuffer to red (1,0,0).
389  - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
390  - Render a triangle fan covering (-1.0, -1.0) to (0.0, 0.0) and
391  write a pixel value of green (0,1,0).
392  - Read back the default framebuffer with ReadPixels
393  - Verify the green pixels at the top and red at the bottom.
394 
395  Repeat the above test with LOWER_LEFT and verify green at the bottom
396  and red at the top.
397  */
398 class ClipControlOriginTest : public ClipControlRenderBaseTest
399 {
400 public:
ClipControlOriginTest(Context & context,const char * name)401     ClipControlOriginTest(Context &context, const char *name)
402         : ClipControlRenderBaseTest(context, name, "Clip Control Origin Test")
403         , m_vao(0)
404         , m_vbo(0)
405     {
406     }
407 
deinit()408     void deinit() override
409     {
410         ClipControlRenderBaseTest::deinit();
411 
412         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
413         if (ClipControlApi::Supported(m_context))
414         {
415             ClipControlApi cc(m_context);
416             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
417         }
418 
419         gl.clearColor(0.0, 0.0, 0.0, 0.0);
420         if (m_vao)
421         {
422             gl.deleteVertexArrays(1, &m_vao);
423         }
424         if (m_vbo)
425         {
426             gl.deleteBuffers(1, &m_vbo);
427         }
428     }
429 
iterate()430     IterateResult iterate() override
431     {
432 
433         tcu::TestLog &log        = m_testCtx.getLog();
434         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
435         ClipControlApi cc(m_context);
436 
437         //Render a triangle fan covering(-1.0, -1.0) to(1.0, 0.0) and
438         //write a pixel value of green(0, 1, 0).
439 
440         de::SharedPtr<glu::ShaderProgram> program(
441             new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
442 
443         log << (*program);
444         if (!program->isOk())
445         {
446             TCU_FAIL("Program compilation failed");
447         }
448 
449         gl.genVertexArrays(1, &m_vao);
450         gl.bindVertexArray(m_vao);
451 
452         gl.genBuffers(1, &m_vbo);
453 
454         const float vertex_data0[] = {-1.0, -1.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.0};
455 
456         gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
457         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
458 
459         gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
460         gl.enableVertexAttribArray(0);
461 
462         gl.useProgram(program->getProgram());
463 
464         glw::GLenum origins[] = {GL_UPPER_LEFT, GL_LOWER_LEFT};
465 
466         qpTestResult result = QP_TEST_RESULT_PASS;
467 
468         for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++)
469         {
470             //Clear the default framebuffer to red(1, 0, 0).
471             gl.clearColor(1.0, 0.0, 0.0, 1.0);
472             gl.clear(GL_COLOR_BUFFER_BIT);
473 
474             //Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
475             cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE);
476             GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
477 
478             //test method modification: use GL_TRIANGLE_STRIP, not FAN.
479             gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
480 
481             //Read back the default framebuffer with ReadPixels
482             //Verify the green pixels at the top and red at the bottom.
483             qpTestResult loopResult = ValidateFramebuffer(m_context, origins[orig]);
484             if (loopResult != QP_TEST_RESULT_PASS)
485             {
486                 result = loopResult;
487             }
488         }
489 
490         m_testCtx.setTestResult(result, qpGetTestResultName(result));
491 
492         return STOP;
493     }
494 
vsh()495     const char *vsh()
496     {
497         return "attribute highp vec2 Position;"
498                "\n"
499                "void main() {"
500                "\n"
501                "    gl_Position = vec4(Position, 0.0, 1.0);"
502                "\n"
503                "}";
504     }
505 
ValidateFramebuffer(Context & context,glw::GLenum origin)506     qpTestResult ValidateFramebuffer(Context &context, glw::GLenum origin)
507     {
508         const tcu::RenderTarget &renderTarget = context.getRenderContext().getRenderTarget();
509         glw::GLsizei viewportW                = renderTarget.getWidth();
510         glw::GLsizei viewportH                = renderTarget.getHeight();
511         tcu::Surface renderedFrame(viewportW, viewportH);
512         tcu::Surface referenceFrame(viewportW, viewportH);
513 
514         tcu::TestLog &log = context.getTestContext().getLog();
515 
516         for (int y = 0; y < renderedFrame.getHeight(); y++)
517         {
518             float yCoord = (float)(y) / (float)renderedFrame.getHeight();
519 
520             for (int x = 0; x < renderedFrame.getWidth(); x++)
521             {
522 
523                 float xCoord = (float)(x) / (float)renderedFrame.getWidth();
524 
525                 bool greenQuadrant;
526 
527                 if (origin == GL_UPPER_LEFT)
528                 {
529                     greenQuadrant = (yCoord > 0.5 && xCoord <= 0.5);
530                 }
531                 else
532                 {
533                     greenQuadrant = (yCoord <= 0.5 && xCoord <= 0.5);
534                 }
535 
536                 if (greenQuadrant)
537                 {
538                     referenceFrame.setPixel(x, y, tcu::RGBA::green());
539                 }
540                 else
541                 {
542                     referenceFrame.setPixel(x, y, tcu::RGBA::red());
543                 }
544             }
545         }
546 
547         glu::readPixels(context.getRenderContext(), 0, 0, renderedFrame.getAccess());
548 
549         if (tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
550                               tcu::COMPARE_LOG_RESULT))
551         {
552             return QP_TEST_RESULT_PASS;
553         }
554         else
555         {
556             return QP_TEST_RESULT_FAIL;
557         }
558     }
559 
560     glw::GLuint m_vao, m_vbo;
561 };
562 
563 /*
564  Clip Control Origin With Face Culling Test
565 
566  * Face culling should be tested with both <origin> settings.
567  The reason for that is, when doing Y-inversion, implementation
568  should not flip the calculated area sign for the triangle.
569  In other words, culling of CCW and CW triangles should
570  be orthogonal to used <origin> mode. Both triangle windings
571  and both <origin> modes should be tested. Here is the basic
572  outline of the test:
573 
574  - Clear the framebuffer to red (1,0,0).
575  - Enable GL_CULL_FACE, leave default front face & cull face (CCW, BACK)
576  - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
577  - Render a counter-clockwise triangles covering
578  (-1.0, -1.0) to (0.0, 1.0) and write a pixel value of green (0,1,0).
579  - Render a clockwise triangles covering
580  (0.0, -1.0) to (1.0, 1.0) and write a pixel value of green (0,1,0).
581  - Read back the framebuffer with ReadPixels
582  - Verify the green pixels at the left and red at the right.
583 
584  Repeat above test for ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE)
585  */
586 class ClipControlFaceCulling : public ClipControlRenderBaseTest
587 {
588 public:
ClipControlFaceCulling(Context & context,const char * name)589     ClipControlFaceCulling(Context &context, const char *name)
590         : ClipControlRenderBaseTest(context, name, "Face culling test, both origins")
591         , m_vao(0)
592         , m_vbo(0)
593     {
594     }
595 
deinit()596     void deinit()
597     {
598         ClipControlRenderBaseTest::deinit();
599 
600         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
601 
602         if (ClipControlApi::Supported(m_context))
603         {
604             ClipControlApi cc(m_context);
605             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
606         }
607 
608         gl.disable(GL_CULL_FACE);
609 
610         gl.clearColor(0.0, 0.0, 0.0, 0.0);
611 
612         gl.disable(GL_DEPTH_TEST);
613         gl.depthFunc(GL_LESS);
614 
615         if (m_vao)
616         {
617             gl.deleteVertexArrays(1, &m_vao);
618         }
619         if (m_vbo)
620         {
621             gl.deleteBuffers(1, &m_vbo);
622         }
623     }
624 
iterate()625     IterateResult iterate()
626     {
627 
628         tcu::TestLog &log        = m_testCtx.getLog();
629         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
630         ClipControlApi cc(m_context);
631 
632         //Enable GL_CULL_FACE, leave default front face & cull face(CCW, BACK)
633         gl.enable(GL_CULL_FACE);
634 
635         //Render a counter-clockwise triangles covering
636         //(-1.0, -1.0) to(0.0, 1.0) and write a pixel value of green(0, 1, 0).
637         //Render a clockwise triangles covering
638         //(0.0, -1.0) to(1.0, 1.0) and write a pixel value of green(0, 1, 0).
639         de::SharedPtr<glu::ShaderProgram> program(
640             new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
641 
642         log << (*program);
643         if (!program->isOk())
644         {
645             TCU_FAIL("Program compilation failed");
646         }
647 
648         gl.genVertexArrays(1, &m_vao);
649         gl.bindVertexArray(m_vao);
650 
651         gl.genBuffers(1, &m_vbo);
652 
653         const float vertex_data0[] = {
654             //CCW
655             -1.0,
656             -1.0,
657             0.0,
658             -1.0,
659             -1.0,
660             1.0,
661             0.0,
662             -1.0,
663             0.0,
664             1.0,
665             -1.0,
666             1.0,
667             //CW
668             0.0,
669             -1.0,
670             0.0,
671             1.0,
672             1.0,
673             -1.0,
674             1.0,
675             -1.0,
676             0.0,
677             1.0,
678             1.0,
679             1.0,
680         };
681 
682         gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
683         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
684 
685         gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
686         gl.enableVertexAttribArray(0);
687 
688         gl.useProgram(program->getProgram());
689 
690         glw::GLenum origins[] = {GL_UPPER_LEFT, GL_LOWER_LEFT};
691 
692         qpTestResult result = QP_TEST_RESULT_PASS;
693 
694         for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++)
695         {
696             //Clear the framebuffer to red (1,0,0).
697             gl.clearColor(1.0, 0.0, 0.0, 1.0);
698             gl.clear(GL_COLOR_BUFFER_BIT);
699 
700             gl.drawArrays(GL_TRIANGLES, 0, 12);
701 
702             //Set ClipControl(<origin>, NEGATIVE_ONE_TO_ONE)
703             cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE);
704             GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
705 
706             //Read back the framebuffer with ReadPixels
707             //Verify the green pixels at the left and red at the right.
708             qpTestResult loopResult = ValidateFramebuffer(m_context);
709             if (loopResult != QP_TEST_RESULT_PASS)
710             {
711                 result = loopResult;
712             }
713         }
714         m_testCtx.setTestResult(result, qpGetTestResultName(result));
715 
716         return STOP;
717     }
718 
vsh()719     const char *vsh()
720     {
721         return "attribute  highp vec3 Position;"
722                "\n"
723                "void main() {"
724                "\n"
725                "    gl_Position = vec4(Position, 1.0);"
726                "\n"
727                "}";
728     }
729 
ValidateFramebuffer(Context & context)730     qpTestResult ValidateFramebuffer(Context &context)
731     {
732         const tcu::RenderTarget &renderTarget = context.getRenderContext().getRenderTarget();
733         glw::GLsizei viewportW                = renderTarget.getWidth();
734         glw::GLsizei viewportH                = renderTarget.getHeight();
735         tcu::Surface renderedColorFrame(viewportW, viewportH);
736         tcu::Surface referenceColorFrame(viewportW, viewportH);
737         tcu::TestLog &log = context.getTestContext().getLog();
738 
739         for (int y = 0; y < renderedColorFrame.getHeight(); y++)
740         {
741             for (int x = 0; x < renderedColorFrame.getWidth(); x++)
742             {
743                 float xCoord = (float)(x) / (float)renderedColorFrame.getWidth();
744 
745                 if (xCoord < 0.5f)
746                 {
747                     referenceColorFrame.setPixel(x, y, tcu::RGBA::green());
748                 }
749                 else
750                 {
751                     referenceColorFrame.setPixel(x, y, tcu::RGBA::red());
752                 }
753             }
754         }
755 
756         glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess());
757         if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame,
758                                0.05f, tcu::COMPARE_LOG_RESULT))
759         {
760 
761             return QP_TEST_RESULT_FAIL;
762         }
763         return QP_TEST_RESULT_PASS;
764     }
765 
766     glw::GLuint m_vao, m_vbo;
767 };
768 
769 /*
770  Viewport Bounds Test
771 
772  * Viewport bounds should be tested, to ensure that rendering with flipped
773  origin affects only viewport area.
774 
775  This can be done by clearing the window to blue, making viewport
776  a non-symmetric-in-any-way subset of the window, than rendering
777  full-viewport multiple color quad. The (-1.0, -1.0)..(0.0, 0.0) quadrant
778  of a quad is red, the rest is green.
779  Whatever the origin is, the area outside of the viewport should stay blue.
780  If origin is LOWER_LEFT the "lower left" portion of the viewport is red,
781  if origin is UPPER_LEFT the "top left" portion of the viewport is red
782  (and in both cases the rest of viewport is green).
783 
784  Here is the basic outline of the test:
785 
786  - Clear the default framebuffer to blue (0,0,1).
787  - Set viewport to A = (x, y, w, h) = (1/8, 1/4, 1/2, 1/4)  in terms of proportional window size
788  - Set ClipControl(UPPER_LEFT, NEGATIVE_ONE_TO_ONE)
789  - Render a triangle strip covering (-1.0, -1.0) to (1.0, 1.0).
790  Write a pixel value of red (0,1,0) to (-1.0, -1.0)..(0.0, 0.0), other parts are green
791  - Reset viewport to defaults
792  - Read back the default framebuffer with ReadPixels
793  - Verify:
794  - regions outside A viewport are green
795  - Inside A viewport upper upper left portion is red, rest is green.
796 
797  Repeat the above test with LOWER_LEFT origin and lower left portion of A is red,
798  rest is green.
799  */
800 class ClipControlViewportBounds : public ClipControlRenderBaseTest
801 {
802 public:
ClipControlViewportBounds(Context & context,const char * name)803     ClipControlViewportBounds(Context &context, const char *name)
804         : ClipControlRenderBaseTest(context, name, "Clip Control Origin Test")
805         , m_vao(0)
806         , m_vbo(0)
807     {
808     }
809 
deinit()810     void deinit() override
811     {
812         ClipControlRenderBaseTest::deinit();
813 
814         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
815         glw::GLsizei windowW                  = renderTarget.getWidth();
816         glw::GLsizei windowH                  = renderTarget.getHeight();
817         const glw::Functions &gl              = m_context.getRenderContext().getFunctions();
818 
819         if (ClipControlApi::Supported(m_context))
820         {
821             ClipControlApi cc(m_context);
822             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
823         }
824 
825         gl.clearColor(0.0, 0.0, 0.0, 0.0);
826         gl.viewport(0, 0, windowW, windowH);
827 
828         if (m_vao)
829         {
830             gl.deleteVertexArrays(1, &m_vao);
831         }
832         if (m_vbo)
833         {
834             gl.deleteBuffers(1, &m_vbo);
835         }
836     }
837 
iterate()838     IterateResult iterate() override
839     {
840         tcu::TestLog &log                     = m_testCtx.getLog();
841         const glw::Functions &gl              = m_context.getRenderContext().getFunctions();
842         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
843         glw::GLsizei windowW                  = renderTarget.getWidth();
844         glw::GLsizei windowH                  = renderTarget.getHeight();
845         ClipControlApi cc(m_context);
846 
847         //Clear the default framebuffer to blue (0,0,1).
848         gl.clearColor(0.0, 0.0, 1.0, 1.0);
849         gl.clear(GL_COLOR_BUFFER_BIT);
850 
851         de::SharedPtr<glu::ShaderProgram> program(
852             new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
853 
854         log << (*program);
855         if (!program->isOk())
856         {
857             TCU_FAIL("Program compilation failed");
858         }
859         gl.genVertexArrays(1, &m_vao);
860         gl.bindVertexArray(m_vao);
861 
862         gl.genBuffers(1, &m_vbo);
863 
864         const float vertex_data0[] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
865 
866         gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
867         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
868 
869         gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
870         gl.enableVertexAttribArray(0);
871 
872         gl.useProgram(program->getProgram());
873 
874         glw::GLenum origins[] = {GL_UPPER_LEFT, GL_LOWER_LEFT};
875 
876         qpTestResult result = QP_TEST_RESULT_PASS;
877 
878         for (size_t orig = 0; orig < DE_LENGTH_OF_ARRAY(origins); orig++)
879         {
880             //Set viewport to A = (x, y, w, h) = (1/8, 1/4, 1/2, 1/4) in terms of proportional window size
881             gl.viewport(static_cast<glw::GLint>((0.125f * static_cast<float>(windowW)) + 0.5f),
882                         static_cast<glw::GLint>((0.25f * static_cast<float>(windowH)) + 0.5f),
883                         static_cast<glw::GLsizei>((0.5f * static_cast<float>(windowW)) + 0.5f),
884                         static_cast<glw::GLsizei>((0.25f * static_cast<float>(windowH)) + 0.5f));
885 
886             //Set ClipControl(<origin>, NEGATIVE_ONE_TO_ONE)
887             cc.clipControl(origins[orig], GL_NEGATIVE_ONE_TO_ONE);
888             GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
889 
890             //Render a triangle strip covering (-1.0, -1.0) to (1.0, 1.0).
891             //Write a pixel value of red (0,1,0) to (-1.0, -1.0)..(0.0, 0.0), other parts are green
892             gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
893 
894             gl.viewport(0, 0, windowW, windowH);
895 
896             //Read back the default framebuffer with ReadPixels
897             //Verify the green pixels at the top and red at the bottom.
898             qpTestResult loopResult = ValidateFramebuffer(m_context, origins[orig]);
899             if (loopResult != QP_TEST_RESULT_PASS)
900             {
901                 result = loopResult;
902             }
903         }
904         m_testCtx.setTestResult(result, qpGetTestResultName(result));
905         return STOP;
906     }
907 
vsh()908     const char *vsh()
909     {
910         return "attribute highp vec2 Position;"
911                "\n"
912                "varying highp vec2 PositionOut;"
913                "\n"
914                "void main() {"
915                "\n"
916                "    gl_Position = vec4(Position, 0.0, 1.0);"
917                "\n"
918                "    PositionOut = Position;"
919                "\n"
920                "}";
921     }
922 
fsh()923     const char *fsh()
924     {
925         return "varying highp vec2 PositionOut;"
926                "\n"
927                "void main() {"
928                "\n"
929                "    if (PositionOut.x < 0.0 && PositionOut.y < 0.0)"
930                "\n"
931                "       gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);"
932                "\n"
933                "    else"
934                "\n"
935                "       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);"
936                "\n"
937                "}";
938     }
939 
ValidateFramebuffer(Context & context,glw::GLenum origin)940     qpTestResult ValidateFramebuffer(Context &context, glw::GLenum origin)
941     {
942         const tcu::RenderTarget &renderTarget = context.getRenderContext().getRenderTarget();
943         glw::GLsizei windowW                  = renderTarget.getWidth();
944         glw::GLsizei windowH                  = renderTarget.getHeight();
945         tcu::Surface renderedFrame(windowW, windowH);
946         tcu::Surface referenceFrame(windowW, windowH);
947 
948         tcu::TestLog &log = context.getTestContext().getLog();
949 
950         for (int y = 0; y < renderedFrame.getHeight(); y++)
951         {
952             float yCoord   = static_cast<float>(y) / static_cast<float>(renderedFrame.getHeight());
953             float yVPCoord = (yCoord - 0.25f) * 4.0f;
954 
955             for (int x = 0; x < renderedFrame.getWidth(); x++)
956             {
957                 float xCoord   = static_cast<float>(x) / static_cast<float>(renderedFrame.getWidth());
958                 float xVPCoord = (xCoord - 0.125f) * 2.0f;
959 
960                 if (xVPCoord > 0.0f && xVPCoord < 1.0f && yVPCoord > 0.0f && yVPCoord < 1.0f)
961                 {
962 
963                     bool greenQuadrant;
964 
965                     //inside viewport
966                     if (origin == GL_UPPER_LEFT)
967                     {
968                         greenQuadrant = (yVPCoord > 0.5f && xVPCoord <= 0.5f);
969                     }
970                     else
971                     {
972                         greenQuadrant = (yVPCoord <= 0.5f && xVPCoord <= 0.5f);
973                     }
974 
975                     if (greenQuadrant)
976                     {
977                         referenceFrame.setPixel(x, y, tcu::RGBA::green());
978                     }
979                     else
980                     {
981                         referenceFrame.setPixel(x, y, tcu::RGBA::red());
982                     }
983                 }
984                 else
985                 {
986                     //outside viewport
987                     referenceFrame.setPixel(x, y, tcu::RGBA::blue());
988                 }
989             }
990         }
991 
992         glu::readPixels(context.getRenderContext(), 0, 0, renderedFrame.getAccess());
993 
994         if (tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
995                               tcu::COMPARE_LOG_RESULT))
996         {
997             return QP_TEST_RESULT_PASS;
998         }
999         else
1000         {
1001             return QP_TEST_RESULT_FAIL;
1002         }
1003     }
1004 
1005     glw::GLuint m_vao, m_vbo;
1006 };
1007 
1008 /*   Depth Mode Test
1009 
1010  * Basic <depth> behavior can be tested by writing specific z_c (z
1011  clip coordinates) and observing its clipping and transformation.
1012  Create and bind a framebuffer object with a floating-point depth
1013  buffer attachment. Make sure depth clamping is disabled. The best
1014  steps for verifying the correct depth mode:
1015 
1016  - Clear the depth buffer to 0.5.
1017  - Set ClipControl(LOWER_LEFT, ZERO_TO_ONE)
1018  - Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1019  - Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1020  - Read back the floating-point depth buffer with ReadPixels
1021  - Verify that the pixels with a Z clip coordinate less than 0.0 are
1022  clipped and those coordinates from 0.0 to 1.0 update the depth
1023  buffer with values 0.0 to 1.0.
1024  */
1025 
1026 class ClipControlDepthModeTest : public ClipControlRenderBaseTest
1027 {
1028 public:
ClipControlDepthModeTest(Context & context,const char * name,const char * subname)1029     ClipControlDepthModeTest(Context &context, const char *name, const char *subname)
1030         : ClipControlRenderBaseTest(context, name, subname)
1031     {
1032     }
1033 
init()1034     void init() override
1035     {
1036         const glw::Functions &gl              = m_context.getRenderContext().getFunctions();
1037         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
1038         glw::GLuint viewportW                 = renderTarget.getWidth();
1039         glw::GLuint viewportH                 = renderTarget.getHeight();
1040 
1041         ClipControlRenderBaseTest::init();
1042 
1043         gl.genFramebuffers(1, &m_fboD);
1044 
1045         gl.genTextures(1, &m_texDepthResolve);
1046         gl.bindTexture(GL_TEXTURE_2D, m_texDepthResolve);
1047         setupTexture();
1048         gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, viewportW, viewportH, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
1049     }
1050 
deinit()1051     void deinit() override
1052     {
1053         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1054 
1055         gl.deleteTextures(1, &m_texDepthResolve);
1056         gl.deleteFramebuffers(1, &m_fboD);
1057 
1058         ClipControlRenderBaseTest::deinit();
1059     }
1060 
setupTexture()1061     void setupTexture()
1062     {
1063         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1064         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1065         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1066         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1067         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1068     }
1069 
readDepthPixels(const tcu::PixelBufferAccess & pixelBuf)1070     void readDepthPixels(const tcu::PixelBufferAccess &pixelBuf)
1071     {
1072 
1073         const char *vs = "\n"
1074                          "attribute vec4 pos;\n"
1075                          "attribute vec2 UV;\n"
1076                          "varying highp vec2 vUV;\n"
1077                          "void main() {\n"
1078                          "  gl_Position = pos;\n"
1079                          "  vUV = UV;\n"
1080                          "}\n";
1081 
1082         const char *fs = "\n"
1083                          "precision mediump float;\n"
1084                          "varying vec2 vUV;\n"
1085                          "uniform sampler2D tex;\n"
1086                          "void main() {\n"
1087                          "  gl_FragColor = texture2D(tex, vUV).rrrr;\n"
1088                          "}\n";
1089 
1090         const glu::RenderContext &renderContext = m_context.getRenderContext();
1091         const glw::Functions &gl                = renderContext.getFunctions();
1092         const tcu::RenderTarget &renderTarget   = renderContext.getRenderTarget();
1093         glw::GLsizei windowW                    = renderTarget.getWidth();
1094         glw::GLsizei windowH                    = renderTarget.getHeight();
1095 
1096         glu::ShaderProgram program(renderContext, glu::makeVtxFragSources(vs, fs));
1097 
1098         gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboD);
1099         gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texDepthResolve, 0);
1100 
1101         gl.disable(GL_DEPTH_TEST);
1102         gl.depthMask(GL_FALSE);
1103         gl.disable(GL_STENCIL_TEST);
1104         gl.viewport(0, 0, windowW, windowH);
1105         gl.clearColor(0.0f, 0.2f, 1.0f, 1.0f);
1106         gl.clear(GL_COLOR_BUFFER_BIT);
1107 
1108         const int texLoc = gl.getUniformLocation(program.getProgram(), "tex");
1109 
1110         gl.bindVertexArray(0);
1111         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
1112 
1113         gl.bindTexture(GL_TEXTURE_2D, getDepthTexture());
1114         setupTexture();
1115 
1116         gl.useProgram(program.getProgram());
1117         gl.uniform1i(texLoc, 0);
1118 
1119         {
1120             const GLfloat vertices[] = {
1121                 -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
1122             };
1123             const GLfloat texCoords[] = {
1124                 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1125             };
1126             const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
1127 
1128             const glu::VertexArrayBinding vertexArray[] = {glu::va::Float("pos", 4, 4, 0, vertices),
1129                                                            glu::va::Float("UV", 2, 4, 0, texCoords)};
1130 
1131             glu::draw(renderContext, program.getProgram(), 2, vertexArray,
1132                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), indices));
1133         }
1134         glu::readPixels(renderContext, 0, 0, pixelBuf);
1135     }
1136 
1137     GLuint m_fboD;
1138     GLuint m_texDepthResolve;
1139 };
1140 
1141 class ClipControlDepthModeZeroToOneTest : public ClipControlDepthModeTest
1142 {
1143 public:
ClipControlDepthModeZeroToOneTest(Context & context,const char * name)1144     ClipControlDepthModeZeroToOneTest(Context &context, const char *name)
1145         : ClipControlDepthModeTest(context, name, "Depth Mode Test, ZERO_TO_ONE")
1146         , m_vao(0)
1147         , m_vbo(0)
1148     {
1149     }
1150 
deinit()1151     void deinit() override
1152     {
1153         ClipControlDepthModeTest::deinit();
1154 
1155         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1156 
1157         if (ClipControlApi::Supported(m_context))
1158         {
1159             ClipControlApi cc(m_context);
1160             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
1161         }
1162 
1163         gl.clearDepthf(0.0f);
1164         gl.clearColor(0.0, 0.0, 0.0, 0.0);
1165 
1166         gl.disable(GL_DEPTH_TEST);
1167         gl.depthFunc(GL_LESS);
1168 
1169         if (m_vao)
1170         {
1171             gl.deleteVertexArrays(1, &m_vao);
1172         }
1173         if (m_vbo)
1174         {
1175             gl.deleteBuffers(1, &m_vbo);
1176         }
1177     }
1178 
iterate()1179     IterateResult iterate() override
1180     {
1181 
1182         tcu::TestLog &log        = m_testCtx.getLog();
1183         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1184         ClipControlApi cc(m_context);
1185 
1186         gl.clearColor(1.0, 0.0, 0.0, 1.0);
1187         gl.clear(GL_COLOR_BUFFER_BIT);
1188 
1189         //Clear the depth buffer to 0.5.
1190         gl.clearDepthf(0.5);
1191         gl.clear(GL_DEPTH_BUFFER_BIT);
1192 
1193         //Set ClipControl(LOWER_LEFT, ZERO_TO_ONE)
1194         cc.clipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
1195         GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
1196 
1197         //Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1198         gl.enable(GL_DEPTH_TEST);
1199         gl.depthFunc(GL_ALWAYS);
1200 
1201         //Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1202         de::SharedPtr<glu::ShaderProgram> program(
1203             new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
1204 
1205         log << (*program);
1206         if (!program->isOk())
1207         {
1208             TCU_FAIL("Program compilation failed");
1209         }
1210 
1211         gl.genVertexArrays(1, &m_vao);
1212         gl.bindVertexArray(m_vao);
1213 
1214         gl.genBuffers(1, &m_vbo);
1215 
1216         const float vertex_data0[] = {
1217             -1.0, -1.0, -1.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0,
1218         };
1219 
1220         gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
1221         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
1222 
1223         gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
1224         gl.enableVertexAttribArray(0);
1225 
1226         gl.useProgram(program->getProgram());
1227 
1228         //test method modification: use GL_TRIANGLE_STRIP, not FAN.
1229         gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1230 
1231         //Read back the floating-point depth buffer with ReadPixels
1232         //Verify that the pixels with a Z clip coordinate less than 0.0 are
1233         //  clipped and those coordinates from 0.0 to 1.0 update the depth
1234         //  buffer with values 0.0 to 1.0.
1235         qpTestResult result = ValidateFramebuffer(m_context);
1236         m_testCtx.setTestResult(result, qpGetTestResultName(result));
1237 
1238         return STOP;
1239     }
1240 
vsh()1241     const char *vsh()
1242     {
1243         return "attribute vec3 Position;"
1244                "\n"
1245                "void main() {"
1246                "\n"
1247                "    gl_Position = vec4(Position, 1.0);"
1248                "\n"
1249                "}";
1250     }
1251 
ValidateFramebuffer(Context & context)1252     qpTestResult ValidateFramebuffer(Context &context)
1253     {
1254         const tcu::RenderTarget &renderTarget = context.getRenderContext().getRenderTarget();
1255         glw::GLuint viewportW                 = renderTarget.getWidth();
1256         glw::GLuint viewportH                 = renderTarget.getHeight();
1257         tcu::Surface renderedColorFrame(viewportW, viewportH);
1258         tcu::Surface referenceColorFrame(viewportW, viewportH);
1259         tcu::TextureFormat depthReadbackFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1260         tcu::TextureFormat depthFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
1261         tcu::TextureLevel renderedDepthFrame(depthReadbackFormat, viewportW, viewportH);
1262         tcu::TextureLevel referenceDepthFrame(depthFormat, viewportW, viewportH);
1263         tcu::TextureLevel importanceMaskFrame(depthFormat, viewportW, viewportH);
1264 
1265         tcu::TestLog &log = context.getTestContext().getLog();
1266 
1267         const float rasterizationError =
1268             2.0f / (float)renderedColorFrame.getHeight() + 2.0f / (float)renderedColorFrame.getWidth();
1269 
1270         for (int y = 0; y < renderedColorFrame.getHeight(); y++)
1271         {
1272             float yCoord = ((float)(y) + 0.5f) / (float)renderedColorFrame.getHeight();
1273 
1274             for (int x = 0; x < renderedColorFrame.getWidth(); x++)
1275             {
1276                 float xCoord = ((float)(x) + 0.5f) / (float)renderedColorFrame.getWidth();
1277 
1278                 if (yCoord >= 1.0 - xCoord - rasterizationError && yCoord <= 1.0 - xCoord + rasterizationError)
1279                 {
1280                     importanceMaskFrame.getAccess().setPixDepth(0.0f, x, y);
1281                 }
1282                 else
1283                 {
1284                     importanceMaskFrame.getAccess().setPixDepth(1.0f, x, y);
1285                 }
1286 
1287                 if (yCoord < 1.0 - xCoord)
1288                 {
1289                     referenceColorFrame.setPixel(x, y, tcu::RGBA::red());
1290                     referenceDepthFrame.getAccess().setPixDepth(0.5f, x, y);
1291                 }
1292                 else
1293                 {
1294                     referenceColorFrame.setPixel(x, y, tcu::RGBA::green());
1295 
1296                     referenceDepthFrame.getAccess().setPixDepth(-1.0f + xCoord + yCoord, x, y);
1297                 }
1298             }
1299         }
1300 
1301         glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess());
1302         if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame,
1303                                0.05f, tcu::COMPARE_LOG_RESULT))
1304         {
1305 
1306             return QP_TEST_RESULT_FAIL;
1307         }
1308 
1309         readDepthPixels(renderedDepthFrame.getAccess());
1310         if (!fuzzyDepthCompare(log, "Result", "Depth image comparison result", referenceDepthFrame, renderedDepthFrame,
1311                                0.05f, &importanceMaskFrame))
1312         {
1313             return QP_TEST_RESULT_FAIL;
1314         }
1315         return QP_TEST_RESULT_PASS;
1316     }
1317 
1318     glw::GLuint m_vao, m_vbo;
1319 };
1320 
1321 /*
1322  Do the same as above, but use the default NEGATIVE_ONE_TO_ONE depth mode:
1323 
1324  - Clear the depth buffer to 0.5.
1325  - Set ClipControl(LOWER_LEFT, NEGATIVE_ONE_TO_ONE)
1326  - Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1327  - Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1328  - Read back the floating-point depth buffer with ReadPixels
1329  - Verify that no pixels are clipped and the depth buffer contains
1330  values from 0.0 to 1.0.
1331  */
1332 class ClipControlDepthModeOneToOneTest : public ClipControlDepthModeTest
1333 {
1334 public:
ClipControlDepthModeOneToOneTest(Context & context,const char * name)1335     ClipControlDepthModeOneToOneTest(Context &context, const char *name)
1336         : ClipControlDepthModeTest(context, name, "Depth Mode Test, ONE_TO_ONE")
1337         , m_vao(0)
1338         , m_vbo(0)
1339     {
1340     }
1341 
deinit()1342     void deinit() override
1343     {
1344         ClipControlDepthModeTest::deinit();
1345 
1346         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1347 
1348         if (ClipControlApi::Supported(m_context))
1349         {
1350             ClipControlApi cc(m_context);
1351             cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
1352         }
1353 
1354         gl.clearDepthf(0.0);
1355         gl.clearColor(0.0, 0.0, 0.0, 0.0);
1356 
1357         gl.disable(GL_DEPTH_TEST);
1358         gl.depthFunc(GL_LESS);
1359 
1360         if (m_vao)
1361         {
1362             gl.deleteVertexArrays(1, &m_vao);
1363         }
1364         if (m_vbo)
1365         {
1366             gl.deleteBuffers(1, &m_vbo);
1367         }
1368     }
1369 
iterate()1370     IterateResult iterate() override
1371     {
1372         tcu::TestLog &log        = m_testCtx.getLog();
1373         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1374         ClipControlApi cc(m_context);
1375 
1376         gl.clearColor(1.0, 0.0, 0.0, 1.0);
1377         gl.clear(GL_COLOR_BUFFER_BIT);
1378 
1379         //Clear the depth buffer to 0.5.
1380         gl.clearDepthf(0.5f);
1381         gl.clear(GL_DEPTH_BUFFER_BIT);
1382 
1383         //Set ClipControl(LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE)
1384         cc.clipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
1385         GLU_EXPECT_NO_ERROR(gl.getError(), "ClipControl()");
1386 
1387         //Enable(DEPTH_TEST) with DepthFunc(ALWAYS)
1388         gl.enable(GL_DEPTH_TEST);
1389         gl.depthFunc(GL_ALWAYS);
1390 
1391         //Render a triangle fan coverage (-1.0,-1.0,-1.0) to (1.0,1.0,1.0).
1392         de::SharedPtr<glu::ShaderProgram> program(
1393             new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh())));
1394 
1395         log << (*program);
1396         if (!program->isOk())
1397         {
1398             TCU_FAIL("Program compilation failed");
1399         }
1400 
1401         gl.genVertexArrays(1, &m_vao);
1402         gl.bindVertexArray(m_vao);
1403 
1404         gl.genBuffers(1, &m_vbo);
1405 
1406         const float vertex_data0[] = {
1407             -1.0, -1.0, -1.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 1.0,
1408         };
1409 
1410         gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo);
1411         gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertex_data0), vertex_data0, GL_STATIC_DRAW);
1412 
1413         gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
1414         gl.enableVertexAttribArray(0);
1415 
1416         gl.useProgram(program->getProgram());
1417 
1418         //test method modification: use GL_TRIANGLE_STRIP, not FAN.
1419         gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1420 
1421         //Read back the floating-point depth buffer with ReadPixels
1422         //Verify that the pixels with a Z clip coordinate less than 0.0 are
1423         //  clipped and those coordinates from 0.0 to 1.0 update the depth
1424         //  buffer with values 0.0 to 1.0.
1425         qpTestResult result = ValidateFramebuffer(m_context);
1426         m_testCtx.setTestResult(result, qpGetTestResultName(result));
1427 
1428         return STOP;
1429     }
1430 
vsh()1431     const char *vsh()
1432     {
1433         return "attribute vec3 Position;"
1434                "\n"
1435                "void main() {"
1436                "\n"
1437                "    gl_Position = vec4(Position, 1.0);"
1438                "\n"
1439                "}";
1440     }
1441 
ValidateFramebuffer(Context & context)1442     qpTestResult ValidateFramebuffer(Context &context)
1443     {
1444         const tcu::RenderTarget &renderTarget = context.getRenderContext().getRenderTarget();
1445         glw::GLuint viewportW                 = renderTarget.getWidth();
1446         glw::GLuint viewportH                 = renderTarget.getHeight();
1447         tcu::Surface renderedColorFrame(viewportW, viewportH);
1448         tcu::Surface referenceColorFrame(viewportW, viewportH);
1449         tcu::TextureFormat depthReadbackFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1450         tcu::TextureFormat depthFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
1451         tcu::TextureLevel renderedDepthFrame(depthReadbackFormat, viewportW, viewportH);
1452         tcu::TextureLevel referenceDepthFrame(depthFormat, viewportW, viewportH);
1453 
1454         tcu::TestLog &log = context.getTestContext().getLog();
1455 
1456         for (int y = 0; y < renderedColorFrame.getHeight(); y++)
1457         {
1458             float yCoord = (float)(y) / (float)renderedColorFrame.getHeight();
1459             for (int x = 0; x < renderedColorFrame.getWidth(); x++)
1460             {
1461                 float xCoord = (float)(x) / (float)renderedColorFrame.getWidth();
1462 
1463                 referenceColorFrame.setPixel(x, y, tcu::RGBA::green());
1464                 referenceDepthFrame.getAccess().setPixDepth((xCoord + yCoord) * 0.5f, x, y);
1465             }
1466         }
1467 
1468         glu::readPixels(context.getRenderContext(), 0, 0, renderedColorFrame.getAccess());
1469         if (!tcu::fuzzyCompare(log, "Result", "Color image comparison result", referenceColorFrame, renderedColorFrame,
1470                                0.05f, tcu::COMPARE_LOG_RESULT))
1471         {
1472             return QP_TEST_RESULT_FAIL;
1473         }
1474 
1475         readDepthPixels(renderedDepthFrame.getAccess());
1476         if (!fuzzyDepthCompare(log, "Result", "Depth image comparison result", referenceDepthFrame, renderedDepthFrame,
1477                                0.05f))
1478         {
1479             return QP_TEST_RESULT_FAIL;
1480         }
1481 
1482         return QP_TEST_RESULT_PASS;
1483     }
1484 
1485     glw::GLuint m_vao, m_vbo;
1486 };
1487 
1488 /** Constructor.
1489  *
1490  *  @param context Rendering context.
1491  **/
ClipControlTests(Context & context)1492 ClipControlTests::ClipControlTests(Context &context)
1493     : TestCaseGroup(context, "clip_control", "Verifies \"clip_control\" functionality")
1494 {
1495     /* Left blank on purpose */
1496 }
1497 
1498 /** Destructor.
1499  *
1500  **/
~ClipControlTests()1501 ClipControlTests::~ClipControlTests()
1502 {
1503 }
1504 
1505 /** Initializes a texture_storage_multisample test group.
1506  *
1507  **/
init(void)1508 void ClipControlTests::init(void)
1509 {
1510     addChild(new ClipControlInitialState(m_context, "initial"));
1511     addChild(new ClipControlModifyGetState(m_context, "modify_get"));
1512     addChild(new ClipControlErrors(m_context, "errors"));
1513     addChild(new ClipControlOriginTest(m_context, "origin"));
1514     addChild(new ClipControlDepthModeZeroToOneTest(m_context, "depth_mode_zero_to_one"));
1515     addChild(new ClipControlDepthModeOneToOneTest(m_context, "depth_mode_one_to_one"));
1516     addChild(new ClipControlFaceCulling(m_context, "face_culling"));
1517     addChild(new ClipControlViewportBounds(m_context, "viewport_bounds"));
1518 }
1519 } // namespace Functional
1520 } // namespace gles2
1521 } // namespace deqp
1522