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
InsertExtensionString("EGL_NV_robustness_video_memory_purge", robustnessVideoMemoryPurgeNV, &extensionStrings);
InsertExtensionString("EGL_KHR_reusable_sync", reusableSyncKHR, &extensionStrings);
InsertExtensionString("EGL_ANGLE_external_context_and_surface", externalContextAndSurface, &extensionStrings);
InsertExtensionString("EGL_EXT_buffer_age", bufferAgeEXT, &extensionStrings);
// clang-format on
return extensionStrings;
......
......@@ -1218,6 +1218,9 @@ struct DisplayExtensions
// EGL_ANGLE_external_context_and_surface
bool externalContextAndSurface = false;
// EGL_EXT_buffer_age
bool bufferAgeEXT = false;
};
struct DeviceExtensions
......
......@@ -17,7 +17,6 @@
#include "libANGLE/Display.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/Texture.h"
#include "libANGLE/Thread.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/EGLImplFactory.h"
#include "libANGLE/trace.h"
......@@ -586,6 +585,21 @@ GLuint Surface::getId() const
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,
egl::Surface *readSurface)
{
......
......@@ -186,6 +186,8 @@ class Surface : public LabeledObject, public gl::FramebufferAttachmentObject
// otherwise.
const gl::Offset &getTextureOffset() const { return mTextureOffset; }
Error getBufferAge(const gl::Context *context, EGLint *age) const;
protected:
Surface(EGLint surfaceType,
const egl::Config *config,
......
......@@ -4155,6 +4155,7 @@ void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *va
}
egl::Error QuerySurfaceAttrib(const Display *display,
const gl::Context *context,
const Surface *surface,
EGLint attribute,
EGLint *value)
......@@ -4253,6 +4254,9 @@ egl::Error QuerySurfaceAttrib(const Display *display,
case EGL_TIMESTAMPS_ANDROID:
*value = surface->isTimestampsEnabled();
break;
case EGL_BUFFER_AGE_EXT:
ANGLE_TRY(surface->getBufferAge(context, value));
break;
default:
UNREACHABLE();
break;
......
......@@ -275,6 +275,7 @@ void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value);
void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value);
egl::Error QuerySurfaceAttrib(const Display *display,
const gl::Context *context,
const Surface *surface,
EGLint attribute,
EGLint *value);
......
......@@ -113,4 +113,11 @@ egl::Error SurfaceImpl::getUserHeight(const egl::Display *display, EGLint *value
*value = getHeight();
return egl::NoError();
}
egl::Error SurfaceImpl::getBufferAge(const gl::Context *context, EGLint *age)
{
UNREACHABLE();
return egl::EglBadMatch();
}
} // namespace rx
......@@ -109,6 +109,7 @@ class SurfaceImpl : public FramebufferAttachmentObjectImpl
EGLint numTimestamps,
const EGLint *timestamps,
EGLnsecsANDROID *values) const;
virtual egl::Error getBufferAge(const gl::Context *context, EGLint *age);
protected:
const egl::SurfaceState &mState;
......
......@@ -699,6 +699,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
outExtensions->bufferAgeEXT = mEGL->hasExtension("EGL_EXT_buffer_age");
DisplayGL::generateExtensions(outExtensions);
}
......
......@@ -42,4 +42,15 @@ egl::Error WindowSurfaceEGL::initialize(const egl::Display *display)
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
......@@ -25,6 +25,8 @@ class WindowSurfaceEGL : public SurfaceEGL
egl::Error initialize(const egl::Display *display) override;
egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
private:
EGLNativeWindowType mWindow;
};
......
......@@ -245,6 +245,8 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->ggpStreamDescriptor = true;
outExtensions->swapWithFrameToken = getRenderer()->getFeatures().supportsGGPFrameToken.enabled;
#endif // defined(ANGLE_PLATFORM_GGP)
outExtensions->bufferAgeEXT = true;
}
void DisplayVk::generateCaps(egl::Caps *outCaps) const
......
......@@ -483,7 +483,8 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativ
mCurrentSwapchainImageIndex(0),
mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex),
mNeedToAcquireNextSwapchainImage(false)
mNeedToAcquireNextSwapchainImage(false),
mFrameCount(1)
{
// 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.
......@@ -1063,6 +1064,7 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
Is90DegreeRotation(getPreTransform()), format, 1,
robustInit);
member.imageViews.init(renderer);
member.mFrameNumber = 0;
}
// Initialize depth/stencil if requested.
......@@ -1440,6 +1442,9 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
VkResult result = renderer->queuePresent(contextVk, contextVk->getPriority(), presentInfo);
// Set FrameNumber for the presented image.
mSwapchainImages[mCurrentSwapchainImageIndex].mFrameNumber = mFrameCount++;
ANGLE_TRY(computePresentOutOfDate(contextVk, result, presentOutOfDate));
return angle::Result::Continue;
......@@ -1897,4 +1902,33 @@ angle::Result WindowSurfaceVk::drawOverlay(ContextVk *contextVk, SwapchainImage
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
......@@ -168,6 +168,7 @@ struct SwapchainImage : angle::NonCopyable
static constexpr size_t kPresentHistorySize = kSwapHistorySize + 1;
std::array<ImagePresentHistory, kPresentHistorySize> presentHistory;
size_t currentPresentHistoryIndex = 0;
uint64_t mFrameNumber = 0;
};
} // namespace impl
......@@ -243,6 +244,8 @@ class WindowSurfaceVk : public SurfaceVk
return mPreTransform;
}
egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
protected:
angle::Result swapImpl(const gl::Context *context,
const EGLint *rects,
......@@ -340,6 +343,9 @@ class WindowSurfaceVk : public SurfaceVk
// True when acquiring the next image is deferred.
bool mNeedToAcquireNextSwapchainImage;
// EGL_EXT_buffer_age: Track frame count.
uint64_t mFrameCount;
};
} // namespace rx
......
......@@ -4982,6 +4982,27 @@ bool ValidateQuerySurface(const ValidationContext *val,
}
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:
val->setError(EGL_BAD_ATTRIBUTE, "Invalid surface attribute.");
return false;
......
......@@ -557,8 +557,9 @@ EGLBoolean QuerySurface(Thread *thread,
{
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface",
GetDisplayIfValid(display), EGL_FALSE);
ANGLE_EGL_TRY_RETURN(thread, QuerySurfaceAttrib(display, eglSurface, attribute, value),
"eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
ANGLE_EGL_TRY_RETURN(
thread, QuerySurfaceAttrib(display, thread->getContext(), eglSurface, attribute, value),
"eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
thread->setSuccess();
return EGL_TRUE;
......
......@@ -6,6 +6,7 @@ angle_end2end_tests_sources = [
"egl_tests/EGLAndroidFrameBufferTargetTest.cpp",
"egl_tests/EGLBackwardsCompatibleContextTest.cpp",
"egl_tests/EGLBlobCacheTest.cpp",
"egl_tests/EGLBufferAgeTest.cpp",
"egl_tests/EGLChooseConfigTest.cpp",
"egl_tests/EGLContextASANTest.cpp",
"egl_tests/EGLContextCompatibilityTest.cpp",
......
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