1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Framebuffer without attachments (GL_ARB_framebuffer_no_attachments) tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es31fFboNoAttachmentTests.hpp"
26 #include "glwDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
30 #include "gluRenderContext.hpp"
31 #include "gluDefs.hpp"
32 #include "gluShaderProgram.hpp"
34 #include "tcuTestContext.hpp"
35 #include "tcuVectorType.hpp"
36 #include "tcuVectorUtil.hpp"
37 #include "tcuTestLog.hpp"
38 #include "tcuCommandLine.hpp"
39 #include "tcuResultCollector.hpp"
42 #include "deRandom.hpp"
44 #include "deStringUtil.hpp"
63 using std::stringstream;
67 bool checkFramebufferSize (TestLog& log, const glu::RenderContext& renderCtx, GLuint framebuffer, const IVec2& size)
69 const glw::Functions& gl = renderCtx.getFunctions();
71 const char* const vertexSource = "#version 310 es\n"
72 "in layout(location = 0) highp vec2 a_position;\n\n"
75 " gl_Position = vec4(a_position, 0.0, 1.0);\n"
78 const char* const fragmentSource = "#version 310 es\n"
79 "uniform layout(location = 0) highp ivec2 u_expectedSize;\n"
80 "out layout(location = 0) mediump vec4 f_color;\n\n"
83 " if (ivec2(gl_FragCoord.xy) != u_expectedSize) discard;\n"
84 " f_color = vec4(1.0, 0.5, 0.25, 1.0);\n"
87 const glu::ShaderProgram program (renderCtx, glu::makeVtxFragSources(vertexSource, fragmentSource));
89 GLuint insidePassed = 0;
90 GLuint outsideXPassed = 0;
91 GLuint outsideYPassed = 0;
96 TCU_CHECK(program.isOk());
98 gl.useProgram(program.getProgram());
99 gl.enable(GL_DEPTH_TEST);
100 gl.depthFunc(GL_ALWAYS);
101 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
102 gl.viewport(0, 0, size.x()*2, size.y()*2); // Oversized viewport so that it will not accidentally limit us to the correct size
104 log << TestLog::Message << "Using " << size.x()*2 << "x" << size.y()*2 << " viewport" << TestLog::EndMessage;
105 log << TestLog::Message << "Discarding fragments outside pixel of interest" << TestLog::EndMessage;
106 log << TestLog::Message << "Using occlusion query to check for rendered fragments" << TestLog::EndMessage;
108 TCU_CHECK(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
122 GLuint vertexArray = 0;
123 GLuint vertexBuffer = 0;
125 gl.genQueries(1, &query);
126 gl.genVertexArrays(1, &vertexArray);
127 gl.bindVertexArray(vertexArray);
129 gl.genBuffers(1, &vertexBuffer);
130 gl.bindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
131 gl.bufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
133 gl.enableVertexAttribArray(0);
134 gl.vertexAttribPointer(0, 2, GL_FLOAT, false, 0, DE_NULL);
136 gl.uniform2i(0, size.x()-1, size.y()-1);
137 gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
138 gl.drawArrays(GL_TRIANGLES, 0, 6);
139 gl.endQuery(GL_ANY_SAMPLES_PASSED);
140 gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &insidePassed);
141 log << TestLog::Message << "A fragment was not discarded at (" << size.x()-1 << ", " << size.y()-1 << "). "
142 << "Occlusion query reports it was " << (insidePassed > 0 ? "rendered." : "not rendered") << TestLog::EndMessage;
144 gl.uniform2i(0, size.x(), size.y()-1);
145 gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
146 gl.drawArrays(GL_TRIANGLES, 0, 6);
147 gl.endQuery(GL_ANY_SAMPLES_PASSED);
148 gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &outsideXPassed);
149 log << TestLog::Message << "A fragment was not discarded at (" << size.x() << ", " << size.y()-1 << "). "
150 << "Occlusion query reports it was " << (outsideXPassed > 0 ? "rendered." : "not rendered") << TestLog::EndMessage;
152 gl.uniform2i(0, size.x()-1, size.y());
153 gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
154 gl.drawArrays(GL_TRIANGLES, 0, 6);
155 gl.endQuery(GL_ANY_SAMPLES_PASSED);
156 gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &outsideYPassed);
157 log << TestLog::Message << "A fragment was not discarded at (" << size.x()-1 << ", " << size.y() << "). "
158 << "Occlusion query reports it was " << (outsideYPassed > 0 ? "rendered." : "not rendered") << TestLog::EndMessage;
160 gl.disableVertexAttribArray(0);
161 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
162 gl.bindVertexArray(0);
163 gl.deleteBuffers(1, &vertexBuffer);
164 gl.deleteVertexArrays(1, &vertexArray);
167 gl.deleteQueries(1, &query);
169 GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
171 return insidePassed && !outsideXPassed && !outsideYPassed;
174 bool checkFramebufferRenderable (TestLog& log, const glu::RenderContext& renderCtx, GLuint framebuffer, const IVec2& size)
176 const glw::Functions& gl = renderCtx.getFunctions();
178 const char* const vertexSource = "#version 310 es\n"
179 "in layout(location = 0) highp vec2 a_position;\n\n"
182 " gl_Position = vec4(a_position, 0.0, 1.0);\n"
185 const char* const fragmentSource = "#version 310 es\n"
186 "out layout(location = 0) mediump vec4 f_color;\n\n"
189 " f_color = vec4(1.0, 0.5, 0.25, 1.0);\n"
192 const glu::ShaderProgram program (renderCtx, glu::makeVtxFragSources(vertexSource, fragmentSource));
198 TCU_CHECK(program.isOk());
200 gl.useProgram(program.getProgram());
201 gl.enable(GL_DEPTH_TEST);
202 gl.depthFunc(GL_ALWAYS);
203 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
204 gl.viewport(0, 0, size.x(), size.y());
206 TCU_CHECK(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
208 log << TestLog::Message << "Rendering full framebuffer quad with color ouput, verifying output presence with occlusion query" << TestLog::EndMessage;
222 GLuint vertexArray = 0;
223 GLuint vertexBuffer = 0;
225 gl.genQueries(1, &query);
226 gl.genVertexArrays(1, &vertexArray);
227 gl.bindVertexArray(vertexArray);
229 gl.genBuffers(1, &vertexBuffer);
230 gl.bindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
231 gl.bufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
233 gl.enableVertexAttribArray(0);
234 gl.vertexAttribPointer(0, 2, GL_FLOAT, false, 0, DE_NULL);
236 gl.beginQuery(GL_ANY_SAMPLES_PASSED, query);
237 gl.drawArrays(GL_TRIANGLES, 0, 6);
238 gl.endQuery(GL_ANY_SAMPLES_PASSED);
240 gl.disableVertexAttribArray(0);
241 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
242 gl.bindVertexArray(0);
243 gl.deleteBuffers(1, &vertexBuffer);
244 gl.deleteVertexArrays(1, &vertexArray);
251 gl.getQueryObjectuiv(query, GL_QUERY_RESULT, &passed);
252 gl.deleteQueries(1, &query);
254 GLU_EXPECT_NO_ERROR(gl.getError(), "Query failed");
257 log << TestLog::Message << "Query passed" << TestLog::EndMessage;
259 log << TestLog::Message << "Query did not pass" << TestLog::EndMessage;
265 class FramebufferCompletenessCase : public tcu::TestCase
268 FramebufferCompletenessCase (tcu::TestContext& testCtx,
269 const glu::RenderContext& renderCtx,
272 virtual ~FramebufferCompletenessCase (void) {}
273 virtual IterateResult iterate (void);
276 const glu::RenderContext& m_renderCtx;
277 tcu::ResultCollector m_results;
280 FramebufferCompletenessCase::FramebufferCompletenessCase (tcu::TestContext& testCtx,
281 const glu::RenderContext& renderCtx,
284 : TestCase (testCtx, name, desc)
285 , m_renderCtx (renderCtx)
289 FramebufferCompletenessCase::IterateResult FramebufferCompletenessCase::iterate (void)
291 const glw::Functions& gl = m_renderCtx.getFunctions();
292 GLuint framebuffer = 0;
294 gl.genFramebuffers(1, &framebuffer);
295 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
297 m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "Framebuffer was incorrectly reported as complete when it had no width, height or attachments");
299 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 16);
300 m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "Framebuffer was incorrectly reported as complete when it only had a width");
302 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 16);
303 m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Framebuffer not reported as complete when it had width and height set");
305 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 0);
306 m_results.check(gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "Framebuffer was incorrectly reported as complete when it only had a height");
308 gl.deleteFramebuffers(1, &framebuffer);
310 m_results.setTestContextResult(m_testCtx);
320 FboSpec(int width_, int height_, int samples_) : width(width_), height(height_), samples(samples_){}
323 class SizeCase : public tcu::TestCase
326 SizeCase (tcu::TestContext& testCtx,
327 const glu::RenderContext& renderCtx,
330 const FboSpec& spec);
331 virtual ~SizeCase (void) {}
333 virtual IterateResult iterate (void);
340 int getWidth (void) const;
341 int getHeight (void) const;
342 int getSamples (void) const;
344 const glu::RenderContext& m_renderCtx;
346 const FboSpec m_spec;
349 SizeCase::SizeCase (tcu::TestContext& testCtx,
350 const glu::RenderContext& renderCtx,
354 : TestCase (testCtx, name, desc)
355 , m_renderCtx (renderCtx)
360 SizeCase::IterateResult SizeCase::iterate (void)
362 const glw::Functions& gl = m_renderCtx.getFunctions();
363 TestLog& log = m_testCtx.getLog();
364 GLuint framebuffer = 0;
365 const int width = getWidth();
366 const int height = getHeight();
367 const int samples = getSamples();
369 gl.genFramebuffers(1, &framebuffer);
370 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
371 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, width);
372 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, height);
373 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, samples);
375 log << TestLog::Message << "Verifying " << width << "x" << height << " framebuffer with " << samples << "x multisampling" << TestLog::EndMessage;
377 if(checkFramebufferRenderable(log, m_renderCtx, framebuffer, IVec2(width, height)) && checkFramebufferSize(log, m_renderCtx, framebuffer, IVec2(width, height)))
378 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
380 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Framebuffer did not behave as expected");
382 gl.deleteFramebuffers(1, &framebuffer);
387 int SizeCase::getWidth (void) const
389 if (m_spec.width != USE_MAXIMUM)
393 const glw::Functions& gl = m_renderCtx.getFunctions();
396 gl.getIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &width);
402 int SizeCase::getHeight (void) const
404 if (m_spec.height != USE_MAXIMUM)
405 return m_spec.height;
408 const glw::Functions& gl = m_renderCtx.getFunctions();
411 gl.getIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &height);
417 int SizeCase::getSamples (void) const
419 if (m_spec.samples != USE_MAXIMUM)
420 return m_spec.samples;
423 const glw::Functions& gl = m_renderCtx.getFunctions();
426 gl.getIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &samples);
432 class AttachmentInteractionCase : public tcu::TestCase
435 AttachmentInteractionCase (tcu::TestContext& testCtx,
436 const glu::RenderContext& renderCtx,
439 const FboSpec& defaultSpec,
440 const FboSpec& attachmentSpec);
441 virtual ~AttachmentInteractionCase (void) {}
443 virtual IterateResult iterate (void);
446 const glu::RenderContext& m_renderCtx;
447 const FboSpec m_defaultSpec;
448 const FboSpec m_attachmentSpec;
451 AttachmentInteractionCase::AttachmentInteractionCase (tcu::TestContext& testCtx,
452 const glu::RenderContext& renderCtx,
455 const FboSpec& defaultSpec,
456 const FboSpec& attachmentSpec)
457 : TestCase (testCtx, name, desc)
458 , m_renderCtx (renderCtx)
459 , m_defaultSpec (defaultSpec)
460 , m_attachmentSpec (attachmentSpec)
464 AttachmentInteractionCase::IterateResult AttachmentInteractionCase::iterate (void)
466 const glw::Functions& gl = m_renderCtx.getFunctions();
467 TestLog& log = m_testCtx.getLog();
468 GLuint framebuffer = 0;
469 GLuint renderbuffer= 0;
471 gl.genFramebuffers(1, &framebuffer);
472 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
473 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, m_defaultSpec.width);
474 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, m_defaultSpec.height);
475 gl.framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, m_defaultSpec.samples);
477 gl.genRenderbuffers(1, &renderbuffer);
478 gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
479 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_attachmentSpec.samples, GL_RGBA8, m_attachmentSpec.width, m_attachmentSpec.height);
480 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
482 log << TestLog::Message << "Verifying " << m_attachmentSpec.width << "x" << m_attachmentSpec.height << " framebuffer with " << m_attachmentSpec.samples << "x multisampling"
483 << " and defaults set to " << m_defaultSpec.width << "x" << m_defaultSpec.height << " with " << m_defaultSpec.samples << "x multisampling" << TestLog::EndMessage;
485 if(checkFramebufferRenderable(log, m_renderCtx, framebuffer, IVec2(m_attachmentSpec.width, m_attachmentSpec.height))
486 && checkFramebufferSize(log, m_renderCtx, framebuffer, IVec2(m_attachmentSpec.width, m_attachmentSpec.height)))
487 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
489 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Framebuffer did not behave as expected");
491 gl.deleteRenderbuffers(1, &renderbuffer);
492 gl.deleteFramebuffers(1, &framebuffer);
499 tcu::TestCaseGroup* createFboNoAttachmentTests(Context& context)
501 const glu::RenderContext& renderCtx = context.getRenderContext();
502 tcu::TestContext& testCtx = context.getTestContext();
504 const int maxWidth = 2048; // MAX_FRAMEBUFFER_WIDTH in ES 3.1
505 const int maxHeight = 2048; // MAX_FRAMEBUFFER_HEIGHT in ES 3.1
506 const int maxSamples = 4;
508 tcu::TestCaseGroup* const root = new tcu::TestCaseGroup(testCtx, "no_attachments", "Framebuffer without attachments");
512 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "size", "Basic functionality tests with varying default size");
514 root->addChild(group);
516 for (int width = 16; width <= maxWidth; width *= 4)
518 for (int height = 16; height <= maxHeight; height *= 4)
520 const FboSpec spec (width, height, 0);
523 name << width << "x" << height;
525 group->addChild(new SizeCase(testCtx, renderCtx, name.str().c_str(), name.str().c_str(), spec));
532 const FboSpec specs[] =
543 FboSpec(127, 127, 0),
544 FboSpec(129, 129, 0),
545 FboSpec(255, 255, 0),
546 FboSpec(257, 257, 0),
547 FboSpec(511, 511, 0),
548 FboSpec(513, 513, 0),
549 FboSpec(1023, 1023, 0),
550 FboSpec(1025, 1025, 0),
551 FboSpec(2047, 2047, 0),
556 FboSpec(129, 127, 0),
557 FboSpec(511, 127, 0),
558 FboSpec(2047, 1025, 0),
560 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "npot_size", "Basic functionality with Non-power-of-two size");
562 root->addChild(group);
564 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(specs); caseNdx++)
566 const FboSpec& spec = specs[caseNdx];
569 name << spec.width << "x" << spec.height;
571 group->addChild(new SizeCase(testCtx, renderCtx, name.str().c_str(), name.str().c_str(), spec));
577 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "multisample", "Basic functionality with multisampled fbo");
579 root->addChild(group);
581 for (int samples = 0; samples <= maxSamples; samples++)
583 const FboSpec spec (128, 128, samples);
586 name << "samples" << samples;
588 group->addChild(new SizeCase(testCtx, renderCtx, name.str().c_str(), name.str().c_str(), spec));
594 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "random", "Randomized size & multisampling");
595 de::Random rng (0xF0E1E2D3 ^ testCtx.getCommandLine().getBaseSeed());
597 root->addChild(group);
599 for (int caseNdx = 0; caseNdx < 16; caseNdx++)
601 const int width = rng.getInt(1, maxWidth);
602 const int height = rng.getInt(1, maxHeight);
603 const int samples = rng.getInt(0, maxSamples);
604 const FboSpec spec (width, height, samples);
605 const string name = de::toString(caseNdx);
607 group->addChild(new SizeCase(testCtx, renderCtx, name.c_str(), name.c_str(), spec));
611 // Normal fbo with defaults set
613 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "interaction", "Interaction of default parameters with normal fbo");
615 root->addChild(group);
617 const FboSpec specs[][2] =
619 { FboSpec(256, 256, 0), FboSpec(128, 128, 1) },
620 { FboSpec(256, 256, 1), FboSpec(128, 128, 0) },
621 { FboSpec(256, 256, 0), FboSpec(512, 512, 2) },
622 { FboSpec(256, 256, 2), FboSpec(128, 512, 0) },
623 { FboSpec(127, 127, 0), FboSpec(129, 129, 0) },
624 { FboSpec(17, 512, 4), FboSpec(16, 16, 2) },
625 { FboSpec(2048, 2048, 4), FboSpec(1, 1, 0) },
626 { FboSpec(1, 1, 0), FboSpec(2048, 2048, 4) },
629 for (int specNdx = 0; specNdx < DE_LENGTH_OF_ARRAY(specs); specNdx++)
631 const FboSpec& baseSpec = specs[specNdx][0];
632 const FboSpec& altSpec = specs[specNdx][1];
633 stringstream baseSpecName, altSpecName;
635 baseSpecName << baseSpec.width << "x" << baseSpec.height << "ms" << baseSpec.samples;
636 altSpecName << altSpec.width << "x" << altSpec.height << "ms" << altSpec.samples;
639 const string name = baseSpecName.str() + "_default_" + altSpecName.str();
641 group->addChild(new AttachmentInteractionCase(testCtx, renderCtx, name.c_str(), name.c_str(), altSpec, baseSpec));
648 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(testCtx, "maximums", "Maximum dimensions");
650 root->addChild(group);
651 group->addChild(new SizeCase(testCtx, renderCtx, "width", "Maximum width", FboSpec(SizeCase::USE_MAXIMUM, 128, 0)));
652 group->addChild(new SizeCase(testCtx, renderCtx, "height", "Maximum height", FboSpec(128, SizeCase::USE_MAXIMUM, 0)));
653 group->addChild(new SizeCase(testCtx, renderCtx, "size", "Maximum size", FboSpec(SizeCase::USE_MAXIMUM, SizeCase::USE_MAXIMUM, 0)));
654 group->addChild(new SizeCase(testCtx, renderCtx, "samples", "Maximum samples", FboSpec(128, 128, SizeCase::USE_MAXIMUM)));
655 group->addChild(new SizeCase(testCtx, renderCtx, "all", "Maximum size & samples", FboSpec(SizeCase::USE_MAXIMUM, SizeCase::USE_MAXIMUM, SizeCase::USE_MAXIMUM)));
661 tcu::TestCaseGroup* createFboNoAttachmentCompletenessTests(Context& context)
663 TestCaseGroup* const group = new TestCaseGroup(context, "completeness", "Completeness tests");
665 group->addChild(new FramebufferCompletenessCase(context.getTestContext(), context.getRenderContext(), "no_attachments", "No attachments completeness"));