gl_surface_glx.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <X11/Xlib.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_surface_glx.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/process_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/cancellation_flag.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/non_thread_safe.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/mesa/MesaLib/include/GL/osmesa.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/x11_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_bindings.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_implementation.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gl/vsync_provider.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// scoped_ptr functor for XFree(). Use as follows:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// where "XVisualInfo" is any X type that is freed with XFree.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScopedPtrXFree {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void operator()(void* x) const {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::XFree(x);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Display* g_display;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* g_glx_extensions = NULL;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool g_glx_context_create = false;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_glx_create_context_robustness_supported = false;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_glx_texture_from_pixmap_supported = false;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_glx_oml_sync_control_supported = false;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// always fails even though GLX_OML_sync_control is reported as being supported.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_glx_get_msc_rate_oml_supported = false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_glx_sgi_video_sync_supported = false;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OMLSyncControlVSyncProvider
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public gfx::SyncControlVSyncProvider {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : SyncControlVSyncProvider(),
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        window_(window) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~OMLSyncControlVSyncProvider() { }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool GetSyncValues(int64* system_time,
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int64* media_stream_counter,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int64* swap_buffer_counter) OVERRIDE {
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return glXGetSyncValuesOML(g_display, window_, system_time,
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               media_stream_counter, swap_buffer_counter);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!g_glx_get_msc_rate_oml_supported)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!glXGetMscRateOML(g_display, window_, numerator, denominator)) {
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Once glXGetMscRateOML has been found to fail, don't try again,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // since each failing call may spew an error message.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      g_glx_get_msc_rate_oml_supported = false;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID window_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SGIVideoSyncThread
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     : public base::Thread,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       public base::NonThreadSafe,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       public base::RefCounted<SGIVideoSyncThread> {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static scoped_refptr<SGIVideoSyncThread> Create() {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!g_video_sync_thread) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_video_sync_thread = new SGIVideoSyncThread();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_video_sync_thread->Start();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return g_video_sync_thread;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCounted<SGIVideoSyncThread>;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SGIVideoSyncThread() : base::Thread("SGI_video_sync") {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~SGIVideoSyncThread() {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_video_sync_thread = NULL;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Stop();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SGIVideoSyncThread* g_video_sync_thread;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class SGIVideoSyncProviderThreadShim {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SGIVideoSyncProviderThreadShim(XID window)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : window_(window),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        context_(NULL),
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        message_loop_(base::MessageLoopProxy::current()),
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cancel_vsync_flag_(),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        vsync_lock_() {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This ensures that creation of |window_| has occured when this shim
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is executing in the same process as the call to create |window_|.
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    XSync(g_display, False);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~SGIVideoSyncProviderThreadShim() {
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (context_) {
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      glXDestroyContext(display_, context_);
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      context_ = NULL;
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::CancellationFlag* cancel_vsync_flag() {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &cancel_vsync_flag_;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock* vsync_lock() {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &vsync_lock_;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Initialize() {
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(display_);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XWindowAttributes attributes;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!XGetWindowAttributes(display_, window_, &attributes)) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "XGetWindowAttributes failed for window " <<
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        window_ << ".";
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XVisualInfo visual_info_template;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int visual_info_count = 0;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        XGetVisualInfo(display_, VisualIDMask,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &visual_info_template, &visual_info_count));
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(visual_info_list.get());
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (visual_info_count == 0) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "No visual info for visual ID.";
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    context_ = glXCreateContext(display_, visual_info_list.get(), NULL, True);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(NULL != context_);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void GetVSyncParameters(const VSyncProvider::UpdateVSyncCallback& callback) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeTicks now;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Don't allow |window_| destruction while we're probing vsync.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock locked(vsync_lock_);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!context_ || cancel_vsync_flag_.IsSet())
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      glXMakeCurrent(display_, window_, context_);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unsigned int retrace_count = 0;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now = base::TimeTicks::HighResNow();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      glXMakeCurrent(display_, 0, 0);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::TimeDelta kDefaultInterval =
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromSeconds(1) / 60;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_loop_->PostTask(
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE, base::Bind(callback, now, kDefaultInterval));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // For initialization of display_ in GLSurface::InitializeOneOff before
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the sandbox goes up.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class gfx::GLSurfaceGLX;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static Display* display_;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XID window_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GLXContext context_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::MessageLoopProxy> message_loop_;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::CancellationFlag cancel_vsync_flag_;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock vsync_lock_;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SGIVideoSyncVSyncProvider
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public gfx::VSyncProvider,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : vsync_thread_(SGIVideoSyncThread::Create()),
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        shim_(new SGIVideoSyncProviderThreadShim(window)),
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cancel_vsync_flag_(shim_->cancel_vsync_flag()),
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        vsync_lock_(shim_->vsync_lock()) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    vsync_thread_->message_loop()->PostTask(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(&SGIVideoSyncProviderThreadShim::Initialize,
24190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Unretained(shim_.get())));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SGIVideoSyncVSyncProvider() {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::AutoLock locked(*vsync_lock_);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cancel_vsync_flag_->Set();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Hand-off |shim_| to be deleted on the |vsync_thread_|.
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    vsync_thread_->message_loop()->DeleteSoon(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        shim_.release());
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void GetVSyncParameters(
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const VSyncProvider::UpdateVSyncCallback& callback) OVERRIDE {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only one outstanding request per surface.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!pending_callback_) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pending_callback_.reset(
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          new VSyncProvider::UpdateVSyncCallback(callback));
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      vsync_thread_->message_loop()->PostTask(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     base::Unretained(shim_.get()),
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     base::Bind(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         &SGIVideoSyncVSyncProvider::PendingCallbackRunner,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         AsWeakPtr())));
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PendingCallbackRunner(const base::TimeTicks timebase,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const base::TimeDelta interval) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pending_callback_);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_callback_->Run(timebase, interval);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_callback_.reset();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SGIVideoSyncThread> vsync_thread_;
28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Thread shim through which the sync provider is accessed on |vsync_thread_|.
28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  scoped_ptr<SGIVideoSyncProviderThreadShim> shim_;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<VSyncProvider::UpdateVSyncCallback> pending_callback_;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Raw pointers to sync primitives owned by the shim_.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These will only be referenced before we post a task to destroy
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the shim_, so they are safe to access.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::CancellationFlag* cancel_vsync_flag_;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock* vsync_lock_;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In order to take advantage of GLX_SGI_video_sync, we need a display
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for use on a separate thread. We must allocate this before the sandbox
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// goes up (rather than on-demand when we start the thread).
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Display* SGIVideoSyncProviderThreadShim::display_ = NULL;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GLSurfaceGLX::GLSurfaceGLX() {}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLSurfaceGLX::InitializeOneOff() {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SGIVideoSyncProviderShim (if instantiated) will issue X commands on
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it's own thread.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XInitThreads();
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_display = base::MessagePumpForUI::GetDefaultXDisplay();
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_display) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "XOpenDisplay failed.";
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int major, minor;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!glXQueryVersion(g_display, &major, &minor)) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "glxQueryVersion failed";
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (major == 1 && minor < 3) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "GLX 1.3 or later is required.";
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_glx_extensions = glXQueryExtensionsString(g_display, 0);
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  g_glx_context_create =
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HasGLXExtension("GLX_ARB_create_context");
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_glx_create_context_robustness_supported =
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HasGLXExtension("GLX_ARB_create_context_robustness");
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_glx_texture_from_pixmap_supported =
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HasGLXExtension("GLX_EXT_texture_from_pixmap");
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_glx_oml_sync_control_supported =
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HasGLXExtension("GLX_OML_sync_control");
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_glx_sgi_video_sync_supported =
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HasGLXExtension("GLX_SGI_video_sync");
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported)
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SGIVideoSyncProviderThreadShim::display_ = XOpenDisplay(NULL);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized = true;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* GLSurfaceGLX::GetGLXExtensions() {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_glx_extensions;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLSurfaceGLX::HasGLXExtension(const char* name) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ExtensionsContain(GetGLXExtensions(), name);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GLSurfaceGLX::IsCreateContextSupported() {
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return g_glx_context_create;
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLSurfaceGLX::IsCreateContextRobustnessSupported() {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_glx_create_context_robustness_supported;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLSurfaceGLX::IsTextureFromPixmapSupported() {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_glx_texture_from_pixmap_supported;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GLSurfaceGLX::IsOMLSyncControlSupported() {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_glx_oml_sync_control_supported;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* GLSurfaceGLX::GetDisplay() {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_display;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GLSurfaceGLX::~GLSurfaceGLX() {}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : window_(window),
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config_(NULL) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativeViewGLSurfaceGLX::Initialize() {
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XWindowAttributes attributes;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!XGetWindowAttributes(g_display, window_, &attributes)) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "XGetWindowAttributes failed for window " << window_ << ".";
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_ = gfx::Size(attributes.width, attributes.height);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_glx_oml_sync_control_supported)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_));
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (g_glx_sgi_video_sync_supported)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_));
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NativeViewGLSurfaceGLX::Destroy() {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Intel drivers, the frame buffer won't be resize until the next swap. If
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only do PostSubBuffer, then we're stuck in the old size. Force a swap
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // now.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer && size_ != size)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SwapBuffers();
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_ = size;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativeViewGLSurfaceGLX::IsOffscreen() {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativeViewGLSurfaceGLX::SwapBuffers() {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glXSwapBuffers(g_display, window_);
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For latency_tests.cc:
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete",
431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                 TRACE_EVENT_SCOPE_THREAD);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size NativeViewGLSurfaceGLX::GetSize() {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return size_;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* NativeViewGLSurfaceGLX::GetHandle() {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reinterpret_cast<void*>(window_);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string NativeViewGLSurfaceGLX::GetExtensions() {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string extensions = GLSurface::GetExtensions();
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions += extensions.empty() ? "" : " ";
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions += "GL_CHROMIUM_post_sub_buffer";
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extensions;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* NativeViewGLSurfaceGLX::GetConfig() {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!config_) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This code path is expensive, but we only take it when
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // attempting to use GLX_ARB_create_context_robustness, in which
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // case we need a GLXFBConfig for the window in order to create a
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // context for it.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(kbr): this is not a reliable code path. On platforms which
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // support it, we should use glXChooseFBConfig in the browser
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // process to choose the FBConfig and from there the X Visual to
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // use when creating the window in the first place. Then we can
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // pass that FBConfig down rather than attempting to reconstitute
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    XWindowAttributes attributes;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!XGetWindowAttributes(
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g_display,
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        window_,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &attributes)) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "XGetWindowAttributes failed for window " <<
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          window_ << ".";
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int visual_id = XVisualIDFromVisual(attributes.visual);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int num_elements = 0;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        glXGetFBConfigs(g_display,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        DefaultScreen(g_display),
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &num_elements));
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!configs.get()) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "glXGetFBConfigs failed.";
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!num_elements) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "glXGetFBConfigs returned 0 elements.";
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool found = false;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = 0; i < num_elements; ++i) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int value;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (glXGetFBConfigAttrib(
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              g_display, configs.get()[i], GLX_VISUAL_ID, &value)) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "glXGetFBConfigAttrib failed.";
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return NULL;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (value == visual_id) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        found = true;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (found) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config_ = configs.get()[i];
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return config_;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NativeViewGLSurfaceGLX::PostSubBuffer(
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x, int y, int width, int height) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glXCopySubBufferMESA(g_display, window_, x, y, width, height);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return vsync_provider_.get();
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX()
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : window_(0),
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config_(NULL) {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Destroy();
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : size_(size),
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config_(NULL),
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pbuffer_(0) {
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PbufferGLSurfaceGLX::Initialize() {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!pbuffer_);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int config_attributes[] = {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_BUFFER_SIZE, 32,
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_ALPHA_SIZE, 8,
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_BLUE_SIZE, 8,
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_GREEN_SIZE, 8,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_RED_SIZE, 8,
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_RENDER_TYPE, GLX_RGBA_BIT,
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_DOUBLEBUFFER, False,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_elements = 0;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      glXChooseFBConfig(g_display,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        DefaultScreen(g_display),
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        config_attributes,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &num_elements));
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!configs.get()) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "glXChooseFBConfig failed.";
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!num_elements) {
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config_ = configs.get()[0];
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int pbuffer_attributes[] = {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_PBUFFER_WIDTH, size_.width(),
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GLX_PBUFFER_HEIGHT, size_.height(),
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pbuffer_ = glXCreatePbuffer(g_display,
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              static_cast<GLXFBConfig>(config_),
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              pbuffer_attributes);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pbuffer_) {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Destroy();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "glXCreatePbuffer failed.";
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PbufferGLSurfaceGLX::Destroy() {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pbuffer_) {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    glXDestroyPbuffer(g_display, pbuffer_);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pbuffer_ = 0;
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config_ = NULL;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PbufferGLSurfaceGLX::IsOffscreen() {
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PbufferGLSurfaceGLX::SwapBuffers() {
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size PbufferGLSurfaceGLX::GetSize() {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return size_;
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* PbufferGLSurfaceGLX::GetHandle() {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reinterpret_cast<void*>(pbuffer_);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* PbufferGLSurfaceGLX::GetConfig() {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return config_;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() {
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Destroy();
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gfx
623