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,8 +557,9 @@ EGLBoolean QuerySurface(Thread *thread, ...@@ -557,8 +557,9 @@ 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(
"eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE); thread, QuerySurfaceAttrib(display, thread->getContext(), eglSurface, attribute, value),
"eglQuerySurface", GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
thread->setSuccess(); thread->setSuccess();
return EGL_TRUE; return EGL_TRUE;
......
...@@ -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",
......
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