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