Commit 22fc9523 by Jeff Vigil Committed by Commit Bot

EGL: implement EGL_EXT_buffer_age

Add extension flag. Add Validation check to surface query. Enable extension for vulkan. Modify AcquireNextImage to ++frame count and tag images with frame number. Buffer age is the difference between current frame count and the tagged frame number on the buffer. getBuffeAge may need to trigger AcquireNextImage to be current. Pass through egl extension and query. Add EGLBufferAgeTest Test: angle_end2end_test --gtest_filter=EGLBufferAgeTest Test: angle_deqp_egl_tests --deqp-case=dEQP-EGL.functional.buffer_age.* Bug: angleproject:3529 Change-Id: I0cb94be1c3e85d6f33e82a6a1ccdc9731b6a7f23 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2684724 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent c11186c2
...@@ -1474,6 +1474,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const ...@@ -1474,6 +1474,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_NV_robustness_video_memory_purge", robustnessVideoMemoryPurgeNV, &extensionStrings); InsertExtensionString("EGL_NV_robustness_video_memory_purge", robustnessVideoMemoryPurgeNV, &extensionStrings);
InsertExtensionString("EGL_KHR_reusable_sync", reusableSyncKHR, &extensionStrings); InsertExtensionString("EGL_KHR_reusable_sync", reusableSyncKHR, &extensionStrings);
InsertExtensionString("EGL_ANGLE_external_context_and_surface", externalContextAndSurface, &extensionStrings); InsertExtensionString("EGL_ANGLE_external_context_and_surface", externalContextAndSurface, &extensionStrings);
InsertExtensionString("EGL_EXT_buffer_age", bufferAgeEXT, &extensionStrings);
// clang-format on // clang-format on
return extensionStrings; return extensionStrings;
......
...@@ -1218,6 +1218,9 @@ struct DisplayExtensions ...@@ -1218,6 +1218,9 @@ struct DisplayExtensions
// EGL_ANGLE_external_context_and_surface // EGL_ANGLE_external_context_and_surface
bool externalContextAndSurface = false; bool externalContextAndSurface = false;
// EGL_EXT_buffer_age
bool bufferAgeEXT = false;
}; };
struct DeviceExtensions struct DeviceExtensions
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/Framebuffer.h" #include "libANGLE/Framebuffer.h"
#include "libANGLE/Texture.h" #include "libANGLE/Texture.h"
#include "libANGLE/Thread.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/EGLImplFactory.h" #include "libANGLE/renderer/EGLImplFactory.h"
#include "libANGLE/trace.h" #include "libANGLE/trace.h"
...@@ -586,6 +585,21 @@ GLuint Surface::getId() const ...@@ -586,6 +585,21 @@ GLuint Surface::getId() const
return 0; return 0;
} }
Error Surface::getBufferAge(const gl::Context *context, EGLint *age) const
{
// When EGL_BUFFER_PRESERVED, the previous frame contents are copied to
// current frame, so the buffer age is always 1.
if (mSwapBehavior == EGL_BUFFER_PRESERVED)
{
if (age != nullptr)
{
*age = 1;
}
return egl::NoError();
}
return mImplementation->getBufferAge(context, age);
}
gl::Framebuffer *Surface::createDefaultFramebuffer(const gl::Context *context, gl::Framebuffer *Surface::createDefaultFramebuffer(const gl::Context *context,
egl::Surface *readSurface) egl::Surface *readSurface)
{ {
......
...@@ -186,6 +186,8 @@ class Surface : public LabeledObject, public gl::FramebufferAttachmentObject ...@@ -186,6 +186,8 @@ class Surface : public LabeledObject, public gl::FramebufferAttachmentObject
// otherwise. // otherwise.
const gl::Offset &getTextureOffset() const { return mTextureOffset; } const gl::Offset &getTextureOffset() const { return mTextureOffset; }
Error getBufferAge(const gl::Context *context, EGLint *age) const;
protected: protected:
Surface(EGLint surfaceType, Surface(EGLint surfaceType,
const egl::Config *config, const egl::Config *config,
......
...@@ -4155,6 +4155,7 @@ void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *va ...@@ -4155,6 +4155,7 @@ void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *va
} }
egl::Error QuerySurfaceAttrib(const Display *display, egl::Error QuerySurfaceAttrib(const Display *display,
const gl::Context *context,
const Surface *surface, const Surface *surface,
EGLint attribute, EGLint attribute,
EGLint *value) EGLint *value)
...@@ -4253,6 +4254,9 @@ egl::Error QuerySurfaceAttrib(const Display *display, ...@@ -4253,6 +4254,9 @@ egl::Error QuerySurfaceAttrib(const Display *display,
case EGL_TIMESTAMPS_ANDROID: case EGL_TIMESTAMPS_ANDROID:
*value = surface->isTimestampsEnabled(); *value = surface->isTimestampsEnabled();
break; break;
case EGL_BUFFER_AGE_EXT:
ANGLE_TRY(surface->getBufferAge(context, value));
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -275,6 +275,7 @@ void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value); ...@@ -275,6 +275,7 @@ void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value);
void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value); void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value);
egl::Error QuerySurfaceAttrib(const Display *display, egl::Error QuerySurfaceAttrib(const Display *display,
const gl::Context *context,
const Surface *surface, const Surface *surface,
EGLint attribute, EGLint attribute,
EGLint *value); EGLint *value);
......
...@@ -113,4 +113,11 @@ egl::Error SurfaceImpl::getUserHeight(const egl::Display *display, EGLint *value ...@@ -113,4 +113,11 @@ egl::Error SurfaceImpl::getUserHeight(const egl::Display *display, EGLint *value
*value = getHeight(); *value = getHeight();
return egl::NoError(); return egl::NoError();
} }
egl::Error SurfaceImpl::getBufferAge(const gl::Context *context, EGLint *age)
{
UNREACHABLE();
return egl::EglBadMatch();
}
} // namespace rx } // namespace rx
...@@ -109,6 +109,7 @@ class SurfaceImpl : public FramebufferAttachmentObjectImpl ...@@ -109,6 +109,7 @@ class SurfaceImpl : public FramebufferAttachmentObjectImpl
EGLint numTimestamps, EGLint numTimestamps,
const EGLint *timestamps, const EGLint *timestamps,
EGLnsecsANDROID *values) const; EGLnsecsANDROID *values) const;
virtual egl::Error getBufferAge(const gl::Context *context, EGLint *age);
protected: protected:
const egl::SurfaceState &mState; const egl::SurfaceState &mState;
......
...@@ -699,6 +699,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -699,6 +699,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge; outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
outExtensions->bufferAgeEXT = mEGL->hasExtension("EGL_EXT_buffer_age");
DisplayGL::generateExtensions(outExtensions); DisplayGL::generateExtensions(outExtensions);
} }
......
...@@ -42,4 +42,15 @@ egl::Error WindowSurfaceEGL::initialize(const egl::Display *display) ...@@ -42,4 +42,15 @@ egl::Error WindowSurfaceEGL::initialize(const egl::Display *display)
return egl::NoError(); return egl::NoError();
} }
egl::Error WindowSurfaceEGL::getBufferAge(const gl::Context *context, EGLint *age)
{
ANGLE_UNUSED_VARIABLE(context);
EGLBoolean result = mEGL->querySurface(mSurface, EGL_BUFFER_AGE_EXT, age);
if (result == EGL_FALSE)
{
return egl::Error(mEGL->getError(), "eglQuerySurface for EGL_BUFFER_AGE_EXT failed");
}
return egl::NoError();
}
} // namespace rx } // namespace rx
...@@ -25,6 +25,8 @@ class WindowSurfaceEGL : public SurfaceEGL ...@@ -25,6 +25,8 @@ class WindowSurfaceEGL : public SurfaceEGL
egl::Error initialize(const egl::Display *display) override; egl::Error initialize(const egl::Display *display) override;
egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
private: private:
EGLNativeWindowType mWindow; EGLNativeWindowType mWindow;
}; };
......
...@@ -245,6 +245,8 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -245,6 +245,8 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->ggpStreamDescriptor = true; outExtensions->ggpStreamDescriptor = true;
outExtensions->swapWithFrameToken = getRenderer()->getFeatures().supportsGGPFrameToken.enabled; outExtensions->swapWithFrameToken = getRenderer()->getFeatures().supportsGGPFrameToken.enabled;
#endif // defined(ANGLE_PLATFORM_GGP) #endif // defined(ANGLE_PLATFORM_GGP)
outExtensions->bufferAgeEXT = true;
} }
void DisplayVk::generateCaps(egl::Caps *outCaps) const void DisplayVk::generateCaps(egl::Caps *outCaps) const
......
...@@ -483,7 +483,8 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ ...@@ -483,7 +483,8 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ
mCurrentSwapchainImageIndex(0), mCurrentSwapchainImageIndex(0),
mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex), mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex), mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex),
mNeedToAcquireNextSwapchainImage(false) mNeedToAcquireNextSwapchainImage(false),
mFrameCount(1)
{ {
// Initialize the color render target with the multisampled targets. If not multisampled, the // Initialize the color render target with the multisampled targets. If not multisampled, the
// render target will be updated to refer to a swapchain image on every acquire. // render target will be updated to refer to a swapchain image on every acquire.
...@@ -1063,6 +1064,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, ...@@ -1063,6 +1064,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
Is90DegreeRotation(getPreTransform()), format, 1, Is90DegreeRotation(getPreTransform()), format, 1,
robustInit); robustInit);
member.imageViews.init(renderer); member.imageViews.init(renderer);
member.mFrameNumber = 0;
} }
// Initialize depth/stencil if requested. // Initialize depth/stencil if requested.
...@@ -1440,6 +1442,9 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk, ...@@ -1440,6 +1442,9 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
VkResult result = renderer->queuePresent(contextVk, contextVk->getPriority(), presentInfo); VkResult result = renderer->queuePresent(contextVk, contextVk->getPriority(), presentInfo);
// Set FrameNumber for the presented image.
mSwapchainImages[mCurrentSwapchainImageIndex].mFrameNumber = mFrameCount++;
ANGLE_TRY(computePresentOutOfDate(contextVk, result, presentOutOfDate)); ANGLE_TRY(computePresentOutOfDate(contextVk, result, presentOutOfDate));
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1897,4 +1902,33 @@ angle::Result WindowSurfaceVk::drawOverlay(ContextVk *contextVk, SwapchainImage ...@@ -1897,4 +1902,33 @@ angle::Result WindowSurfaceVk::drawOverlay(ContextVk *contextVk, SwapchainImage
return angle::Result::Continue; return angle::Result::Continue;
} }
egl::Error WindowSurfaceVk::getBufferAge(const gl::Context *context, EGLint *age)
{
if (mNeedToAcquireNextSwapchainImage)
{
// Acquire the current image if needed.
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
egl::Error result =
angle::ToEGL(doDeferredAcquireNextImage(context, false), displayVk, EGL_BAD_SURFACE);
if (result.isError())
{
return result;
}
}
if (age != nullptr)
{
uint64_t frameNumber = mSwapchainImages[mCurrentSwapchainImageIndex].mFrameNumber;
if (frameNumber == 0)
{
*age = 0; // Has not been used for rendering yet, no age.
}
else
{
*age = static_cast<EGLint>(mFrameCount - frameNumber);
}
}
return egl::NoError();
}
} // namespace rx } // namespace rx
...@@ -168,6 +168,7 @@ struct SwapchainImage : angle::NonCopyable ...@@ -168,6 +168,7 @@ struct SwapchainImage : angle::NonCopyable
static constexpr size_t kPresentHistorySize = kSwapHistorySize + 1; static constexpr size_t kPresentHistorySize = kSwapHistorySize + 1;
std::array<ImagePresentHistory, kPresentHistorySize> presentHistory; std::array<ImagePresentHistory, kPresentHistorySize> presentHistory;
size_t currentPresentHistoryIndex = 0; size_t currentPresentHistoryIndex = 0;
uint64_t mFrameNumber = 0;
}; };
} // namespace impl } // namespace impl
...@@ -243,6 +244,8 @@ class WindowSurfaceVk : public SurfaceVk ...@@ -243,6 +244,8 @@ class WindowSurfaceVk : public SurfaceVk
return mPreTransform; return mPreTransform;
} }
egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
protected: protected:
angle::Result swapImpl(const gl::Context *context, angle::Result swapImpl(const gl::Context *context,
const EGLint *rects, const EGLint *rects,
...@@ -340,6 +343,9 @@ class WindowSurfaceVk : public SurfaceVk ...@@ -340,6 +343,9 @@ class WindowSurfaceVk : public SurfaceVk
// True when acquiring the next image is deferred. // True when acquiring the next image is deferred.
bool mNeedToAcquireNextSwapchainImage; bool mNeedToAcquireNextSwapchainImage;
// EGL_EXT_buffer_age: Track frame count.
uint64_t mFrameCount;
}; };
} // namespace rx } // namespace rx
......
...@@ -4982,6 +4982,27 @@ bool ValidateQuerySurface(const ValidationContext *val, ...@@ -4982,6 +4982,27 @@ bool ValidateQuerySurface(const ValidationContext *val,
} }
break; break;
case EGL_BUFFER_AGE_EXT:
{
if (!display->getExtensions().bufferAgeEXT)
{
val->setError(EGL_BAD_ATTRIBUTE,
"EGL_BUFFER_AGE_EXT cannot be used without "
"EGL_EXT_buffer_age support.");
return false;
}
gl::Context *context = val->eglThread->getContext();
if ((context == nullptr) || (context->getCurrentDrawSurface() != surface))
{
val->setError(EGL_BAD_SURFACE,
"The surface must be current to the current context "
"in order to query buffer age per extension "
"EGL_EXT_buffer_age.");
return false;
}
}
break;
default: default:
val->setError(EGL_BAD_ATTRIBUTE, "Invalid surface attribute."); val->setError(EGL_BAD_ATTRIBUTE, "Invalid surface attribute.");
return false; return false;
......
...@@ -557,7 +557,8 @@ EGLBoolean QuerySurface(Thread *thread, ...@@ -557,7 +557,8 @@ EGLBoolean QuerySurface(Thread *thread,
{ {
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface", ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface",
GetDisplayIfValid(display), EGL_FALSE); GetDisplayIfValid(display), EGL_FALSE);
ANGLE_EGL_TRY_RETURN(thread, QuerySurfaceAttrib(display, eglSurface, attribute, value), ANGLE_EGL_TRY_RETURN(
thread, QuerySurfaceAttrib(display, thread->getContext(), eglSurface, attribute, value),
"eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); "eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
thread->setSuccess(); thread->setSuccess();
......
...@@ -6,6 +6,7 @@ angle_end2end_tests_sources = [ ...@@ -6,6 +6,7 @@ angle_end2end_tests_sources = [
"egl_tests/EGLAndroidFrameBufferTargetTest.cpp", "egl_tests/EGLAndroidFrameBufferTargetTest.cpp",
"egl_tests/EGLBackwardsCompatibleContextTest.cpp", "egl_tests/EGLBackwardsCompatibleContextTest.cpp",
"egl_tests/EGLBlobCacheTest.cpp", "egl_tests/EGLBlobCacheTest.cpp",
"egl_tests/EGLBufferAgeTest.cpp",
"egl_tests/EGLChooseConfigTest.cpp", "egl_tests/EGLChooseConfigTest.cpp",
"egl_tests/EGLContextASANTest.cpp", "egl_tests/EGLContextASANTest.cpp",
"egl_tests/EGLContextCompatibilityTest.cpp", "egl_tests/EGLContextCompatibilityTest.cpp",
......
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLBufferAgeTest.cpp:
// EGL extension EGL_EXT_buffer_age
//
#include <gtest/gtest.h>
#include "test_utils/ANGLETest.h"
#include "util/EGLWindow.h"
#include "util/OSWindow.h"
using namespace angle;
class EGLBufferAgeTest : public ANGLETest
{
public:
EGLBufferAgeTest() : mDisplay(EGL_NO_DISPLAY) {}
void testSetUp() override
{
EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
mDisplay = eglGetPlatformDisplayEXT(
EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
mMajorVersion = GetParam().majorVersion;
mExtensionSupported = IsEGLDisplayExtensionEnabled(mDisplay, "EGL_EXT_buffer_age");
}
void testTearDown() override
{
if (mDisplay != EGL_NO_DISPLAY)
{
eglTerminate(mDisplay);
eglReleaseThread();
mDisplay = EGL_NO_DISPLAY;
}
ASSERT_EGL_SUCCESS() << "Error during test TearDown";
}
bool chooseConfig(EGLConfig *config)
{
bool result = false;
EGLint count = 0;
EGLint clientVersion = mMajorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
EGLint attribs[] = {EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_ALPHA_SIZE,
0,
EGL_RENDERABLE_TYPE,
clientVersion,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_NONE};
result = eglChooseConfig(mDisplay, attribs, config, 1, &count);
EXPECT_EGL_TRUE(result && (count > 0));
return result;
}
bool createContext(EGLConfig config, EGLContext *context)
{
bool result = false;
EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, mMajorVersion, EGL_NONE};
*context = eglCreateContext(mDisplay, config, nullptr, attribs);
result = (*context != EGL_NO_CONTEXT);
EXPECT_TRUE(result);
return result;
}
bool createWindowSurface(EGLConfig config, EGLNativeWindowType win, EGLSurface *surface)
{
bool result = false;
EGLint attribs[] = {EGL_NONE};
*surface = eglCreateWindowSurface(mDisplay, config, win, attribs);
result = (*surface != EGL_NO_SURFACE);
EXPECT_TRUE(result);
return result;
}
EGLint queryAge(EGLSurface surface)
{
EGLint value = 0;
bool result = eglQuerySurface(mDisplay, surface, EGL_BUFFER_AGE_EXT, &value);
EXPECT_TRUE(result);
return value;
}
EGLDisplay mDisplay = EGL_NO_DISPLAY;
EGLint mMajorVersion = 0;
const EGLint kWidth = 64;
const EGLint kHeight = 64;
bool mExtensionSupported = false;
};
// Query for buffer age
TEST_P(EGLBufferAgeTest, QueryBufferAge)
{
ANGLE_SKIP_TEST_IF(!mExtensionSupported);
EGLConfig config = EGL_NO_CONFIG_KHR;
EXPECT_TRUE(chooseConfig(&config));
EGLContext context = EGL_NO_CONTEXT;
EXPECT_TRUE(createContext(config, &context));
ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
EGLSurface surface = EGL_NO_SURFACE;
OSWindow *osWindow = OSWindow::New();
osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, context));
ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
glClearColor(1.0, 0.0, 0.0, 1.0);
const uint32_t loopcount = 15;
EGLint expectedAge = 0;
for (uint32_t i = 0; i < loopcount; i++)
{
EGLint age = queryAge(surface);
// Should start with zero age and then flip to buffer count - which we don't know.
if ((expectedAge == 0) && (age > 0))
{
expectedAge = age;
}
EXPECT_EQ(age, expectedAge);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR() << "glClear failed";
eglSwapBuffers(mDisplay, surface);
ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
}
EXPECT_GT(expectedAge, 0);
EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
eglDestroySurface(mDisplay, surface);
surface = EGL_NO_SURFACE;
osWindow->destroy();
OSWindow::Delete(&osWindow);
eglDestroyContext(mDisplay, context);
context = EGL_NO_CONTEXT;
}
// Verify contents of buffer are as expected
TEST_P(EGLBufferAgeTest, VerifyContents)
{
ANGLE_SKIP_TEST_IF(!mExtensionSupported);
EGLConfig config = EGL_NO_CONFIG_KHR;
EXPECT_TRUE(chooseConfig(&config));
EGLContext context = EGL_NO_CONTEXT;
EXPECT_TRUE(createContext(config, &context));
ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
EGLSurface surface = EGL_NO_SURFACE;
OSWindow *osWindow = OSWindow::New();
osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, context));
ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
const angle::GLColor kLightGray(191, 191, 191, 255); // 0.75
const angle::GLColor kDarkGray(64, 64, 64, 255); // 0.25
const angle::GLColor kColorSet[] = {
GLColor::blue, GLColor::cyan, kDarkGray, GLColor::green, GLColor::red,
GLColor::white, GLColor::yellow, GLColor::black, GLColor::magenta, kLightGray,
GLColor::black, // Extra loops until color cycled through
GLColor::black, GLColor::black, GLColor::black, GLColor::black};
EGLint age = 0;
angle::GLColor expectedColor = GLColor::black;
int loopCount = (sizeof(kColorSet) / sizeof(kColorSet[0]));
for (int i = 0; i < loopCount; i++)
{
age = queryAge(surface);
if (age > 0)
{
// Check that color/content is what we expect
expectedColor = kColorSet[i - age];
EXPECT_PIXEL_COLOR_EQ(1, 1, expectedColor);
}
float red = kColorSet[i].R / 255.0;
float green = kColorSet[i].G / 255.0;
float blue = kColorSet[i].B / 255.0;
float alpha = kColorSet[i].A / 255.0;
glClearColor(red, green, blue, alpha);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR() << "glClear failed";
eglSwapBuffers(mDisplay, surface);
ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
}
EXPECT_GT(age, 0);
EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
eglDestroySurface(mDisplay, surface);
surface = EGL_NO_SURFACE;
osWindow->destroy();
OSWindow::Delete(&osWindow);
eglDestroyContext(mDisplay, context);
context = EGL_NO_CONTEXT;
}
// Verify EGL_BAD_SURFACE when not current
TEST_P(EGLBufferAgeTest, UncurrentContextBadSurface)
{
ANGLE_SKIP_TEST_IF(!mExtensionSupported);
EGLConfig config = EGL_NO_CONFIG_KHR;
EXPECT_TRUE(chooseConfig(&config));
EGLContext context = EGL_NO_CONTEXT;
EXPECT_TRUE(createContext(config, &context));
ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
EGLSurface surface = EGL_NO_SURFACE;
OSWindow *osWindow = OSWindow::New();
osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
// No current context
EGLint value = 0;
EXPECT_EGL_FALSE(eglQuerySurface(mDisplay, surface, EGL_BUFFER_AGE_EXT, &value));
EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
EGLContext otherContext = EGL_NO_CONTEXT;
EXPECT_TRUE(createContext(config, &otherContext));
ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
// Surface current to another context
EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, otherContext));
// Make context the active context
EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
value = 0;
EXPECT_EGL_FALSE(eglQuerySurface(mDisplay, surface, EGL_BUFFER_AGE_EXT, &value));
EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
eglDestroySurface(mDisplay, surface);
surface = EGL_NO_SURFACE;
osWindow->destroy();
OSWindow::Delete(&osWindow);
eglDestroyContext(mDisplay, otherContext);
otherContext = EGL_NO_CONTEXT;
eglDestroyContext(mDisplay, context);
context = EGL_NO_CONTEXT;
}
// Expect age always == 1 when EGL_BUFFER_PRESERVED is chosen
TEST_P(EGLBufferAgeTest, BufferPreserved)
{
ANGLE_SKIP_TEST_IF(!mExtensionSupported);
EGLConfig config = EGL_NO_CONFIG_KHR;
EGLint count = 0;
EGLint clientVersion = mMajorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
EGLint attribs[] = {EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_ALPHA_SIZE,
0,
EGL_RENDERABLE_TYPE,
clientVersion,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT,
EGL_NONE};
EXPECT_EGL_TRUE(eglChooseConfig(mDisplay, attribs, &config, 1, &count));
// Skip if no configs, this indicates EGL_BUFFER_PRESERVED is not supported.
ANGLE_SKIP_TEST_IF(count == 0);
EGLContext context = EGL_NO_CONTEXT;
EXPECT_TRUE(createContext(config, &context));
ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
EGLSurface surface = EGL_NO_SURFACE;
OSWindow *osWindow = OSWindow::New();
osWindow->initialize("EGLBufferAgeTest", kWidth, kHeight);
EXPECT_TRUE(createWindowSurface(config, osWindow->getNativeWindow(), &surface));
ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
EXPECT_TRUE(eglMakeCurrent(mDisplay, surface, surface, context));
ASSERT_EGL_SUCCESS() << "eglMakeCurrent failed.";
glClearColor(1.0, 0.0, 0.0, 1.0);
const uint32_t loopcount = 10;
EGLint expectedAge = 1;
for (uint32_t i = 0; i < loopcount; i++)
{
EGLint age = queryAge(surface);
EXPECT_EQ(age, expectedAge);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR() << "glClear failed";
eglSwapBuffers(mDisplay, surface);
ASSERT_EGL_SUCCESS() << "eglSwapBuffers failed.";
}
EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
ASSERT_EGL_SUCCESS() << "eglMakeCurrent - uncurrent failed.";
eglDestroySurface(mDisplay, surface);
surface = EGL_NO_SURFACE;
osWindow->destroy();
OSWindow::Delete(&osWindow);
eglDestroyContext(mDisplay, context);
context = EGL_NO_CONTEXT;
}
ANGLE_INSTANTIATE_TEST(EGLBufferAgeTest,
WithNoFixture(ES2_OPENGLES()),
WithNoFixture(ES3_OPENGLES()),
WithNoFixture(ES2_OPENGL()),
WithNoFixture(ES3_OPENGL()),
WithNoFixture(ES2_VULKAN()),
WithNoFixture(ES3_VULKAN()));
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment