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