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