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