You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
12 KiB
400 lines
12 KiB
/*-------------------------------------------------------------------------
|
|
* 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;
|
|
|
|
using std::vector;
|
|
|
|
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
|
|
};
|
|
|
|
if (m_enableConfigBit)
|
|
{
|
|
m_eglConfig = eglu::chooseSingleConfig(egl, m_eglDisplay, attribs);
|
|
}
|
|
else
|
|
{
|
|
const vector<EGLConfig> configs = eglu::chooseConfigs(egl, m_eglDisplay, attribsNoBit);
|
|
|
|
for (vector<EGLConfig>::const_iterator config = configs.begin(); config != configs.end(); ++config)
|
|
{
|
|
EGLint surfaceType = -1;
|
|
EGLU_CHECK_CALL(egl, getConfigAttrib(m_eglDisplay, *config, EGL_SURFACE_TYPE, &surfaceType));
|
|
|
|
if (!(surfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR))
|
|
{
|
|
m_eglConfig = *config;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_eglConfig == DE_NULL)
|
|
TCU_THROW(NotSupportedError, "No config without support for mutable_render_buffer found");
|
|
}
|
|
|
|
// 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((float)color/255.f, (float)color/255.f, (float)color/255.f, (float)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;
|
|
|
|
// run a few back-buffered frames even if we can't verify their contents
|
|
for (; frameNumber < 5; frameNumber++)
|
|
{
|
|
drawAndSwap(egl, frameNumber, false);
|
|
}
|
|
|
|
// switch to single-buffer rendering
|
|
EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
|
|
|
|
// Use eglSwapBuffers for the first frame
|
|
drawAndSwap(egl, frameNumber, false);
|
|
frameNumber++;
|
|
|
|
// test a few single-buffered frames
|
|
for (; frameNumber < 10; frameNumber++)
|
|
{
|
|
deUint32 backBufferPixel = 0xFFFFFFFF;
|
|
deUint32 frontBufferPixel = drawAndSwap(egl, frameNumber, true);
|
|
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 isn't 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));
|
|
|
|
// run a few back-buffered frames even if we can't verify their contents
|
|
for (; frameNumber < 14; frameNumber++)
|
|
{
|
|
drawAndSwap(egl, frameNumber, false);
|
|
}
|
|
|
|
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
|