Commit a9d41393 authored by Tom Anderson's avatar Tom Anderson Committed by Commit Bot

[XProto] Remove usage of all Xlib and XCB extensions

BUG=1066670

Change-Id: I324c66b3848c4ef6dd40326ae08270c8f14c9eee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2354916
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarNick Yamane <nickdiego@igalia.com>
Reviewed-by: default avatarLambros Lambrou <lambroslambrou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800759}
parent 501c2a63
...@@ -40,27 +40,9 @@ config("x11") { ...@@ -40,27 +40,9 @@ config("x11") {
"X11", "X11",
"X11-xcb", "X11-xcb",
"xcb", "xcb",
"xcb-dri3",
"Xcomposite",
"Xdamage",
"Xext",
"Xfixes",
"Xrender",
] ]
} }
config("xcomposite") {
libs = [ "Xcomposite" ]
}
config("xext") {
libs = [ "Xext" ]
}
config("xfixes") {
libs = [ "Xfixes" ]
}
config("libcap") { config("libcap") {
libs = [ "cap" ] libs = [ "cap" ]
} }
......
...@@ -19,11 +19,12 @@ ...@@ -19,11 +19,12 @@
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_error_tracker.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto_types.h"
namespace viz { namespace viz {
SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(gfx::AcceleratedWidget widget) SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(gfx::AcceleratedWidget widget)
: x11_software_bitmap_presenter_(widget) { : x11_software_bitmap_presenter_(x11::Connection::Get(), widget, true) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
} }
......
...@@ -418,7 +418,10 @@ if (is_win || is_mac || (is_linux && !is_chromeos)) { ...@@ -418,7 +418,10 @@ if (is_win || is_mac || (is_linux && !is_chromeos)) {
"test/linux_output_window.h", "test/linux_output_window.h",
] ]
public_deps += [ "//ui/gfx/x" ] public_deps += [ "//ui/gfx/x" ]
deps += [ "//third_party/libyuv" ] deps += [
"//cc/paint",
"//ui/base/x",
]
} }
} }
......
...@@ -7,11 +7,16 @@ ...@@ -7,11 +7,16 @@
#include <stdint.h> #include <stdint.h>
#include <algorithm> #include <algorithm>
#include <memory>
#include "base/logging.h" #include "base/logging.h"
#include "cc/paint/skia_paint_canvas.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "third_party/libyuv/include/libyuv/convert.h" #include "media/renderers/paint_canvas_video_renderer.h"
#include "ui/base/x/x11_software_bitmap_presenter.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/gfx/x/xproto.h"
namespace media { namespace media {
namespace cast { namespace cast {
...@@ -26,14 +31,9 @@ LinuxOutputWindow::LinuxOutputWindow(int x_pos, ...@@ -26,14 +31,9 @@ LinuxOutputWindow::LinuxOutputWindow(int x_pos,
} }
LinuxOutputWindow::~LinuxOutputWindow() { LinuxOutputWindow::~LinuxOutputWindow() {
if (display_ && window_) { if (window_ != x11::Window::None)
XUnmapWindow(display_, window_); connection_.DestroyWindow({window_});
XDestroyWindow(display_, window_); connection_.Flush();
XSync(display_, false);
if (gc_)
XFreeGC(display_, gc_);
XCloseDisplay(display_);
}
} }
void LinuxOutputWindow::CreateWindow(int x_pos, void LinuxOutputWindow::CreateWindow(int x_pos,
...@@ -41,108 +41,74 @@ void LinuxOutputWindow::CreateWindow(int x_pos, ...@@ -41,108 +41,74 @@ void LinuxOutputWindow::CreateWindow(int x_pos,
int width, int width,
int height, int height,
const std::string& name) { const std::string& name) {
display_ = XOpenDisplay(nullptr); if (!connection_.Ready()) {
if (display_ == nullptr) {
// There's no point to continue if this happens: nothing will work anyway. // There's no point to continue if this happens: nothing will work anyway.
VLOG(1) << "Failed to connect to X server: X environment likely broken"; VLOG(1) << "Failed to connect to X server: X environment likely broken";
NOTREACHED(); NOTREACHED();
} }
int screen = DefaultScreen(display_); x11::VisualId visual;
uint8_t depth;
// Try to establish a 24-bit TrueColor display. x11::ColorMap colormap;
// (our environment must allow this). ui::XVisualManager::GetInstance()->ChooseVisualForWindow(
XVisualInfo visual_info; false, &visual, &depth, &colormap, nullptr);
if (XMatchVisualInfo(display_, screen, 24, window_ = connection_.GenerateId<x11::Window>();
static_cast<int>(x11::VisualClass::TrueColor), connection_.CreateWindow({
&visual_info) == 0) { .depth = depth,
VLOG(1) << "Failed to establish 24-bit TrueColor in X environment."; .wid = window_,
NOTREACHED(); .parent = connection_.default_root(),
} .x = x_pos,
.y = y_pos,
// Create suitable window attributes. .width = width,
XSetWindowAttributes window_attributes; .height = height,
window_attributes.colormap = XCreateColormap( .border_width = 0,
display_, DefaultRootWindow(display_), visual_info.visual, AllocNone); .c_class = x11::WindowClass::InputOutput,
window_attributes.event_mask = StructureNotifyMask | ExposureMask; .visual = visual,
window_attributes.background_pixel = 0; .background_pixel = 0,
window_attributes.border_pixel = 0; .border_pixel = 0,
.event_mask = x11::EventMask::StructureNotify,
unsigned long attribute_mask = .colormap = colormap,
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; });
window_ = XCreateWindow(
display_, DefaultRootWindow(display_), x_pos, y_pos, width, height, 0,
visual_info.depth, static_cast<int>(x11::WindowClass::InputOutput),
visual_info.visual, attribute_mask, &window_attributes);
// Set window name. // Set window name.
XStoreName(display_, window_, name.c_str()); ui::SetStringProperty(window_, x11::Atom::WM_NAME, x11::Atom::STRING, name);
XSetIconName(display_, window_, name.c_str()); ui::SetStringProperty(window_, x11::Atom::WM_ICON_NAME, x11::Atom::STRING,
name);
// Make x report events for mask.
XSelectInput(display_, window_, StructureNotifyMask);
// Map the window to the display. // Map the window to the display.
XMapWindow(display_, window_); connection_.MapWindow({window_});
connection_.Flush();
// Wait for map event. // Wait for map event.
XEvent event; while (connection_.Ready()) {
do { auto event = connection_.WaitForNextEvent();
XNextEvent(display_, &event); auto* map = event.As<x11::MapNotifyEvent>();
} while (event.type != MapNotify || event.xmap.event != window_); if (map && map->event == window_)
break;
gc_ = XCreateGC(display_, window_, 0, nullptr);
// create shared memory image
image_ = XShmCreateImage(display_, nullptr, 24,
static_cast<int>(x11::ImageFormat::ZPixmap), nullptr,
&shminfo_, width, height);
shminfo_.shmid = shmget(
IPC_PRIVATE, (image_->bytes_per_line * image_->height), IPC_CREAT | 0777);
shminfo_.shmaddr = image_->data =
static_cast<char*>(shmat(shminfo_.shmid, nullptr, 0));
if (image_->data == reinterpret_cast<char*>(-1)) {
VLOG(1) << "XShmCreateImage failed";
NOTREACHED();
} }
shminfo_.readOnly = false;
// Attach image to display. size_ = {width, height};
if (!XShmAttach(display_, &shminfo_)) { presenter_ = std::make_unique<ui::X11SoftwareBitmapPresenter>(
VLOG(1) << "XShmAttach failed"; &connection_, static_cast<gfx::AcceleratedWidget>(window_), false);
NOTREACHED(); presenter_->Resize(size_);
} connection_.Flush();
XSync(display_, false);
} }
void LinuxOutputWindow::RenderFrame(const media::VideoFrame& video_frame) { void LinuxOutputWindow::RenderFrame(const media::VideoFrame& video_frame) {
const gfx::Size damage_size( const gfx::Size damage_size(
std::min(video_frame.visible_rect().width(), image_->width), std::min(video_frame.visible_rect().width(), size_.width()),
std::min(video_frame.visible_rect().height(), image_->height)); std::min(video_frame.visible_rect().height(), size_.height()));
if (damage_size.width() < image_->width || if (damage_size.IsEmpty())
damage_size.height() < image_->height) return;
memset(image_->data, 0x00, image_->bytes_per_line * image_->height);
if (!damage_size.IsEmpty()) {
libyuv::I420ToARGB(video_frame.visible_data(VideoFrame::kYPlane),
video_frame.stride(VideoFrame::kYPlane),
video_frame.visible_data(VideoFrame::kUPlane),
video_frame.stride(VideoFrame::kUPlane),
video_frame.visible_data(VideoFrame::kVPlane),
video_frame.stride(VideoFrame::kVPlane),
reinterpret_cast<uint8_t*>(image_->data),
image_->bytes_per_line, damage_size.width(),
damage_size.height());
}
// Place image in window. PaintCanvasVideoRenderer renderer;
XShmPutImage(display_, window_, gc_, image_, 0, 0, 0, 0, image_->width, cc::SkiaPaintCanvas canvas(presenter_->GetSkCanvas());
image_->height, true); renderer.Copy(const_cast<media::VideoFrame*>(&video_frame), &canvas, nullptr);
presenter_->EndPaint(gfx::Rect(damage_size));
// Very important for the image to update properly! // Very important for the image to update properly!
XSync(display_, false); connection_.Flush();
} }
} // namespace test } // namespace test
......
...@@ -12,8 +12,13 @@ ...@@ -12,8 +12,13 @@
#include <string> #include <string>
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
namespace ui {
class X11SoftwareBitmapPresenter;
}
namespace media { namespace media {
class VideoFrame; class VideoFrame;
} }
...@@ -39,11 +44,10 @@ class LinuxOutputWindow { ...@@ -39,11 +44,10 @@ class LinuxOutputWindow {
int width, int width,
int height, int height,
const std::string& name); const std::string& name);
Display* display_; x11::Connection connection_;
Window window_; x11::Window window_{};
XShmSegmentInfo shminfo_; gfx::Size size_;
GC gc_; std::unique_ptr<ui::X11SoftwareBitmapPresenter> presenter_;
XImage* image_;
}; };
} // namespace test } // namespace test
......
...@@ -13,12 +13,14 @@ ...@@ -13,12 +13,14 @@
#include "remoting/host/linux/x_server_clipboard.h" #include "remoting/host/linux/x_server_clipboard.h"
#include "remoting/proto/event.pb.h" #include "remoting/proto/event.pb.h"
#include "remoting/protocol/clipboard_stub.h" #include "remoting/protocol/clipboard_stub.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/xproto_types.h"
namespace remoting { namespace remoting {
// This code is expected to be called on the desktop thread only. // This code is expected to be called on the desktop thread only.
class ClipboardX11 : public Clipboard { class ClipboardX11 : public Clipboard, public x11::Connection::Delegate {
public: public:
ClipboardX11(); ClipboardX11();
~ClipboardX11() override; ~ClipboardX11() override;
...@@ -33,6 +35,10 @@ class ClipboardX11 : public Clipboard { ...@@ -33,6 +35,10 @@ class ClipboardX11 : public Clipboard {
const std::string& data); const std::string& data);
void PumpXEvents(); void PumpXEvents();
// x11::Connection::Delegate:
bool ShouldContinueStream() const override;
void DispatchXEvent(x11::Event* event) override;
std::unique_ptr<protocol::ClipboardStub> client_clipboard_; std::unique_ptr<protocol::ClipboardStub> client_clipboard_;
// Underlying X11 clipboard implementation. // Underlying X11 clipboard implementation.
...@@ -40,7 +46,7 @@ class ClipboardX11 : public Clipboard { ...@@ -40,7 +46,7 @@ class ClipboardX11 : public Clipboard {
// Connection to the X server, used by |x_server_clipboard_|. This is created // Connection to the X server, used by |x_server_clipboard_|. This is created
// and owned by this class. // and owned by this class.
Display* display_; std::unique_ptr<x11::Connection> connection_;
// Watcher used to handle X11 events from |display_|. // Watcher used to handle X11 events from |display_|.
std::unique_ptr<base::FileDescriptorWatcher::Controller> std::unique_ptr<base::FileDescriptorWatcher::Controller>
...@@ -49,39 +55,34 @@ class ClipboardX11 : public Clipboard { ...@@ -49,39 +55,34 @@ class ClipboardX11 : public Clipboard {
DISALLOW_COPY_AND_ASSIGN(ClipboardX11); DISALLOW_COPY_AND_ASSIGN(ClipboardX11);
}; };
ClipboardX11::ClipboardX11() ClipboardX11::ClipboardX11() = default;
: display_(nullptr) {
}
ClipboardX11::~ClipboardX11() { ClipboardX11::~ClipboardX11() {
x_connection_watch_controller_ = nullptr; x_connection_watch_controller_ = nullptr;
if (display_)
XCloseDisplay(display_);
} }
void ClipboardX11::Start( void ClipboardX11::Start(
std::unique_ptr<protocol::ClipboardStub> client_clipboard) { std::unique_ptr<protocol::ClipboardStub> client_clipboard) {
// TODO(lambroslambrou): Share the X connection with InputInjector. // TODO(lambroslambrou): Share the X connection with InputInjector.
DCHECK(!display_); DCHECK(!connection_);
display_ = XOpenDisplay(nullptr); connection_ = std::make_unique<x11::Connection>();
if (!display_) { if (!connection_->Ready()) {
LOG(ERROR) << "Couldn't open X display"; LOG(ERROR) << "Couldn't open X display";
return; return;
} }
client_clipboard_.swap(client_clipboard); client_clipboard_.swap(client_clipboard);
x_server_clipboard_.Init( x_server_clipboard_.Init(
display_, base::BindRepeating(&ClipboardX11::OnClipboardChanged, connection_.get(), base::BindRepeating(&ClipboardX11::OnClipboardChanged,
base::Unretained(this))); base::Unretained(this)));
x_connection_watch_controller_ = base::FileDescriptorWatcher::WatchReadable( x_connection_watch_controller_ = base::FileDescriptorWatcher::WatchReadable(
ConnectionNumber(display_), ConnectionNumber(connection_->display()),
base::BindRepeating(&ClipboardX11::PumpXEvents, base::Unretained(this))); base::BindRepeating(&ClipboardX11::PumpXEvents, base::Unretained(this)));
PumpXEvents(); PumpXEvents();
} }
void ClipboardX11::InjectClipboardEvent( void ClipboardX11::InjectClipboardEvent(const protocol::ClipboardEvent& event) {
const protocol::ClipboardEvent& event) {
x_server_clipboard_.SetClipboard(event.mime_type(), event.data()); x_server_clipboard_.SetClipboard(event.mime_type(), event.data());
} }
...@@ -97,13 +98,17 @@ void ClipboardX11::OnClipboardChanged(const std::string& mime_type, ...@@ -97,13 +98,17 @@ void ClipboardX11::OnClipboardChanged(const std::string& mime_type,
} }
void ClipboardX11::PumpXEvents() { void ClipboardX11::PumpXEvents() {
DCHECK(display_); DCHECK(connection_->Ready());
while (XPending(display_)) { connection_->Dispatch(this);
XEvent event; }
XNextEvent(display_, &event);
x_server_clipboard_.ProcessXEvent(&event); bool ClipboardX11::ShouldContinueStream() const {
} return true;
}
void ClipboardX11::DispatchXEvent(x11::Event* event) {
x_server_clipboard_.ProcessXEvent(*event);
} }
std::unique_ptr<Clipboard> Clipboard::Create() { std::unique_ptr<Clipboard> Clipboard::Create() {
......
This diff is collapsed.
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/xfixes.h"
#include "ui/gfx/x/xproto.h"
namespace remoting { namespace remoting {
...@@ -35,26 +37,27 @@ class XServerClipboard { ...@@ -35,26 +37,27 @@ class XServerClipboard {
XServerClipboard(); XServerClipboard();
~XServerClipboard(); ~XServerClipboard();
// Start monitoring |display|'s selections, and invoke |callback| whenever // Start monitoring |connection|'s selections, and invoke |callback| whenever
// their content changes. The caller must ensure |display| is still valid // their content changes. The caller must ensure |connection| is still valid
// whenever any other methods are called on this object. // whenever any other methods are called on this object.
void Init(Display* display, const ClipboardChangedCallback& callback); void Init(x11::Connection* connection,
const ClipboardChangedCallback& callback);
// Copy data to the X Clipboard. This acquires ownership of the // Copy data to the X Clipboard. This acquires ownership of the
// PRIMARY and CLIPBOARD selections. // PRIMARY and CLIPBOARD selections.
void SetClipboard(const std::string& mime_type, const std::string& data); void SetClipboard(const std::string& mime_type, const std::string& data);
// Process |event| if it is an X selection notification. The caller should // Process |event| if it is an X selection notification. The caller should
// invoke this for every event it receives from |display|. // invoke this for every event it receives from |connection|.
void ProcessXEvent(XEvent* event); void ProcessXEvent(const x11::Event& event);
private: private:
// Handlers called by ProcessXEvent() for each event type. // Handlers called by ProcessXEvent() for each event type.
void OnSetSelectionOwnerNotify(Atom selection, Time timestamp); void OnSetSelectionOwnerNotify(Atom selection, Time timestamp);
void OnPropertyNotify(XEvent* event); void OnPropertyNotify(const x11::PropertyNotifyEvent& event);
void OnSelectionNotify(XEvent* event); void OnSelectionNotify(const x11::SelectionNotifyEvent& event);
void OnSelectionRequest(XEvent* event); void OnSelectionRequest(const x11::SelectionRequestEvent& event);
void OnSelectionClear(XEvent* event); void OnSelectionClear(const x11::SelectionClearEvent& event);
// Used by OnSelectionRequest() to respond to requests for details of our // Used by OnSelectionRequest() to respond to requests for details of our
// clipboard content. This is done by changing the property |property| of the // clipboard content. This is done by changing the property |property| of the
...@@ -69,7 +72,7 @@ class XServerClipboard { ...@@ -69,7 +72,7 @@ class XServerClipboard {
// |event| is the raw X event from the notification. // |event| is the raw X event from the notification.
// |type|, |format| etc are the results from XGetWindowProperty(), or 0 if // |type|, |format| etc are the results from XGetWindowProperty(), or 0 if
// there is no associated data. // there is no associated data.
void HandleSelectionNotify(XSelectionEvent* event, void HandleSelectionNotify(const x11::SelectionNotifyEvent& event,
Atom type, Atom type,
int format, int format,
int item_count, int item_count,
...@@ -78,11 +81,11 @@ class XServerClipboard { ...@@ -78,11 +81,11 @@ class XServerClipboard {
// These methods return true if selection processing is complete, false // These methods return true if selection processing is complete, false
// otherwise. They are called from HandleSelectionNotify(), and take the same // otherwise. They are called from HandleSelectionNotify(), and take the same
// arguments. // arguments.
bool HandleSelectionTargetsEvent(XSelectionEvent* event, bool HandleSelectionTargetsEvent(const x11::SelectionNotifyEvent& event,
int format, int format,
int item_count, int item_count,
void* data); void* data);
bool HandleSelectionStringEvent(XSelectionEvent* event, bool HandleSelectionStringEvent(const x11::SelectionNotifyEvent& event,
int format, int format,
int item_count, int item_count,
void* data); void* data);
...@@ -99,18 +102,13 @@ class XServerClipboard { ...@@ -99,18 +102,13 @@ class XServerClipboard {
void AssertSelectionOwnership(Atom selection); void AssertSelectionOwnership(Atom selection);
bool IsSelectionOwner(Atom selection); bool IsSelectionOwner(Atom selection);
// Stores the Display* supplied to Init(). // Stores the connection supplied to Init().
Display* display_; x11::Connection* connection_ = nullptr;
// Window through which clipboard events are received, or BadValue if the // Window through which clipboard events are received, or BadValue if the
// window could not be created. // window could not be created.
Window clipboard_window_; Window clipboard_window_;
// The event base returned by XFixesQueryExtension(). If XFixes is
// unavailable, the clipboard window will not be created, and no
// event-processing will take place.
int xfixes_event_base_;
// Cached atoms for various strings, initialized during Init(). // Cached atoms for various strings, initialized during Init().
Atom clipboard_atom_; Atom clipboard_atom_;
Atom large_selection_atom_; Atom large_selection_atom_;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <memory>
#include <string> #include <string>
#include "base/bind.h" #include "base/bind.h"
...@@ -9,21 +10,22 @@ ...@@ -9,21 +10,22 @@
#include "remoting/base/constants.h" #include "remoting/base/constants.h"
#include "remoting/host/linux/x_server_clipboard.h" #include "remoting/host/linux/x_server_clipboard.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
namespace remoting { namespace remoting {
namespace { namespace {
class ClipboardTestClient { class ClipboardTestClient : public x11::Connection::Delegate {
public: public:
ClipboardTestClient() : display_(nullptr) {} ClipboardTestClient() = default;
~ClipboardTestClient() = default; ~ClipboardTestClient() override = default;
void Init(Display* display) { void Init(x11::Connection* connection) {
display_ = display; connection_ = connection;
clipboard_.Init( clipboard_.Init(connection, base::BindRepeating(
display, base::BindRepeating(&ClipboardTestClient::OnClipboardChanged, &ClipboardTestClient::OnClipboardChanged,
base::Unretained(this))); base::Unretained(this)));
} }
...@@ -40,23 +42,27 @@ class ClipboardTestClient { ...@@ -40,23 +42,27 @@ class ClipboardTestClient {
// Process X events on the connection, returning true if any events were // Process X events on the connection, returning true if any events were
// processed. // processed.
bool PumpXEvents() { bool PumpXEvents() {
bool result = false; dispatched_event_ = false;
while (XPending(display_)) { connection_->Sync();
XEvent event; connection_->Dispatch(this);
XNextEvent(display_, &event); return dispatched_event_;
clipboard_.ProcessXEvent(&event);
result = true;
} }
return result;
bool ShouldContinueStream() const override { return true; }
void DispatchXEvent(x11::Event* event) override {
dispatched_event_ = true;
clipboard_.ProcessXEvent(*event);
} }
const std::string& clipboard_data() const { return clipboard_data_; } const std::string& clipboard_data() const { return clipboard_data_; }
Display* display() const { return display_; } x11::Connection* connection() const { return connection_; }
private: private:
std::string clipboard_data_; std::string clipboard_data_;
XServerClipboard clipboard_; XServerClipboard clipboard_;
Display* display_; x11::Connection* connection_ = nullptr;
bool dispatched_event_ = false;
DISALLOW_COPY_AND_ASSIGN(ClipboardTestClient); DISALLOW_COPY_AND_ASSIGN(ClipboardTestClient);
}; };
...@@ -66,29 +72,30 @@ class ClipboardTestClient { ...@@ -66,29 +72,30 @@ class ClipboardTestClient {
class XServerClipboardTest : public testing::Test { class XServerClipboardTest : public testing::Test {
public: public:
void SetUp() override { void SetUp() override {
// XSynchronize() ensures that PumpXEvents() fully processes all X server // SynchronizeForTest() ensures that PumpXEvents() fully processes all X
// requests and responses before returning to the caller. // server requests and responses before returning to the caller.
Display* display1 = XOpenDisplay(nullptr); connection1_ = std::make_unique<x11::Connection>();
XSynchronize(display1, x11::True); connection1_->SynchronizeForTest(true);
client1_.Init(display1); client1_.Init(connection1_.get());
Display* display2 = XOpenDisplay(nullptr); connection2_ = std::make_unique<x11::Connection>();
XSynchronize(display2, x11::True); connection2_->SynchronizeForTest(true);
client2_.Init(display2); client2_.Init(connection2_.get());
} }
void TearDown() override { void TearDown() override {
XCloseDisplay(client1_.display()); connection1_.reset();
XCloseDisplay(client2_.display()); connection2_.reset();
} }
void PumpXEvents() { void PumpXEvents() {
while (true) { while (true) {
if (!client1_.PumpXEvents() && !client2_.PumpXEvents()) { if (!client1_.PumpXEvents() && !client2_.PumpXEvents())
break; break;
} }
} }
}
std::unique_ptr<x11::Connection> connection1_;
std::unique_ptr<x11::Connection> connection2_;
ClipboardTestClient client1_; ClipboardTestClient client1_;
ClipboardTestClient client2_; ClipboardTestClient client2_;
}; };
......
...@@ -117,17 +117,21 @@ XShmImagePool::XShmImagePool(x11::Connection* connection, ...@@ -117,17 +117,21 @@ XShmImagePool::XShmImagePool(x11::Connection* connection,
x11::Drawable drawable, x11::Drawable drawable,
x11::VisualId visual, x11::VisualId visual,
int depth, int depth,
std::size_t frames_pending) std::size_t frames_pending,
bool enable_multibuffering)
: connection_(connection), : connection_(connection),
drawable_(drawable), drawable_(drawable),
visual_(visual), visual_(visual),
depth_(depth), depth_(depth),
enable_multibuffering_(enable_multibuffering),
frame_states_(frames_pending) { frame_states_(frames_pending) {
if (enable_multibuffering_)
X11EventSource::GetInstance()->AddXEventDispatcher(this); X11EventSource::GetInstance()->AddXEventDispatcher(this);
} }
XShmImagePool::~XShmImagePool() { XShmImagePool::~XShmImagePool() {
Cleanup(); Cleanup();
if (enable_multibuffering_)
X11EventSource::GetInstance()->RemoveXEventDispatcher(this); X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
} }
...@@ -254,6 +258,7 @@ x11::Shm::Seg XShmImagePool::CurrentSegment() { ...@@ -254,6 +258,7 @@ x11::Shm::Seg XShmImagePool::CurrentSegment() {
void XShmImagePool::SwapBuffers( void XShmImagePool::SwapBuffers(
base::OnceCallback<void(const gfx::Size&)> callback) { base::OnceCallback<void(const gfx::Size&)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(enable_multibuffering_);
swap_closures_.emplace_back(); swap_closures_.emplace_back();
SwapClosure& swap_closure = swap_closures_.back(); SwapClosure& swap_closure = swap_closures_.back();
...@@ -267,6 +272,7 @@ void XShmImagePool::DispatchShmCompletionEvent( ...@@ -267,6 +272,7 @@ void XShmImagePool::DispatchShmCompletionEvent(
x11::Shm::CompletionEvent event) { x11::Shm::CompletionEvent event) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(event.offset, 0UL); DCHECK_EQ(event.offset, 0UL);
DCHECK(enable_multibuffering_);
for (auto it = swap_closures_.begin(); it != swap_closures_.end(); ++it) { for (auto it = swap_closures_.begin(); it != swap_closures_.end(); ++it) {
if (event.shmseg == it->shmseg) { if (event.shmseg == it->shmseg) {
...@@ -279,6 +285,7 @@ void XShmImagePool::DispatchShmCompletionEvent( ...@@ -279,6 +285,7 @@ void XShmImagePool::DispatchShmCompletionEvent(
bool XShmImagePool::DispatchXEvent(x11::Event* xev) { bool XShmImagePool::DispatchXEvent(x11::Event* xev) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(enable_multibuffering_);
auto* completion = xev->As<x11::Shm::CompletionEvent>(); auto* completion = xev->As<x11::Shm::CompletionEvent>();
if (!completion || completion->drawable.value != drawable_.value) if (!completion || completion->drawable.value != drawable_.value)
......
...@@ -33,7 +33,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher { ...@@ -33,7 +33,8 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher {
x11::Drawable drawable, x11::Drawable drawable,
x11::VisualId visual, x11::VisualId visual,
int depth, int depth,
std::size_t max_frames_pending); std::size_t max_frames_pending,
bool enable_multibuffering);
~XShmImagePool() override; ~XShmImagePool() override;
...@@ -86,6 +87,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher { ...@@ -86,6 +87,7 @@ class COMPONENT_EXPORT(UI_BASE_X) XShmImagePool : public XEventDispatcher {
const x11::Drawable drawable_; const x11::Drawable drawable_;
const x11::VisualId visual_; const x11::VisualId visual_;
const int depth_; const int depth_;
const bool enable_multibuffering_;
bool ready_ = false; bool ready_ = false;
gfx::Size pixel_size_; gfx::Size pixel_size_;
......
...@@ -117,9 +117,12 @@ bool X11SoftwareBitmapPresenter::CompositeBitmap(x11::Connection* connection, ...@@ -117,9 +117,12 @@ bool X11SoftwareBitmapPresenter::CompositeBitmap(x11::Connection* connection,
} }
X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter( X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter(
gfx::AcceleratedWidget widget) x11::Connection* connection,
gfx::AcceleratedWidget widget,
bool enable_multibuffering)
: widget_(static_cast<x11::Window>(widget)), : widget_(static_cast<x11::Window>(widget)),
connection_(x11::Connection::Get()) { connection_(connection),
enable_multibuffering_(enable_multibuffering) {
DCHECK_NE(widget_, x11::Window::None); DCHECK_NE(widget_, x11::Window::None);
gc_ = connection_->GenerateId<x11::GraphicsContext>(); gc_ = connection_->GenerateId<x11::GraphicsContext>();
...@@ -135,7 +138,8 @@ X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter( ...@@ -135,7 +138,8 @@ X11SoftwareBitmapPresenter::X11SoftwareBitmapPresenter(
} }
shm_pool_ = std::make_unique<ui::XShmImagePool>(connection_, widget_, visual_, shm_pool_ = std::make_unique<ui::XShmImagePool>(connection_, widget_, visual_,
depth_, kMaxFramesPending); depth_, MaxFramesPending(),
enable_multibuffering_);
// TODO(thomasanderson): Avoid going through the X11 server to plumb this // TODO(thomasanderson): Avoid going through the X11 server to plumb this
// property in. // property in.
...@@ -209,7 +213,7 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) { ...@@ -209,7 +213,7 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) {
.dst_y = rect.y(), .dst_y = rect.y(),
.depth = depth_, .depth = depth_,
.format = x11::ImageFormat::ZPixmap, .format = x11::ImageFormat::ZPixmap,
.send_event = true, .send_event = enable_multibuffering_,
.shmseg = shm_pool_->CurrentSegment(), .shmseg = shm_pool_->CurrentSegment(),
.offset = 0, .offset = 0,
}); });
...@@ -239,7 +243,7 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) { ...@@ -239,7 +243,7 @@ void X11SoftwareBitmapPresenter::EndPaint(const gfx::Rect& damage_rect) {
void X11SoftwareBitmapPresenter::OnSwapBuffers( void X11SoftwareBitmapPresenter::OnSwapBuffers(
SwapBuffersCallback swap_ack_callback) { SwapBuffersCallback swap_ack_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (ShmPoolReady() && needs_swap_) if (enable_multibuffering_ && ShmPoolReady() && needs_swap_)
shm_pool_->SwapBuffers(std::move(swap_ack_callback)); shm_pool_->SwapBuffers(std::move(swap_ack_callback));
else else
std::move(swap_ack_callback).Run(viewport_pixel_size_); std::move(swap_ack_callback).Run(viewport_pixel_size_);
...@@ -247,7 +251,8 @@ void X11SoftwareBitmapPresenter::OnSwapBuffers( ...@@ -247,7 +251,8 @@ void X11SoftwareBitmapPresenter::OnSwapBuffers(
} }
int X11SoftwareBitmapPresenter::MaxFramesPending() const { int X11SoftwareBitmapPresenter::MaxFramesPending() const {
return kMaxFramesPending; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return enable_multibuffering_ ? kMaxFramesPending : 1;
} }
} // namespace ui } // namespace ui
...@@ -30,7 +30,9 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter { ...@@ -30,7 +30,9 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter {
// Corresponds to SwapBuffersCallback alias in SoftwareOutputDevice. // Corresponds to SwapBuffersCallback alias in SoftwareOutputDevice.
using SwapBuffersCallback = base::OnceCallback<void(const gfx::Size&)>; using SwapBuffersCallback = base::OnceCallback<void(const gfx::Size&)>;
explicit X11SoftwareBitmapPresenter(gfx::AcceleratedWidget widget); X11SoftwareBitmapPresenter(x11::Connection* connection,
gfx::AcceleratedWidget widget,
bool enable_multibuffering);
~X11SoftwareBitmapPresenter(); ~X11SoftwareBitmapPresenter();
...@@ -61,6 +63,8 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter { ...@@ -61,6 +63,8 @@ class COMPONENT_EXPORT(UI_BASE_X) X11SoftwareBitmapPresenter {
x11::VisualId visual_{}; x11::VisualId visual_{};
int depth_ = 0; int depth_ = 0;
const bool enable_multibuffering_;
// If nonzero, indicates that the widget should be drawn over its // If nonzero, indicates that the widget should be drawn over its
// parent-relative background. // parent-relative background.
int composite_ = 0; int composite_ = 0;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <algorithm> #include <algorithm>
#include "base/auto_reset.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/i18n/case_conversion.h" #include "base/i18n/case_conversion.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
...@@ -326,7 +327,20 @@ void Connection::Flush() { ...@@ -326,7 +327,20 @@ void Connection::Flush() {
void Connection::Sync() { void Connection::Sync() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (syncing_)
return;
{
base::AutoReset<bool>(&syncing_, true);
GetInputFocus({}).Sync(); GetInputFocus({}).Sync();
}
}
void Connection::SynchronizeForTest(bool synchronous) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
XSynchronize(display(), synchronous);
synchronous_ = synchronous;
if (synchronous_)
Sync();
} }
void Connection::ReadResponses() { void Connection::ReadResponses() {
...@@ -337,6 +351,21 @@ void Connection::ReadResponses() { ...@@ -337,6 +351,21 @@ void Connection::ReadResponses() {
} }
} }
Event Connection::WaitForNextEvent() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!events_.empty()) {
Event event = std::move(events_.front());
events_.pop_front();
return event;
}
auto* xcb_event = xcb_wait_for_event(XcbConnection());
if (xcb_event) {
return Event(base::MakeRefCounted<MallocedRefCountedMemory>(xcb_event),
this);
}
return Event();
}
bool Connection::HasPendingResponses() const { bool Connection::HasPendingResponses() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return !events_.empty() || HasNextResponse(); return !events_.empty() || HasNextResponse();
......
...@@ -96,9 +96,16 @@ class COMPONENT_EXPORT(X11) Connection : public XProto, ...@@ -96,9 +96,16 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
// Flush and block until the server has responded to all requests. // Flush and block until the server has responded to all requests.
void Sync(); void Sync();
// If |synchronous| is true, this makes all requests Sync().
void SynchronizeForTest(bool synchronous);
bool synchronous() const { return synchronous_; }
// Read all responses from the socket without blocking. // Read all responses from the socket without blocking.
void ReadResponses(); void ReadResponses();
Event WaitForNextEvent();
// Are there any events, errors, or replies already buffered? // Are there any events, errors, or replies already buffered?
bool HasPendingResponses() const; bool HasPendingResponses() const;
...@@ -158,6 +165,9 @@ class COMPONENT_EXPORT(X11) Connection : public XProto, ...@@ -158,6 +165,9 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
XDisplay* const display_; XDisplay* const display_;
bool synchronous_ = false;
bool syncing_ = false;
uint32_t extended_max_request_length_ = 0; uint32_t extended_max_request_length_ = 0;
Setup setup_; Setup setup_;
......
...@@ -23,10 +23,6 @@ extern "C" { ...@@ -23,10 +23,6 @@ extern "C" {
#include <X11/Xregion.h> #include <X11/Xregion.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/cursorfont.h> #include <X11/cursorfont.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/sync.h>
// Define XK_xxx before the #include of <X11/keysym.h> so that <X11/keysym.h> // Define XK_xxx before the #include of <X11/keysym.h> so that <X11/keysym.h>
// defines all KeySyms we need. // defines all KeySyms we need.
......
...@@ -152,6 +152,8 @@ base::Optional<unsigned int> SendRequestImpl(x11::Connection* connection, ...@@ -152,6 +152,8 @@ base::Optional<unsigned int> SendRequestImpl(x11::Connection* connection,
} }
if (xcb_connection_has_error(conn)) if (xcb_connection_has_error(conn))
return base::nullopt; return base::nullopt;
if (connection->synchronous())
connection->Sync();
return sequence; return sequence;
} }
......
...@@ -4,13 +4,12 @@ ...@@ -4,13 +4,12 @@
#include "ui/gl/gl_image_glx_native_pixmap.h" #include "ui/gl/gl_image_glx_native_pixmap.h"
#include <xcb/dri3.h>
#include <xcb/xcb.h>
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "ui/gfx/buffer_types.h" #include "ui/gfx/buffer_types.h"
#include "ui/gfx/linux/native_pixmap_dmabuf.h" #include "ui/gfx/linux/native_pixmap_dmabuf.h"
#include "ui/gfx/x/dri3.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/xproto_types.h"
#include "ui/gl/buffer_format_utils.h" #include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
...@@ -52,20 +51,20 @@ int Bpp(gfx::BufferFormat format) { ...@@ -52,20 +51,20 @@ int Bpp(gfx::BufferFormat format) {
XID XPixmapFromNativePixmap(const gfx::NativePixmapDmaBuf& native_pixmap, XID XPixmapFromNativePixmap(const gfx::NativePixmapDmaBuf& native_pixmap,
int depth, int depth,
int bpp) { int bpp) {
XDisplay* display = gfx::GetXDisplay(); auto fd = HANDLE_EINTR(dup(native_pixmap.GetDmaBufFd(0)));
xcb_connection_t* connection = XGetXCBConnection(display);
int fd = HANDLE_EINTR(dup(native_pixmap.GetDmaBufFd(0)));
if (fd < 0) if (fd < 0)
return 0; return 0;
base::ScopedFD scoped_fd(fd);
uint32_t pixmap_id = xcb_generate_id(connection); auto* connection = x11::Connection::Get();
xcb_dri3_pixmap_from_buffer(connection, pixmap_id, DefaultRootWindow(display), x11::Pixmap pixmap_id = connection->GenerateId<x11::Pixmap>();
connection->dri3().PixmapFromBuffer({pixmap_id, connection->default_root(),
native_pixmap.GetDmaBufPlaneSize(0), native_pixmap.GetDmaBufPlaneSize(0),
native_pixmap.GetBufferSize().width(), native_pixmap.GetBufferSize().width(),
native_pixmap.GetBufferSize().height(), native_pixmap.GetBufferSize().height(),
native_pixmap.GetDmaBufPitch(0), depth, bpp, fd); native_pixmap.GetDmaBufPitch(0), depth,
return pixmap_id; bpp, std::move(scoped_fd)});
return static_cast<uint32_t>(pixmap_id);
} }
} // namespace } // namespace
......
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/gfx/vsync_provider.h" #include "ui/gfx/vsync_provider.h"
#include "ui/gfx/x/connection.h"
namespace ui { namespace ui {
X11CanvasSurface::X11CanvasSurface(gfx::AcceleratedWidget widget) X11CanvasSurface::X11CanvasSurface(gfx::AcceleratedWidget widget)
: x11_software_bitmap_presenter_(widget) {} : x11_software_bitmap_presenter_(x11::Connection::Get(), widget, true) {}
X11CanvasSurface::~X11CanvasSurface() = default; X11CanvasSurface::~X11CanvasSurface() = default;
......
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