Commit 436e32ae by Corentin Wallez

GLX backend: check for child window resizes on eglWaitNative

This is the standard way, if not often used, for application to notify the driver of window size changes. Chromium uses it to resize when it is done rendering and swapping so that drivers do not clobber the backbuffer. This fixes black flickering appearing when resizing the Chromium windows with --use-gl=angle. BUG=angleproject:1281 Change-Id: Ic76f3c3ef453eae07eb59122135290411f86764d Reviewed-on: https://chromium-review.googlesource.com/322390Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tryjob-Request: Corentin Wallez <cwallez@chromium.org> Tested-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent c1069a08
...@@ -817,9 +817,9 @@ Error Display::waitClient() const ...@@ -817,9 +817,9 @@ Error Display::waitClient() const
return mImplementation->waitClient(); return mImplementation->waitClient();
} }
Error Display::waitNative(EGLint engine) const Error Display::waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const
{ {
return mImplementation->waitNative(engine); return mImplementation->waitNative(engine, drawSurface, readSurface);
} }
const Caps &Display::getCaps() const const Caps &Display::getCaps() const
......
...@@ -92,7 +92,7 @@ class Display final : angle::NonCopyable ...@@ -92,7 +92,7 @@ class Display final : angle::NonCopyable
void notifyDeviceLost(); void notifyDeviceLost();
Error waitClient() const; Error waitClient() const;
Error waitNative(EGLint engine) const; Error waitNative(EGLint engine, egl::Surface *drawSurface, egl::Surface *readSurface) const;
const Caps &getCaps() const; const Caps &getCaps() const;
......
...@@ -83,7 +83,9 @@ class DisplayImpl : angle::NonCopyable ...@@ -83,7 +83,9 @@ class DisplayImpl : angle::NonCopyable
virtual egl::Error getDevice(DeviceImpl **device) = 0; virtual egl::Error getDevice(DeviceImpl **device) = 0;
virtual egl::Error waitClient() const = 0; virtual egl::Error waitClient() const = 0;
virtual egl::Error waitNative(EGLint engine) const = 0; virtual egl::Error waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const = 0;
const egl::Caps &getCaps() const; const egl::Caps &getCaps() const;
......
...@@ -346,10 +346,11 @@ egl::Error DisplayD3D::waitClient() const ...@@ -346,10 +346,11 @@ egl::Error DisplayD3D::waitClient() const
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
egl::Error DisplayD3D::waitNative(EGLint engine) const egl::Error DisplayD3D::waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const
{ {
// Unimplemented as it is a noop on D3D // Unimplemented as it is a noop on D3D
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
} }
...@@ -60,7 +60,9 @@ class DisplayD3D : public DisplayImpl ...@@ -60,7 +60,9 @@ class DisplayD3D : public DisplayImpl
std::string getVendorString() const override; std::string getVendorString() const override;
egl::Error waitClient() const override; egl::Error waitClient() const override;
egl::Error waitNative(EGLint engine) const override; egl::Error waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const override;
private: private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override; void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
......
...@@ -51,7 +51,9 @@ class DisplayCGL : public DisplayGL ...@@ -51,7 +51,9 @@ class DisplayCGL : public DisplayGL
std::string getVendorString() const override; std::string getVendorString() const override;
egl::Error waitClient() const override; egl::Error waitClient() const override;
egl::Error waitNative(EGLint engine) const override; egl::Error waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const override;
private: private:
const FunctionsGL *getFunctionsGL() const override; const FunctionsGL *getFunctionsGL() const override;
......
...@@ -262,7 +262,9 @@ egl::Error DisplayCGL::waitClient() const ...@@ -262,7 +262,9 @@ egl::Error DisplayCGL::waitClient() const
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
egl::Error DisplayCGL::waitNative(EGLint engine) const egl::Error DisplayCGL::waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const
{ {
// TODO(cwallez) UNIMPLEMENTED() // TODO(cwallez) UNIMPLEMENTED()
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
......
...@@ -645,8 +645,37 @@ egl::Error DisplayGLX::waitClient() const ...@@ -645,8 +645,37 @@ egl::Error DisplayGLX::waitClient() const
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
egl::Error DisplayGLX::waitNative(EGLint engine) const egl::Error DisplayGLX::waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const
{ {
// eglWaitNative is used to notice the driver of changes in X11 for the current surface, such as
// changes of the window size. We use this event to update the child window of WindowSurfaceGLX
// to match its parent window's size.
// Handling eglWaitNative this way helps the application control when resize happens. This is
// important because drivers have a tendency to clobber the back buffer when the windows are
// resized. See http://crbug.com/326995
if (drawSurface != nullptr)
{
SurfaceGLX *glxDrawSurface = GetImplAs<SurfaceGLX>(drawSurface);
egl::Error error = glxDrawSurface->checkForResize();
if (error.isError())
{
return error;
}
}
if (readSurface != drawSurface && readSurface != nullptr)
{
SurfaceGLX *glxReadSurface = GetImplAs<SurfaceGLX>(readSurface);
egl::Error error = glxReadSurface->checkForResize();
if (error.isError())
{
return error;
}
}
// We still need to forward the resizing of the child window to the driver.
mGLX.waitX(); mGLX.waitX();
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
......
...@@ -68,7 +68,9 @@ class DisplayGLX : public DisplayGL ...@@ -68,7 +68,9 @@ class DisplayGLX : public DisplayGL
std::string getVendorString() const override; std::string getVendorString() const override;
egl::Error waitClient() const override; egl::Error waitClient() const override;
egl::Error waitNative(EGLint engine) const override; egl::Error waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const override;
// Synchronizes with the X server, if the display has been opened by ANGLE. // Synchronizes with the X server, if the display has been opened by ANGLE.
// Calling this is required at the end of every functions that does buffered // Calling this is required at the end of every functions that does buffered
......
...@@ -22,7 +22,7 @@ PbufferSurfaceGLX::PbufferSurfaceGLX(RendererGL *renderer, ...@@ -22,7 +22,7 @@ PbufferSurfaceGLX::PbufferSurfaceGLX(RendererGL *renderer,
const FunctionsGLX &glx, const FunctionsGLX &glx,
glx::Context context, glx::Context context,
glx::FBConfig fbConfig) glx::FBConfig fbConfig)
: SurfaceGL(renderer), : SurfaceGLX(renderer),
mWidth(width), mWidth(width),
mHeight(height), mHeight(height),
mLargest(largest), mLargest(largest),
...@@ -134,4 +134,9 @@ EGLint PbufferSurfaceGLX::getSwapBehavior() const ...@@ -134,4 +134,9 @@ EGLint PbufferSurfaceGLX::getSwapBehavior() const
return EGL_BUFFER_PRESERVED; return EGL_BUFFER_PRESERVED;
} }
egl::Error PbufferSurfaceGLX::checkForResize()
{
// The size of pbuffers never change
return egl::Error(EGL_SUCCESS);
}
} }
...@@ -9,16 +9,15 @@ ...@@ -9,16 +9,15 @@
#ifndef LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_ #ifndef LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_
#define LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_ #define LIBANGLE_RENDERER_GL_GLX_PBUFFERSURFACEGLX_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/renderer/gl/glx/platform_glx.h" #include "libANGLE/renderer/gl/glx/platform_glx.h"
#include "libANGLE/renderer/gl/glx/SurfaceGLX.h"
namespace rx namespace rx
{ {
class DisplayGLX;
class FunctionsGLX; class FunctionsGLX;
class PbufferSurfaceGLX : public SurfaceGL class PbufferSurfaceGLX : public SurfaceGLX
{ {
public: public:
PbufferSurfaceGLX(RendererGL *renderer, PbufferSurfaceGLX(RendererGL *renderer,
...@@ -46,6 +45,8 @@ class PbufferSurfaceGLX : public SurfaceGL ...@@ -46,6 +45,8 @@ class PbufferSurfaceGLX : public SurfaceGL
EGLint isPostSubBufferSupported() const override; EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override; EGLint getSwapBehavior() const override;
egl::Error checkForResize() override;
private: private:
unsigned mWidth; unsigned mWidth;
unsigned mHeight; unsigned mHeight;
......
//
// Copyright (c) 2016 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.
//
// SurfaceGLX.h: common interface for GLX surfaces
#ifndef LIBANGLE_RENDERER_GL_GLX_SURFACEGLX_H_
#define LIBANGLE_RENDERER_GL_GLX_SURFACEGLX_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
namespace rx
{
class SurfaceGLX : public SurfaceGL
{
public:
SurfaceGLX(RendererGL *renderer) : SurfaceGL(renderer) {}
virtual egl::Error checkForResize() = 0;
};
}
#endif // LIBANGLE_RENDERER_GL_GLX_SURFACEGLX_H_
...@@ -28,7 +28,7 @@ WindowSurfaceGLX::WindowSurfaceGLX(const FunctionsGLX &glx, ...@@ -28,7 +28,7 @@ WindowSurfaceGLX::WindowSurfaceGLX(const FunctionsGLX &glx,
Display *display, Display *display,
glx::Context context, glx::Context context,
glx::FBConfig fbConfig) glx::FBConfig fbConfig)
: SurfaceGL(renderer), : SurfaceGLX(renderer),
mParent(window), mParent(window),
mWindow(0), mWindow(0),
mDisplay(display), mDisplay(display),
...@@ -142,27 +142,17 @@ egl::Error WindowSurfaceGLX::makeCurrent() ...@@ -142,27 +142,17 @@ egl::Error WindowSurfaceGLX::makeCurrent()
egl::Error WindowSurfaceGLX::swap() egl::Error WindowSurfaceGLX::swap()
{ {
//TODO(cwallez) set up our own error handler to see if the call failed // We need to swap before resizing as some drivers clobber the back buffer
unsigned int newParentWidth, newParentHeight; // when the window is resized.
if (!getWindowDimensions(mParent, &newParentWidth, &newParentHeight)) mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl);
{ mGLX.swapBuffers(mGLXWindow);
// TODO(cwallez) What error type here?
return egl::Error(EGL_BAD_CURRENT_SURFACE, "Failed to retrieve the size of the parent window.");
}
if (mParentWidth != newParentWidth || mParentHeight != newParentHeight) egl::Error error = checkForResize();
if (error.isError())
{ {
mParentWidth = newParentWidth; return error;
mParentHeight = newParentHeight;
mGLX.waitGL();
XResizeWindow(mDisplay, mWindow, mParentWidth, mParentHeight);
mGLX.waitX();
} }
mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl);
mGLX.swapBuffers(mGLXWindow);
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
...@@ -218,6 +208,30 @@ EGLint WindowSurfaceGLX::getSwapBehavior() const ...@@ -218,6 +208,30 @@ EGLint WindowSurfaceGLX::getSwapBehavior() const
return EGL_BUFFER_PRESERVED; return EGL_BUFFER_PRESERVED;
} }
egl::Error WindowSurfaceGLX::checkForResize()
{
// TODO(cwallez) set up our own error handler to see if the call failed
unsigned int newParentWidth, newParentHeight;
if (!getWindowDimensions(mParent, &newParentWidth, &newParentHeight))
{
return egl::Error(EGL_BAD_CURRENT_SURFACE,
"Failed to retrieve the size of the parent window.");
}
if (mParentWidth != newParentWidth || mParentHeight != newParentHeight)
{
mParentWidth = newParentWidth;
mParentHeight = newParentHeight;
mGLX.waitGL();
XResizeWindow(mDisplay, mWindow, mParentWidth, mParentHeight);
mGLX.waitX();
XSync(mDisplay, False);
}
return egl::Error(EGL_SUCCESS);
}
bool WindowSurfaceGLX::getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const bool WindowSurfaceGLX::getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const
{ {
Window root; Window root;
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
#ifndef LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_ #ifndef LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_
#define LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_ #define LIBANGLE_RENDERER_GL_GLX_WINDOWSURFACEGLX_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/renderer/gl/glx/DisplayGLX.h" #include "libANGLE/renderer/gl/glx/DisplayGLX.h"
#include "libANGLE/renderer/gl/glx/platform_glx.h" #include "libANGLE/renderer/gl/glx/platform_glx.h"
#include "libANGLE/renderer/gl/glx/SurfaceGLX.h"
namespace rx namespace rx
{ {
...@@ -19,7 +19,7 @@ namespace rx ...@@ -19,7 +19,7 @@ namespace rx
class DisplayGLX; class DisplayGLX;
class FunctionsGLX; class FunctionsGLX;
class WindowSurfaceGLX : public SurfaceGL class WindowSurfaceGLX : public SurfaceGLX
{ {
public: public:
WindowSurfaceGLX(const FunctionsGLX &glx, WindowSurfaceGLX(const FunctionsGLX &glx,
...@@ -47,6 +47,8 @@ class WindowSurfaceGLX : public SurfaceGL ...@@ -47,6 +47,8 @@ class WindowSurfaceGLX : public SurfaceGL
EGLint isPostSubBufferSupported() const override; EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override; EGLint getSwapBehavior() const override;
egl::Error checkForResize() override;
private: private:
bool getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const; bool getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const;
......
...@@ -514,7 +514,9 @@ egl::Error DisplayWGL::waitClient() const ...@@ -514,7 +514,9 @@ egl::Error DisplayWGL::waitClient() const
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
egl::Error DisplayWGL::waitNative(EGLint engine) const egl::Error DisplayWGL::waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const
{ {
// Unimplemented as this is not needed for WGL // Unimplemented as this is not needed for WGL
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
......
...@@ -53,7 +53,9 @@ class DisplayWGL : public DisplayGL ...@@ -53,7 +53,9 @@ class DisplayWGL : public DisplayGL
std::string getVendorString() const override; std::string getVendorString() const override;
egl::Error waitClient() const override; egl::Error waitClient() const override;
egl::Error waitNative(EGLint engine) const override; egl::Error waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const override;
private: private:
const FunctionsGL *getFunctionsGL() const override; const FunctionsGL *getFunctionsGL() const override;
......
...@@ -480,6 +480,7 @@ ...@@ -480,6 +480,7 @@
'libANGLE/renderer/gl/glx/FunctionsGLX.h', 'libANGLE/renderer/gl/glx/FunctionsGLX.h',
'libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp', 'libANGLE/renderer/gl/glx/PbufferSurfaceGLX.cpp',
'libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h', 'libANGLE/renderer/gl/glx/PbufferSurfaceGLX.h',
'libANGLE/renderer/gl/glx/SurfaceGLX.h',
'libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp', 'libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp',
'libANGLE/renderer/gl/glx/WindowSurfaceGLX.h', 'libANGLE/renderer/gl/glx/WindowSurfaceGLX.h',
'libANGLE/renderer/gl/glx/functionsglx_typedefs.h', 'libANGLE/renderer/gl/glx/functionsglx_typedefs.h',
......
...@@ -786,7 +786,7 @@ EGLBoolean EGLAPIENTRY WaitNative(EGLint engine) ...@@ -786,7 +786,7 @@ EGLBoolean EGLAPIENTRY WaitNative(EGLint engine)
Error(EGL_BAD_PARAMETER, "the 'engine' parameter has an unrecognized value")); Error(EGL_BAD_PARAMETER, "the 'engine' parameter has an unrecognized value"));
} }
error = display->waitNative(engine); error = display->waitNative(engine, GetGlobalDrawSurface(), GetGlobalReadSurface());
if (error.isError()) if (error.isError())
{ {
SetGlobalError(error); SetGlobalError(error);
......
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