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