0

[XProto] Ensure x11::Connection is only used on a single thread

This fixes bug 1109422 which is caused by using the same
x11::Connection from both the GPU main thread and the viz compositor
thread.

Summary of changes:

* x11::Connection is now stored in TLS instead of as a singleton.  This
  does not affect the browser process, but it means the GPU process
  will now have 2 connections: 1 for the main thread and 1 for the viz
  compositor thread.  Additionally, chrome will have 3 connections
  when running in single-process-mode.

* In X11 and Ozone/X11 contexts, the viz compositor thread must be a
  UI thread now so it can dispatch X events.  This required making
  MessagePumpGlib compatible with multiple threads.

* The GPU sandbox presents a challenge: we cannot open an X11
  connection once it's up, since the socket() and connect()
  syscalls are blocked.  To workaround this, we must open the viz
  compositor X11 connection the same time we open the main thread's
  X11 connection.  For now, we stuff it in ui::X11UiThread as an
  obnoxious global variable.

XShmImagePool and X11SoftwareBitmapPresenter are simplified as they
are now only used on one thread.  Also CreateVizCompositorThread() no
longer requires a TaskRunner argument.

With this change, once we remove the rest of Xlib, we can remove any
locking when using X11.

BUG=1066670,1078392,1109422
R=nickdiego,sky,msisov,rjkroege

Change-Id: If122c071a2eef38ba0469fe592ab9cc71ccf6011
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2343314
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
Reviewed-by: Maksim Sisov (GMT+3) <msisov@igalia.com>
Reviewed-by: Nick Yamane <nickdiego@igalia.com>
Reviewed-by: kylechar <kylechar@chromium.org>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799697}
This commit is contained in:
Tom Anderson
2020-08-19 17:26:17 +00:00
committed by Commit Bot
parent a929446fd0
commit b960daf4e6
45 changed files with 398 additions and 334 deletions

