blob: d85d99967dadb80036d15115741d96c9c068a9f4 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gl/gl_surface_egl_x11.h"
#include "base/containers/contains.h"
#include "ui/base/x/x11_util.h"
#include "ui/base/x/x11_xrandr_interval_only_vsync_provider.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_util.h"
#include "ui/gl/egl_util.h"
namespace gl {
NativeViewGLSurfaceEGLX11::NativeViewGLSurfaceEGLX11(x11::Window window)
: NativeViewGLSurfaceEGL(static_cast<uint32_t>(window), nullptr) {}
bool NativeViewGLSurfaceEGLX11::Initialize(GLSurfaceFormat format) {
if (!NativeViewGLSurfaceEGL::Initialize(format))
return false;
auto* connection = x11::Connection::Get();
// Query all child windows and store them. ANGLE creates a child window when
// eglCreateWindowSurface is called on X11 and expose events from this window
// need to be received by this class. Since ANGLE is using a separate
// connection, we have to select expose events on our own connection.
if (auto reply =
connection->QueryTree({static_cast<x11::Window>(window_)}).Sync()) {
children_ = std::move(reply->children);
}
for (auto child : children_) {
connection->ChangeWindowAttributes(
{.window = child, .event_mask = x11::EventMask::Exposure});
}
dispatcher_set_ = true;
connection->AddEventObserver(this);
return true;
}
void NativeViewGLSurfaceEGLX11::Destroy() {
NativeViewGLSurfaceEGL::Destroy();
if (dispatcher_set_)
x11::Connection::Get()->RemoveEventObserver(this);
}
gfx::SwapResult NativeViewGLSurfaceEGLX11::SwapBuffers(
PresentationCallback callback) {
auto result = NativeViewGLSurfaceEGL::SwapBuffers(std::move(callback));
if (result == gfx::SwapResult::SWAP_FAILED)
return result;
// We need to restore the background pixel that we set to WhitePixel on
// views::DesktopWindowTreeHostX11::InitX11Window back to None for the
// XWindow associated to this surface after the first SwapBuffers has
// happened, to avoid showing a weird white background while resizing.
if (GetXNativeConnection()->Ready() && !has_swapped_buffers_) {
GetXNativeConnection()->ChangeWindowAttributes({
.window = static_cast<x11::Window>(window_),
.background_pixmap = x11::Pixmap::None,
});
GetXNativeConnection()->Flush();
has_swapped_buffers_ = true;
}
return result;
}
NativeViewGLSurfaceEGLX11::~NativeViewGLSurfaceEGLX11() {
Destroy();
}
x11::Connection* NativeViewGLSurfaceEGLX11::GetXNativeConnection() const {
return x11::Connection::Get();
}
std::unique_ptr<gfx::VSyncProvider>
NativeViewGLSurfaceEGLX11::CreateVsyncProviderInternal() {
return std::make_unique<ui::XrandrIntervalOnlyVSyncProvider>();
}
void NativeViewGLSurfaceEGLX11::OnEvent(const x11::Event& x11_event) {
// When ANGLE is used for EGL, it creates an X11 child window. Expose events
// from this window need to be forwarded to this class.
auto* expose = x11_event.As<x11::ExposeEvent>();
if (!expose || !base::Contains(children_, expose->window))
return;
auto expose_copy = *expose;
auto window = static_cast<x11::Window>(window_);
expose_copy.window = window;
x11::SendEvent(expose_copy, window, x11::EventMask::Exposure);
x11::Connection::Get()->Flush();
}
} // namespace gl