Commit 05f9838f authored by James Darpinian's avatar James Darpinian Committed by Commit Bot

Extend refresh rate fix to ANGLE also

https://crrev.com/c/1812241 reads the monitor refresh rate with xrandr
when we're using desktop GL on Linux Nvidia. This applies the same fix
when we're using ANGLE (--use-cmd-decoder=passthrough).

Also fixes X11 errors when the primary display is disconnected.

Bug: 1012262, 535392
Change-Id: I0c54371496aa141643c5f6a2950935e22ba0f534
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1857091
Commit-Queue: James Darpinian <jdarpinian@chromium.org>
Reviewed-by: default avatarSunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706259}
parent 70c046ff
...@@ -101,8 +101,6 @@ void ClipWorkArea(std::vector<display::Display>* displays, ...@@ -101,8 +101,6 @@ void ClipWorkArea(std::vector<display::Display>* displays,
primary.set_work_area(work_area); primary.set_work_area(work_area);
} }
} // namespace
float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes, float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes,
int num_of_mode, int num_of_mode,
RRMode current_mode_id) { RRMode current_mode_id) {
...@@ -120,6 +118,8 @@ float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes, ...@@ -120,6 +118,8 @@ float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes,
return 0; return 0;
} }
} // namespace
int GetXrandrVersion(XDisplay* xdisplay) { int GetXrandrVersion(XDisplay* xdisplay) {
int xrandr_version = 0; int xrandr_version = 0;
// We only support 1.3+. There were library changes before this and we should // We only support 1.3+. There were library changes before this and we should
...@@ -274,4 +274,53 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -274,4 +274,53 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
return displays; return displays;
} }
base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) {
constexpr base::TimeDelta kDefaultInterval =
base::TimeDelta::FromSecondsD(1. / 60);
GLXWindow root = DefaultRootWindow(display);
gfx::XScopedPtr<
XRRScreenResources,
gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
resources(XRRGetScreenResourcesCurrent(display, root));
if (!resources)
return kDefaultInterval;
// 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
// might be synced to the primary output anyway. Needs investigation.
RROutput primary_output = XRRGetOutputPrimary(display, root);
bool disconnected_primary = false;
for (int i = 0; i < resources->noutput; i++) {
if (!disconnected_primary && resources->outputs[i] != primary_output)
continue;
gfx::XScopedPtr<XRROutputInfo,
gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
output_info(XRRGetOutputInfo(display, resources.get(), primary_output));
if (!output_info)
continue;
if (output_info->connection != RR_Connected) {
// If the primary monitor is disconnected, then start over and choose the
// first connected monitor instead.
if (!disconnected_primary) {
disconnected_primary = true;
i = -1;
}
continue;
}
gfx::XScopedPtr<XRRCrtcInfo,
gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
crtc(XRRGetCrtcInfo(display, resources.get(), output_info->crtc));
if (!crtc)
continue;
float refresh_rate = GetRefreshRateFromXRRModeInfo(
resources->modes, resources->nmode, crtc->mode);
if (refresh_rate == 0)
continue;
return base::TimeDelta::FromSecondsD(1. / refresh_rate);
}
return kDefaultInterval;
}
} // namespace ui } // namespace ui
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define UI_BASE_X_X11_DISPLAY_UTIL_H_ #define UI_BASE_X_X11_DISPLAY_UTIL_H_
#include "base/component_export.h" #include "base/component_export.h"
#include "base/time/time.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h" #include "ui/gfx/x/x11_types.h"
...@@ -29,11 +30,10 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo( ...@@ -29,11 +30,10 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
float scale, float scale,
int64_t* primary_display_index_out); int64_t* primary_display_index_out);
// Calculates the refresh rate of an xrandr mode. // Returns the refresh interval of the primary display. If there is no connected
// primary display, returns the refresh interval of the first connected display.
COMPONENT_EXPORT(UI_BASE_X) COMPONENT_EXPORT(UI_BASE_X)
float GetRefreshRateFromXRRModeInfo(XRRModeInfo* modes, base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display);
int num_of_mode,
RRMode current_mode_id);
} // namespace ui } // namespace ui
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/platform_event_source.h"
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
#include "ui/gl/sync_control_vsync_provider.h" #include "ui/gl/sync_control_vsync_provider.h"
#if defined(USE_X11) #if defined(USE_X11)
#include "ui/base/x/x11_display_util.h"
#include "ui/base/x/x11_util_internal.h" // nogncheck #include "ui/base/x/x11_util_internal.h" // nogncheck
#include "ui/gfx/x/x11.h" #include "ui/gfx/x/x11.h"
#endif #endif
...@@ -199,6 +201,37 @@ struct TraceSwapEventsInitializer { ...@@ -199,6 +201,37 @@ struct TraceSwapEventsInitializer {
static base::LazyInstance<TraceSwapEventsInitializer>::Leaky static base::LazyInstance<TraceSwapEventsInitializer>::Leaky
g_trace_swap_enabled = LAZY_INSTANCE_INITIALIZER; g_trace_swap_enabled = LAZY_INSTANCE_INITIALIZER;
#if defined(USE_X11)
class XrandrIntervalOnlyVSyncProvider : public gfx::VSyncProvider {
public:
XrandrIntervalOnlyVSyncProvider(Display* display)
: display_(display), interval_(base::TimeDelta::FromSeconds(1 / 60.)) {}
void GetVSyncParameters(UpdateVSyncCallback callback) override {
if (++calls_since_last_update_ >= kCallsBetweenUpdates) {
calls_since_last_update_ = 0;
interval_ = ui::GetPrimaryDisplayRefreshIntervalFromXrandr(display_);
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), base::TimeTicks(), interval_));
}
bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
base::TimeDelta* interval) override {
return false;
}
bool SupportGetVSyncParametersIfAvailable() const override { return false; }
bool IsHWClock() const override { return false; }
private:
Display* const display_ = nullptr;
base::TimeDelta interval_;
static const int kCallsBetweenUpdates = 100;
int calls_since_last_update_ = kCallsBetweenUpdates;
};
#endif
class EGLSyncControlVSyncProvider : public SyncControlVSyncProvider { class EGLSyncControlVSyncProvider : public SyncControlVSyncProvider {
public: public:
explicit EGLSyncControlVSyncProvider(EGLSurface surface) explicit EGLSyncControlVSyncProvider(EGLSurface surface)
...@@ -1204,6 +1237,21 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) { ...@@ -1204,6 +1237,21 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) {
return false; return false;
} }
if (g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
EGLint surfaceVal;
EGLBoolean retVal = eglQuerySurface(
GetDisplay(), surface_, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceVal);
supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
}
supports_swap_buffer_with_damage_ =
g_driver_egl.ext.b_EGL_KHR_swap_buffers_with_damage;
if (!vsync_provider_external_ && EGLSyncControlVSyncProvider::IsSupported()) {
vsync_provider_internal_ =
std::make_unique<EGLSyncControlVSyncProvider>(surface_);
}
#if defined(USE_X11) #if defined(USE_X11)
// Query all child windows and store them. ANGLE creates a child window when // Query all child windows and store them. ANGLE creates a child window when
// eglCreateWidnowSurface is called on X11 and expose events from this window // eglCreateWidnowSurface is called on X11 and expose events from this window
...@@ -1226,22 +1274,13 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) { ...@@ -1226,22 +1274,13 @@ bool NativeViewGLSurfaceEGL::Initialize(GLSurfaceFormat format) {
if (PlatformEventSource* source = PlatformEventSource::GetInstance()) { if (PlatformEventSource* source = PlatformEventSource::GetInstance()) {
source->AddPlatformEventDispatcher(this); source->AddPlatformEventDispatcher(this);
} }
#endif
if (g_driver_egl.ext.b_EGL_NV_post_sub_buffer) { if (!vsync_provider_external_ && !vsync_provider_internal_) {
EGLint surfaceVal;
EGLBoolean retVal = eglQuerySurface(
GetDisplay(), surface_, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceVal);
supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
}
supports_swap_buffer_with_damage_ =
g_driver_egl.ext.b_EGL_KHR_swap_buffers_with_damage;
if (!vsync_provider_external_ && EGLSyncControlVSyncProvider::IsSupported()) {
vsync_provider_internal_ = vsync_provider_internal_ =
std::make_unique<EGLSyncControlVSyncProvider>(surface_); std::make_unique<XrandrIntervalOnlyVSyncProvider>(x11_display);
} }
#endif
presentation_helper_ = presentation_helper_ =
std::make_unique<GLSurfacePresentationHelper>(GetVSyncProvider()); std::make_unique<GLSurfacePresentationHelper>(GetVSyncProvider());
return true; return true;
......
...@@ -58,43 +58,6 @@ Visual* g_visual = nullptr; ...@@ -58,43 +58,6 @@ Visual* g_visual = nullptr;
int g_depth = CopyFromParent; int g_depth = CopyFromParent;
Colormap g_colormap = CopyFromParent; Colormap g_colormap = CopyFromParent;
base::TimeDelta GetPrimaryDisplayRefreshIntervalFromXrandr(Display* display) {
constexpr base::TimeDelta kDefaultInterval =
base::TimeDelta::FromSecondsD(1. / 60);
GLXWindow root = DefaultRootWindow(display);
gfx::XScopedPtr<
XRRScreenResources,
gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
resources(XRRGetScreenResourcesCurrent(display, root));
if (!resources)
return kDefaultInterval;
// 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
// might be synced to the primary output anyway. Needs investigation.
RROutput primary_output = XRRGetOutputPrimary(display, root);
for (int i = 0; i < resources->noutput; i++) {
if (resources->outputs[i] != primary_output)
continue;
gfx::XScopedPtr<XRROutputInfo,
gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
output_info(XRRGetOutputInfo(display, resources.get(), primary_output));
if (!output_info)
return kDefaultInterval;
gfx::XScopedPtr<XRRCrtcInfo,
gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
crtc(XRRGetCrtcInfo(display, resources.get(), output_info->crtc));
if (!crtc)
return kDefaultInterval;
float refresh_rate = ui::GetRefreshRateFromXRRModeInfo(
resources->modes, resources->nmode, crtc->mode);
if (refresh_rate == 0)
return kDefaultInterval;
return base::TimeDelta::FromSecondsD(1. / refresh_rate);
}
return kDefaultInterval;
}
GLXFBConfig GetConfigForWindow(Display* display, GLXFBConfig GetConfigForWindow(Display* display,
gfx::AcceleratedWidget window) { gfx::AcceleratedWidget window) {
DCHECK(window != 0); DCHECK(window != 0);
...@@ -356,8 +319,8 @@ class SGIVideoSyncProviderThreadShim { ...@@ -356,8 +319,8 @@ class SGIVideoSyncProviderThreadShim {
if (!vsync_thread_->GetGLXContext() || cancel_vsync_flag_.IsSet()) if (!vsync_thread_->GetGLXContext() || cancel_vsync_flag_.IsSet())
return; return;
base::TimeDelta interval = base::TimeDelta interval = ui::GetPrimaryDisplayRefreshIntervalFromXrandr(
GetPrimaryDisplayRefreshIntervalFromXrandr(vsync_thread_->GetDisplay()); 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