Commit 2f3d2af6 authored by Tom Anderson's avatar Tom Anderson Committed by Commit Bot

[XProto] Remove most Xlib usage from x11_display_util

BUG=1066670
R=msisov
CC=sky

Change-Id: I7072c4511358f992e373450c6100fe0b63b31551
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2210822Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarMaksim Sisov <msisov@igalia.com>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771113}
parent 008f5f08
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "ui/gfx/geometry/matrix3_f.h" #include "ui/gfx/geometry/matrix3_f.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector3d_f.h" #include "ui/gfx/geometry/vector3d_f.h"
#include "ui/gfx/x/randr.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_atom_cache.h"
...@@ -27,32 +28,15 @@ namespace { ...@@ -27,32 +28,15 @@ namespace {
constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3. constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3.
typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*); std::map<x11::RandR::Output, int> GetMonitors(int version,
typedef void (*XRRFreeMonitors)(XRRMonitorInfo*); x11::RandR* randr,
x11::Window window) {
NO_SANITIZE("cfi-icall") std::map<x11::RandR::Output, int> output_to_monitor;
std::map<RROutput, int> GetMonitors(int version,
XDisplay* xdisplay,
GLXWindow window) {
std::map<RROutput, int> output_to_monitor;
if (version >= 105) { if (version >= 105) {
void* xrandr_lib = dlopen(nullptr, RTLD_NOW); if (auto reply = randr->GetMonitors({window}).Sync()) {
if (xrandr_lib) { for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) {
static XRRGetMonitors XRRGetMonitors_ptr = for (x11::RandR::Output output : reply->monitors[monitor].outputs)
reinterpret_cast<XRRGetMonitors>(dlsym(xrandr_lib, "XRRGetMonitors")); output_to_monitor[output] = monitor;
static XRRFreeMonitors XRRFreeMonitors_ptr =
reinterpret_cast<XRRFreeMonitors>(
dlsym(xrandr_lib, "XRRFreeMonitors"));
if (XRRGetMonitors_ptr && XRRFreeMonitors_ptr) {
int nmonitors = 0;
XRRMonitorInfo* monitors =
XRRGetMonitors_ptr(xdisplay, window, false, &nmonitors);
for (int monitor = 0; monitor < nmonitors; monitor++) {
for (int j = 0; j < monitors[monitor].noutput; j++) {
output_to_monitor[monitors[monitor].outputs[j]] = monitor;
}
}
XRRFreeMonitors_ptr(monitors);
} }
} }
} }
...@@ -65,8 +49,7 @@ std::map<RROutput, int> GetMonitors(int version, ...@@ -65,8 +49,7 @@ std::map<RROutput, int> GetMonitors(int version,
void ClipWorkArea(std::vector<display::Display>* displays, void ClipWorkArea(std::vector<display::Display>* displays,
int64_t primary_display_index, int64_t primary_display_index,
float scale) { float scale) {
XDisplay* xdisplay = gfx::GetXDisplay(); GLXWindow x_root_window = ui::GetX11RootWindow();
GLXWindow x_root_window = DefaultRootWindow(xdisplay);
std::vector<int> value; std::vector<int> value;
if (!ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) || if (!ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) ||
...@@ -103,19 +86,18 @@ void ClipWorkArea(std::vector<display::Display>* displays, ...@@ -103,19 +86,18 @@ void ClipWorkArea(std::vector<display::Display>* displays,
primary.set_work_area(work_area); primary.set_work_area(work_area);
} }
float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes, float GetRefreshRateFromXRRModeInfo(
int num_of_mode, const std::vector<x11::RandR::ModeInfo>& modes,
RRMode current_mode_id) { x11::RandR::Mode current_mode_id) {
for (int i = 0; i < num_of_mode; i++) { for (const auto& mode_info : modes) {
XRRModeInfo mode_info = modes[i]; if (static_cast<x11::RandR::Mode>(mode_info.id) != current_mode_id)
if (mode_info.id != current_mode_id)
continue; continue;
if (!mode_info.hTotal || !mode_info.vTotal) if (!mode_info.htotal || !mode_info.vtotal)
return 0; return 0;
// Refresh Rate = Pixel Clock / (Horizontal Total * Vertical Total) // Refresh Rate = Pixel Clock / (Horizontal Total * Vertical Total)
return mode_info.dotClock / return mode_info.dot_clock /
static_cast<float>(mode_info.hTotal * mode_info.vTotal); static_cast<float>(mode_info.htotal * mode_info.vtotal);
} }
return 0; return 0;
} }
...@@ -156,53 +138,19 @@ int DefaultBitsPerComponent(XDisplay* xdisplay) { ...@@ -156,53 +138,19 @@ int DefaultBitsPerComponent(XDisplay* xdisplay) {
return visual->bits_per_rgb; return visual->bits_per_rgb;
} }
bool IsRandRAvailable() {
int randr_version_major = 0;
int randr_version_minor = 0;
static bool is_randr_available = XRRQueryVersion(
gfx::GetXDisplay(), &randr_version_major, &randr_version_minor);
return is_randr_available;
}
// Get the EDID data from the |output| and stores to |edid|. // Get the EDID data from the |output| and stores to |edid|.
void GetEDIDProperty(XID output, std::vector<uint8_t>* edid) { std::vector<uint8_t> GetEDIDProperty(x11::RandR* randr,
if (!IsRandRAvailable()) x11::RandR::Output output) {
return; auto future = randr->GetOutputProperty({
.output = output,
Display* display = gfx::GetXDisplay(); .property = gfx::GetAtom(RR_PROPERTY_RANDR_EDID),
.long_length = 128,
x11::Atom edid_property = gfx::GetAtom(RR_PROPERTY_RANDR_EDID); });
auto response = future.Sync();
bool has_edid_property = false; std::vector<uint8_t> edid;
int num_properties = 0; if (response && response->format == 8 && response->type != x11::Atom::None)
gfx::XScopedPtr<Atom[]> properties( edid = std::move(response->data);
XRRListOutputProperties(display, output, &num_properties)); return edid;
for (int i = 0; i < num_properties; ++i) {
if (static_cast<x11::Atom>(properties[i]) == edid_property) {
has_edid_property = true;
break;
}
}
if (!has_edid_property)
return;
Atom actual_type;
int actual_format;
unsigned long bytes_after;
unsigned long nitems = 0;
unsigned char* prop = nullptr;
XRRGetOutputProperty(display, output, static_cast<uint32_t>(edid_property),
0, // offset
128, // length
false, // _delete
false, // pending
AnyPropertyType, // req_type
&actual_type, &actual_format, &nitems, &bytes_after,
&prop);
DCHECK_EQ(XA_INTEGER, actual_type);
DCHECK_EQ(8, actual_format);
edid->assign(prop, prop + nitems);
XFree(prop);
} }
} // namespace } // namespace
...@@ -253,56 +201,59 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -253,56 +201,59 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
int64_t* primary_display_index_out) { int64_t* primary_display_index_out) {
DCHECK(primary_display_index_out); DCHECK(primary_display_index_out);
DCHECK_GE(version, kMinVersionXrandr); DCHECK_GE(version, kMinVersionXrandr);
XDisplay* xdisplay = gfx::GetXDisplay(); auto* randr = x11::Connection::Get()->randr();
GLXWindow x_root_window = DefaultRootWindow(xdisplay); if (!randr)
return GetFallbackDisplayList(scale);
auto x_root_window = static_cast<x11::Window>(ui::GetX11RootWindow());
std::vector<display::Display> displays; std::vector<display::Display> displays;
gfx::XScopedPtr< auto resources = randr->GetScreenResourcesCurrent({x_root_window}).Sync();
XRRScreenResources,
gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
resources(XRRGetScreenResourcesCurrent(xdisplay, x_root_window));
if (!resources) { if (!resources) {
LOG(ERROR) << "XRandR returned no displays; falling back to root window"; LOG(ERROR) << "XRandR returned no displays; falling back to root window";
return GetFallbackDisplayList(scale); return GetFallbackDisplayList(scale);
} }
const int depth = DefaultScreenDepth(xdisplay); const int depth = DefaultScreenDepth(gfx::GetXDisplay());
const int bits_per_component = DefaultBitsPerComponent(xdisplay); const int bits_per_component = DefaultBitsPerComponent(gfx::GetXDisplay());
std::map<RROutput, int> output_to_monitor = std::map<x11::RandR::Output, int> output_to_monitor =
GetMonitors(version, xdisplay, x_root_window); GetMonitors(version, randr, x_root_window);
*primary_display_index_out = 0; *primary_display_index_out = 0;
RROutput primary_display_id = XRRGetOutputPrimary(xdisplay, x_root_window); auto output_primary = randr->GetOutputPrimary({x_root_window}).Sync();
if (!output_primary)
return GetFallbackDisplayList(scale);
x11::RandR::Output primary_display_id = output_primary->output;
int explicit_primary_display_index = -1; int explicit_primary_display_index = -1;
int monitor_order_primary_display_index = -1; int monitor_order_primary_display_index = -1;
// As per-display scale factor is not supported right now, // As per-display scale factor is not supported right now,
// the X11 root window's scale factor is always used. // the X11 root window's scale factor is always used.
for (int i = 0; i < resources->noutput; ++i) { for (size_t i = 0; i < resources->outputs.size(); i++) {
RROutput output_id = resources->outputs[i]; x11::RandR::Output output_id = resources->outputs[i];
gfx::XScopedPtr<XRROutputInfo, auto output_info =
gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>> randr->GetOutputInfo({output_id, resources->config_timestamp}).Sync();
output_info(XRRGetOutputInfo(xdisplay, resources.get(), output_id));
// XRRGetOutputInfo returns null in some cases: https://crbug.com/921490
if (!output_info) if (!output_info)
continue; continue;
bool is_connected = (output_info->connection == RR_Connected); if (output_info->connection != x11::RandR::Connection::Connected)
if (!is_connected)
continue; continue;
bool is_primary_display = (output_id == primary_display_id); bool is_primary_display = (output_id == primary_display_id);
if (output_info->crtc) { if (output_info->crtc == static_cast<x11::RandR::Crtc>(0))
gfx::XScopedPtr<XRRCrtcInfo, continue;
gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
crtc(XRRGetCrtcInfo(xdisplay, resources.get(), output_info->crtc)); auto crtc =
randr->GetCrtcInfo({output_info->crtc, resources->config_timestamp})
.Sync();
if (!crtc)
continue;
std::vector<uint8_t> edid_bytes; display::EdidParser edid_parser(
GetEDIDProperty(output_id, &edid_bytes); GetEDIDProperty(randr, static_cast<x11::RandR::Output>(output_id)));
display::EdidParser edid_parser(edid_bytes); auto output_32 = static_cast<uint32_t>(output_id);
int64_t display_id = edid_parser.GetDisplayId(output_id); int64_t display_id =
output_32 > 0xff ? 0 : edid_parser.GetDisplayId(output_32);
// It isn't ideal, but if we can't parse the EDID data, fall back on the // It isn't ideal, but if we can't parse the EDID data, fall back on the
// display number. // display number.
if (!display_id) if (!display_id)
...@@ -318,24 +269,28 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -318,24 +269,28 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
} }
switch (crtc->rotation) { switch (crtc->rotation) {
case RR_Rotate_0: case x11::RandR::Rotation::Rotate_0:
display.set_rotation(display::Display::ROTATE_0); display.set_rotation(display::Display::ROTATE_0);
break; break;
case RR_Rotate_90: case x11::RandR::Rotation::Rotate_90:
display.set_rotation(display::Display::ROTATE_90); display.set_rotation(display::Display::ROTATE_90);
break; break;
case RR_Rotate_180: case x11::RandR::Rotation::Rotate_180:
display.set_rotation(display::Display::ROTATE_180); display.set_rotation(display::Display::ROTATE_180);
break; break;
case RR_Rotate_270: case x11::RandR::Rotation::Rotate_270:
display.set_rotation(display::Display::ROTATE_270); display.set_rotation(display::Display::ROTATE_270);
break; break;
case x11::RandR::Rotation::Reflect_X:
case x11::RandR::Rotation::Reflect_Y:
NOTIMPLEMENTED();
} }
if (is_primary_display) if (is_primary_display)
explicit_primary_display_index = displays.size(); explicit_primary_display_index = displays.size();
auto monitor_iter = output_to_monitor.find(output_id); auto monitor_iter =
output_to_monitor.find(static_cast<x11::RandR::Output>(output_id));
if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0) if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
monitor_order_primary_display_index = displays.size(); monitor_order_primary_display_index = displays.size();
...@@ -359,19 +314,17 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -359,19 +314,17 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
display.set_depth_per_component(bits_per_component); display.set_depth_per_component(bits_per_component);
// Set monitor refresh rate // Set monitor refresh rate
int refresh_rate = static_cast<int>(GetRefreshRateFromXRRModeInfo( int refresh_rate = static_cast<int>(
resources->modes, resources->nmode, crtc->mode)); GetRefreshRateFromXRRModeInfo(resources->modes, crtc->mode));
display.set_display_frequency(refresh_rate); display.set_display_frequency(refresh_rate);
displays.push_back(display); displays.push_back(display);
} }
}
if (explicit_primary_display_index != -1) { if (explicit_primary_display_index != -1)
*primary_display_index_out = explicit_primary_display_index; *primary_display_index_out = explicit_primary_display_index;
} else if (monitor_order_primary_display_index != -1) { else if (monitor_order_primary_display_index != -1)
*primary_display_index_out = monitor_order_primary_display_index; *primary_display_index_out = monitor_order_primary_display_index;
}
if (displays.empty()) if (displays.empty())
return GetFallbackDisplayList(scale); return GetFallbackDisplayList(scale);
...@@ -380,32 +333,35 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -380,32 +333,35 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
return displays; return displays;
} }
base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) { base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr() {
constexpr base::TimeDelta kDefaultInterval = constexpr base::TimeDelta kDefaultInterval =
base::TimeDelta::FromSecondsD(1. / 60); base::TimeDelta::FromSecondsD(1. / 60);
GLXWindow root = DefaultRootWindow(display); x11::RandR* randr = x11::Connection::Get()->randr();
gfx::XScopedPtr< if (!randr)
XRRScreenResources, return kDefaultInterval;
gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>> auto root = static_cast<x11::Window>(ui::GetX11RootWindow());
resources(XRRGetScreenResourcesCurrent(display, root)); auto resources = randr->GetScreenResourcesCurrent({root}).Sync();
if (!resources) if (!resources)
return kDefaultInterval; return kDefaultInterval;
// TODO(crbug.com/726842): It might make sense here to pick the output that // TODO(crbug.com/726842): It might make sense here to pick the output that
// the window is on. On the other hand, if compositing is enabled, all drawing // the window is on. On the other hand, if compositing is enabled, all drawing
// might be synced to the primary output anyway. Needs investigation. // might be synced to the primary output anyway. Needs investigation.
RROutput primary_output = XRRGetOutputPrimary(display, root); auto output_primary = randr->GetOutputPrimary({root}).Sync();
if (!output_primary)
return kDefaultInterval;
x11::RandR::Output primary_output = output_primary->output;
bool disconnected_primary = false; bool disconnected_primary = false;
for (int i = 0; i < resources->noutput; i++) { for (size_t i = 0; i < resources->outputs.size(); i++) {
if (!disconnected_primary && resources->outputs[i] != primary_output) if (!disconnected_primary && resources->outputs[i] != primary_output)
continue; continue;
gfx::XScopedPtr<XRROutputInfo, auto output_info =
gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>> randr->GetOutputInfo({primary_output, resources->config_timestamp})
output_info(XRRGetOutputInfo(display, resources.get(), primary_output)); .Sync();
if (!output_info) if (!output_info)
continue; continue;
if (output_info->connection != RR_Connected) { if (output_info->connection != x11::RandR::Connection::Connected) {
// If the primary monitor is disconnected, then start over and choose the // If the primary monitor is disconnected, then start over and choose the
// first connected monitor instead. // first connected monitor instead.
if (!disconnected_primary) { if (!disconnected_primary) {
...@@ -414,13 +370,13 @@ base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) { ...@@ -414,13 +370,13 @@ base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) {
} }
continue; continue;
} }
gfx::XScopedPtr<XRRCrtcInfo, auto crtc =
gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>> randr->GetCrtcInfo({output_info->crtc, resources->config_timestamp})
crtc(XRRGetCrtcInfo(display, resources.get(), output_info->crtc)); .Sync();
if (!crtc) if (!crtc)
continue; continue;
float refresh_rate = GetRefreshRateFromXRRModeInfo( float refresh_rate =
resources->modes, resources->nmode, crtc->mode); GetRefreshRateFromXRRModeInfo(resources->modes, crtc->mode);
if (refresh_rate == 0) if (refresh_rate == 0)
continue; continue;
......
...@@ -33,7 +33,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -33,7 +33,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
// Returns the refresh interval of the primary display. If there is no connected // Returns the refresh interval of the primary display. If there is no connected
// primary display, returns the refresh interval of the first connected display. // primary display, returns the refresh interval of the first connected display.
COMPONENT_EXPORT(UI_BASE_X) COMPONENT_EXPORT(UI_BASE_X)
base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display); base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr();
} // namespace ui } // namespace ui
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "ui/base/x/x11_display_util.h" #include "ui/base/x/x11_display_util.h"
#include "ui/gfx/x/randr.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/xproto.h" #include "ui/gfx/x/xproto.h"
#include "ui/gl/egl_util.h" #include "ui/gl/egl_util.h"
...@@ -17,12 +18,12 @@ namespace { ...@@ -17,12 +18,12 @@ namespace {
class XrandrIntervalOnlyVSyncProvider : public gfx::VSyncProvider { class XrandrIntervalOnlyVSyncProvider : public gfx::VSyncProvider {
public: public:
explicit XrandrIntervalOnlyVSyncProvider(Display* display) explicit XrandrIntervalOnlyVSyncProvider(Display* display)
: display_(display), interval_(base::TimeDelta::FromSeconds(1 / 60.)) {} : interval_(base::TimeDelta::FromSeconds(1 / 60.)) {}
void GetVSyncParameters(UpdateVSyncCallback callback) override { void GetVSyncParameters(UpdateVSyncCallback callback) override {
if (++calls_since_last_update_ >= kCallsBetweenUpdates) { if (++calls_since_last_update_ >= kCallsBetweenUpdates) {
calls_since_last_update_ = 0; calls_since_last_update_ = 0;
interval_ = ui::GetPrimaryDisplayRefreshIntervalFromXrandr(display_); interval_ = ui::GetPrimaryDisplayRefreshIntervalFromXrandr();
} }
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE,
...@@ -37,7 +38,6 @@ class XrandrIntervalOnlyVSyncProvider : public gfx::VSyncProvider { ...@@ -37,7 +38,6 @@ class XrandrIntervalOnlyVSyncProvider : public gfx::VSyncProvider {
bool IsHWClock() const override { return false; } bool IsHWClock() const override { return false; }
private: private:
Display* const display_ = nullptr;
base::TimeDelta interval_; base::TimeDelta interval_;
static const int kCallsBetweenUpdates = 100; static const int kCallsBetweenUpdates = 100;
int calls_since_last_update_ = kCallsBetweenUpdates; int calls_since_last_update_ = kCallsBetweenUpdates;
......
...@@ -324,8 +324,7 @@ class SGIVideoSyncProviderThreadShim { ...@@ -324,8 +324,7 @@ class SGIVideoSyncProviderThreadShim {
if (!vsync_thread_->GetGLXContext() || cancel_vsync_flag_.IsSet()) if (!vsync_thread_->GetGLXContext() || cancel_vsync_flag_.IsSet())
return; return;
base::TimeDelta interval = ui::GetPrimaryDisplayRefreshIntervalFromXrandr( base::TimeDelta interval = ui::GetPrimaryDisplayRefreshIntervalFromXrandr();
vsync_thread_->GetDisplay());
glXMakeContextCurrent(vsync_thread_->GetDisplay(), glx_window_, glx_window_, glXMakeContextCurrent(vsync_thread_->GetDisplay(), glx_window_, glx_window_,
vsync_thread_->GetGLXContext()); vsync_thread_->GetGLXContext());
......
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