Commit 2f6607f2 authored by Tom Anderson's avatar Tom Anderson Committed by Chromium LUCI CQ

Reland "[X11] Split PutImage requests into multiple requests if necessary"

This is a reland of 3fe154df

Original change's description:
> [X11] Split PutImage requests into multiple requests if necessary
>
> R=sky
>
> Change-Id: I1befaef494c74797333d6bf02e204bcdc721e752
> Bug: 1164669
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2643711
> Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
> Commit-Queue: Scott Violet <sky@chromium.org>
> Reviewed-by: Scott Violet <sky@chromium.org>
> Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#846344}

Bug: 1164669
Change-Id: I932bbeb1dd8be92067ab69ebf22ac19d95daa3e4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2644750Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846430}
parent 27a70557
...@@ -39,16 +39,11 @@ const int kIncrementalTransferTimeoutMs = 10000; ...@@ -39,16 +39,11 @@ const int kIncrementalTransferTimeoutMs = 10000;
static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs, static_assert(KSelectionOwnerTimerPeriodMs <= kIncrementalTransferTimeoutMs,
"timer period must be <= transfer timeout"); "timer period must be <= transfer timeout");
// Returns a conservative max size of the data we can pass into size_t GetMaxIncrementalTransferSize() {
// XChangeProperty(). Copied from GTK. ssize_t size = x11::Connection::Get()->MaxRequestSizeInBytes();
size_t GetMaxRequestSize(x11::Connection* connection) { // Conservatively subtract 100 bytes for the GetProperty request, padding etc.
long extended_max_size = connection->extended_max_request_length(); DCHECK_GT(size, 100);
long max_size = return std::min<size_t>(size - 100, 0x100000);
(extended_max_size ? extended_max_size
: connection->setup().maximum_request_length) -
100;
return std::min(static_cast<long>(0x40000),
std::max(static_cast<long>(0), max_size));
} }
// Gets the value of an atom pair array property. On success, true is returned // Gets the value of an atom pair array property. On success, true is returned
...@@ -85,9 +80,7 @@ void SetSelectionOwner(x11::Window window, ...@@ -85,9 +80,7 @@ void SetSelectionOwner(x11::Window window,
SelectionOwner::SelectionOwner(x11::Connection* connection, SelectionOwner::SelectionOwner(x11::Connection* connection,
x11::Window x_window, x11::Window x_window,
x11::Atom selection_name) x11::Atom selection_name)
: x_window_(x_window), : x_window_(x_window), selection_name_(selection_name) {}
selection_name_(selection_name),
max_request_size_(GetMaxRequestSize(connection)) {}
SelectionOwner::~SelectionOwner() { SelectionOwner::~SelectionOwner() {
// If we are the selection owner, we need to release the selection so we // If we are the selection owner, we need to release the selection so we
...@@ -217,7 +210,7 @@ bool SelectionOwner::ProcessTarget(x11::Atom target, ...@@ -217,7 +210,7 @@ bool SelectionOwner::ProcessTarget(x11::Atom target,
// Try to find the data type in map. // Try to find the data type in map.
auto it = format_map_.find(target); auto it = format_map_.find(target);
if (it != format_map_.end()) { if (it != format_map_.end()) {
if (it->second->size() > max_request_size_) { if (it->second->size() > GetMaxIncrementalTransferSize()) {
// We must send the data back in several chunks due to a limitation in // We must send the data back in several chunks due to a limitation in
// the size of X requests. Notify the selection requestor that the data // the size of X requests. Notify the selection requestor that the data
// will be sent incrementally by returning data of type "INCR". // will be sent incrementally by returning data of type "INCR".
...@@ -260,7 +253,7 @@ bool SelectionOwner::ProcessTarget(x11::Atom target, ...@@ -260,7 +253,7 @@ bool SelectionOwner::ProcessTarget(x11::Atom target,
void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) { void SelectionOwner::ProcessIncrementalTransfer(IncrementalTransfer* transfer) {
size_t remaining = transfer->data->size() - transfer->offset; size_t remaining = transfer->data->size() - transfer->offset;
size_t chunk_length = std::min(remaining, max_request_size_); size_t chunk_length = std::min(remaining, GetMaxIncrementalTransferSize());
const uint8_t* data = transfer->data->front() + transfer->offset; const uint8_t* data = transfer->data->front() + transfer->offset;
std::vector<uint8_t> buf(data, data + chunk_length); std::vector<uint8_t> buf(data, data + chunk_length);
SetArrayProperty(transfer->window, transfer->property, transfer->target, buf); SetArrayProperty(transfer->window, transfer->property, transfer->target, buf);
......
...@@ -136,9 +136,6 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner { ...@@ -136,9 +136,6 @@ class COMPONENT_EXPORT(UI_BASE_X) SelectionOwner {
// The time that this instance took ownership of its selection. // The time that this instance took ownership of its selection.
x11::Time acquired_selection_timestamp_; x11::Time acquired_selection_timestamp_;
// The maximum size of data we can put in XChangeProperty().
size_t max_request_size_;
// The data we are currently serving. // The data we are currently serving.
SelectionFormatMap format_map_; SelectionFormatMap format_map_;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "base/location.h" #include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
...@@ -248,6 +249,10 @@ void DrawPixmap(x11::Connection* connection, ...@@ -248,6 +249,10 @@ void DrawPixmap(x11::Connection* connection,
int dst_y, int dst_y,
int width, int width,
int height) { int height) {
// 24 bytes for the PutImage header, an additional 4 bytes in case this is an
// extended size request, and an additional 4 bytes in case padding is needed.
constexpr size_t kPutImageExtraSize = 32;
const auto* visual_info = connection->GetVisualInfoFromId(visual); const auto* visual_info = connection->GetVisualInfoFromId(visual);
if (!visual_info) if (!visual_info)
return; return;
...@@ -271,19 +276,30 @@ void DrawPixmap(x11::Connection* connection, ...@@ -271,19 +276,30 @@ void DrawPixmap(x11::Connection* connection,
std::vector<uint8_t> vec(row_bytes * height); std::vector<uint8_t> vec(row_bytes * height);
SkPixmap pixmap(image_info, vec.data(), row_bytes); SkPixmap pixmap(image_info, vec.data(), row_bytes);
skia_pixmap.readPixels(pixmap, src_x, src_y); skia_pixmap.readPixels(pixmap, src_x, src_y);
x11::PutImageRequest put_image_request{
DCHECK_GT(connection->MaxRequestSizeInBytes(), kPutImageExtraSize);
int rows_per_request =
(connection->MaxRequestSizeInBytes() - kPutImageExtraSize) / row_bytes;
DCHECK_GT(rows_per_request, 1);
for (int row = 0; row < height; row += rows_per_request) {
size_t n_rows = std::min<size_t>(rows_per_request, height - row);
auto data = base::MakeRefCounted<base::RefCountedStaticMemory>(
vec.data() + row * row_bytes, n_rows * row_bytes);
connection->PutImage({
.format = x11::ImageFormat::ZPixmap, .format = x11::ImageFormat::ZPixmap,
.drawable = drawable, .drawable = drawable,
.gc = gc, .gc = gc,
.width = width, .width = width,
.height = height, .height = n_rows,
.dst_x = dst_x, .dst_x = dst_x,
.dst_y = dst_y, .dst_y = dst_y + row,
.left_pad = 0, .left_pad = 0,
.depth = visual_info->format->depth, .depth = visual_info->format->depth,
.data = base::RefCountedBytes::TakeVector(&vec), .data = data,
}; });
connection->PutImage(put_image_request); }
// Flush since the PutImage requests depend on |vec| being alive.
connection->Flush();
} }
bool IsXInput2Available() { bool IsXInput2Available() {
......
...@@ -184,6 +184,11 @@ Connection::~Connection() { ...@@ -184,6 +184,11 @@ Connection::~Connection() {
xcb_disconnect(connection_); xcb_disconnect(connection_);
} }
size_t Connection::MaxRequestSizeInBytes() const {
return 4 * std::max<size_t>(extended_max_request_length_,
setup_.maximum_request_length);
}
XlibDisplayWrapper Connection::GetXlibDisplay(XlibDisplayType type) { XlibDisplayWrapper Connection::GetXlibDisplay(XlibDisplayType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!xlib_display_) if (!xlib_display_)
......
...@@ -90,10 +90,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto, ...@@ -90,10 +90,7 @@ class COMPONENT_EXPORT(X11) Connection : public XProto,
XlibDisplayWrapper GetXlibDisplay( XlibDisplayWrapper GetXlibDisplay(
XlibDisplayType type = XlibDisplayType::kNormal); XlibDisplayType type = XlibDisplayType::kNormal);
uint32_t extended_max_request_length() const { size_t MaxRequestSizeInBytes() const;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return extended_max_request_length_;
}
const Setup& setup() const { const Setup& setup() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......
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