Move content_settings_pattern and content_settings_pattern_parser to the content_sett...
[chromium-blink-merge.git] / ui / gl / gl_surface_glx.cc
blobb131b380a61dbcaf2b257b0a18a6844732164200
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.
5 extern "C" {
6 #include <X11/Xlib.h>
9 #include "ui/gl/gl_surface_glx.h"
11 #include "base/basictypes.h"
12 #include "base/debug/trace_event.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/synchronization/cancellation_flag.h"
20 #include "base/synchronization/lock.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "base/threading/non_thread_safe.h"
23 #include "base/threading/thread.h"
24 #include "base/time/time.h"
25 #include "ui/events/platform/platform_event_source.h"
26 #include "ui/gfx/x/x11_connection.h"
27 #include "ui/gfx/x/x11_types.h"
28 #include "ui/gl/gl_bindings.h"
29 #include "ui/gl/gl_implementation.h"
30 #include "ui/gl/sync_control_vsync_provider.h"
32 namespace gfx {
34 namespace {
36 // scoped_ptr functor for XFree(). Use as follows:
37 // scoped_ptr<XVisualInfo, ScopedPtrXFree> foo(...);
38 // where "XVisualInfo" is any X type that is freed with XFree.
39 struct ScopedPtrXFree {
40 void operator()(void* x) const {
41 ::XFree(x);
45 Display* g_display = NULL;
46 const char* g_glx_extensions = NULL;
47 bool g_glx_context_create = false;
48 bool g_glx_create_context_robustness_supported = false;
49 bool g_glx_texture_from_pixmap_supported = false;
50 bool g_glx_oml_sync_control_supported = false;
52 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a
53 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML
54 // always fails even though GLX_OML_sync_control is reported as being supported.
55 bool g_glx_get_msc_rate_oml_supported = false;
57 bool g_glx_sgi_video_sync_supported = false;
59 class OMLSyncControlVSyncProvider
60 : public gfx::SyncControlVSyncProvider {
61 public:
62 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window)
63 : SyncControlVSyncProvider(),
64 window_(window) {
67 virtual ~OMLSyncControlVSyncProvider() { }
69 protected:
70 virtual bool GetSyncValues(int64* system_time,
71 int64* media_stream_counter,
72 int64* swap_buffer_counter) OVERRIDE {
73 return glXGetSyncValuesOML(g_display, window_, system_time,
74 media_stream_counter, swap_buffer_counter);
77 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
78 if (!g_glx_get_msc_rate_oml_supported)
79 return false;
81 if (!glXGetMscRateOML(g_display, window_, numerator, denominator)) {
82 // Once glXGetMscRateOML has been found to fail, don't try again,
83 // since each failing call may spew an error message.
84 g_glx_get_msc_rate_oml_supported = false;
85 return false;
88 return true;
91 private:
92 XID window_;
94 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider);
97 class SGIVideoSyncThread
98 : public base::Thread,
99 public base::NonThreadSafe,
100 public base::RefCounted<SGIVideoSyncThread> {
101 public:
102 static scoped_refptr<SGIVideoSyncThread> Create() {
103 if (!g_video_sync_thread) {
104 g_video_sync_thread = new SGIVideoSyncThread();
105 g_video_sync_thread->Start();
107 return g_video_sync_thread;
110 private:
111 friend class base::RefCounted<SGIVideoSyncThread>;
113 SGIVideoSyncThread() : base::Thread("SGI_video_sync") {
114 DCHECK(CalledOnValidThread());
117 virtual ~SGIVideoSyncThread() {
118 DCHECK(CalledOnValidThread());
119 g_video_sync_thread = NULL;
120 Stop();
123 static SGIVideoSyncThread* g_video_sync_thread;
125 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread);
128 class SGIVideoSyncProviderThreadShim {
129 public:
130 explicit SGIVideoSyncProviderThreadShim(XID window)
131 : window_(window),
132 context_(NULL),
133 task_runner_(base::ThreadTaskRunnerHandle::Get()),
134 cancel_vsync_flag_(),
135 vsync_lock_() {
136 // This ensures that creation of |window_| has occured when this shim
137 // is executing in the same process as the call to create |window_|.
138 XSync(g_display, False);
141 virtual ~SGIVideoSyncProviderThreadShim() {
142 if (context_) {
143 glXDestroyContext(display_, context_);
144 context_ = NULL;
148 base::CancellationFlag* cancel_vsync_flag() {
149 return &cancel_vsync_flag_;
152 base::Lock* vsync_lock() {
153 return &vsync_lock_;
156 void Initialize() {
157 DCHECK(display_);
159 XWindowAttributes attributes;
160 if (!XGetWindowAttributes(display_, window_, &attributes)) {
161 LOG(ERROR) << "XGetWindowAttributes failed for window " <<
162 window_ << ".";
163 return;
166 XVisualInfo visual_info_template;
167 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
169 int visual_info_count = 0;
170 scoped_ptr<XVisualInfo, ScopedPtrXFree> visual_info_list(
171 XGetVisualInfo(display_, VisualIDMask,
172 &visual_info_template, &visual_info_count));
174 DCHECK(visual_info_list.get());
175 if (visual_info_count == 0) {
176 LOG(ERROR) << "No visual info for visual ID.";
177 return;
180 context_ = glXCreateContext(display_, visual_info_list.get(), NULL, True);
182 DCHECK(NULL != context_);
185 void GetVSyncParameters(const VSyncProvider::UpdateVSyncCallback& callback) {
186 base::TimeTicks now;
188 // Don't allow |window_| destruction while we're probing vsync.
189 base::AutoLock locked(vsync_lock_);
191 if (!context_ || cancel_vsync_flag_.IsSet())
192 return;
194 glXMakeCurrent(display_, window_, context_);
196 unsigned int retrace_count = 0;
197 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0)
198 return;
200 TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD);
201 now = base::TimeTicks::HighResNow();
203 glXMakeCurrent(display_, 0, 0);
206 const base::TimeDelta kDefaultInterval =
207 base::TimeDelta::FromSeconds(1) / 60;
209 task_runner_->PostTask(
210 FROM_HERE, base::Bind(callback, now, kDefaultInterval));
213 private:
214 // For initialization of display_ in GLSurface::InitializeOneOff before
215 // the sandbox goes up.
216 friend class gfx::GLSurfaceGLX;
218 static Display* display_;
220 XID window_;
221 GLXContext context_;
223 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
225 base::CancellationFlag cancel_vsync_flag_;
226 base::Lock vsync_lock_;
228 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim);
231 class SGIVideoSyncVSyncProvider
232 : public gfx::VSyncProvider,
233 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> {
234 public:
235 explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window)
236 : vsync_thread_(SGIVideoSyncThread::Create()),
237 shim_(new SGIVideoSyncProviderThreadShim(window)),
238 cancel_vsync_flag_(shim_->cancel_vsync_flag()),
239 vsync_lock_(shim_->vsync_lock()) {
240 vsync_thread_->message_loop()->PostTask(
241 FROM_HERE,
242 base::Bind(&SGIVideoSyncProviderThreadShim::Initialize,
243 base::Unretained(shim_.get())));
246 virtual ~SGIVideoSyncVSyncProvider() {
248 base::AutoLock locked(*vsync_lock_);
249 cancel_vsync_flag_->Set();
252 // Hand-off |shim_| to be deleted on the |vsync_thread_|.
253 vsync_thread_->message_loop()->DeleteSoon(
254 FROM_HERE,
255 shim_.release());
258 virtual void GetVSyncParameters(
259 const VSyncProvider::UpdateVSyncCallback& callback) OVERRIDE {
260 // Only one outstanding request per surface.
261 if (!pending_callback_) {
262 pending_callback_.reset(
263 new VSyncProvider::UpdateVSyncCallback(callback));
264 vsync_thread_->message_loop()->PostTask(
265 FROM_HERE,
266 base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
267 base::Unretained(shim_.get()),
268 base::Bind(
269 &SGIVideoSyncVSyncProvider::PendingCallbackRunner,
270 AsWeakPtr())));
274 private:
275 void PendingCallbackRunner(const base::TimeTicks timebase,
276 const base::TimeDelta interval) {
277 DCHECK(pending_callback_);
278 pending_callback_->Run(timebase, interval);
279 pending_callback_.reset();
282 scoped_refptr<SGIVideoSyncThread> vsync_thread_;
284 // Thread shim through which the sync provider is accessed on |vsync_thread_|.
285 scoped_ptr<SGIVideoSyncProviderThreadShim> shim_;
287 scoped_ptr<VSyncProvider::UpdateVSyncCallback> pending_callback_;
289 // Raw pointers to sync primitives owned by the shim_.
290 // These will only be referenced before we post a task to destroy
291 // the shim_, so they are safe to access.
292 base::CancellationFlag* cancel_vsync_flag_;
293 base::Lock* vsync_lock_;
295 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider);
298 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL;
300 // In order to take advantage of GLX_SGI_video_sync, we need a display
301 // for use on a separate thread. We must allocate this before the sandbox
302 // goes up (rather than on-demand when we start the thread).
303 Display* SGIVideoSyncProviderThreadShim::display_ = NULL;
305 } // namespace
307 GLSurfaceGLX::GLSurfaceGLX() {}
309 bool GLSurfaceGLX::InitializeOneOff() {
310 static bool initialized = false;
311 if (initialized)
312 return true;
314 // http://crbug.com/245466
315 setenv("force_s3tc_enable", "true", 1);
317 // SGIVideoSyncProviderShim (if instantiated) will issue X commands on
318 // it's own thread.
319 gfx::InitializeThreadedX11();
320 g_display = gfx::GetXDisplay();
322 if (!g_display) {
323 LOG(ERROR) << "XOpenDisplay failed.";
324 return false;
327 int major, minor;
328 if (!glXQueryVersion(g_display, &major, &minor)) {
329 LOG(ERROR) << "glxQueryVersion failed";
330 return false;
333 if (major == 1 && minor < 3) {
334 LOG(ERROR) << "GLX 1.3 or later is required.";
335 return false;
338 g_glx_extensions = glXQueryExtensionsString(g_display, 0);
339 g_glx_context_create =
340 HasGLXExtension("GLX_ARB_create_context");
341 g_glx_create_context_robustness_supported =
342 HasGLXExtension("GLX_ARB_create_context_robustness");
343 g_glx_texture_from_pixmap_supported =
344 HasGLXExtension("GLX_EXT_texture_from_pixmap");
345 g_glx_oml_sync_control_supported =
346 HasGLXExtension("GLX_OML_sync_control");
347 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported;
348 g_glx_sgi_video_sync_supported =
349 HasGLXExtension("GLX_SGI_video_sync");
351 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported)
352 SGIVideoSyncProviderThreadShim::display_ = gfx::OpenNewXDisplay();
354 initialized = true;
355 return true;
358 // static
359 const char* GLSurfaceGLX::GetGLXExtensions() {
360 return g_glx_extensions;
363 // static
364 bool GLSurfaceGLX::HasGLXExtension(const char* name) {
365 return ExtensionsContain(GetGLXExtensions(), name);
368 // static
369 bool GLSurfaceGLX::IsCreateContextSupported() {
370 return g_glx_context_create;
373 // static
374 bool GLSurfaceGLX::IsCreateContextRobustnessSupported() {
375 return g_glx_create_context_robustness_supported;
378 // static
379 bool GLSurfaceGLX::IsTextureFromPixmapSupported() {
380 return g_glx_texture_from_pixmap_supported;
383 // static
384 bool GLSurfaceGLX::IsOMLSyncControlSupported() {
385 return g_glx_oml_sync_control_supported;
388 void* GLSurfaceGLX::GetDisplay() {
389 return g_display;
392 GLSurfaceGLX::~GLSurfaceGLX() {}
394 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
395 : parent_window_(window),
396 window_(0),
397 config_(NULL) {
400 gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const {
401 return window_;
404 bool NativeViewGLSurfaceGLX::Initialize() {
405 XWindowAttributes attributes;
406 if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) {
407 LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_
408 << ".";
409 return false;
411 size_ = gfx::Size(attributes.width, attributes.height);
412 // Create a child window, with a CopyFromParent visual (to avoid inducing
413 // extra blits in the driver), that we can resize exactly in Resize(),
414 // correctly ordered with GL, so that we don't have invalid transient states.
415 // See https://crbug.com/326995.
416 window_ = XCreateWindow(g_display,
417 parent_window_,
420 size_.width(),
421 size_.height(),
423 CopyFromParent,
424 InputOutput,
425 CopyFromParent,
427 NULL);
428 XMapWindow(g_display, window_);
430 ui::PlatformEventSource* event_source =
431 ui::PlatformEventSource::GetInstance();
432 // Can be NULL in tests, when we don't care about Exposes.
433 if (event_source) {
434 XSelectInput(g_display, window_, ExposureMask);
435 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
437 XFlush(g_display);
439 gfx::AcceleratedWidget window_for_vsync = window_;
441 if (g_glx_oml_sync_control_supported)
442 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync));
443 else if (g_glx_sgi_video_sync_supported)
444 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_for_vsync));
446 return true;
449 void NativeViewGLSurfaceGLX::Destroy() {
450 if (window_) {
451 ui::PlatformEventSource* event_source =
452 ui::PlatformEventSource::GetInstance();
453 if (event_source)
454 event_source->RemovePlatformEventDispatcher(this);
455 XDestroyWindow(g_display, window_);
456 XFlush(g_display);
460 bool NativeViewGLSurfaceGLX::CanDispatchEvent(const ui::PlatformEvent& event) {
461 return event->type == Expose && event->xexpose.window == window_;
464 uint32_t NativeViewGLSurfaceGLX::DispatchEvent(const ui::PlatformEvent& event) {
465 XEvent forwarded_event = *event;
466 forwarded_event.xexpose.window = parent_window_;
467 XSendEvent(g_display, parent_window_, False, ExposureMask,
468 &forwarded_event);
469 XFlush(g_display);
470 return ui::POST_DISPATCH_STOP_PROPAGATION;
473 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) {
474 size_ = size;
475 glXWaitGL();
476 XResizeWindow(g_display, window_, size.width(), size.height());
477 glXWaitX();
478 return true;
481 bool NativeViewGLSurfaceGLX::IsOffscreen() {
482 return false;
485 bool NativeViewGLSurfaceGLX::SwapBuffers() {
486 TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers",
487 "width", GetSize().width(),
488 "height", GetSize().height());
490 glXSwapBuffers(g_display, GetDrawableHandle());
491 return true;
494 gfx::Size NativeViewGLSurfaceGLX::GetSize() {
495 return size_;
498 void* NativeViewGLSurfaceGLX::GetHandle() {
499 return reinterpret_cast<void*>(GetDrawableHandle());
502 bool NativeViewGLSurfaceGLX::SupportsPostSubBuffer() {
503 return gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer;
506 void* NativeViewGLSurfaceGLX::GetConfig() {
507 if (!config_) {
508 // This code path is expensive, but we only take it when
509 // attempting to use GLX_ARB_create_context_robustness, in which
510 // case we need a GLXFBConfig for the window in order to create a
511 // context for it.
513 // TODO(kbr): this is not a reliable code path. On platforms which
514 // support it, we should use glXChooseFBConfig in the browser
515 // process to choose the FBConfig and from there the X Visual to
516 // use when creating the window in the first place. Then we can
517 // pass that FBConfig down rather than attempting to reconstitute
518 // it.
520 XWindowAttributes attributes;
521 if (!XGetWindowAttributes(
522 g_display,
523 window_,
524 &attributes)) {
525 LOG(ERROR) << "XGetWindowAttributes failed for window " <<
526 window_ << ".";
527 return NULL;
530 int visual_id = XVisualIDFromVisual(attributes.visual);
532 int num_elements = 0;
533 scoped_ptr<GLXFBConfig, ScopedPtrXFree> configs(
534 glXGetFBConfigs(g_display,
535 DefaultScreen(g_display),
536 &num_elements));
537 if (!configs.get()) {
538 LOG(ERROR) << "glXGetFBConfigs failed.";
539 return NULL;
541 if (!num_elements) {
542 LOG(ERROR) << "glXGetFBConfigs returned 0 elements.";
543 return NULL;
545 bool found = false;
546 int i;
547 for (i = 0; i < num_elements; ++i) {
548 int value;
549 if (glXGetFBConfigAttrib(
550 g_display, configs.get()[i], GLX_VISUAL_ID, &value)) {
551 LOG(ERROR) << "glXGetFBConfigAttrib failed.";
552 return NULL;
554 if (value == visual_id) {
555 found = true;
556 break;
559 if (found) {
560 config_ = configs.get()[i];
564 return config_;
567 bool NativeViewGLSurfaceGLX::PostSubBuffer(
568 int x, int y, int width, int height) {
569 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
570 glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
571 return true;
574 VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
575 return vsync_provider_.get();
578 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
579 Destroy();
582 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size)
583 : size_(size),
584 config_(NULL),
585 pbuffer_(0) {
586 // Some implementations of Pbuffer do not support having a 0 size. For such
587 // cases use a (1, 1) surface.
588 if (size_.GetArea() == 0)
589 size_.SetSize(1, 1);
592 bool PbufferGLSurfaceGLX::Initialize() {
593 DCHECK(!pbuffer_);
595 static const int config_attributes[] = {
596 GLX_BUFFER_SIZE, 32,
597 GLX_ALPHA_SIZE, 8,
598 GLX_BLUE_SIZE, 8,
599 GLX_GREEN_SIZE, 8,
600 GLX_RED_SIZE, 8,
601 GLX_RENDER_TYPE, GLX_RGBA_BIT,
602 GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
603 GLX_DOUBLEBUFFER, False,
607 int num_elements = 0;
608 scoped_ptr<GLXFBConfig, ScopedPtrXFree> configs(
609 glXChooseFBConfig(g_display,
610 DefaultScreen(g_display),
611 config_attributes,
612 &num_elements));
613 if (!configs.get()) {
614 LOG(ERROR) << "glXChooseFBConfig failed.";
615 return false;
617 if (!num_elements) {
618 LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
619 return false;
622 config_ = configs.get()[0];
624 const int pbuffer_attributes[] = {
625 GLX_PBUFFER_WIDTH, size_.width(),
626 GLX_PBUFFER_HEIGHT, size_.height(),
629 pbuffer_ = glXCreatePbuffer(g_display,
630 static_cast<GLXFBConfig>(config_),
631 pbuffer_attributes);
632 if (!pbuffer_) {
633 Destroy();
634 LOG(ERROR) << "glXCreatePbuffer failed.";
635 return false;
638 return true;
641 void PbufferGLSurfaceGLX::Destroy() {
642 if (pbuffer_) {
643 glXDestroyPbuffer(g_display, pbuffer_);
644 pbuffer_ = 0;
647 config_ = NULL;
650 bool PbufferGLSurfaceGLX::IsOffscreen() {
651 return true;
654 bool PbufferGLSurfaceGLX::SwapBuffers() {
655 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
656 return false;
659 gfx::Size PbufferGLSurfaceGLX::GetSize() {
660 return size_;
663 void* PbufferGLSurfaceGLX::GetHandle() {
664 return reinterpret_cast<void*>(pbuffer_);
667 void* PbufferGLSurfaceGLX::GetConfig() {
668 return config_;
671 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() {
672 Destroy();
675 } // namespace gfx