зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1484812 - Use SwapBuffersWithDamage on EGL platforms (Wayland/Android) r=jnicol,mstange,jgilbert
EGL_KHR_swap_buffers_with_damage (or EGL_EXT_swap_buffers_with_damage) is an EGL extension that allows the application to inform the display server (system compositor) which areas of the window have changed. This commit implements support for that extension in the layers compositor. The layers compositor always renders the whole frame, so we're only getting the benefit of not redrawing unchanged areas *in the system compositor*, not actually doing partial invalidation/compositing, but that makes the implementation simpler (no need to track buffer age). Differential Revision: https://phabricator.services.mozilla.com/D51517 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f62b4f716b
Коммит
2befd54d63
|
@ -36,6 +36,7 @@
|
|||
#include "GLDefs.h"
|
||||
#include "GLLibraryLoader.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsRegionFwd.h"
|
||||
#include "plstr.h"
|
||||
#include "GLContextTypes.h"
|
||||
#include "SurfaceTypes.h"
|
||||
|
@ -3351,6 +3352,16 @@ class GLContext : public GenericAtomicRefCounted,
|
|||
*/
|
||||
virtual bool SwapBuffers() { return false; }
|
||||
|
||||
/**
|
||||
* Stores a damage region (in origin bottom left coordinates), which
|
||||
* makes the next SwapBuffers call do eglSwapBuffersWithDamage if supported.
|
||||
*
|
||||
* Note that even if only part of the context is damaged, the entire buffer
|
||||
* needs to be filled with up-to-date contents. This region is only a hint
|
||||
* telling the system compositor which parts of the buffer were updated.
|
||||
*/
|
||||
virtual void SetDamage(const nsIntRegion& aDamageRegion) {}
|
||||
|
||||
/**
|
||||
* Defines a two-dimensional texture image for context target surface
|
||||
*/
|
||||
|
|
|
@ -70,6 +70,8 @@ class GLContextEGL : public GLContext {
|
|||
|
||||
virtual bool SwapBuffers() override;
|
||||
|
||||
virtual void SetDamage(const nsIntRegion& aDamageRegion) override;
|
||||
|
||||
virtual void GetWSIInfo(nsCString* const out) const override;
|
||||
|
||||
// hold a reference to the given surface
|
||||
|
@ -117,6 +119,8 @@ class GLContextEGL : public GLContext {
|
|||
bool mShareWithEGLImage = false;
|
||||
bool mOwnsContext = true;
|
||||
|
||||
nsIntRegion mDamageRegion;
|
||||
|
||||
static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(
|
||||
GLLibraryEGL*, EGLConfig config, EGLenum bindToTextureFormat,
|
||||
gfx::IntSize& pbsize);
|
||||
|
|
|
@ -506,12 +506,32 @@ bool GLContextEGL::SwapBuffers() {
|
|||
EGLSurface surface =
|
||||
mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
|
||||
if (surface) {
|
||||
if ((mEgl->IsExtensionSupported(
|
||||
GLLibraryEGL::EXT_swap_buffers_with_damage) ||
|
||||
mEgl->IsExtensionSupported(
|
||||
GLLibraryEGL::KHR_swap_buffers_with_damage))) {
|
||||
std::vector<EGLint> rects;
|
||||
for (auto iter = mDamageRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const IntRect& r = iter.Get();
|
||||
rects.push_back(r.X());
|
||||
rects.push_back(r.Y());
|
||||
rects.push_back(r.Width());
|
||||
rects.push_back(r.Height());
|
||||
}
|
||||
mDamageRegion.SetEmpty();
|
||||
return mEgl->fSwapBuffersWithDamage(mEgl->Display(), surface,
|
||||
rects.data(), rects.size() / 4);
|
||||
}
|
||||
return mEgl->fSwapBuffers(mEgl->Display(), surface);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContextEGL::SetDamage(const nsIntRegion& aDamageRegion) {
|
||||
mDamageRegion = aDamageRegion;
|
||||
}
|
||||
|
||||
void GLContextEGL::GetWSIInfo(nsCString* const out) const {
|
||||
out->AppendLiteral("EGL_VENDOR: ");
|
||||
out->Append(
|
||||
|
|
|
@ -72,7 +72,9 @@ static const char* sEGLExtensionNames[] = {
|
|||
"EGL_ANGLE_device_creation_d3d11",
|
||||
"EGL_KHR_surfaceless_context",
|
||||
"EGL_KHR_create_context_no_error",
|
||||
"EGL_MOZ_create_context_provoking_vertex_dont_care"};
|
||||
"EGL_MOZ_create_context_provoking_vertex_dont_care",
|
||||
"EGL_EXT_swap_buffers_with_damage",
|
||||
"EGL_KHR_swap_buffers_with_damage"};
|
||||
|
||||
PRLibrary* LoadApitraceLibrary() {
|
||||
const char* path = nullptr;
|
||||
|
@ -703,6 +705,32 @@ bool GLLibraryEGL::DoEnsureInitialized(bool forceAccel,
|
|||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(EXT_swap_buffers_with_damage)) {
|
||||
const SymLoadStruct symbols[] = {
|
||||
{(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage,
|
||||
{{"eglSwapBuffersWithDamageEXT"}}},
|
||||
END_OF_SYMBOLS};
|
||||
if (!fnLoadSymbols(symbols)) {
|
||||
NS_ERROR(
|
||||
"EGL supports EXT_swap_buffers_with_damage without exposing its "
|
||||
"functions!");
|
||||
MarkExtensionUnsupported(EXT_swap_buffers_with_damage);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExtensionSupported(KHR_swap_buffers_with_damage)) {
|
||||
const SymLoadStruct symbols[] = {
|
||||
{(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage,
|
||||
{{"eglSwapBuffersWithDamageKHR"}}},
|
||||
END_OF_SYMBOLS};
|
||||
if (!fnLoadSymbols(symbols)) {
|
||||
NS_ERROR(
|
||||
"EGL supports KHR_swap_buffers_with_damage without exposing its "
|
||||
"functions!");
|
||||
MarkExtensionUnsupported(KHR_swap_buffers_with_damage);
|
||||
}
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
reporter.SetSuccessful();
|
||||
return true;
|
||||
|
|
|
@ -85,6 +85,8 @@ class GLLibraryEGL final {
|
|||
KHR_surfaceless_context,
|
||||
KHR_create_context_no_error,
|
||||
MOZ_create_context_provoking_vertex_dont_care,
|
||||
EXT_swap_buffers_with_damage,
|
||||
KHR_swap_buffers_with_damage,
|
||||
Extensions_Max
|
||||
};
|
||||
|
||||
|
@ -349,6 +351,11 @@ class GLLibraryEGL final {
|
|||
|
||||
EGLBoolean fReleaseDeviceANGLE(EGLDeviceEXT device)
|
||||
WRAP(fReleaseDeviceANGLE(device))
|
||||
|
||||
// EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage
|
||||
EGLBoolean fSwapBuffersWithDamage(EGLDisplay dpy, EGLSurface surface,
|
||||
const EGLint* rects, EGLint n_rects)
|
||||
WRAP(fSwapBuffersWithDamage(dpy, surface, rects, n_rects))
|
||||
#undef WRAP
|
||||
#undef VOID_WRAP
|
||||
#undef PROFILE_CALL
|
||||
|
@ -520,7 +527,11 @@ class GLLibraryEGL final {
|
|||
void* native_device,
|
||||
const EGLAttrib* attrib_list);
|
||||
EGLBoolean(GLAPIENTRY* fReleaseDeviceANGLE)(EGLDeviceEXT device);
|
||||
|
||||
// EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage
|
||||
EGLBoolean(GLAPIENTRY* fSwapBuffersWithDamage)(EGLDisplay dpy,
|
||||
EGLSurface surface,
|
||||
const EGLint* rects,
|
||||
EGLint n_rects);
|
||||
} mSymbols = {};
|
||||
|
||||
private:
|
||||
|
|
|
@ -1045,6 +1045,12 @@ Maybe<IntRect> CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
|||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const IntRect& r = iter.Get();
|
||||
mCurrentFrameInvalidRegion.OrWith(
|
||||
IntRect(r.X(), FlipY(r.YMost()), r.Width(), r.Height()));
|
||||
}
|
||||
|
||||
return Some(rect);
|
||||
}
|
||||
|
||||
|
@ -2033,6 +2039,7 @@ void CompositorOGL::EndFrame() {
|
|||
|
||||
InsertFrameDoneSync();
|
||||
|
||||
mGLContext->SetDamage(mCurrentFrameInvalidRegion);
|
||||
mGLContext->SwapBuffers();
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
|
||||
|
@ -2045,6 +2052,8 @@ void CompositorOGL::EndFrame() {
|
|||
}
|
||||
}
|
||||
|
||||
mCurrentFrameInvalidRegion.SetEmpty();
|
||||
|
||||
Compositor::EndFrame();
|
||||
}
|
||||
|
||||
|
|
|
@ -523,6 +523,8 @@ class CompositorOGL final : public Compositor {
|
|||
*/
|
||||
gfx::IntSize mViewportSize;
|
||||
|
||||
gfx::IntRegion mCurrentFrameInvalidRegion;
|
||||
|
||||
ShaderProgramOGL* mCurrentProgram;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче