--- /dev/null
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program EGL Module
+ * ---------------------------------------
+ *
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Test KHR_mutable_render_buffer
+ *//*--------------------------------------------------------------------*/
+
+#include "teglMutableRenderBufferTests.hpp"
+
+#include "egluUtil.hpp"
+
+#include "eglwLibrary.hpp"
+#include "eglwEnums.hpp"
+
+#include "gluDefs.hpp"
+#include "gluRenderContext.hpp"
+
+#include "glwFunctions.hpp"
+#include "glwEnums.hpp"
+
+using namespace eglw;
+
+namespace deqp
+{
+namespace egl
+{
+namespace
+{
+
+class MutableRenderBufferTest : public TestCase
+{
+public:
+ MutableRenderBufferTest (EglTestContext& eglTestCtx,
+ const char* name,
+ const char* description,
+ bool enableConfigBit);
+ ~MutableRenderBufferTest (void);
+ void init (void);
+ void deinit (void);
+ IterateResult iterate (void);
+
+protected:
+ deUint32 drawAndSwap (const Library& egl,
+ deUint32 color,
+ bool flush);
+ bool m_enableConfigBit;
+ EGLDisplay m_eglDisplay;
+ EGLSurface m_eglSurface;
+ EGLConfig m_eglConfig;
+ eglu::NativeWindow* m_window;
+ EGLContext m_eglContext;
+ glw::Functions m_gl;
+};
+
+MutableRenderBufferTest::MutableRenderBufferTest (EglTestContext& eglTestCtx,
+ const char* name, const char* description,
+ bool enableConfigBit)
+ : TestCase (eglTestCtx, name, description)
+ , m_enableConfigBit (enableConfigBit)
+ , m_eglDisplay (EGL_NO_DISPLAY)
+ , m_eglSurface (EGL_NO_SURFACE)
+ , m_eglConfig (DE_NULL)
+ , m_window (DE_NULL)
+ , m_eglContext (EGL_NO_CONTEXT)
+{
+}
+
+MutableRenderBufferTest::~MutableRenderBufferTest (void)
+{
+ deinit();
+}
+
+void MutableRenderBufferTest::init (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ // create display
+ m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
+
+ if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_mutable_render_buffer"))
+ {
+ TCU_THROW(NotSupportedError, "EGL_KHR_mutable_render_buffer is not supported");
+ }
+
+ // get mutable render buffer config
+ const EGLint attribs[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_MUTABLE_RENDER_BUFFER_BIT_KHR,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+ const EGLint attribsNoBit[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+ m_eglConfig = m_enableConfigBit ?
+ eglu::chooseSingleConfig(egl, m_eglDisplay, attribs) :
+ eglu::chooseSingleConfig(egl, m_eglDisplay, attribsNoBit);
+
+ // create surface
+ const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
+ m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, m_eglConfig, DE_NULL,
+ eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
+ m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, m_eglConfig, DE_NULL);
+
+ // create context and make current
+ const EGLint contextAttribList[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ egl.bindAPI(EGL_OPENGL_ES_API);
+ m_eglContext = egl.createContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttribList);
+ EGLU_CHECK_MSG(egl, "eglCreateContext");
+ TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
+ egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ EGLU_CHECK_MSG(egl, "eglMakeCurrent");
+
+ m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
+}
+
+void MutableRenderBufferTest::deinit (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ if (m_eglContext != EGL_NO_CONTEXT)
+ {
+ egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ egl.destroyContext(m_eglDisplay, m_eglContext);
+ m_eglContext = EGL_NO_CONTEXT;
+ }
+
+ if (m_eglSurface != EGL_NO_SURFACE)
+ {
+ egl.destroySurface(m_eglDisplay, m_eglSurface);
+ m_eglSurface = EGL_NO_SURFACE;
+ }
+
+ if (m_eglDisplay != EGL_NO_DISPLAY)
+ {
+ egl.terminate(m_eglDisplay);
+ m_eglDisplay = EGL_NO_DISPLAY;
+ }
+
+ if (m_window != DE_NULL)
+ {
+ delete m_window;
+ m_window = DE_NULL;
+ }
+}
+
+deUint32 MutableRenderBufferTest::drawAndSwap (const Library& egl, deUint32 color, bool flush)
+{
+ DE_ASSERT(color < 256);
+ m_gl.clearColor(color/255.f, color/255.f, color/255.f, color/255.f);
+ m_gl.clear(GL_COLOR_BUFFER_BIT);
+ if (flush)
+ {
+ m_gl.flush();
+ }
+ else
+ {
+ EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
+ }
+ return (color | color << 8 | color << 16 | color << 24);
+}
+
+TestCase::IterateResult MutableRenderBufferTest::iterate (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ int frameNumber = 1;
+
+ // test a few back-buffered frames
+ for(; frameNumber < 5; frameNumber++)
+ {
+ deUint32 backBufferPixel = 0xFFFFFFFF;
+ deUint32 frontBufferPixel = drawAndSwap(egl, frameNumber, false);
+ m_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &backBufferPixel);
+
+ // the front-buffer and the back-buffer should have different contents
+ if (backBufferPixel == frontBufferPixel)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface isn't being back-buffered");
+ return STOP;
+ }
+ }
+
+ // switch to single-buffer rendering
+ EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
+
+ // test a few single-buffered frames
+ for (; frameNumber < 10; frameNumber++)
+ {
+ deUint32 backBufferPixel = 0xFFFFFFFF;
+ deUint32 frontBufferPixel = drawAndSwap(egl, frameNumber, frameNumber > 5); // only the first frame should eglSwapBuffers
+ m_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &backBufferPixel);
+
+ // when single buffered, front-buffer == back-buffer
+ if (backBufferPixel != frontBufferPixel)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch to being single-buffered");
+ return STOP;
+ }
+ }
+
+ // switch back to back-buffer rendering
+ EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER));
+
+ // test a few back-buffered frames
+ for (; frameNumber < 15; frameNumber++)
+ {
+ deUint32 backBufferPixel = 0xFFFFFFFF;
+ deUint32 frontBufferPixel = drawAndSwap(egl, frameNumber, false);
+ m_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &backBufferPixel);
+
+ // the front-buffer and the back-buffer should have different contents
+ if (backBufferPixel == frontBufferPixel)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch back to being back-buffered");
+ return STOP;
+ }
+ }
+
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ return STOP;
+}
+
+class MutableRenderBufferQueryTest : public MutableRenderBufferTest
+{
+public:
+ MutableRenderBufferQueryTest (EglTestContext& eglTestCtx,
+ const char* name,
+ const char* description);
+ ~MutableRenderBufferQueryTest (void);
+ IterateResult iterate (void);
+};
+
+MutableRenderBufferQueryTest::MutableRenderBufferQueryTest (EglTestContext& eglTestCtx,
+ const char* name, const char* description)
+ : MutableRenderBufferTest (eglTestCtx, name, description, true)
+{
+}
+
+MutableRenderBufferQueryTest::~MutableRenderBufferQueryTest (void)
+{
+ deinit();
+}
+
+TestCase::IterateResult MutableRenderBufferQueryTest::iterate (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ // check that by default the query returns back buffered
+ EGLint curRenderBuffer = -1;
+ EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
+ if (curRenderBuffer != EGL_BACK_BUFFER)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering");
+ return STOP;
+ }
+
+ // switch to single-buffer rendering and check that the query output changed
+ EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
+ EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
+ if (curRenderBuffer != EGL_SINGLE_BUFFER)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch to single-buffer rendering");
+ return STOP;
+ }
+
+ // switch back to back-buffer rendering and check the query again
+ EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER));
+ EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
+ if (curRenderBuffer != EGL_BACK_BUFFER)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch back to back-buffer rendering");
+ return STOP;
+ }
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ return STOP;
+}
+
+class MutableRenderBufferQueryNegativeTest : public MutableRenderBufferTest
+{
+public:
+ MutableRenderBufferQueryNegativeTest (EglTestContext& eglTestCtx,
+ const char* name,
+ const char* description);
+ ~MutableRenderBufferQueryNegativeTest (void);
+ IterateResult iterate (void);
+};
+
+MutableRenderBufferQueryNegativeTest::MutableRenderBufferQueryNegativeTest (EglTestContext& eglTestCtx,
+ const char* name, const char* description)
+ : MutableRenderBufferTest (eglTestCtx, name, description, false)
+{
+}
+
+MutableRenderBufferQueryNegativeTest::~MutableRenderBufferQueryNegativeTest (void)
+{
+ deinit();
+}
+
+TestCase::IterateResult MutableRenderBufferQueryNegativeTest::iterate (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ // check that by default the query returns back buffered
+ EGLint curRenderBuffer = -1;
+ EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
+ if (curRenderBuffer != EGL_BACK_BUFFER)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering");
+ return STOP;
+ }
+
+ // check that trying to switch to single-buffer rendering fails when the config bit is not set
+ EGLBoolean ret = egl.surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
+ EGLint err = egl.getError();
+ if (ret != EGL_FALSE)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
+ "eglSurfaceAttrib didn't return false when trying to enable single-buffering on a context without the mutable render buffer bit set");
+ return STOP;
+ }
+ if (err != EGL_BAD_MATCH)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
+ "eglSurfaceAttrib didn't set the EGL_BAD_MATCH error when trying to enable single-buffering on a context without the mutable render buffer bit set");
+ return STOP;
+ }
+
+ EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
+ if (curRenderBuffer != EGL_BACK_BUFFER)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't stay in back-buffered rendering after error");
+ return STOP;
+ }
+
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ return STOP;
+}
+
+} // anonymous
+
+MutableRenderBufferTests::MutableRenderBufferTests (EglTestContext& eglTestCtx)
+ : TestCaseGroup(eglTestCtx, "mutable_render_buffer", "Mutable render buffer tests")
+{
+}
+
+void MutableRenderBufferTests::init (void)
+{
+ addChild(new MutableRenderBufferQueryTest(m_eglTestCtx, "querySurface",
+ "Tests if querySurface returns the correct value after surfaceAttrib is called"));
+ addChild(new MutableRenderBufferQueryNegativeTest(m_eglTestCtx, "negativeConfigBit",
+ "Tests trying to enable single-buffering on a context without the mutable render buffer bit set"));
+ addChild(new MutableRenderBufferTest(m_eglTestCtx, "basic",
+ "Tests enabling/disabling single-buffer rendering and checks the buffering behavior", true));
+}
+
+} // egl
+} // deqp