gl_surface_glx.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/gl_surface_glx.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/command_line.h"
  8. #include "base/lazy_instance.h"
  9. #include "base/logging.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/memory/weak_ptr.h"
  12. #include "base/no_destructor.h"
  13. #include "base/synchronization/atomic_flag.h"
  14. #include "base/synchronization/lock.h"
  15. #include "base/task/single_thread_task_runner.h"
  16. #include "base/threading/thread.h"
  17. #include "base/threading/thread_checker.h"
  18. #include "base/threading/thread_task_runner_handle.h"
  19. #include "base/time/time.h"
  20. #include "base/trace_event/trace_event.h"
  21. #include "build/build_config.h"
  22. #include "ui/base/x/visual_picker_glx.h"
  23. #include "ui/base/x/x11_display_util.h"
  24. #include "ui/base/x/x11_util.h"
  25. #include "ui/base/x/x11_xrandr_interval_only_vsync_provider.h"
  26. #include "ui/events/platform/platform_event_source.h"
  27. #include "ui/gfx/native_widget_types.h"
  28. #include "ui/gfx/x/xproto_util.h"
  29. #include "ui/gl/gl_bindings.h"
  30. #include "ui/gl/gl_context.h"
  31. #include "ui/gl/gl_display.h"
  32. #include "ui/gl/gl_display_manager.h"
  33. #include "ui/gl/gl_implementation.h"
  34. #include "ui/gl/gl_surface_presentation_helper.h"
  35. #include "ui/gl/glx_util.h"
  36. #include "ui/gl/sync_control_vsync_provider.h"
  37. namespace gl {
  38. namespace {
  39. bool g_glx_context_create = false;
  40. bool g_glx_create_context_robustness_supported = false;
  41. bool g_glx_robustness_video_memory_purge_supported = false;
  42. bool g_glx_create_context_profile_supported = false;
  43. bool g_glx_create_context_profile_es2_supported = false;
  44. bool g_glx_texture_from_pixmap_supported = false;
  45. bool g_glx_oml_sync_control_supported = false;
  46. // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a
  47. // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML
  48. // always fails even though GLX_OML_sync_control is reported as being supported.
  49. bool g_glx_get_msc_rate_oml_supported = false;
  50. bool g_glx_ext_swap_control_supported = false;
  51. bool g_glx_mesa_swap_control_supported = false;
  52. bool g_glx_sgi_video_sync_supported = false;
  53. // A 24-bit RGB visual and colormap to use when creating offscreen surfaces.
  54. x11::VisualId g_visual{};
  55. int g_depth = static_cast<int>(x11::WindowClass::CopyFromParent);
  56. x11::ColorMap g_colormap{};
  57. bool CreateDummyWindow(x11::Connection* conn) {
  58. DCHECK(conn);
  59. auto parent_window = conn->default_root();
  60. auto window = conn->GenerateId<x11::Window>();
  61. auto create_window = conn->CreateWindow(x11::CreateWindowRequest{
  62. .wid = window,
  63. .parent = parent_window,
  64. .width = 1,
  65. .height = 1,
  66. .c_class = x11::WindowClass::InputOutput,
  67. });
  68. if (create_window.Sync().error) {
  69. LOG(ERROR) << "Failed to create window";
  70. return false;
  71. }
  72. GLXFBConfig config = GetFbConfigForWindow(conn, window);
  73. if (!config) {
  74. LOG(ERROR) << "Failed to get GLXConfig";
  75. conn->DestroyWindow({window});
  76. return false;
  77. }
  78. GLXWindow glx_window = glXCreateWindow(
  79. conn->GetXlibDisplay(), config, static_cast<uint32_t>(window), nullptr);
  80. if (!glx_window) {
  81. LOG(ERROR) << "glXCreateWindow failed";
  82. conn->DestroyWindow({window});
  83. return false;
  84. }
  85. glXDestroyWindow(conn->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  86. glx_window);
  87. conn->DestroyWindow({window});
  88. return true;
  89. }
  90. class OMLSyncControlVSyncProvider : public SyncControlVSyncProvider {
  91. public:
  92. explicit OMLSyncControlVSyncProvider(GLXWindow glx_window)
  93. : SyncControlVSyncProvider(), glx_window_(glx_window) {}
  94. OMLSyncControlVSyncProvider(const OMLSyncControlVSyncProvider&) = delete;
  95. OMLSyncControlVSyncProvider& operator=(const OMLSyncControlVSyncProvider&) =
  96. delete;
  97. ~OMLSyncControlVSyncProvider() override = default;
  98. protected:
  99. bool GetSyncValues(int64_t* system_time,
  100. int64_t* media_stream_counter,
  101. int64_t* swap_buffer_counter) override {
  102. x11::Connection::Get()->Flush();
  103. return glXGetSyncValuesOML(x11::Connection::Get()->GetXlibDisplay(),
  104. glx_window_, system_time, media_stream_counter,
  105. swap_buffer_counter);
  106. }
  107. bool GetMscRate(int32_t* numerator, int32_t* denominator) override {
  108. if (!g_glx_get_msc_rate_oml_supported)
  109. return false;
  110. if (!glXGetMscRateOML(x11::Connection::Get()->GetXlibDisplay(), glx_window_,
  111. numerator, denominator)) {
  112. // Once glXGetMscRateOML has been found to fail, don't try again,
  113. // since each failing call may spew an error message.
  114. g_glx_get_msc_rate_oml_supported = false;
  115. return false;
  116. }
  117. return true;
  118. }
  119. bool IsHWClock() const override { return true; }
  120. private:
  121. GLXWindow glx_window_;
  122. };
  123. class SGIVideoSyncThread : public base::Thread,
  124. public base::RefCounted<SGIVideoSyncThread> {
  125. public:
  126. // Create a connection to the X server for use on g_video_sync_thread before
  127. // the sandbox starts.
  128. static bool InitializeBeforeSandboxStarts() {
  129. auto* connection = GetConnectionImpl();
  130. if (!connection || !connection->Ready())
  131. return false;
  132. if (!CreateDummyWindow(connection)) {
  133. LOG(ERROR) << "CreateDummyWindow(display) failed";
  134. return false;
  135. }
  136. connection->DetachFromSequence();
  137. return true;
  138. }
  139. static scoped_refptr<SGIVideoSyncThread> Create() {
  140. if (!g_video_sync_thread) {
  141. g_video_sync_thread = new SGIVideoSyncThread();
  142. g_video_sync_thread->Start();
  143. }
  144. return g_video_sync_thread;
  145. }
  146. SGIVideoSyncThread(const SGIVideoSyncThread&) = delete;
  147. SGIVideoSyncThread& operator=(const SGIVideoSyncThread&) = delete;
  148. x11::Connection* GetConnection() {
  149. DCHECK(task_runner()->BelongsToCurrentThread());
  150. return GetConnectionImpl();
  151. }
  152. void MaybeCreateGLXContext(GLXFBConfig config) {
  153. DCHECK(task_runner()->BelongsToCurrentThread());
  154. if (!context_) {
  155. context_ = glXCreateNewContext(
  156. GetConnection()->GetXlibDisplay(x11::XlibDisplayType::kSyncing),
  157. config, GLX_RGBA_TYPE, nullptr, true);
  158. }
  159. LOG_IF(ERROR, !context_) << "video_sync: glXCreateNewContext failed";
  160. }
  161. // Destroy |context_| on the thread where it is used.
  162. void CleanUp() override {
  163. DCHECK(task_runner()->BelongsToCurrentThread());
  164. if (context_)
  165. glXDestroyContext(
  166. GetConnection()->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  167. context_);
  168. // Release the connection from this thread's sequence so that a new
  169. // SGIVideoSyncThread can reuse the connection. The connection must be
  170. // reused since it can only be created before sandbox initialization.
  171. GetConnection()->DetachFromSequence();
  172. }
  173. GLXContext GetGLXContext() {
  174. DCHECK(task_runner()->BelongsToCurrentThread());
  175. return context_;
  176. }
  177. private:
  178. friend class base::RefCounted<SGIVideoSyncThread>;
  179. SGIVideoSyncThread() : base::Thread("SGI_video_sync") {
  180. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  181. }
  182. ~SGIVideoSyncThread() override {
  183. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  184. g_video_sync_thread = nullptr;
  185. Stop();
  186. }
  187. static x11::Connection* GetConnectionImpl() {
  188. if (!g_connection)
  189. g_connection = x11::Connection::Get()->Clone().release();
  190. return g_connection;
  191. }
  192. static SGIVideoSyncThread* g_video_sync_thread;
  193. static x11::Connection* g_connection;
  194. GLXContext context_ = nullptr;
  195. THREAD_CHECKER(thread_checker_);
  196. };
  197. class SGIVideoSyncProviderThreadShim {
  198. public:
  199. SGIVideoSyncProviderThreadShim(gfx::AcceleratedWidget parent_window,
  200. SGIVideoSyncThread* vsync_thread)
  201. : parent_window_(parent_window),
  202. vsync_thread_(vsync_thread),
  203. glx_window_(0),
  204. task_runner_(base::ThreadTaskRunnerHandle::Get()),
  205. cancel_vsync_flag_(),
  206. vsync_lock_() {
  207. // This ensures that creation of |parent_window_| has occured when this shim
  208. // is executing in the same thread as the call to create |parent_window_|.
  209. x11::Connection::Get()->Sync();
  210. }
  211. SGIVideoSyncProviderThreadShim(const SGIVideoSyncProviderThreadShim&) =
  212. delete;
  213. SGIVideoSyncProviderThreadShim& operator=(
  214. const SGIVideoSyncProviderThreadShim&) = delete;
  215. ~SGIVideoSyncProviderThreadShim() {
  216. auto* connection = vsync_thread_->GetConnection();
  217. if (glx_window_) {
  218. glXDestroyWindow(
  219. connection->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  220. glx_window_);
  221. }
  222. if (window_ != x11::Window::None)
  223. connection->DestroyWindow({window_});
  224. }
  225. base::AtomicFlag* cancel_vsync_flag() { return &cancel_vsync_flag_; }
  226. base::Lock* vsync_lock() { return &vsync_lock_; }
  227. void Initialize() {
  228. auto* connection = vsync_thread_->GetConnection();
  229. DCHECK(connection);
  230. auto window = connection->GenerateId<x11::Window>();
  231. auto req = connection->CreateWindow(x11::CreateWindowRequest{
  232. .wid = window,
  233. .parent = static_cast<x11::Window>(parent_window_),
  234. .width = 1,
  235. .height = 1,
  236. .c_class = x11::WindowClass::InputOutput,
  237. });
  238. if (req.Sync().error) {
  239. LOG(ERROR) << "video_sync: XCreateWindow failed";
  240. return;
  241. }
  242. window_ = window;
  243. GLXFBConfig config = GetFbConfigForWindow(connection, window_);
  244. if (!config) {
  245. LOG(ERROR) << "video_sync: Failed to get GLXConfig";
  246. return;
  247. }
  248. glx_window_ = glXCreateWindow(
  249. connection->GetXlibDisplay(x11::XlibDisplayType::kSyncing), config,
  250. static_cast<uint32_t>(window_), nullptr);
  251. if (!glx_window_) {
  252. LOG(ERROR) << "video_sync: glXCreateWindow failed";
  253. return;
  254. }
  255. vsync_thread_->MaybeCreateGLXContext(config);
  256. }
  257. void GetVSyncParameters(gfx::VSyncProvider::UpdateVSyncCallback callback) {
  258. // Don't allow |window_| destruction while we're probing vsync.
  259. base::AutoLock locked(vsync_lock_);
  260. if (!vsync_thread_->GetGLXContext() || cancel_vsync_flag_.IsSet())
  261. return;
  262. base::TimeDelta interval = ui::GetPrimaryDisplayRefreshIntervalFromXrandr();
  263. auto* connection = vsync_thread_->GetConnection();
  264. glXMakeContextCurrent(
  265. connection->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  266. glx_window_, glx_window_, vsync_thread_->GetGLXContext());
  267. unsigned int retrace_count = 0;
  268. if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0)
  269. return;
  270. base::TimeTicks now = base::TimeTicks::Now();
  271. TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD);
  272. glXMakeContextCurrent(
  273. connection->GetXlibDisplay(x11::XlibDisplayType::kFlushing), 0, 0,
  274. nullptr);
  275. task_runner_->PostTask(FROM_HERE,
  276. base::BindOnce(std::move(callback), now, interval));
  277. }
  278. private:
  279. gfx::AcceleratedWidget parent_window_;
  280. raw_ptr<SGIVideoSyncThread> vsync_thread_;
  281. x11::Window window_ = x11::Window::None;
  282. GLXWindow glx_window_;
  283. scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
  284. base::AtomicFlag cancel_vsync_flag_;
  285. base::Lock vsync_lock_;
  286. };
  287. class SGIVideoSyncVSyncProvider
  288. : public gfx::VSyncProvider,
  289. public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> {
  290. public:
  291. explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget parent_window)
  292. : vsync_thread_(SGIVideoSyncThread::Create()),
  293. shim_(new SGIVideoSyncProviderThreadShim(parent_window,
  294. vsync_thread_.get())),
  295. cancel_vsync_flag_(shim_->cancel_vsync_flag()),
  296. vsync_lock_(shim_->vsync_lock()) {
  297. vsync_thread_->task_runner()->PostTask(
  298. FROM_HERE, base::BindOnce(&SGIVideoSyncProviderThreadShim::Initialize,
  299. base::Unretained(shim_.get())));
  300. }
  301. SGIVideoSyncVSyncProvider(const SGIVideoSyncVSyncProvider&) = delete;
  302. SGIVideoSyncVSyncProvider& operator=(const SGIVideoSyncVSyncProvider&) =
  303. delete;
  304. ~SGIVideoSyncVSyncProvider() override {
  305. {
  306. base::AutoLock locked(*vsync_lock_);
  307. cancel_vsync_flag_->Set();
  308. }
  309. // Hand-off |shim_| to be deleted on the |vsync_thread_|.
  310. vsync_thread_->task_runner()->DeleteSoon(FROM_HERE, shim_.release());
  311. }
  312. void GetVSyncParameters(
  313. gfx::VSyncProvider::UpdateVSyncCallback callback) override {
  314. // Only one outstanding request per surface.
  315. if (!pending_callback_) {
  316. DCHECK(callback);
  317. pending_callback_ = std::move(callback);
  318. vsync_thread_->task_runner()->PostTask(
  319. FROM_HERE,
  320. base::BindOnce(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
  321. base::Unretained(shim_.get()),
  322. base::BindRepeating(
  323. &SGIVideoSyncVSyncProvider::PendingCallbackRunner,
  324. AsWeakPtr())));
  325. }
  326. }
  327. bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
  328. base::TimeDelta* interval) override {
  329. return false;
  330. }
  331. bool SupportGetVSyncParametersIfAvailable() const override { return false; }
  332. bool IsHWClock() const override { return false; }
  333. private:
  334. void PendingCallbackRunner(const base::TimeTicks timebase,
  335. const base::TimeDelta interval) {
  336. DCHECK(pending_callback_);
  337. std::move(pending_callback_).Run(timebase, interval);
  338. }
  339. scoped_refptr<SGIVideoSyncThread> vsync_thread_;
  340. // Thread shim through which the sync provider is accessed on |vsync_thread_|.
  341. std::unique_ptr<SGIVideoSyncProviderThreadShim> shim_;
  342. gfx::VSyncProvider::UpdateVSyncCallback pending_callback_;
  343. // Raw pointers to sync primitives owned by the shim_.
  344. // These will only be referenced before we post a task to destroy
  345. // the shim_, so they are safe to access.
  346. raw_ptr<base::AtomicFlag> cancel_vsync_flag_;
  347. raw_ptr<base::Lock> vsync_lock_;
  348. };
  349. SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = nullptr;
  350. x11::Connection* SGIVideoSyncThread::g_connection = nullptr;
  351. } // namespace
  352. bool GLSurfaceGLX::initialized_ = false;
  353. GLSurfaceGLX::GLSurfaceGLX() {
  354. display_ =
  355. GLDisplayManagerX11::GetInstance()->GetDisplay(GpuPreference::kDefault);
  356. }
  357. bool GLSurfaceGLX::InitializeOneOff() {
  358. if (initialized_)
  359. return true;
  360. // http://crbug.com/245466
  361. setenv("force_s3tc_enable", "true", 1);
  362. if (!x11::Connection::Get()->Ready()) {
  363. LOG(ERROR) << "Could not open X11 connection.";
  364. return false;
  365. }
  366. int major = 0, minor = 0;
  367. if (!glXQueryVersion(x11::Connection::Get()->GetXlibDisplay(), &major,
  368. &minor)) {
  369. LOG(ERROR) << "glxQueryVersion failed";
  370. return false;
  371. }
  372. if (major == 1 && minor < 3) {
  373. LOG(ERROR) << "GLX 1.3 or later is required.";
  374. return false;
  375. }
  376. auto* visual_picker = ui::VisualPickerGlx::GetInstance();
  377. auto visual_id = visual_picker->rgba_visual();
  378. if (visual_id == x11::VisualId{})
  379. visual_id = visual_picker->system_visual();
  380. g_visual = visual_id;
  381. auto* connection = x11::Connection::Get();
  382. g_depth = connection->GetVisualInfoFromId(visual_id)->format->depth;
  383. g_colormap = connection->GenerateId<x11::ColorMap>();
  384. connection->CreateColormap({x11::ColormapAlloc::None, g_colormap,
  385. connection->default_root(), g_visual});
  386. // We create a dummy unmapped window for both the main Display and the video
  387. // sync Display so that the Nvidia driver can initialize itself before the
  388. // sandbox is set up.
  389. // Unfortunately some fds e.g. /dev/nvidia0 are cached per thread and because
  390. // we can't start threads before the sandbox is set up, these are accessed
  391. // through the broker process. See GpuProcessPolicy::InitGpuBrokerProcess.
  392. if (!CreateDummyWindow(x11::Connection::Get())) {
  393. LOG(ERROR) << "CreateDummyWindow() failed";
  394. return false;
  395. }
  396. initialized_ = true;
  397. return true;
  398. }
  399. // static
  400. bool GLSurfaceGLX::InitializeExtensionSettingsOneOff() {
  401. if (!initialized_)
  402. return false;
  403. g_driver_glx.InitializeExtensionBindings();
  404. g_glx_context_create = HasGLXExtension("GLX_ARB_create_context");
  405. g_glx_create_context_robustness_supported =
  406. HasGLXExtension("GLX_ARB_create_context_robustness");
  407. g_glx_robustness_video_memory_purge_supported =
  408. HasGLXExtension("GLX_NV_robustness_video_memory_purge");
  409. g_glx_create_context_profile_supported =
  410. HasGLXExtension("GLX_ARB_create_context_profile");
  411. g_glx_create_context_profile_es2_supported =
  412. HasGLXExtension("GLX_ARB_create_context_es2_profile");
  413. g_glx_texture_from_pixmap_supported =
  414. HasGLXExtension("GLX_EXT_texture_from_pixmap");
  415. g_glx_oml_sync_control_supported = HasGLXExtension("GLX_OML_sync_control");
  416. g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported;
  417. g_glx_ext_swap_control_supported = HasGLXExtension("GLX_EXT_swap_control");
  418. g_glx_mesa_swap_control_supported = HasGLXExtension("GLX_MESA_swap_control");
  419. g_glx_sgi_video_sync_supported = HasGLXExtension("GLX_SGI_video_sync");
  420. if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported) {
  421. if (!SGIVideoSyncThread::InitializeBeforeSandboxStarts())
  422. return false;
  423. }
  424. return true;
  425. }
  426. // static
  427. void GLSurfaceGLX::ShutdownOneOff() {
  428. initialized_ = false;
  429. g_glx_context_create = false;
  430. g_glx_create_context_robustness_supported = false;
  431. g_glx_robustness_video_memory_purge_supported = false;
  432. g_glx_create_context_profile_supported = false;
  433. g_glx_create_context_profile_es2_supported = false;
  434. g_glx_texture_from_pixmap_supported = false;
  435. g_glx_oml_sync_control_supported = false;
  436. g_glx_get_msc_rate_oml_supported = false;
  437. g_glx_ext_swap_control_supported = false;
  438. g_glx_mesa_swap_control_supported = false;
  439. g_glx_sgi_video_sync_supported = false;
  440. g_visual = {};
  441. g_depth = static_cast<int>(x11::WindowClass::CopyFromParent);
  442. g_colormap = {};
  443. }
  444. // static
  445. std::string GLSurfaceGLX::QueryGLXExtensions() {
  446. auto* connection = x11::Connection::Get();
  447. const int screen = connection ? connection->DefaultScreenId() : 0;
  448. const char* extensions =
  449. glXQueryExtensionsString(connection->GetXlibDisplay(), screen);
  450. if (extensions)
  451. return std::string(extensions);
  452. return "";
  453. }
  454. // static
  455. const char* GLSurfaceGLX::GetGLXExtensions() {
  456. static base::NoDestructor<std::string> glx_extensions("");
  457. if (glx_extensions->empty()) {
  458. *glx_extensions = QueryGLXExtensions();
  459. }
  460. return glx_extensions->c_str();
  461. }
  462. // static
  463. bool GLSurfaceGLX::HasGLXExtension(const char* name) {
  464. return ExtensionsContain(GetGLXExtensions(), name);
  465. }
  466. // static
  467. bool GLSurfaceGLX::IsCreateContextSupported() {
  468. return g_glx_context_create;
  469. }
  470. // static
  471. bool GLSurfaceGLX::IsCreateContextRobustnessSupported() {
  472. return g_glx_create_context_robustness_supported;
  473. }
  474. // static
  475. bool GLSurfaceGLX::IsRobustnessVideoMemoryPurgeSupported() {
  476. return g_glx_robustness_video_memory_purge_supported;
  477. }
  478. // static
  479. bool GLSurfaceGLX::IsCreateContextProfileSupported() {
  480. return g_glx_create_context_profile_supported;
  481. }
  482. // static
  483. bool GLSurfaceGLX::IsCreateContextES2ProfileSupported() {
  484. return g_glx_create_context_profile_es2_supported;
  485. }
  486. // static
  487. bool GLSurfaceGLX::IsTextureFromPixmapSupported() {
  488. return g_glx_texture_from_pixmap_supported;
  489. }
  490. // static
  491. bool GLSurfaceGLX::IsEXTSwapControlSupported() {
  492. return g_glx_ext_swap_control_supported;
  493. }
  494. // static
  495. bool GLSurfaceGLX::IsMESASwapControlSupported() {
  496. return g_glx_mesa_swap_control_supported;
  497. }
  498. // static
  499. bool GLSurfaceGLX::IsOMLSyncControlSupported() {
  500. return g_glx_oml_sync_control_supported;
  501. }
  502. GLDisplay* GLSurfaceGLX::GetGLDisplay() {
  503. return display_;
  504. }
  505. GLSurfaceGLX::~GLSurfaceGLX() = default;
  506. NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
  507. : parent_window_(window),
  508. window_(x11::Window::None),
  509. glx_window_(),
  510. config_(nullptr),
  511. has_swapped_buffers_(false) {}
  512. bool NativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
  513. auto* conn = x11::Connection::Get();
  514. auto parent = static_cast<x11::Window>(parent_window_);
  515. auto attributes_req = conn->GetWindowAttributes({parent});
  516. auto geometry_req = conn->GetGeometry(parent);
  517. conn->Flush();
  518. auto attributes = attributes_req.Sync();
  519. auto geometry = geometry_req.Sync();
  520. if (!attributes || !geometry) {
  521. LOG(ERROR) << "GetGeometry/GetWindowAttribues failed for window "
  522. << static_cast<uint32_t>(parent_window_) << ".";
  523. return false;
  524. }
  525. size_ = gfx::Size(geometry->width, geometry->height);
  526. window_ = conn->GenerateId<x11::Window>();
  527. x11::CreateWindowRequest req{
  528. .depth = static_cast<uint8_t>(g_depth),
  529. .wid = window_,
  530. .parent = static_cast<x11::Window>(parent_window_),
  531. .width = static_cast<uint16_t>(size_.width()),
  532. .height = static_cast<uint16_t>(size_.height()),
  533. .c_class = x11::WindowClass::InputOutput,
  534. .visual = g_visual,
  535. .background_pixmap = x11::Pixmap::None,
  536. .border_pixel = 0,
  537. .bit_gravity = x11::Gravity::NorthWest,
  538. .colormap = g_colormap,
  539. };
  540. if (ui::IsCompositingManagerPresent() && attributes->visual == g_visual) {
  541. // When parent and child are using the same visual, the back buffer will be
  542. // shared between parent and child. If WM compositing is enabled, we set
  543. // child's background pixel to ARGB(0,0,0,0), so ARGB(0,0,0,0) will be
  544. // filled to the shared buffer, when the child window is mapped. It can
  545. // avoid an annoying flash when the child window is mapped below.
  546. // If WM compositing is disabled, we don't set the background pixel, so
  547. // nothing will be draw when the child window is mapped.
  548. req.background_pixel = 0; // ARGB(0,0,0,0) for compositing WM
  549. }
  550. conn->CreateWindow(req);
  551. conn->MapWindow({window_});
  552. RegisterEvents();
  553. conn->Sync();
  554. GetConfig();
  555. if (!config_) {
  556. LOG(ERROR) << "Failed to get GLXConfig";
  557. return false;
  558. }
  559. glx_window_ = static_cast<x11::Glx::Window>(
  560. glXCreateWindow(conn->GetXlibDisplay(x11::XlibDisplayType::kSyncing),
  561. config_, static_cast<uint32_t>(window_), nullptr));
  562. if (!GetDrawableHandle()) {
  563. LOG(ERROR) << "glXCreateWindow failed";
  564. return false;
  565. }
  566. if (g_glx_oml_sync_control_supported) {
  567. vsync_provider_ = std::make_unique<OMLSyncControlVSyncProvider>(
  568. static_cast<GLXWindow>(glx_window_));
  569. presentation_helper_ =
  570. std::make_unique<GLSurfacePresentationHelper>(vsync_provider_.get());
  571. } else if (g_glx_sgi_video_sync_supported) {
  572. vsync_provider_ =
  573. std::make_unique<SGIVideoSyncVSyncProvider>(parent_window_);
  574. presentation_helper_ =
  575. std::make_unique<GLSurfacePresentationHelper>(vsync_provider_.get());
  576. } else {
  577. vsync_provider_ = std::make_unique<ui::XrandrIntervalOnlyVSyncProvider>();
  578. presentation_helper_ = std::make_unique<GLSurfacePresentationHelper>(
  579. base::TimeTicks(), ui::GetPrimaryDisplayRefreshIntervalFromXrandr());
  580. }
  581. return true;
  582. }
  583. void NativeViewGLSurfaceGLX::Destroy() {
  584. presentation_helper_ = nullptr;
  585. vsync_provider_ = nullptr;
  586. if (GetDrawableHandle()) {
  587. glXDestroyWindow(
  588. x11::Connection::Get()->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  589. GetDrawableHandle());
  590. glx_window_ = {};
  591. }
  592. if (window_ != x11::Window::None) {
  593. UnregisterEvents();
  594. x11::Connection::Get()->DestroyWindow({window_});
  595. window_ = x11::Window::None;
  596. x11::Connection::Get()->Flush();
  597. }
  598. }
  599. bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size,
  600. float scale_factor,
  601. const gfx::ColorSpace& color_space,
  602. bool has_alpha) {
  603. size_ = size;
  604. glXWaitGL();
  605. x11::Connection::Get()->ConfigureWindow(
  606. {.window = window_, .width = size.width(), .height = size.height()});
  607. glXWaitX();
  608. return true;
  609. }
  610. bool NativeViewGLSurfaceGLX::IsOffscreen() {
  611. return false;
  612. }
  613. gfx::SwapResult NativeViewGLSurfaceGLX::SwapBuffers(
  614. PresentationCallback callback) {
  615. TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers", "width",
  616. GetSize().width(), "height", GetSize().height());
  617. GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
  618. presentation_helper_.get(), std::move(callback));
  619. auto* connection = x11::Connection::Get();
  620. glXSwapBuffers(connection->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  621. GetDrawableHandle());
  622. // We need to restore the background pixel that we set to WhitePixel on
  623. // views::DesktopWindowTreeHostX11::InitX11Window back to None for the
  624. // XWindow associated to this surface after the first SwapBuffers has
  625. // happened, to avoid showing a weird white background while resizing.
  626. if (!has_swapped_buffers_) {
  627. connection->ChangeWindowAttributes({
  628. .window = static_cast<x11::Window>(parent_window_),
  629. .background_pixmap = x11::Pixmap::None,
  630. });
  631. has_swapped_buffers_ = true;
  632. }
  633. return scoped_swap_buffers.result();
  634. }
  635. gfx::Size NativeViewGLSurfaceGLX::GetSize() {
  636. return size_;
  637. }
  638. void* NativeViewGLSurfaceGLX::GetHandle() {
  639. return reinterpret_cast<void*>(GetDrawableHandle());
  640. }
  641. bool NativeViewGLSurfaceGLX::SupportsPostSubBuffer() {
  642. return g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer;
  643. }
  644. void* NativeViewGLSurfaceGLX::GetConfig() {
  645. if (!config_)
  646. config_ = GetFbConfigForWindow(x11::Connection::Get(), window_);
  647. return config_;
  648. }
  649. GLSurfaceFormat NativeViewGLSurfaceGLX::GetFormat() {
  650. return GLSurfaceFormat();
  651. }
  652. gfx::SwapResult NativeViewGLSurfaceGLX::PostSubBuffer(
  653. int x,
  654. int y,
  655. int width,
  656. int height,
  657. PresentationCallback callback) {
  658. DCHECK(g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
  659. GLSurfacePresentationHelper::ScopedSwapBuffers scoped_swap_buffers(
  660. presentation_helper_.get(), std::move(callback));
  661. glXCopySubBufferMESA(
  662. x11::Connection::Get()->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  663. GetDrawableHandle(), x, y, width, height);
  664. return scoped_swap_buffers.result();
  665. }
  666. bool NativeViewGLSurfaceGLX::OnMakeCurrent(GLContext* context) {
  667. presentation_helper_->OnMakeCurrent(context, this);
  668. return GLSurfaceGLX::OnMakeCurrent(context);
  669. }
  670. gfx::VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
  671. return vsync_provider_.get();
  672. }
  673. void NativeViewGLSurfaceGLX::SetVSyncEnabled(bool enabled) {
  674. DCHECK(GLContext::GetCurrent() && GLContext::GetCurrent()->IsCurrent(this));
  675. int interval = enabled ? 1 : 0;
  676. if (GLSurfaceGLX::IsEXTSwapControlSupported()) {
  677. glXSwapIntervalEXT(
  678. x11::Connection::Get()->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  679. GetDrawableHandle(), interval);
  680. } else if (GLSurfaceGLX::IsMESASwapControlSupported()) {
  681. glXSwapIntervalMESA(interval);
  682. } else if (interval == 0) {
  683. LOG(WARNING)
  684. << "Could not disable vsync: driver does not support swap control";
  685. }
  686. }
  687. NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
  688. Destroy();
  689. }
  690. void NativeViewGLSurfaceGLX::ForwardExposeEvent(const x11::Event& event) {
  691. auto forwarded_event = *event.As<x11::ExposeEvent>();
  692. auto window = static_cast<x11::Window>(parent_window_);
  693. forwarded_event.window = window;
  694. x11::SendEvent(forwarded_event, window, x11::EventMask::Exposure);
  695. x11::Connection::Get()->Flush();
  696. }
  697. bool NativeViewGLSurfaceGLX::CanHandleEvent(const x11::Event& x11_event) {
  698. auto* expose = x11_event.As<x11::ExposeEvent>();
  699. return expose && expose->window == static_cast<x11::Window>(window_);
  700. }
  701. uint32_t NativeViewGLSurfaceGLX::GetDrawableHandle() const {
  702. return static_cast<uint32_t>(glx_window_);
  703. }
  704. UnmappedNativeViewGLSurfaceGLX::UnmappedNativeViewGLSurfaceGLX(
  705. const gfx::Size& size)
  706. : size_(size), config_(nullptr), window_(x11::Window::None), glx_window_() {
  707. // Ensure that we don't create a window with zero size.
  708. if (size_.GetArea() == 0)
  709. size_.SetSize(1, 1);
  710. }
  711. bool UnmappedNativeViewGLSurfaceGLX::Initialize(GLSurfaceFormat format) {
  712. DCHECK_EQ(window_, x11::Window::None);
  713. auto parent_window = ui::GetX11RootWindow();
  714. auto* conn = x11::Connection::Get();
  715. window_ = conn->GenerateId<x11::Window>();
  716. conn->CreateWindow(x11::CreateWindowRequest{
  717. .depth = static_cast<uint8_t>(g_depth),
  718. .wid = window_,
  719. .parent = parent_window,
  720. .width = static_cast<uint16_t>(size_.width()),
  721. .height = static_cast<uint16_t>(size_.height()),
  722. .c_class = x11::WindowClass::InputOutput,
  723. .visual = g_visual,
  724. .border_pixel = 0,
  725. .colormap = g_colormap,
  726. })
  727. .Sync();
  728. GetConfig();
  729. if (!config_) {
  730. LOG(ERROR) << "Failed to get GLXConfig";
  731. return false;
  732. }
  733. glx_window_ = static_cast<x11::Glx::Window>(
  734. glXCreateWindow(conn->GetXlibDisplay(x11::XlibDisplayType::kSyncing),
  735. config_, static_cast<uint32_t>(window_), nullptr));
  736. if (glx_window_ == x11::Glx::Window{}) {
  737. LOG(ERROR) << "glXCreateWindow failed";
  738. return false;
  739. }
  740. return true;
  741. }
  742. void UnmappedNativeViewGLSurfaceGLX::Destroy() {
  743. config_ = nullptr;
  744. if (glx_window_ != x11::Glx::Window{}) {
  745. glXDestroyWindow(
  746. x11::Connection::Get()->GetXlibDisplay(x11::XlibDisplayType::kFlushing),
  747. static_cast<uint32_t>(glx_window_));
  748. glx_window_ = {};
  749. }
  750. if (window_ != x11::Window::None) {
  751. x11::Connection::Get()->DestroyWindow({window_});
  752. window_ = x11::Window::None;
  753. }
  754. }
  755. bool UnmappedNativeViewGLSurfaceGLX::IsOffscreen() {
  756. return true;
  757. }
  758. gfx::SwapResult UnmappedNativeViewGLSurfaceGLX::SwapBuffers(
  759. PresentationCallback callback) {
  760. NOTREACHED() << "Attempted to call SwapBuffers on an unmapped window.";
  761. return gfx::SwapResult::SWAP_FAILED;
  762. }
  763. gfx::Size UnmappedNativeViewGLSurfaceGLX::GetSize() {
  764. return size_;
  765. }
  766. void* UnmappedNativeViewGLSurfaceGLX::GetHandle() {
  767. return reinterpret_cast<void*>(glx_window_);
  768. }
  769. void* UnmappedNativeViewGLSurfaceGLX::GetConfig() {
  770. if (!config_)
  771. config_ = GetFbConfigForWindow(x11::Connection::Get(), window_);
  772. return config_;
  773. }
  774. GLSurfaceFormat UnmappedNativeViewGLSurfaceGLX::GetFormat() {
  775. return GLSurfaceFormat();
  776. }
  777. UnmappedNativeViewGLSurfaceGLX::~UnmappedNativeViewGLSurfaceGLX() {
  778. Destroy();
  779. }
  780. } // namespace gl