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