1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #define PANGO_ENABLE_BACKEND
7 #define PANGO_ENABLE_ENGINE
9 #include "gfxPlatformGtk.h"
12 #include "nsUnicharUtils.h"
13 #include "nsUnicodeProperties.h"
14 #include "gfx2DGlue.h"
15 #include "gfxFcPlatformFontList.h"
16 #include "gfxConfig.h"
17 #include "gfxContext.h"
18 #include "gfxUserFontSet.h"
20 #include "gfxFT2FontBase.h"
21 #include "gfxTextRun.h"
22 #include "VsyncSource.h"
23 #include "mozilla/Atomics.h"
24 #include "mozilla/Monitor.h"
25 #include "mozilla/StaticPrefs_layers.h"
26 #include "base/task.h"
27 #include "base/thread.h"
28 #include "base/message_loop.h"
29 #include "mozilla/FontPropertyTypes.h"
30 #include "mozilla/gfx/Logging.h"
32 #include "mozilla/gfx/2D.h"
37 #include "gfxImageSurface.h"
39 # include <gdk/gdkx.h>
40 # include "gfxXlibSurface.h"
41 # include "cairo-xlib.h"
42 # include "mozilla/Preferences.h"
43 # include "mozilla/X11Util.h"
45 # include "GLContextProvider.h"
46 # include "GLContextGLX.h"
47 # include "GLXLibrary.h"
49 /* Undefine the Status from Xlib since it will conflict with system headers on
51 # if defined(__APPLE__) && defined(Status)
56 # include <gdk/gdkwayland.h>
61 #include <fontconfig/fontconfig.h>
63 #include "nsMathUtils.h"
65 #define GDK_PIXMAP_SIZE_MAX 32767
67 #define GFX_PREF_MAX_GENERIC_SUBSTITUTIONS \
68 "gfx.font_rendering.fontconfig.max_generic_substitutions"
70 using namespace mozilla
;
71 using namespace mozilla::gfx
;
72 using namespace mozilla::unicode
;
73 using mozilla::dom::SystemFontListEntry
;
75 gfxPlatformGtk::gfxPlatformGtk() {
76 if (!gfxPlatform::IsHeadless()) {
77 gtk_init(nullptr, nullptr);
80 mMaxGenericSubstitutions
= UNINITIALIZED_VALUE
;
83 if (!gfxPlatform::IsHeadless() && XRE_IsParentProcess()) {
84 if (GDK_IS_X11_DISPLAY(gdk_display_get_default()) &&
85 mozilla::Preferences::GetBool("gfx.xrender.enabled")) {
86 gfxVars::SetUseXRender(true);
91 InitBackendPrefs(GetBackendPrefs());
94 if (gfxPlatform::IsHeadless() &&
95 GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
96 mCompositorDisplay
= XOpenDisplay(nullptr);
97 MOZ_ASSERT(mCompositorDisplay
, "Failed to create compositor display!");
99 mCompositorDisplay
= nullptr;
103 // Wayland compositors use g_get_monotonic_time() to get timestamps.
104 mWaylandLastVsyncTimestamp
= (g_get_monotonic_time() / 1000);
105 // Set default display fps to 60
106 mWaylandFrameDelay
= 1000 / 60;
110 gfxPlatformGtk::~gfxPlatformGtk() {
112 if (mCompositorDisplay
) {
113 XCloseDisplay(mCompositorDisplay
);
118 void gfxPlatformGtk::FlushContentDrawing() {
119 if (gfxVars::UseXRender()) {
120 XFlush(DefaultXDisplay());
124 void gfxPlatformGtk::InitPlatformGPUProcessPrefs() {
126 if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
127 FeatureState
& gpuProc
= gfxConfig::GetFeature(Feature::GPU_PROCESS
);
128 gpuProc
.ForceDisable(FeatureStatus::Blocked
,
129 "Wayland does not work in the GPU process",
130 NS_LITERAL_CSTRING("FEATURE_FAILURE_WAYLAND"));
135 already_AddRefed
<gfxASurface
> gfxPlatformGtk::CreateOffscreenSurface(
136 const IntSize
& aSize
, gfxImageFormat aFormat
) {
137 if (!Factory::AllowedSurfaceSize(aSize
)) {
141 RefPtr
<gfxASurface
> newSurface
;
142 bool needsClear
= true;
144 // XXX we really need a different interface here, something that passes
145 // in more context, including the display and/or target surface type that
146 // we should try to match
147 GdkScreen
* gdkScreen
= gdk_screen_get_default();
149 // When forcing PaintedLayers to use image surfaces for content,
150 // force creation of gfxImageSurface surfaces.
151 if (gfxVars::UseXRender() && !UseImageOffscreenSurfaces()) {
152 Screen
* screen
= gdk_x11_screen_get_xscreen(gdkScreen
);
153 XRenderPictFormat
* xrenderFormat
=
154 gfxXlibSurface::FindRenderFormat(DisplayOfScreen(screen
), aFormat
);
157 newSurface
= gfxXlibSurface::Create(screen
, xrenderFormat
, aSize
);
160 // We're not going to use XRender, so we don't need to
161 // search for a render format
162 newSurface
= new gfxImageSurface(aSize
, aFormat
);
163 // The gfxImageSurface ctor zeroes this for us, no need to
164 // waste time clearing again
171 // We couldn't create a native surface for whatever reason;
172 // e.g., no display, no RENDER, bad size, etc.
173 // Fall back to image surface for the data.
174 newSurface
= new gfxImageSurface(aSize
, aFormat
);
177 if (newSurface
->CairoStatus()) {
178 newSurface
= nullptr; // surface isn't valid for some reason
181 if (newSurface
&& needsClear
) {
182 gfxUtils::ClearThebesSurface(newSurface
);
185 return newSurface
.forget();
188 nsresult
gfxPlatformGtk::GetFontList(nsAtom
* aLangGroup
,
189 const nsACString
& aGenericFamily
,
190 nsTArray
<nsString
>& aListOfFonts
) {
191 gfxPlatformFontList::PlatformFontList()->GetFontList(
192 aLangGroup
, aGenericFamily
, aListOfFonts
);
196 nsresult
gfxPlatformGtk::UpdateFontList() {
197 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
201 // xxx - this is ubuntu centric, need to go through other distros and flesh
202 // out a more general list
203 static const char kFontDejaVuSans
[] = "DejaVu Sans";
204 static const char kFontDejaVuSerif
[] = "DejaVu Serif";
205 static const char kFontFreeSans
[] = "FreeSans";
206 static const char kFontFreeSerif
[] = "FreeSerif";
207 static const char kFontTakaoPGothic
[] = "TakaoPGothic";
208 static const char kFontTwemojiMozilla
[] = "Twemoji Mozilla";
209 static const char kFontDroidSansFallback
[] = "Droid Sans Fallback";
210 static const char kFontWenQuanYiMicroHei
[] = "WenQuanYi Micro Hei";
211 static const char kFontNanumGothic
[] = "NanumGothic";
212 static const char kFontSymbola
[] = "Symbola";
214 void gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh
, uint32_t aNextCh
,
216 nsTArray
<const char*>& aFontList
) {
217 EmojiPresentation emoji
= GetEmojiPresentation(aCh
);
218 if (emoji
!= EmojiPresentation::TextOnly
) {
219 if (aNextCh
== kVariationSelector16
||
220 (aNextCh
!= kVariationSelector15
&&
221 emoji
== EmojiPresentation::EmojiDefault
)) {
222 // if char is followed by VS16, try for a color emoji glyph
223 aFontList
.AppendElement(kFontTwemojiMozilla
);
227 aFontList
.AppendElement(kFontDejaVuSerif
);
228 aFontList
.AppendElement(kFontFreeSerif
);
229 aFontList
.AppendElement(kFontDejaVuSans
);
230 aFontList
.AppendElement(kFontFreeSans
);
231 aFontList
.AppendElement(kFontSymbola
);
233 // add fonts for CJK ranges
234 // xxx - this isn't really correct, should use the same CJK font ordering
235 // as the pref font code
236 if (aCh
>= 0x3000 && ((aCh
< 0xe000) || (aCh
>= 0xf900 && aCh
< 0xfff0) ||
237 ((aCh
>> 16) == 2))) {
238 aFontList
.AppendElement(kFontTakaoPGothic
);
239 aFontList
.AppendElement(kFontDroidSansFallback
);
240 aFontList
.AppendElement(kFontWenQuanYiMicroHei
);
241 aFontList
.AppendElement(kFontNanumGothic
);
245 void gfxPlatformGtk::ReadSystemFontList(
246 nsTArray
<SystemFontListEntry
>* retValue
) {
247 gfxFcPlatformFontList::PlatformFontList()->ReadSystemFontList(retValue
);
250 gfxPlatformFontList
* gfxPlatformGtk::CreatePlatformFontList() {
251 gfxPlatformFontList
* list
= new gfxFcPlatformFontList();
252 if (NS_SUCCEEDED(list
->InitFontList())) {
255 gfxPlatformFontList::Shutdown();
259 gfxFontGroup
* gfxPlatformGtk::CreateFontGroup(
260 const FontFamilyList
& aFontFamilyList
, const gfxFontStyle
* aStyle
,
261 gfxTextPerfMetrics
* aTextPerf
, gfxUserFontSet
* aUserFontSet
,
262 gfxFloat aDevToCssSize
) {
263 return new gfxFontGroup(aFontFamilyList
, aStyle
, aTextPerf
, aUserFontSet
,
267 FT_Library
gfxPlatformGtk::GetFTLibrary() {
268 return gfxFcPlatformFontList::GetFTLibrary();
271 static int32_t sDPI
= 0;
273 int32_t gfxPlatformGtk::GetFontScaleDPI() {
275 // Make sure init is run so we have a resolution
276 GdkScreen
* screen
= gdk_screen_get_default();
277 gtk_settings_get_for_screen(screen
);
278 sDPI
= int32_t(round(gdk_screen_get_resolution(screen
)));
280 // Fall back to something sane
287 double gfxPlatformGtk::GetFontScaleFactor() {
288 // Integer scale factors work well with GTK window scaling, image scaling,
289 // and pixel alignment, but there is a range where 1 is too small and 2 is
290 // too big. An additional step of 1.5 is added because this is common
291 // scale on WINNT and at this ratio the advantages of larger rendering
292 // outweigh the disadvantages from scaling and pixel mis-alignment.
293 int32_t dpi
= GetFontScaleDPI();
300 return round(dpi
/ 96.0);
303 bool gfxPlatformGtk::UseImageOffscreenSurfaces() {
304 return GetDefaultContentBackend() != mozilla::gfx::BackendType::CAIRO
||
305 StaticPrefs::layers_use_image_offscreen_surfaces_AtStartup();
308 gfxImageFormat
gfxPlatformGtk::GetOffscreenFormat() {
309 // Make sure there is a screen
310 GdkScreen
* screen
= gdk_screen_get_default();
311 if (screen
&& gdk_visual_get_depth(gdk_visual_get_system()) == 16) {
312 return SurfaceFormat::R5G6B5_UINT16
;
315 return SurfaceFormat::X8R8G8B8_UINT32
;
318 void gfxPlatformGtk::FontsPrefsChanged(const char* aPref
) {
319 // only checking for generic substitions, pass other changes up
320 if (strcmp(GFX_PREF_MAX_GENERIC_SUBSTITUTIONS
, aPref
)) {
321 gfxPlatform::FontsPrefsChanged(aPref
);
325 mMaxGenericSubstitutions
= UNINITIALIZED_VALUE
;
326 gfxFcPlatformFontList
* pfl
= gfxFcPlatformFontList::PlatformFontList();
327 pfl
->ClearGenericMappings();
328 FlushFontAndWordCaches();
331 uint32_t gfxPlatformGtk::MaxGenericSubstitions() {
332 if (mMaxGenericSubstitutions
== UNINITIALIZED_VALUE
) {
333 mMaxGenericSubstitutions
=
334 Preferences::GetInt(GFX_PREF_MAX_GENERIC_SUBSTITUTIONS
, 3);
335 if (mMaxGenericSubstitutions
< 0) {
336 mMaxGenericSubstitutions
= 3;
340 return uint32_t(mMaxGenericSubstitutions
);
343 bool gfxPlatformGtk::AccelerateLayersByDefault() { return true; }
345 void gfxPlatformGtk::GetPlatformCMSOutputProfile(void*& mem
, size_t& size
) {
350 GdkDisplay
* display
= gdk_display_get_default();
351 if (!GDK_IS_X11_DISPLAY(display
)) return;
353 const char EDID1_ATOM_NAME
[] = "XFree86_DDC_EDID1_RAWDATA";
354 const char ICC_PROFILE_ATOM_NAME
[] = "_ICC_PROFILE";
356 Atom edidAtom
, iccAtom
;
357 Display
* dpy
= GDK_DISPLAY_XDISPLAY(display
);
358 // In xpcshell tests, we never initialize X and hence don't have a Display.
359 // In this case, there's no output colour management to be done, so we just
360 // return with nullptr.
363 Window root
= gdk_x11_get_default_root_xwindow();
367 unsigned long retLength
, retAfter
;
368 unsigned char* retProperty
;
370 iccAtom
= XInternAtom(dpy
, ICC_PROFILE_ATOM_NAME
, TRUE
);
372 // read once to get size, once for the data
373 if (Success
== XGetWindowProperty(dpy
, root
, iccAtom
, 0,
374 INT_MAX
/* length */, X11False
,
375 AnyPropertyType
, &retAtom
, &retFormat
,
376 &retLength
, &retAfter
, &retProperty
)) {
378 void* buffer
= malloc(retLength
);
380 memcpy(buffer
, retProperty
, retLength
);
389 fprintf(stderr
, "ICM profile read from %s successfully\n",
390 ICC_PROFILE_ATOM_NAME
);
397 edidAtom
= XInternAtom(dpy
, EDID1_ATOM_NAME
, TRUE
);
399 if (Success
== XGetWindowProperty(dpy
, root
, edidAtom
, 0, 32, X11False
,
400 AnyPropertyType
, &retAtom
, &retFormat
,
401 &retLength
, &retAfter
, &retProperty
)) {
403 qcms_CIE_xyY whitePoint
;
404 qcms_CIE_xyYTRIPLE primaries
;
406 if (retLength
!= 128) {
408 fprintf(stderr
, "Short EDID data\n");
413 // Format documented in "VESA E-EDID Implementation Guide"
415 gamma
= (100 + retProperty
[0x17]) / 100.0;
417 ((retProperty
[0x21] << 2) | (retProperty
[0x1a] >> 2 & 3)) / 1024.0;
419 ((retProperty
[0x22] << 2) | (retProperty
[0x1a] >> 0 & 3)) / 1024.0;
423 ((retProperty
[0x1b] << 2) | (retProperty
[0x19] >> 6 & 3)) / 1024.0;
425 ((retProperty
[0x1c] << 2) | (retProperty
[0x19] >> 4 & 3)) / 1024.0;
426 primaries
.red
.Y
= 1.0;
429 ((retProperty
[0x1d] << 2) | (retProperty
[0x19] >> 2 & 3)) / 1024.0;
431 ((retProperty
[0x1e] << 2) | (retProperty
[0x19] >> 0 & 3)) / 1024.0;
432 primaries
.green
.Y
= 1.0;
435 ((retProperty
[0x1f] << 2) | (retProperty
[0x1a] >> 6 & 3)) / 1024.0;
437 ((retProperty
[0x20] << 2) | (retProperty
[0x1a] >> 4 & 3)) / 1024.0;
438 primaries
.blue
.Y
= 1.0;
443 fprintf(stderr
, "EDID gamma: %f\n", gamma
);
444 fprintf(stderr
, "EDID whitepoint: %f %f %f\n", whitePoint
.x
, whitePoint
.y
,
446 fprintf(stderr
, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
447 primaries
.Red
.x
, primaries
.Red
.y
, primaries
.Red
.Y
,
448 primaries
.Green
.x
, primaries
.Green
.y
, primaries
.Green
.Y
,
449 primaries
.Blue
.x
, primaries
.Blue
.y
, primaries
.Blue
.Y
);
452 qcms_data_create_rgb_with_gamma(whitePoint
, primaries
, gamma
, &mem
,
457 fprintf(stderr
, "ICM profile read from %s successfully\n",
466 bool gfxPlatformGtk::CheckVariationFontSupport() {
467 // Although there was some variation/multiple-master support in FreeType
468 // in older versions, it seems too incomplete/unstable for us to use
469 // until at least 2.7.1.
470 FT_Int major
, minor
, patch
;
471 FT_Library_Version(GetFTLibrary(), &major
, &minor
, &patch
);
472 return major
* 1000000 + minor
* 1000 + patch
>= 2007001;
477 class GtkVsyncSource final
: public VsyncSource
{
480 MOZ_ASSERT(NS_IsMainThread());
481 mGlobalDisplay
= new GLXDisplay();
484 virtual ~GtkVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
486 virtual Display
& GetGlobalDisplay() override
{ return *mGlobalDisplay
; }
488 class GLXDisplay final
: public VsyncSource::Display
{
489 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLXDisplay
)
493 : mGLContext(nullptr),
495 mSetupLock("GLXVsyncSetupLock"),
496 mVsyncThread("GLXVsyncThread"),
498 mVsyncEnabledLock("GLXVsyncEnabledLock"),
502 mIsWaylandDisplay(false)
507 // Sets up the display's GL context on a worker thread.
508 // Required as GLContexts may only be used by the creating thread.
509 // Returns true if setup was a success.
511 MonitorAutoLock
lock(mSetupLock
);
512 MOZ_ASSERT(NS_IsMainThread());
513 if (!mVsyncThread
.Start()) return false;
515 RefPtr
<Runnable
> vsyncSetup
=
516 NewRunnableMethod("GtkVsyncSource::GLXDisplay::SetupGLContext", this,
517 &GLXDisplay::SetupGLContext
);
518 mVsyncThread
.message_loop()->PostTask(vsyncSetup
.forget());
519 // Wait until the setup has completed.
521 return mGLContext
!= nullptr;
525 bool SetupWayland() {
526 MonitorAutoLock
lock(mSetupLock
);
527 MOZ_ASSERT(NS_IsMainThread());
528 mIsWaylandDisplay
= true;
529 return mVsyncThread
.Start();
533 // Called on the Vsync thread to setup the GL context.
534 void SetupGLContext() {
535 MonitorAutoLock
lock(mSetupLock
);
536 MOZ_ASSERT(!NS_IsMainThread());
537 MOZ_ASSERT(!mGLContext
, "GLContext already setup!");
539 // Create video sync timer on a separate Display to prevent locking the
540 // main thread X display.
541 mXDisplay
= XOpenDisplay(nullptr);
547 // Most compositors wait for vsync events on the root window.
548 Window root
= DefaultRootWindow(mXDisplay
);
549 int screen
= DefaultScreen(mXDisplay
);
551 ScopedXFree
<GLXFBConfig
> cfgs
;
554 bool forWebRender
= false;
555 if (!gl::GLContextGLX::FindFBConfigForWindow(
556 mXDisplay
, screen
, root
, &cfgs
, &config
, &visid
, forWebRender
)) {
561 mGLContext
= gl::GLContextGLX::CreateGLContext(
562 gl::CreateContextFlags::NONE
, gl::SurfaceCaps::Any(), false,
563 mXDisplay
, root
, config
, false, nullptr);
570 mGLContext
->MakeCurrent();
572 // Test that SGI_video_sync lets us get the counter.
573 unsigned int syncCounter
= 0;
574 if (gl::sGLXLibrary
.fGetVideoSync(&syncCounter
) != 0) {
575 mGLContext
= nullptr;
581 virtual void EnableVsync() override
{
582 MOZ_ASSERT(NS_IsMainThread());
583 # if !defined(MOZ_WAYLAND)
584 MOZ_ASSERT(mGLContext
, "GLContext not setup!");
587 MonitorAutoLock
lock(mVsyncEnabledLock
);
591 mVsyncEnabled
= true;
593 // If the task has not nulled itself out, it hasn't yet realized
594 // that vsync was disabled earlier, so continue its execution.
597 NewRunnableMethod("GtkVsyncSource::GLXDisplay::RunVsync", this,
598 # if defined(MOZ_WAYLAND)
599 mIsWaylandDisplay
? &GLXDisplay::RunVsyncWayland
:
601 &GLXDisplay::RunVsync
);
602 RefPtr
<Runnable
> addrefedTask
= mVsyncTask
;
603 mVsyncThread
.message_loop()->PostTask(addrefedTask
.forget());
607 virtual void DisableVsync() override
{
608 MonitorAutoLock
lock(mVsyncEnabledLock
);
609 mVsyncEnabled
= false;
612 virtual bool IsVsyncEnabled() override
{
613 MonitorAutoLock
lock(mVsyncEnabledLock
);
614 return mVsyncEnabled
;
617 virtual void Shutdown() override
{
618 MOZ_ASSERT(NS_IsMainThread());
621 // Cleanup thread-specific resources before shutting down.
622 RefPtr
<Runnable
> shutdownTask
= NewRunnableMethod(
623 "GtkVsyncSource::GLXDisplay::Cleanup", this, &GLXDisplay::Cleanup
);
624 mVsyncThread
.message_loop()->PostTask(shutdownTask
.forget());
626 // Stop, waiting for the cleanup task to finish execution.
631 virtual ~GLXDisplay() = default;
634 MOZ_ASSERT(!NS_IsMainThread());
636 mGLContext
->MakeCurrent();
638 unsigned int syncCounter
= 0;
639 gl::sGLXLibrary
.fGetVideoSync(&syncCounter
);
642 MonitorAutoLock
lock(mVsyncEnabledLock
);
643 if (!mVsyncEnabled
) {
644 mVsyncTask
= nullptr;
649 TimeStamp lastVsync
= TimeStamp::Now();
650 bool useSoftware
= false;
652 // Wait until the video sync counter reaches the next value by waiting
653 // until the parity of the counter value changes.
654 unsigned int nextSync
= syncCounter
+ 1;
656 if ((status
= gl::sGLXLibrary
.fWaitVideoSync(2, nextSync
% 2,
657 &syncCounter
)) != 0) {
658 gfxWarningOnce() << "glXWaitVideoSync returned " << status
;
662 if (syncCounter
== (nextSync
- 1)) {
664 << "glXWaitVideoSync failed to increment the sync counter.";
670 (1000.f
/ 60.f
) - (TimeStamp::Now() - lastVsync
).ToMilliseconds();
672 PlatformThread::Sleep(remaining
);
676 lastVsync
= TimeStamp::Now();
677 NotifyVsync(lastVsync
);
682 /* VSync on Wayland is tricky as we can get only "last VSync" event signal.
683 * That means we should draw next frame at "last Vsync + frame delay" time.
685 void RunVsyncWayland() {
686 MOZ_ASSERT(!NS_IsMainThread());
690 MonitorAutoLock
lock(mVsyncEnabledLock
);
691 if (!mVsyncEnabled
) {
692 mVsyncTask
= nullptr;
697 gint64 lastVsync
= gfxPlatformGtk::GetPlatform()->GetWaylandLastVsync();
698 gint64 currTime
= (g_get_monotonic_time() / 1000);
701 gfxPlatformGtk::GetPlatform()->GetWaylandFrameDelay() -
702 (currTime
- lastVsync
);
704 PlatformThread::Sleep(remaining
);
706 // Time from last HW Vsync is longer than our frame delay,
707 // use our approximation then.
708 gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(currTime
);
711 NotifyVsync(TimeStamp::Now());
717 MOZ_ASSERT(!NS_IsMainThread());
719 mGLContext
= nullptr;
720 if (mXDisplay
) XCloseDisplay(mXDisplay
);
723 // Owned by the vsync thread.
724 RefPtr
<gl::GLContextGLX
> mGLContext
;
725 _XDisplay
* mXDisplay
;
727 base::Thread mVsyncThread
;
728 RefPtr
<Runnable
> mVsyncTask
;
729 Monitor mVsyncEnabledLock
;
732 bool mIsWaylandDisplay
;
737 // We need a refcounted VsyncSource::Display to use chromium IPC runnables.
738 RefPtr
<GLXDisplay
> mGlobalDisplay
;
741 already_AddRefed
<gfx::VsyncSource
> gfxPlatformGtk::CreateHardwareVsyncSource() {
743 if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
744 RefPtr
<VsyncSource
> vsyncSource
= new GtkVsyncSource();
745 VsyncSource::Display
& display
= vsyncSource
->GetGlobalDisplay();
746 static_cast<GtkVsyncSource::GLXDisplay
&>(display
).SetupWayland();
747 return vsyncSource
.forget();
751 // Only use GLX vsync when the OpenGL compositor is being used.
752 // The extra cost of initializing a GLX context while blocking the main
753 // thread is not worth it when using basic composition.
754 if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING
)) {
755 if (gl::sGLXLibrary
.SupportsVideoSync()) {
756 RefPtr
<VsyncSource
> vsyncSource
= new GtkVsyncSource();
757 VsyncSource::Display
& display
= vsyncSource
->GetGlobalDisplay();
758 if (!static_cast<GtkVsyncSource::GLXDisplay
&>(display
).Setup()) {
760 "Failed to setup GLContext, falling back to software vsync.");
761 return gfxPlatform::CreateHardwareVsyncSource();
763 return vsyncSource
.forget();
765 NS_WARNING("SGI_video_sync unsupported. Falling back to software vsync.");
767 return gfxPlatform::CreateHardwareVsyncSource();