@ -5,16 +5,13 @@
#include "base/message_loop/message_pump_glib.h"
#include <fcntl.h>
#include <glib.h>
#include <math.h>
#include <glib.h>
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
#include "base/posix/eintr_wrapper.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
namespace base {
@ -50,6 +47,12 @@ int GetTimeIntervalMilliseconds(TimeTicks next_task_time) {
return timeout_ms < 0 ? 0 : saturated_cast<int>(timeout_ms);
}
bool RunningOnMainThread() {
auto pid = getpid();
auto tid = PlatformThread::CurrentId();
return pid > 0 && tid > 0 && pid == tid;
}
// A brief refresher on GLib:
// GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
// On each iteration of the GLib pump, it calls each source's Prepare function.
@ -102,8 +105,7 @@ struct WorkSource : public GSource {
MessagePumpGlib* pump;
};
gboolean WorkSourcePrepare(GSource* source,
gint* timeout_ms) {
gboolean WorkSourcePrepare(GSource* source, gint* timeout_ms) {
*timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare();
// We always return FALSE, so that our timeout is honored. If we were
// to return TRUE, the timeout would be considered to be 0 and the poll
@ -128,52 +130,6 @@ gboolean WorkSourceDispatch(GSource* source,
GSourceFuncs WorkSourceFuncs = {WorkSourcePrepare, WorkSourceCheck,
WorkSourceDispatch, nullptr};
// The following is used to make sure we only run the MessagePumpGlib on one
// thread. X only has one message pump so we can only have one UI loop per
// process.
#ifndef NDEBUG
// Tracks the pump the most recent pump that has been run.
struct ThreadInfo {
// The pump.
MessagePumpGlib* pump;
// ID of the thread the pump was run on.
PlatformThreadId thread_id;
};
// Used for accesing |thread_info|.
Lock& GetThreadInfoLock() {
static NoDestructor<Lock> thread_info_lock;
return *thread_info_lock;
}
// If non-null it means a MessagePumpGlib exists and has been Run. This is
// destroyed when the MessagePump is destroyed.
ThreadInfo* g_thread_info = nullptr;
void CheckThread(MessagePumpGlib* pump) {
AutoLock auto_lock(GetThreadInfoLock());
if (!g_thread_info) {
g_thread_info = new ThreadInfo;
g_thread_info->pump = pump;
g_thread_info->thread_id = PlatformThread::CurrentId();
}
DCHECK_EQ(g_thread_info->thread_id, PlatformThread::CurrentId())
<< "Running MessagePumpGlib on two different threads; "
"this is unsupported by GLib!";
}
void PumpDestroyed(MessagePumpGlib* pump) {
AutoLock auto_lock(GetThreadInfoLock());
if (g_thread_info && g_thread_info->pump == pump) {
delete g_thread_info;
g_thread_info = nullptr;
}
}
#endif
struct FdWatchSource : public GSource {
MessagePumpGlib* pump;
MessagePumpGlib::FdWatchController* controller;
@ -218,16 +174,23 @@ struct MessagePumpGlib::RunState {
};
MessagePumpGlib::MessagePumpGlib()
: state_(nullptr),
context_(g_main_context_default()),
wakeup_gpollfd_(new GPollFD) {
: state_(nullptr), wakeup_gpollfd_(std::make_unique<GPollFD>()) {
DCHECK(!g_main_context_get_thread_default());
if (RunningOnMainThread()) {
context_ = g_main_context_default();
} else {
context_ = g_main_context_new();
g_main_context_push_thread_default(context_);
context_owned_ = true;
}
// Create our wakeup pipe, which is used to flag when work was scheduled.
int fds[2];
int ret = pipe(fds);
DCHECK_EQ(ret, 0);
(void)ret; // Prevent warning in release mode.
wakeup_pipe_read_ = fds[0];
wakeup_pipe_read_ = fds[0];
wakeup_pipe_write_ = fds[1];
wakeup_gpollfd_->fd = wakeup_pipe_read_;
wakeup_gpollfd_->events = G_IO_IN;
@ -242,13 +205,15 @@ MessagePumpGlib::MessagePumpGlib()
}
MessagePumpGlib::~MessagePumpGlib() {
#ifndef NDEBUG
PumpDestroyed(this);
#endif
g_source_destroy(work_source_);
g_source_unref(work_source_);
close(wakeup_pipe_read_);
close(wakeup_pipe_write_);
if (context_owned_) {
g_main_context_pop_thread_default(context_);
g_main_context_unref(context_);
}
}
MessagePumpGlib::FdWatchController::FdWatchController(const Location& location)
@ -410,10 +375,6 @@ void MessagePumpGlib::HandleDispatch() {
}
void MessagePumpGlib::Run(Delegate* delegate) {
#ifndef NDEBUG
CheckThread(this);
#endif
RunState state;
state.delegate = delegate;
state.should_quit = false;

@ -112,10 +112,11 @@ class BASE_EXPORT MessagePumpGlib : public MessagePump,
RunState* state_;
// This is a GLib structure that we can add event sources to. We use the
// default GLib context, which is the one to which all GTK events are
// dispatched.
GMainContext* context_;
// This is a GLib structure that we can add event sources to. On the main
// thread, we use the default GLib context, which is the one to which all GTK
// events are dispatched.
GMainContext* context_ = nullptr;
bool context_owned_ = false;
// The work source. It is shared by all calls to Run and destroyed when
// the message pump is destroyed.

@ -240,11 +240,8 @@ OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform(
ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
std::unique_ptr<ui::PlatformWindowSurface> platform_window_surface =
factory->CreatePlatformWindowSurface(surface_handle);
scoped_refptr<base::SequencedTaskRunner> main_runner;
if (gpu_service_impl_ && !gpu_service_impl_->in_host_process())
main_runner = gpu_service_impl_->main_runner();
std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
factory->CreateCanvasForWidget(surface_handle, std::move(main_runner));
factory->CreateCanvasForWidget(surface_handle);
CHECK(surface_ozone);
return std::make_unique<SoftwareOutputDeviceOzone>(
std::move(platform_window_surface), std::move(surface_ozone));
@ -252,11 +249,7 @@ OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform(
#endif
#if defined(USE_X11)
scoped_refptr<base::SequencedTaskRunner> main_runner;
if (gpu_service_impl_ && !gpu_service_impl_->in_host_process())
main_runner = gpu_service_impl_->main_runner();
return std::make_unique<SoftwareOutputDeviceX11>(surface_handle,
std::move(main_runner));
return std::make_unique<SoftwareOutputDeviceX11>(surface_handle);
#else
NOTREACHED();
return nullptr;

@ -22,12 +22,8 @@
namespace viz {
SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner)
: x11_software_bitmap_presenter_(widget,
task_runner_.get(),
std::move(gpu_task_runner)) {
SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(gfx::AcceleratedWidget widget)
: x11_software_bitmap_presenter_(widget) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}

@ -19,9 +19,7 @@ namespace viz {
class VIZ_SERVICE_EXPORT SoftwareOutputDeviceX11 : public SoftwareOutputDevice {
public:
SoftwareOutputDeviceX11(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner);
explicit SoftwareOutputDeviceX11(gfx::AcceleratedWidget widget);
~SoftwareOutputDeviceX11() override;

@ -52,4 +52,8 @@ source_set("main") {
if (is_chromecast) {
deps += [ "//chromecast/media/service/mojom" ]
}
if (use_x11) {
deps += [ "//ui/base/x" ]
}
}

@ -37,6 +37,15 @@
#include "components/ui_devtools/viz/overlay_agent_viz.h"
#endif
#if defined(USE_OZONE)
#include "ui/base/ui_base_features.h"
#include "ui/ozone/public/ozone_platform.h"
#endif
#if defined(USE_X11)
#include "ui/base/x/x11_ui_thread.h"
#endif
namespace viz {
namespace {
@ -53,9 +62,25 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
thread->Start();
return thread;
#else // !defined(OS_ANDROID)
auto thread = std::make_unique<base::Thread>(kThreadName);
std::unique_ptr<base::Thread> thread;
base::Thread::Options thread_options;
#if defined(USE_OZONE)
if (features::IsUsingOzonePlatform()) {
auto* platform = ui::OzonePlatform::GetInstance();
thread_options.message_pump_type =
platform->GetPlatformProperties().message_pump_type_for_viz_compositor;
thread = std::make_unique<base::Thread>(kThreadName);
}
#endif
#if defined(USE_X11)
if (!thread) {
thread = std::make_unique<ui::X11UiThread>(kThreadName);
thread_options.message_pump_type = base::MessagePumpType::UI;
}
#endif
if (!thread)
thread = std::make_unique<base::Thread>(kThreadName);
#if defined(OS_FUCHSIA)
// An IO message pump is needed to use FIDL.

@ -78,6 +78,7 @@
#endif
#if defined(USE_X11)
#include "ui/base/x/x11_ui_thread.h" // nogncheck
#include "ui/base/x/x11_util.h" // nogncheck
#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h" // nogncheck
#include "ui/gfx/x/x11.h" // nogncheck
@ -286,6 +287,10 @@ int GpuMain(const MainFunctionParams& parameters) {
std::make_unique<base::SingleThreadTaskExecutor>(
base::MessagePumpType::UI);
event_source = ui::PlatformEventSource::CreateDefault();
// Set up the X11UiThread before the sandbox gets set up. This cannot be
// done later since opening the connection requires socket() and
// connect().
ui::X11UiThread::SetConnection(x11::Connection::Get()->Clone().release());
}
#endif
#if defined(USE_OZONE)

@ -42,6 +42,8 @@ component("x") {
"x11_software_bitmap_presenter.h",
"x11_topmost_window_finder.cc",
"x11_topmost_window_finder.h",
"x11_ui_thread.cc",
"x11_ui_thread.h",
"x11_util.cc",
"x11_util.h",
"x11_whole_screen_move_loop.cc",

@ -113,26 +113,27 @@ XShmImagePool::SwapClosure::SwapClosure() = default;
XShmImagePool::SwapClosure::~SwapClosure() = default;
XShmImagePool::XShmImagePool(
scoped_refptr<base::SequencedTaskRunner> host_task_runner,
scoped_refptr<base::SequencedTaskRunner> event_task_runner,
XDisplay* display,
x11::Drawable drawable,
Visual* visual,
int depth,
std::size_t frames_pending)
: host_task_runner_(std::move(host_task_runner)),
event_task_runner_(std::move(event_task_runner)),
display_(display),
XShmImagePool::XShmImagePool(x11::Connection* connection,
x11::Drawable drawable,
Visual* visual,
int depth,
std::size_t frames_pending)
: connection_(connection),
display_(connection_->display()),
drawable_(drawable),
visual_(visual),
depth_(depth),
frame_states_(frames_pending) {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
X11EventSource::GetInstance()->AddXEventDispatcher(this);
}
XShmImagePool::~XShmImagePool() {
Cleanup();
X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
}
bool XShmImagePool::Resize(const gfx::Size& pixel_size) {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (pixel_size == pixel_size_)
return true;
@ -141,9 +142,6 @@ bool XShmImagePool::Resize(const gfx::Size& pixel_size) {
std::unique_ptr<XShmImagePool, decltype(cleanup_fn)> cleanup{this,
cleanup_fn};
if (!event_task_runner_)
return false;
#if !defined(OS_CHROMEOS)
if (!ShouldUseMitShm(display_))
return false;
@ -246,31 +244,31 @@ bool XShmImagePool::Resize(const gfx::Size& pixel_size) {
}
bool XShmImagePool::Ready() {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return ready_;
}
SkBitmap& XShmImagePool::CurrentBitmap() {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return frame_states_[current_frame_index_].bitmap;
}
SkCanvas* XShmImagePool::CurrentCanvas() {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return frame_states_[current_frame_index_].canvas.get();
}
XImage* XShmImagePool::CurrentImage() {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return frame_states_[current_frame_index_].image.get();
}
void XShmImagePool::SwapBuffers(
base::OnceCallback<void(const gfx::Size&)> callback) {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
swap_closures_.emplace_back();
SwapClosure& swap_closure = swap_closures_.back();
@ -280,30 +278,9 @@ void XShmImagePool::SwapBuffers(
current_frame_index_ = (current_frame_index_ + 1) % frame_states_.size();
}
void XShmImagePool::Initialize() {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
if (event_task_runner_)
event_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&XShmImagePool::InitializeOnGpu, this));
}
void XShmImagePool::Teardown() {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
if (event_task_runner_)
event_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&XShmImagePool::TeardownOnGpu, this));
}
XShmImagePool::~XShmImagePool() {
Cleanup();
#ifndef NDEBUG
DCHECK(!dispatcher_registered_);
#endif
}
void XShmImagePool::DispatchShmCompletionEvent(
x11::Shm::CompletionEvent event) {
DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(event.offset, 0UL);
for (auto it = swap_closures_.begin(); it != swap_closures_.end(); ++it) {
@ -316,32 +293,16 @@ void XShmImagePool::DispatchShmCompletionEvent(
}
bool XShmImagePool::DispatchXEvent(x11::Event* xev) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto* completion = xev->As<x11::Shm::CompletionEvent>();
if (!completion || completion->drawable.value != drawable_.value)
return false;
host_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&XShmImagePool::DispatchShmCompletionEvent,
this, *completion));
DispatchShmCompletionEvent(*completion);
return true;
}
void XShmImagePool::InitializeOnGpu() {
DCHECK(event_task_runner_->RunsTasksInCurrentSequence());
X11EventSource::GetInstance()->AddXEventDispatcher(this);
#ifndef NDEBUG
dispatcher_registered_ = true;
#endif
}
void XShmImagePool::TeardownOnGpu() {
DCHECK(event_task_runner_->RunsTasksInCurrentSequence());
X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
#ifndef NDEBUG
dispatcher_registered_ = false;
#endif
}
void XShmImagePool::Cleanup() {
for (FrameState& state : frame_states_) {
if (state.shminfo_.shmaddr)

@ -13,7 +13,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/task_runner.h"
#include "base/sequence_checker.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/x/x11_util.h"
@ -25,22 +25,18 @@
namespace ui {
// Base class that creates XImages using shared memory that will be sent to
// XServer for processing. As Ozone and non-Ozone X11 have different
// PlatformEvent types, Ozone and non-Ozone provide own implementations that
// handles events. See AddEventDispatcher and RemoveEventDispatcher below.
class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool
: public base::RefCountedThreadSafe<XShmImagePool>,
public XEventDispatcher {
// Creates XImages backed by shared memory that will be shared with the X11
// server for processing.
class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher {
public:
XShmImagePool(scoped_refptr<base::SequencedTaskRunner> host_task_runner,
scoped_refptr<base::SequencedTaskRunner> event_task_runner,
XDisplay* display,
XShmImagePool(x11::Connection* connection,
x11::Drawable drawable,
Visual* visual,
int depth,
std::size_t max_frames_pending);
~XShmImagePool() override;
bool Resize(const gfx::Size& pixel_size);
// Is XSHM supported by the server and are the shared buffers ready for use?
@ -55,26 +51,9 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool
// change to reflect the new frame.
void SwapBuffers(base::OnceCallback<void(const gfx::Size&)> callback);
// Part of setup and teardown must be done on the event task runner. Posting
// the tasks cannot be done in the constructor/destructor because because this
// would cause subtle problems with the reference count for this object. So
// Initialize() must be called after constructing and Teardown() must be
// called before destructing.
void Initialize();
void Teardown();
protected:
~XShmImagePool() override;
void DispatchShmCompletionEvent(x11::Shm::CompletionEvent event);
const scoped_refptr<base::SequencedTaskRunner> host_task_runner_;
const scoped_refptr<base::SequencedTaskRunner> event_task_runner_;
#ifndef NDEBUG
bool dispatcher_registered_ = false;
#endif
private:
friend class base::RefCountedThreadSafe<XShmImagePool>;
@ -100,11 +79,9 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool
// XEventDispatcher:
bool DispatchXEvent(x11::Event* xev) override;
void InitializeOnGpu();
void TeardownOnGpu();
void Cleanup();
x11::Connection* const connection_;
XDisplay* const display_;
const x11::Drawable drawable_;
Visual* const visual_;
@ -117,6 +94,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool
std::size_t current_frame_index_ = 0;
std::list<SwapClosure> swap_closures_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(XShmImagePool);
};

@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/task/current_thread.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkSurface.h"
@ -122,15 +123,12 @@ bool X11SoftwareBitmapPresenter::CompositeBitmap(XDisplay* display,
}
X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> host_task_runner,
scoped_refptr<base::SequencedTaskRunner> event_task_runner)
gfx::AcceleratedWidget widget)
: widget_(static_cast<x11::Window>(widget)),
display_(gfx::GetXDisplay()),
gc_(nullptr),
host_task_runner_(host_task_runner),
event_task_runner_(event_task_runner) {
DCHECK(widget_ != x11::Window::None);
connection_(x11::Connection::Get()),
display_(connection_->display()),
gc_(nullptr) {
DCHECK_NE(widget_, x11::Window::None);
gc_ = XCreateGC(display_, static_cast<uint32_t>(widget_), 0, nullptr);
memset(&attributes_, 0, sizeof(attributes_));
if (!XGetWindowAttributes(display_, static_cast<uint32_t>(widget_),
@ -140,10 +138,9 @@ X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter(
return;
}
shm_pool_ = base::MakeRefCounted<ui::XShmImagePool>(
host_task_runner, event_task_runner, display_, widget_,
attributes_.visual, attributes_.depth, kMaxFramesPending);
shm_pool_->Initialize();
shm_pool_ = std::make_unique<ui::XShmImagePool>(
connection_, widget_, attributes_.visual, attributes_.depth,
kMaxFramesPending);
// TODO(thomasanderson): Avoid going through the X11 server to plumb this
// property in.
@ -151,41 +148,17 @@ X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter(
}
X11SoftwareBitmapPresenter::~X11SoftwareBitmapPresenter() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (gc_)
XFreeGC(display_, gc_);
if (shm_pool_)
shm_pool_->Teardown();
}
bool X11SoftwareBitmapPresenter::ShmPoolReady() const {
return shm_pool_ && shm_pool_->Ready();
}
void X11SoftwareBitmapPresenter::FlushAfterPutImage() {
// Ensure the new window content appears immediately. On a TYPE_UI thread we
// can rely on the message loop to flush for us so XFlush() isn't necessary.
// However, this code can run on a different thread and would have to wait for
// the TYPE_UI thread to no longer be idle before a flush happens.
XFlush(display_);
// Work around a race condition caused by XFlush above. Explanation: XFlush()
// flushes all requests and *also* reads events. It's unclear why it does
// this, but there's no alternative Xlib function that flushes the requests
// and *doesn't* read any events, so this workaround is necessary. In
// |event_task_runner_|'s message loop, poll() is called on the underlying
// XDisplay's fd to dispatch toplevel events. When the fd is readable, poll()
// exits and we (via Xlib) check for new events by read()ing from the fd. But
// if the event dispatcher is currently dispatching an event, then our call to
// XFlush() may read events into the event queue which will make the fd
// blocking since there's no more data to read, so poll() won't wake up until
// a new event comes, which may take a long time. Forcing the event loop to
// wake up with a dummy event fixes the race condition.
if (event_task_runner_)
event_task_runner_->PostTask(FROM_HERE, base::BindOnce([] {}));
}
void X11SoftwareBitmapPresenter::Resize(const gfx::Size& pixel_size) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (pixel_size == viewport_pixel_size_)
return;
viewport_pixel_size_ = pixel_size;
@ -209,6 +182,7 @@ void X11SoftwareBitmapPresenter::Resize(const gfx::Size& pixel_size) {
}
SkCanvas* X11SoftwareBitmapPresenter::GetSkCanvas() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (ShmPoolReady())
return shm_pool_->CurrentCanvas();
else if (surface_)
@ -217,6 +191,7 @@ SkCanvas* X11SoftwareBitmapPresenter::GetSkCanvas() {
}
void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gfx::Rect rect = damage_rect;
rect.Intersect(gfx::Rect(viewport_pixel_size_));
if (rect.IsEmpty())
@ -231,7 +206,6 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) {
shm_pool_->CurrentImage(), rect.x(), rect.y(), rect.x(),
rect.y(), rect.width(), rect.height(), x11::True)) {
needs_swap_ = true;
FlushAfterPutImage();
return;
}
skia_pixmap = shm_pool_->CurrentBitmap().pixmap();
@ -246,7 +220,6 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) {
CompositeBitmap(display_, static_cast<uint32_t>(widget_), rect.x(),
rect.y(), rect.width(), rect.height(), attributes_.depth,
gc_, skia_pixmap.addr())) {
FlushAfterPutImage();
return;
}
@ -257,22 +230,18 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) {
gc, skia_pixmap, rect.x(), rect.y(), rect.x(), rect.y(),
rect.width(), rect.height());
FlushAfterPutImage();
// We must be running on a UI thread so that the connection will be flushed.
DCHECK(base::CurrentUIThread::IsSet());
}
void X11SoftwareBitmapPresenter::OnSwapBuffers(
SwapBuffersCallback swap_ack_callback) {
if (ShmPoolReady()) {
if (needs_swap_)
shm_pool_->SwapBuffers(std::move(swap_ack_callback));
else
std::move(swap_ack_callback).Run(viewport_pixel_size_);
needs_swap_ = false;
} else {
host_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(swap_ack_callback), viewport_pixel_size_));
}
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (ShmPoolReady() && needs_swap_)
shm_pool_->SwapBuffers(std::move(swap_ack_callback));
else
std::move(swap_ack_callback).Run(viewport_pixel_size_);
needs_swap_ = false;
}
int X11SoftwareBitmapPresenter::MaxFramesPending() const {

@ -8,6 +8,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSurface.h"
@ -28,10 +29,7 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter {
// Corresponds to SwapBuffersCallback alias in SoftwareOutputDevice.
using SwapBuffersCallback = base::OnceCallback<void(const gfx::Size&)>;
X11SoftwareBitmapPresenter(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> host_task_runner,
scoped_refptr<base::SequencedTaskRunner> event_task_runner);
explicit X11SoftwareBitmapPresenter(gfx::AcceleratedWidget widget);
~X11SoftwareBitmapPresenter();
@ -56,9 +54,8 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter {
bool ShmPoolReady() const;
void FlushAfterPutImage();
x11::Window widget_;
x11::Connection* connection_;
XDisplay* display_;
GC gc_;
XWindowAttributes attributes_;
@ -67,15 +64,15 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter {
// parent-relative background.
int composite_ = 0;
scoped_refptr<ui::XShmImagePool> shm_pool_;
std::unique_ptr<ui::XShmImagePool> shm_pool_;
bool needs_swap_ = false;
scoped_refptr<base::SequencedTaskRunner> host_task_runner_;
scoped_refptr<base::SequencedTaskRunner> event_task_runner_;
sk_sp<SkSurface> surface_;
gfx::Size viewport_pixel_size_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(X11SoftwareBitmapPresenter);
};

@ -0,0 +1,49 @@
// 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/base/x/x11_ui_thread.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/connection.h"
namespace ui {
namespace {
x11::Connection* g_connection = nullptr;
}
X11UiThread::X11UiThread(const std::string& thread_name)
: base::Thread(thread_name) {
connection_.reset(g_connection);
g_connection = nullptr;
// When using in-process GPU, g_connection doesn't get set. But we can just
// open a new connection now since there's no GPU sandbox in place.
if (!connection_)
connection_ = x11::Connection::Get()->Clone();
connection_->DetachFromSequence();
}
X11UiThread::~X11UiThread() = default;
void X11UiThread::SetConnection(x11::Connection* connection) {
DCHECK(!g_connection);
g_connection = connection;
}
void X11UiThread::Init() {
// Connection and X11EventSource make use of TLS, so these calls must be made
// on the thread, not in the constructor/destructor.
auto* connection = connection_.get();
x11::Connection::Set(std::move(connection_));
event_source_ = std::make_unique<X11EventSource>(connection);
}
void X11UiThread::CleanUp() {
event_source_.reset();
connection_.reset();
}
} // namespace ui

48
ui/base/x/x11_ui_thread.h Normal file

@ -0,0 +1,48 @@
// 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.
#ifndef UI_BASE_X_X11_UI_THREAD_H_
#define UI_BASE_X_X11_UI_THREAD_H_
#include "base/component_export.h"
#include "base/threading/thread.h"
namespace x11 {
class Connection;
}
namespace ui {
class X11EventSource;
// A thread-local x11::Connection may be used on this thread, stored in TLS and
// obtained via x11::Connection::Get(). X11 events for the connection may also
// dispatch events on this thread. This thread must be started as TYPE_UI.
// TODO(thomasanderson): This can be removed once Linux switches to ozone.
class COMPONENT_EXPORT(UI_BASE_X) X11UiThread : public base::Thread {
public:
explicit X11UiThread(const std::string& thread_name);
~X11UiThread() override;
X11UiThread(const X11UiThread&) = delete;
X11UiThread& operator=(const X11UiThread&) = delete;
// Sets the global connection which will have its ownership transferred to the
// next X11UiThread created.
static void SetConnection(x11::Connection* connection);
protected:
// base::Thread:
void Init() override;
void CleanUp() override;
private:
std::unique_ptr<x11::Connection> connection_;
std::unique_ptr<X11EventSource> event_source_;
};
} // namespace ui
#endif // UI_BASE_X_X11_UI_THREAD_H_

@ -198,8 +198,7 @@ DeviceDataManagerX11* DeviceDataManagerX11::GetInstance() {
DeviceDataManagerX11::DeviceDataManagerX11()
: xi_opcode_(-1),
high_precision_scrolling_disabled_(IsHighPrecisionScrollingDisabled()),
button_map_count_(0) {
high_precision_scrolling_disabled_(IsHighPrecisionScrollingDisabled()) {
CHECK(x11::Connection::Get());
InitializeXInputInternal();
@ -651,13 +650,14 @@ void DeviceDataManagerX11::GetMetricsData(const x11::Event& xev,
}
int DeviceDataManagerX11::GetMappedButton(int button) {
return button > 0 && button <= button_map_count_ ? button_map_[button - 1]
: button;
return button > 0 && static_cast<unsigned int>(button) <= button_map_.size()
? button_map_[button - 1]
: button;
}
void DeviceDataManagerX11::UpdateButtonMap() {
button_map_count_ = XGetPointerMapping(gfx::GetXDisplay(), button_map_,
base::size(button_map_));
if (auto reply = x11::Connection::Get()->GetPointerMapping({}).Sync())
button_map_ = std::move(reply->map);
}
void DeviceDataManagerX11::GetGestureTimes(const x11::Event& xev,

@ -391,8 +391,7 @@ class EVENTS_DEVICES_X11_EXPORT DeviceDataManagerX11
// devices when they are re-enabled.
std::map<x11::Input::DeviceId, ui::InputDevice> blocked_keyboard_devices_;
unsigned char button_map_[256];
int button_map_count_;
std::vector<uint8_t> button_map_;
DISALLOW_COPY_AND_ASSIGN(DeviceDataManagerX11);
};

@ -123,17 +123,12 @@ using X11EventWatcherImpl = X11EventWatcherGlib;
using X11EventWatcherImpl = X11EventWatcherFdWatch;
#endif
X11EventSource* X11EventSource::instance_ = nullptr;
X11EventSource::X11EventSource(x11::Connection* connection)
: watcher_(std::make_unique<X11EventWatcherImpl>(this)),
connection_(connection),
dispatching_event_(nullptr),
dummy_initialized_(false),
distribution_(0, 999) {
DCHECK(!instance_);
instance_ = this;
DCHECK(connection_);
DeviceDataManagerX11::CreateInstance();
InitializeXkb(connection_);
@ -142,20 +137,18 @@ X11EventSource::X11EventSource(x11::Connection* connection)
}
X11EventSource::~X11EventSource() {
DCHECK_EQ(this, instance_);
instance_ = nullptr;
if (dummy_initialized_)
connection_->DestroyWindow({dummy_window_});
}
// static
bool X11EventSource::HasInstance() {
return instance_;
return GetInstance();
}
// static
X11EventSource* X11EventSource::GetInstance() {
DCHECK(instance_);
return instance_;
return static_cast<X11EventSource*>(PlatformEventSource::GetInstance());
}
////////////////////////////////////////////////////////////////////////////////

@ -200,8 +200,6 @@ class EVENTS_EXPORT X11EventSource : public PlatformEventSource,
void RestoreOverridenXEventDispatcher();
static X11EventSource* instance_;
std::unique_ptr<X11EventWatcher> watcher_;
// The connection to the X11 server used to receive the events.

@ -61,7 +61,8 @@ void X11EventWatcherGlib::StartWatching() {
return;
XDisplay* display = event_source_->connection()->display();
DCHECK(display) << "Unable to get connection to X server";
if (!display)
return;
x_poll_ = std::make_unique<GPollFD>();
x_poll_->fd = ConnectionNumber(display);
@ -77,7 +78,10 @@ void X11EventWatcherGlib::StartWatching() {
g_source_add_poll(x_source_, x_poll_.get());
g_source_set_can_recurse(x_source_, TRUE);
g_source_set_callback(x_source_, nullptr, event_source_, nullptr);
g_source_attach(x_source_, g_main_context_default());
auto* context = g_main_context_get_thread_default();
if (!context)
context = g_main_context_default();
g_source_attach(x_source_, context);
started_ = true;
}

@ -83,6 +83,7 @@ component("xprotos") {
":gen_xprotos",
"//base",
"//base:i18n",
"//ui/events/platform",
]
sources = get_target_outputs(":gen_xprotos") + [
"xproto_internal.h",

3
ui/gfx/x/DEPS Normal file

@ -0,0 +1,3 @@
include_rules = [
"+ui/events/platform/platform_event_source.h",
]

@ -14,7 +14,9 @@
#include "base/command_line.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/strings/string16.h"
#include "base/threading/thread_local.h"
#include "ui/gfx/x/bigreq.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/randr.h"
@ -201,11 +203,30 @@ bool IsPrivateKeypadKey(KeySym keysym) {
return key >= 0x11000000 && key <= 0x1100FFFF;
}
base::ThreadLocalOwnedPointer<Connection>& GetConnectionTLS() {
static base::NoDestructor<base::ThreadLocalOwnedPointer<Connection>> tls;
return *tls;
}
} // namespace
// static
Connection* Connection::Get() {
static Connection* instance = new Connection;
return instance;
auto& tls = GetConnectionTLS();
if (Connection* connection = tls.Get())
return connection;
auto connection = std::make_unique<Connection>();
auto* p_connection = connection.get();
tls.Set(std::move(connection));
return p_connection;
}
// static
void Connection::Set(std::unique_ptr<x11::Connection> connection) {
DCHECK_CALLED_ON_VALID_SEQUENCE(connection->sequence_checker_);
auto& tls = GetConnectionTLS();
DCHECK(!tls.Get());
tls.Set(std::move(connection));
}
Connection::Connection(const std::string& address)
@ -256,11 +277,14 @@ Connection::Connection(const std::string& address)
}
Connection::~Connection() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
platform_event_source.reset();
if (display_)
XCloseDisplay(display_);
}
xcb_connection_t* Connection::XcbConnection() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!display())
return nullptr;
return XGetXCBConnection(display());
@ -282,6 +306,7 @@ bool Connection::HasNextResponse() const {
}
int Connection::DefaultScreenId() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This is not part of the setup data as the server has no concept of a
// default screen. Instead, it's part of the display name. Eg in
// "localhost:0.0", the screen ID is the second "0".
@ -289,19 +314,23 @@ int Connection::DefaultScreenId() const {
}
bool Connection::Ready() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return display_ && !xcb_connection_has_error(XGetXCBConnection(display_));
}
void Connection::Flush() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (display_)
XFlush(display_);
}
void Connection::Sync() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
GetInputFocus({}).Sync();
}
void Connection::ReadResponses() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
while (auto* event = xcb_poll_for_event(XcbConnection())) {
events_.emplace_back(base::MakeRefCounted<MallocedRefCountedMemory>(event),
this);
@ -309,11 +338,13 @@ void Connection::ReadResponses() {
}
bool Connection::HasPendingResponses() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return !events_.empty() || HasNextResponse();
}
const Connection::VisualInfo* Connection::GetVisualInfoFromId(
VisualId id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = default_screen_visuals_.find(id);
if (it != default_screen_visuals_.end())
return &it->second;
@ -321,6 +352,7 @@ const Connection::VisualInfo* Connection::GetVisualInfoFromId(
}
KeyCode Connection::KeysymToKeycode(KeySym keysym) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
uint8_t min_keycode = static_cast<uint8_t>(setup_.min_keycode);
uint8_t max_keycode = static_cast<uint8_t>(setup_.max_keycode);
uint8_t count = max_keycode - min_keycode + 1;
@ -336,15 +368,23 @@ KeyCode Connection::KeysymToKeycode(KeySym keysym) {
}
KeySym Connection::KeycodeToKeysym(uint32_t keycode, unsigned int modifiers) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto sym = TranslateKey(keycode, modifiers);
return sym == static_cast<KeySym>(XK_VoidSymbol) ? kNoSymbol : sym;
}
std::unique_ptr<Connection> Connection::Clone() const {
return std::make_unique<Connection>(XDisplayString(display_));
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return std::make_unique<Connection>(display_ ? XDisplayString(display_) : "");
}
void Connection::DetachFromSequence() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DETACH_FROM_SEQUENCE(sequence_checker_);
}
void Connection::Dispatch(Delegate* delegate) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(display_);
auto process_next_response = [&] {
@ -404,6 +444,7 @@ void Connection::Dispatch(Delegate* delegate) {
void Connection::AddRequest(unsigned int sequence,
FutureBase::ResponseCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(requests_.empty() ||
CompareSequenceIds(requests_.back().sequence, sequence) < 0);

@ -9,6 +9,8 @@
#include <queue>
#include "base/component_export.h"
#include "base/sequence_checker.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/extension_manager.h"
#include "ui/gfx/x/xproto.h"
@ -33,27 +35,47 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
const VisualType* visual_type;
};
// Gets or creates the singleton connection.
// Gets or creates the thread local connection instance.
static Connection* Get();
// Sets the thread local connection instance.
static void Set(std::unique_ptr<x11::Connection> connection);
explicit Connection(const std::string& address = "");
~Connection();
Connection(const Connection&) = delete;
Connection(Connection&&) = delete;
XDisplay* display() const { return display_; }
XDisplay* display() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return display_;
}
xcb_connection_t* XcbConnection();
uint32_t extended_max_request_length() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return extended_max_request_length_;
}
const Setup& setup() const { return setup_; }
const Screen& default_screen() const { return *default_screen_; }
x11::Window default_root() const { return default_screen().root; }
const Depth& default_root_depth() const { return *default_root_depth_; }
const Setup& setup() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return setup_;
}
const Screen& default_screen() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return *default_screen_;
}
x11::Window default_root() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return default_screen().root;
}
const Depth& default_root_depth() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return *default_root_depth_;
}
const VisualType& default_root_visual() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return *default_root_visual_;
}
@ -61,6 +83,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
template <typename T>
T GenerateId() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return static_cast<T>(xcb_generate_id(XcbConnection()));
}
@ -91,10 +114,22 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
KeySym KeycodeToKeysym(uint32_t keycode, unsigned int modifiers);
// Access the event buffer. Clients can add, delete, or modify events.
std::list<Event>& events() { return events_; }
std::list<Event>& events() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return events_;
}
std::unique_ptr<Connection> Clone() const;
// Releases ownership of this connection to a different thread.
void DetachFromSequence();
// The viz compositor thread hangs a PlatformEventSource off the connection so
// that it gets destroyed at the appropriate time.
// TODO(thomasanderson): This is a layering violation and this should be moved
// somewhere else.
std::unique_ptr<ui::PlatformEventSource> platform_event_source;
private:
friend class FutureBase;
@ -142,6 +177,8 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
std::list<Event> events_;
std::queue<Request> requests_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace x11

@ -33,14 +33,12 @@ SoftwareRenderer::SoftwareRenderer(
vsync_period_(
base::TimeDelta::FromMilliseconds(kFrameDelayMilliseconds)) {}
SoftwareRenderer::~SoftwareRenderer() {}
SoftwareRenderer::~SoftwareRenderer() = default;
bool SoftwareRenderer::Initialize() {
software_surface_ =
ui::OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->CreateCanvasForWidget(widget_,
base::ThreadTaskRunnerHandle::Get().get());
software_surface_ = ui::OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->CreateCanvasForWidget(widget_);
if (!software_surface_) {
LOG(ERROR) << "Failed to create software surface";
return false;

@ -113,8 +113,7 @@ GLOzone* SurfaceFactoryCast::GetGLOzone(gl::GLImplementation implementation) {
}
std::unique_ptr<SurfaceOzoneCanvas> SurfaceFactoryCast::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
gfx::AcceleratedWidget widget) {
// Software canvas support only in headless mode
if (egl_implementation_)
return nullptr;

@ -32,8 +32,7 @@ class SurfaceFactoryCast : public SurfaceFactoryOzone {
std::vector<gl::GLImplementation> GetAllowedGLImplementations() override;
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
VkDevice vk_device,

@ -350,8 +350,7 @@ std::unique_ptr<OverlaySurface> GbmSurfaceFactory::CreateOverlaySurface(
}
std::unique_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
gfx::AcceleratedWidget widget) {
DCHECK(thread_checker_.CalledOnValidThread());
LOG(ERROR) << "Software rendering mode is not supported with GBM platform";
return nullptr;

@ -54,8 +54,7 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone {
std::unique_ptr<OverlaySurface> CreateOverlaySurface(
gfx::AcceleratedWidget window) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
VkDevice vk_device,

@ -234,9 +234,7 @@ GLOzone* HeadlessSurfaceFactory::GetGLOzone(
}
std::unique_ptr<SurfaceOzoneCanvas>
HeadlessSurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
HeadlessSurfaceFactory::CreateCanvasForWidget(gfx::AcceleratedWidget widget) {
return std::make_unique<FileSurface>(GetPathForWidget(base_path_, widget));
}

@ -24,8 +24,7 @@ class HeadlessSurfaceFactory : public SurfaceFactoryOzone {
std::vector<gl::GLImplementation> GetAllowedGLImplementations() override;
GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
VkDevice vk_device,

@ -44,11 +44,11 @@ namespace ui {
namespace {
constexpr OzonePlatform::PlatformProperties kScenicPlatformProperties{
/*needs_view_token=*/true,
/*custom_frame_pref_default=*/false,
/*use_system_title_bar=*/false,
/*message_pump_type_for_gpu=*/base::MessagePumpType::IO,
/*supports_vulkan_swap_chain=*/true,
.needs_view_token = true,
.custom_frame_pref_default = false,
.use_system_title_bar = false,
.message_pump_type_for_gpu = base::MessagePumpType::IO,
.supports_vulkan_swap_chain = true,
};
class ScenicPlatformEventSource : public ui::PlatformEventSource {

@ -207,8 +207,7 @@ ScenicSurfaceFactory::CreatePlatformWindowSurface(
}
std::unique_ptr<SurfaceOzoneCanvas> ScenicSurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
gfx::AcceleratedWidget widget) {
ScenicSurface* surface = GetSurface(widget);
return std::make_unique<ScenicWindowCanvas>(surface);
}

@ -47,8 +47,7 @@ class ScenicSurfaceFactory : public SurfaceFactoryOzone {
std::unique_ptr<PlatformWindowSurface> CreatePlatformWindowSurface(
gfx::AcceleratedWidget widget) override;
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
VkDevice vk_device,

@ -136,9 +136,7 @@ WaylandSurfaceFactory::WaylandSurfaceFactory(
WaylandSurfaceFactory::~WaylandSurfaceFactory() = default;
std::unique_ptr<SurfaceOzoneCanvas>
WaylandSurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
WaylandSurfaceFactory::CreateCanvasForWidget(gfx::AcceleratedWidget widget) {
return std::make_unique<WaylandCanvasSurface>(buffer_manager_, widget);
}

@ -35,8 +35,7 @@ class WaylandSurfaceFactory : public SurfaceFactoryOzone {
bool enforce_protected_memory) override;
#endif
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
gfx::AcceleratedWidget widget) override;
scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
gfx::AcceleratedWidget widget,
VkDevice vk_device,

@ -185,8 +185,7 @@ class WaylandSurfaceFactoryTest : public WaylandTest {
protected:
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvas(
gfx::AcceleratedWidget widget) {
auto canvas = surface_factory_->CreateCanvasForWidget(
widget_, base::ThreadTaskRunnerHandle::Get().get());
auto canvas = surface_factory_->CreateCanvasForWidget(widget_);
base::RunLoop().RunUntilIdle();
return canvas;

@ -72,6 +72,9 @@ constexpr OzonePlatform::PlatformProperties kX11PlatformProperties{
// When the Ozone X11 backend is running, use a UI loop to grab Expose
// events. See GLSurfaceGLX and https://crbug.com/326995.
.message_pump_type_for_gpu = base::MessagePumpType::UI,
// When the Ozone X11 backend is running, use a UI loop to dispatch
// SHM completion events.
.message_pump_type_for_viz_compositor = base::MessagePumpType::UI,
.supports_vulkan_swap_chain = true,
.platform_shows_drag_image = false,
.supports_global_application_menus = true};
@ -205,7 +208,12 @@ class OzonePlatformX11 : public OzonePlatform,
if (!params.single_process)
CreatePlatformEventSource();
surface_factory_ozone_ = std::make_unique<X11SurfaceFactory>();
// Set up the X11 connection before the sandbox gets set up. This cannot be
// done later since opening the connection requires socket() and connect().
auto connection = x11::Connection::Get()->Clone();
connection->DetachFromSequence();
surface_factory_ozone_ =
std::make_unique<X11SurfaceFactory>(std::move(connection));
gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
}

@ -11,13 +11,8 @@
namespace ui {
X11CanvasSurface::X11CanvasSurface(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner)
: task_runner_(base::SequencedTaskRunnerHandle::Get()),
x11_software_bitmap_presenter_(widget,
task_runner_.get(),
std::move(gpu_task_runner)) {}
X11CanvasSurface::X11CanvasSurface(gfx::AcceleratedWidget widget)
: x11_software_bitmap_presenter_(widget) {}
X11CanvasSurface::~X11CanvasSurface() = default;

@ -28,8 +28,7 @@ namespace ui {
// the software output is destroyed.
class X11CanvasSurface : public SurfaceOzoneCanvas {
public:
X11CanvasSurface(gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> gpu_task_runner);
explicit X11CanvasSurface(gfx::AcceleratedWidget widget);
~X11CanvasSurface() override;
// SurfaceOzoneCanvas overrides:
@ -45,8 +44,6 @@ class X11CanvasSurface : public SurfaceOzoneCanvas {
// Current surface we paint to.
sk_sp<SkSurface> surface_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Helper X11 bitmap presenter that presents the contents.
X11SoftwareBitmapPresenter x11_software_bitmap_presenter_;

@ -7,6 +7,8 @@
#include <memory>
#include "gpu/vulkan/buildflags.h"
#include "ui/events/platform/x11/x11_event_source.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/gl_surface_egl.h"
@ -73,11 +75,13 @@ class GLOzoneEGLX11 : public GLOzoneEGL {
} // namespace
X11SurfaceFactory::X11SurfaceFactory()
X11SurfaceFactory::X11SurfaceFactory(
std::unique_ptr<x11::Connection> connection)
: glx_implementation_(std::make_unique<GLOzoneGLX>()),
egl_implementation_(std::make_unique<GLOzoneEGLX11>()) {}
egl_implementation_(std::make_unique<GLOzoneEGLX11>()),
connection_(std::move(connection)) {}
X11SurfaceFactory::~X11SurfaceFactory() {}
X11SurfaceFactory::~X11SurfaceFactory() = default;
std::vector<gl::GLImplementation>
X11SurfaceFactory::GetAllowedGLImplementations() {
@ -107,9 +111,16 @@ X11SurfaceFactory::CreateVulkanImplementation(bool allow_protected_memory,
#endif
std::unique_ptr<SurfaceOzoneCanvas> X11SurfaceFactory::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
return std::make_unique<X11CanvasSurface>(widget, std::move(task_runner));
gfx::AcceleratedWidget widget) {
// X11SoftwareBitmapPresenter (created via X11CanvasSurface) requres a
// Connection TLS instance and a PlatformEventSource.
if (connection_) {
auto* connection = connection_.get();
x11::Connection::Set(std::move(connection_));
connection->platform_event_source =
std::make_unique<X11EventSource>(connection);
}
return std::make_unique<X11CanvasSurface>(widget);
}
} // namespace ui

@ -10,6 +10,7 @@
#include "base/macros.h"
#include "gpu/vulkan/buildflags.h"
#include "ui/gfx/x/connection.h"
#include "ui/gl/gl_surface.h"
#include "ui/ozone/public/gl_ozone.h"
#include "ui/ozone/public/surface_factory_ozone.h"
@ -19,7 +20,7 @@ namespace ui {
// Handles GL initialization and surface/context creation for X11.
class X11SurfaceFactory : public SurfaceFactoryOzone {
public:
X11SurfaceFactory();
explicit X11SurfaceFactory(std::unique_ptr<x11::Connection> connection);
~X11SurfaceFactory() override;
// SurfaceFactoryOzone:
@ -31,13 +32,14 @@ class X11SurfaceFactory : public SurfaceFactoryOzone {
bool enforce_protected_memory) override;
#endif
std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) override;
gfx::AcceleratedWidget widget) override;
private:
std::unique_ptr<GLOzone> glx_implementation_;
std::unique_ptr<GLOzone> egl_implementation_;
std::unique_ptr<x11::Connection> connection_;
DISALLOW_COPY_AND_ASSIGN(X11SurfaceFactory);
};

@ -87,6 +87,11 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
base::MessagePumpType message_pump_type_for_gpu =
base::MessagePumpType::DEFAULT;
// Determines the type of message pump that should be used for viz
// compositor thread.
base::MessagePumpType message_pump_type_for_viz_compositor =
base::MessagePumpType::DEFAULT;
// Determines if the platform supports vulkan swap chain.
bool supports_vulkan_swap_chain = false;

@ -66,8 +66,7 @@ std::unique_ptr<OverlaySurface> SurfaceFactoryOzone::CreateOverlaySurface(
}
std::unique_ptr<SurfaceOzoneCanvas> SurfaceFactoryOzone::CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
gfx::AcceleratedWidget widget) {
return nullptr;
}

@ -108,14 +108,12 @@ class COMPONENT_EXPORT(OZONE_BASE) SurfaceFactoryOzone {
virtual std::unique_ptr<OverlaySurface> CreateOverlaySurface(
gfx::AcceleratedWidget window);
// Create SurfaceOzoneCanvas for the specified gfx::AcceleratedWidget. The
// |task_runner| may be null if the gpu service runs in a host process.
// Create SurfaceOzoneCanvas for the specified gfx::AcceleratedWidget.
//
// Note: The platform must support creation of SurfaceOzoneCanvas from the
// Browser Process using only the handle contained in gfx::AcceleratedWidget.
virtual std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
gfx::AcceleratedWidget widget,
scoped_refptr<base::SequencedTaskRunner> task_runner);
gfx::AcceleratedWidget widget);
// Create a single native buffer to be used for overlay planes or zero copy
// for |widget| representing a particular display controller or default