Implement nacl_irt_memory for non-sfi mode.
[chromium-blink-merge.git] / ui / gl / gl_surface_glx.cc
blobcb3c06df2a55e4c4a0920a603e98aa7088c2a8e4
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/synchronization/cancellation_flag.h"
19 #include "base/synchronization/lock.h"
20 #include "base/threading/non_thread_safe.h"
21 #include "base/threading/thread.h"
22 #include "base/time/time.h"
23 #include "third_party/mesa/src/include/GL/osmesa.h"
24 #include "ui/gfx/x/x11_types.h"
25 #include "ui/gl/gl_bindings.h"
26 #include "ui/gl/gl_implementation.h"
27 #include "ui/gl/sync_control_vsync_provider.h"
29 namespace gfx {
31 namespace {
33 // scoped_ptr functor for XFree(). Use as follows:
34 // scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...);
35 // where "XVisualInfo" is any X type that is freed with XFree.
36 class ScopedPtrXFree {
37 public:
38 void operator()(void* x) const {
39 ::XFree(x);
43 Display* g_display = NULL;
44 const char* g_glx_extensions = NULL;
45 bool g_glx_context_create = false;
46 bool g_glx_create_context_robustness_supported = false;
47 bool g_glx_texture_from_pixmap_supported = false;
48 bool g_glx_oml_sync_control_supported = false;
50 // Track support of glXGetMscRateOML separately from GLX_OML_sync_control as a
51 // whole since on some platforms (e.g. crosbug.com/34585), glXGetMscRateOML
52 // always fails even though GLX_OML_sync_control is reported as being supported.
53 bool g_glx_get_msc_rate_oml_supported = false;
55 bool g_glx_sgi_video_sync_supported = false;
57 class OMLSyncControlVSyncProvider
58 : public gfx::SyncControlVSyncProvider {
59 public:
60 explicit OMLSyncControlVSyncProvider(gfx::AcceleratedWidget window)
61 : SyncControlVSyncProvider(),
62 window_(window) {
65 virtual ~OMLSyncControlVSyncProvider() { }
67 protected:
68 virtual bool GetSyncValues(int64* system_time,
69 int64* media_stream_counter,
70 int64* swap_buffer_counter) OVERRIDE {
71 return glXGetSyncValuesOML(g_display, window_, system_time,
72 media_stream_counter, swap_buffer_counter);
75 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
76 if (!g_glx_get_msc_rate_oml_supported)
77 return false;
79 if (!glXGetMscRateOML(g_display, window_, numerator, denominator)) {
80 // Once glXGetMscRateOML has been found to fail, don't try again,
81 // since each failing call may spew an error message.
82 g_glx_get_msc_rate_oml_supported = false;
83 return false;
86 return true;
89 private:
90 XID window_;
92 DISALLOW_COPY_AND_ASSIGN(OMLSyncControlVSyncProvider);
95 class SGIVideoSyncThread
96 : public base::Thread,
97 public base::NonThreadSafe,
98 public base::RefCounted<SGIVideoSyncThread> {
99 public:
100 static scoped_refptr<SGIVideoSyncThread> Create() {
101 if (!g_video_sync_thread) {
102 g_video_sync_thread = new SGIVideoSyncThread();
103 g_video_sync_thread->Start();
105 return g_video_sync_thread;
108 private:
109 friend class base::RefCounted<SGIVideoSyncThread>;
111 SGIVideoSyncThread() : base::Thread("SGI_video_sync") {
112 DCHECK(CalledOnValidThread());
115 virtual ~SGIVideoSyncThread() {
116 DCHECK(CalledOnValidThread());
117 g_video_sync_thread = NULL;
118 Stop();
121 static SGIVideoSyncThread* g_video_sync_thread;
123 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncThread);
126 class SGIVideoSyncProviderThreadShim {
127 public:
128 explicit SGIVideoSyncProviderThreadShim(XID window)
129 : window_(window),
130 context_(NULL),
131 message_loop_(base::MessageLoopProxy::current()),
132 cancel_vsync_flag_(),
133 vsync_lock_() {
134 // This ensures that creation of |window_| has occured when this shim
135 // is executing in the same process as the call to create |window_|.
136 XSync(g_display, False);
139 virtual ~SGIVideoSyncProviderThreadShim() {
140 if (context_) {
141 glXDestroyContext(display_, context_);
142 context_ = NULL;
146 base::CancellationFlag* cancel_vsync_flag() {
147 return &cancel_vsync_flag_;
150 base::Lock* vsync_lock() {
151 return &vsync_lock_;
154 void Initialize() {
155 DCHECK(display_);
157 XWindowAttributes attributes;
158 if (!XGetWindowAttributes(display_, window_, &attributes)) {
159 LOG(ERROR) << "XGetWindowAttributes failed for window " <<
160 window_ << ".";
161 return;
164 XVisualInfo visual_info_template;
165 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
167 int visual_info_count = 0;
168 scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list(
169 XGetVisualInfo(display_, VisualIDMask,
170 &visual_info_template, &visual_info_count));
172 DCHECK(visual_info_list.get());
173 if (visual_info_count == 0) {
174 LOG(ERROR) << "No visual info for visual ID.";
175 return;
178 context_ = glXCreateContext(display_, visual_info_list.get(), NULL, True);
180 DCHECK(NULL != context_);
183 void GetVSyncParameters(const VSyncProvider::UpdateVSyncCallback& callback) {
184 base::TimeTicks now;
186 // Don't allow |window_| destruction while we're probing vsync.
187 base::AutoLock locked(vsync_lock_);
189 if (!context_ || cancel_vsync_flag_.IsSet())
190 return;
192 glXMakeCurrent(display_, window_, context_);
194 unsigned int retrace_count = 0;
195 if (glXWaitVideoSyncSGI(1, 0, &retrace_count) != 0)
196 return;
198 TRACE_EVENT_INSTANT0("gpu", "vblank", TRACE_EVENT_SCOPE_THREAD);
199 now = base::TimeTicks::HighResNow();
201 glXMakeCurrent(display_, 0, 0);
204 const base::TimeDelta kDefaultInterval =
205 base::TimeDelta::FromSeconds(1) / 60;
207 message_loop_->PostTask(
208 FROM_HERE, base::Bind(callback, now, kDefaultInterval));
211 private:
212 // For initialization of display_ in GLSurface::InitializeOneOff before
213 // the sandbox goes up.
214 friend class gfx::GLSurfaceGLX;
216 static Display* display_;
218 XID window_;
219 GLXContext context_;
221 scoped_refptr<base::MessageLoopProxy> message_loop_;
223 base::CancellationFlag cancel_vsync_flag_;
224 base::Lock vsync_lock_;
226 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncProviderThreadShim);
229 class SGIVideoSyncVSyncProvider
230 : public gfx::VSyncProvider,
231 public base::SupportsWeakPtr<SGIVideoSyncVSyncProvider> {
232 public:
233 explicit SGIVideoSyncVSyncProvider(gfx::AcceleratedWidget window)
234 : vsync_thread_(SGIVideoSyncThread::Create()),
235 shim_(new SGIVideoSyncProviderThreadShim(window)),
236 cancel_vsync_flag_(shim_->cancel_vsync_flag()),
237 vsync_lock_(shim_->vsync_lock()) {
238 vsync_thread_->message_loop()->PostTask(
239 FROM_HERE,
240 base::Bind(&SGIVideoSyncProviderThreadShim::Initialize,
241 base::Unretained(shim_.get())));
244 virtual ~SGIVideoSyncVSyncProvider() {
246 base::AutoLock locked(*vsync_lock_);
247 cancel_vsync_flag_->Set();
250 // Hand-off |shim_| to be deleted on the |vsync_thread_|.
251 vsync_thread_->message_loop()->DeleteSoon(
252 FROM_HERE,
253 shim_.release());
256 virtual void GetVSyncParameters(
257 const VSyncProvider::UpdateVSyncCallback& callback) OVERRIDE {
258 // Only one outstanding request per surface.
259 if (!pending_callback_) {
260 pending_callback_.reset(
261 new VSyncProvider::UpdateVSyncCallback(callback));
262 vsync_thread_->message_loop()->PostTask(
263 FROM_HERE,
264 base::Bind(&SGIVideoSyncProviderThreadShim::GetVSyncParameters,
265 base::Unretained(shim_.get()),
266 base::Bind(
267 &SGIVideoSyncVSyncProvider::PendingCallbackRunner,
268 AsWeakPtr())));
272 private:
273 void PendingCallbackRunner(const base::TimeTicks timebase,
274 const base::TimeDelta interval) {
275 DCHECK(pending_callback_);
276 pending_callback_->Run(timebase, interval);
277 pending_callback_.reset();
280 scoped_refptr<SGIVideoSyncThread> vsync_thread_;
282 // Thread shim through which the sync provider is accessed on |vsync_thread_|.
283 scoped_ptr<SGIVideoSyncProviderThreadShim> shim_;
285 scoped_ptr<VSyncProvider::UpdateVSyncCallback> pending_callback_;
287 // Raw pointers to sync primitives owned by the shim_.
288 // These will only be referenced before we post a task to destroy
289 // the shim_, so they are safe to access.
290 base::CancellationFlag* cancel_vsync_flag_;
291 base::Lock* vsync_lock_;
293 DISALLOW_COPY_AND_ASSIGN(SGIVideoSyncVSyncProvider);
296 SGIVideoSyncThread* SGIVideoSyncThread::g_video_sync_thread = NULL;
298 // In order to take advantage of GLX_SGI_video_sync, we need a display
299 // for use on a separate thread. We must allocate this before the sandbox
300 // goes up (rather than on-demand when we start the thread).
301 Display* SGIVideoSyncProviderThreadShim::display_ = NULL;
303 #if defined(TOOLKIT_GTK)
304 // A mechanism for forwarding XExpose events from one window to another.
305 // Because in the workaround for http://crbug.com/145600 the child window
306 // is placed on top of the parent window, only the child window will receive
307 // all expose events. These need to be forwared to the parent window to inform
308 // it that it should paint.
309 class XExposeEventForwarder : public base::MessagePumpObserver {
310 public:
311 XExposeEventForwarder() {}
312 virtual ~XExposeEventForwarder() {
313 DCHECK(child_to_parent_map_.empty());
315 void AddParentChildPair(gfx::AcceleratedWidget parent_window,
316 gfx::AcceleratedWidget child_window) {
317 if (child_to_parent_map_.empty())
318 base::MessagePumpX11::Current()->AddObserver(this);
320 DCHECK(child_to_parent_map_.find(child_window) ==
321 child_to_parent_map_.end());
322 child_to_parent_map_.insert(std::make_pair(
323 child_window, parent_window));
325 void RemoveParentChildPair(gfx::AcceleratedWidget parent_window,
326 gfx::AcceleratedWidget child_window) {
327 DCHECK(child_to_parent_map_.find(child_window) !=
328 child_to_parent_map_.end());
329 child_to_parent_map_.erase(child_window);
331 if (child_to_parent_map_.empty())
332 base::MessagePumpX11::Current()->RemoveObserver(this);
335 private:
336 virtual base::EventStatus WillProcessEvent (
337 const base::NativeEvent& xevent) OVERRIDE {
338 if (xevent->type != Expose)
339 return base::EVENT_CONTINUE;
341 WindowMap::const_iterator found = child_to_parent_map_.find(
342 xevent->xexpose.window);
343 if (found == child_to_parent_map_.end())
344 return base::EVENT_CONTINUE;
346 gfx::AcceleratedWidget target_window = found->second;
347 XEvent forwarded_event = *xevent;
348 forwarded_event.xexpose.window = target_window;
349 XSendEvent(g_display, target_window, False, ExposureMask,
350 &forwarded_event);
351 return base::EVENT_CONTINUE;
353 virtual void DidProcessEvent(const base::NativeEvent& xevent) OVERRIDE {
356 typedef std::map<gfx::AcceleratedWidget, gfx::AcceleratedWidget> WindowMap;
357 WindowMap child_to_parent_map_;
359 DISALLOW_COPY_AND_ASSIGN(XExposeEventForwarder);
362 static base::LazyInstance<XExposeEventForwarder> g_xexpose_event_forwarder =
363 LAZY_INSTANCE_INITIALIZER;
365 // Do not use this workaround when running in test harnesses that do not have
366 // a message loop or do not have a TYPE_GPU message loop.
367 bool g_create_child_windows = false;
368 #endif
370 } // namespace
372 GLSurfaceGLX::GLSurfaceGLX() {}
374 bool GLSurfaceGLX::InitializeOneOff() {
375 static bool initialized = false;
376 if (initialized)
377 return true;
379 // http://crbug.com/245466
380 setenv("force_s3tc_enable", "true", 1);
382 // SGIVideoSyncProviderShim (if instantiated) will issue X commands on
383 // it's own thread.
384 XInitThreads();
386 #if defined(TOOLKIT_GTK)
387 // Be sure to use the X display handle and not the GTK display handle if this
388 // is the GPU process.
389 g_create_child_windows =
390 base::MessageLoop::current() &&
391 base::MessageLoop::current()->type() == base::MessageLoop::TYPE_GPU;
393 if (g_create_child_windows)
394 g_display = base::MessagePumpX11::GetDefaultXDisplay();
395 else
396 g_display = base::MessagePumpForUI::GetDefaultXDisplay();
397 #else
398 g_display = base::MessagePumpForUI::GetDefaultXDisplay();
399 #endif
401 if (!g_display) {
402 LOG(ERROR) << "XOpenDisplay failed.";
403 return false;
406 int major, minor;
407 if (!glXQueryVersion(g_display, &major, &minor)) {
408 LOG(ERROR) << "glxQueryVersion failed";
409 return false;
412 if (major == 1 && minor < 3) {
413 LOG(ERROR) << "GLX 1.3 or later is required.";
414 return false;
417 g_glx_extensions = glXQueryExtensionsString(g_display, 0);
418 g_glx_context_create =
419 HasGLXExtension("GLX_ARB_create_context");
420 g_glx_create_context_robustness_supported =
421 HasGLXExtension("GLX_ARB_create_context_robustness");
422 g_glx_texture_from_pixmap_supported =
423 HasGLXExtension("GLX_EXT_texture_from_pixmap");
424 g_glx_oml_sync_control_supported =
425 HasGLXExtension("GLX_OML_sync_control");
426 g_glx_get_msc_rate_oml_supported = g_glx_oml_sync_control_supported;
427 g_glx_sgi_video_sync_supported =
428 HasGLXExtension("GLX_SGI_video_sync");
430 if (!g_glx_get_msc_rate_oml_supported && g_glx_sgi_video_sync_supported)
431 SGIVideoSyncProviderThreadShim::display_ = XOpenDisplay(NULL);
433 initialized = true;
434 return true;
437 // static
438 const char* GLSurfaceGLX::GetGLXExtensions() {
439 return g_glx_extensions;
442 // static
443 bool GLSurfaceGLX::HasGLXExtension(const char* name) {
444 return ExtensionsContain(GetGLXExtensions(), name);
447 // static
448 bool GLSurfaceGLX::IsCreateContextSupported() {
449 return g_glx_context_create;
452 // static
453 bool GLSurfaceGLX::IsCreateContextRobustnessSupported() {
454 return g_glx_create_context_robustness_supported;
457 // static
458 bool GLSurfaceGLX::IsTextureFromPixmapSupported() {
459 return g_glx_texture_from_pixmap_supported;
462 // static
463 bool GLSurfaceGLX::IsOMLSyncControlSupported() {
464 return g_glx_oml_sync_control_supported;
467 void* GLSurfaceGLX::GetDisplay() {
468 return g_display;
471 GLSurfaceGLX::~GLSurfaceGLX() {}
473 #if defined(TOOLKIT_GTK)
474 bool NativeViewGLSurfaceGLX::SetBackbufferAllocation(bool allocated) {
475 backbuffer_allocated_ = allocated;
476 AdjustBufferAllocation();
477 return true;
480 void NativeViewGLSurfaceGLX::SetFrontbufferAllocation(bool allocated) {
481 frontbuffer_allocated_ = allocated;
482 AdjustBufferAllocation();
485 void NativeViewGLSurfaceGLX::AdjustBufferAllocation() {
486 if (!g_create_child_windows)
487 return;
489 if (frontbuffer_allocated_ || backbuffer_allocated_)
490 CreateChildWindow();
491 else
492 DestroyChildWindow();
495 void NativeViewGLSurfaceGLX::CreateChildWindow() {
496 DCHECK(g_create_child_windows);
498 if (child_window_)
499 return;
501 XSetWindowAttributes set_window_attributes;
502 set_window_attributes.event_mask = ExposureMask;
503 child_window_ = XCreateWindow(
504 g_display, parent_window_, 0, 0, size_.width(), size_.height(), 0,
505 CopyFromParent, InputOutput, CopyFromParent, CWEventMask,
506 &set_window_attributes);
507 g_xexpose_event_forwarder.Pointer()->AddParentChildPair(
508 parent_window_, child_window_);
510 XMapWindow(g_display, child_window_);
511 XFlush(g_display);
514 void NativeViewGLSurfaceGLX::DestroyChildWindow() {
515 if (!child_window_)
516 return;
518 g_xexpose_event_forwarder.Pointer()->RemoveParentChildPair(
519 parent_window_, child_window_);
520 XDestroyWindow(g_display, child_window_);
521 XFlush(g_display);
522 child_window_ = 0;
524 #endif
526 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX(gfx::AcceleratedWidget window)
527 : parent_window_(window),
528 #if defined(TOOLKIT_GTK)
529 child_window_(0),
530 dummy_window_(0),
531 backbuffer_allocated_(true),
532 frontbuffer_allocated_(true),
533 #endif
534 config_(NULL) {
537 gfx::AcceleratedWidget NativeViewGLSurfaceGLX::GetDrawableHandle() const {
538 #if defined(TOOLKIT_GTK)
539 if (g_create_child_windows) {
540 if (child_window_)
541 return child_window_;
542 return dummy_window_;
544 #endif
545 return parent_window_;
548 bool NativeViewGLSurfaceGLX::Initialize() {
549 XWindowAttributes attributes;
550 if (!XGetWindowAttributes(g_display, parent_window_, &attributes)) {
551 LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_
552 << ".";
553 return false;
555 size_ = gfx::Size(attributes.width, attributes.height);
557 gfx::AcceleratedWidget window_for_vsync = parent_window_;
559 #if defined(TOOLKIT_GTK)
560 if (g_create_child_windows) {
561 dummy_window_ = XCreateWindow(
562 g_display,
563 RootWindow(g_display, XScreenNumberOfScreen(attributes.screen)),
564 0, 0, 1, 1, 0, CopyFromParent, InputOutput, attributes.visual, 0, NULL);
565 window_for_vsync = dummy_window_;
566 CreateChildWindow();
568 #endif
570 if (g_glx_oml_sync_control_supported)
571 vsync_provider_.reset(new OMLSyncControlVSyncProvider(window_for_vsync));
572 else if (g_glx_sgi_video_sync_supported)
573 vsync_provider_.reset(new SGIVideoSyncVSyncProvider(window_for_vsync));
575 return true;
578 void NativeViewGLSurfaceGLX::Destroy() {
579 #if defined(TOOLKIT_GTK)
580 DestroyChildWindow();
581 if (dummy_window_)
582 XDestroyWindow(g_display, dummy_window_);
583 dummy_window_ = 0;
584 #endif
587 bool NativeViewGLSurfaceGLX::Resize(const gfx::Size& size) {
588 #if defined(TOOLKIT_GTK)
589 if (child_window_) {
590 XResizeWindow(g_display, child_window_, size.width(), size.height());
591 XFlush(g_display);
593 #endif
594 size_ = size;
595 return true;
598 bool NativeViewGLSurfaceGLX::IsOffscreen() {
599 return false;
602 bool NativeViewGLSurfaceGLX::SwapBuffers() {
603 TRACE_EVENT2("gpu", "NativeViewGLSurfaceGLX:RealSwapBuffers",
604 "width", GetSize().width(),
605 "height", GetSize().height());
607 glXSwapBuffers(g_display, GetDrawableHandle());
608 return true;
611 gfx::Size NativeViewGLSurfaceGLX::GetSize() {
612 return size_;
615 void* NativeViewGLSurfaceGLX::GetHandle() {
616 return reinterpret_cast<void*>(GetDrawableHandle());
619 std::string NativeViewGLSurfaceGLX::GetExtensions() {
620 std::string extensions = GLSurface::GetExtensions();
621 if (gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer) {
622 extensions += extensions.empty() ? "" : " ";
623 extensions += "GL_CHROMIUM_post_sub_buffer";
625 return extensions;
628 void* NativeViewGLSurfaceGLX::GetConfig() {
629 if (!config_) {
630 // This code path is expensive, but we only take it when
631 // attempting to use GLX_ARB_create_context_robustness, in which
632 // case we need a GLXFBConfig for the window in order to create a
633 // context for it.
635 // TODO(kbr): this is not a reliable code path. On platforms which
636 // support it, we should use glXChooseFBConfig in the browser
637 // process to choose the FBConfig and from there the X Visual to
638 // use when creating the window in the first place. Then we can
639 // pass that FBConfig down rather than attempting to reconstitute
640 // it.
642 XWindowAttributes attributes;
643 if (!XGetWindowAttributes(
644 g_display,
645 parent_window_,
646 &attributes)) {
647 LOG(ERROR) << "XGetWindowAttributes failed for window " <<
648 parent_window_ << ".";
649 return NULL;
652 int visual_id = XVisualIDFromVisual(attributes.visual);
654 int num_elements = 0;
655 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
656 glXGetFBConfigs(g_display,
657 DefaultScreen(g_display),
658 &num_elements));
659 if (!configs.get()) {
660 LOG(ERROR) << "glXGetFBConfigs failed.";
661 return NULL;
663 if (!num_elements) {
664 LOG(ERROR) << "glXGetFBConfigs returned 0 elements.";
665 return NULL;
667 bool found = false;
668 int i;
669 for (i = 0; i < num_elements; ++i) {
670 int value;
671 if (glXGetFBConfigAttrib(
672 g_display, configs.get()[i], GLX_VISUAL_ID, &value)) {
673 LOG(ERROR) << "glXGetFBConfigAttrib failed.";
674 return NULL;
676 if (value == visual_id) {
677 found = true;
678 break;
681 if (found) {
682 config_ = configs.get()[i];
686 return config_;
689 bool NativeViewGLSurfaceGLX::PostSubBuffer(
690 int x, int y, int width, int height) {
691 DCHECK(gfx::g_driver_glx.ext.b_GLX_MESA_copy_sub_buffer);
692 glXCopySubBufferMESA(g_display, GetDrawableHandle(), x, y, width, height);
693 return true;
696 VSyncProvider* NativeViewGLSurfaceGLX::GetVSyncProvider() {
697 return vsync_provider_.get();
700 NativeViewGLSurfaceGLX::NativeViewGLSurfaceGLX()
701 : parent_window_(0),
702 #if defined(TOOLKIT_GTK)
703 child_window_(0),
704 dummy_window_(0),
705 backbuffer_allocated_(true),
706 frontbuffer_allocated_(true),
707 #endif
708 config_(NULL) {
711 NativeViewGLSurfaceGLX::~NativeViewGLSurfaceGLX() {
712 Destroy();
715 PbufferGLSurfaceGLX::PbufferGLSurfaceGLX(const gfx::Size& size)
716 : size_(size),
717 config_(NULL),
718 pbuffer_(0) {
721 bool PbufferGLSurfaceGLX::Initialize() {
722 DCHECK(!pbuffer_);
724 static const int config_attributes[] = {
725 GLX_BUFFER_SIZE, 32,
726 GLX_ALPHA_SIZE, 8,
727 GLX_BLUE_SIZE, 8,
728 GLX_GREEN_SIZE, 8,
729 GLX_RED_SIZE, 8,
730 GLX_RENDER_TYPE, GLX_RGBA_BIT,
731 GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
732 GLX_DOUBLEBUFFER, False,
736 int num_elements = 0;
737 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> configs(
738 glXChooseFBConfig(g_display,
739 DefaultScreen(g_display),
740 config_attributes,
741 &num_elements));
742 if (!configs.get()) {
743 LOG(ERROR) << "glXChooseFBConfig failed.";
744 return false;
746 if (!num_elements) {
747 LOG(ERROR) << "glXChooseFBConfig returned 0 elements.";
748 return false;
751 config_ = configs.get()[0];
753 const int pbuffer_attributes[] = {
754 GLX_PBUFFER_WIDTH, size_.width(),
755 GLX_PBUFFER_HEIGHT, size_.height(),
758 pbuffer_ = glXCreatePbuffer(g_display,
759 static_cast<GLXFBConfig>(config_),
760 pbuffer_attributes);
761 if (!pbuffer_) {
762 Destroy();
763 LOG(ERROR) << "glXCreatePbuffer failed.";
764 return false;
767 return true;
770 void PbufferGLSurfaceGLX::Destroy() {
771 if (pbuffer_) {
772 glXDestroyPbuffer(g_display, pbuffer_);
773 pbuffer_ = 0;
776 config_ = NULL;
779 bool PbufferGLSurfaceGLX::IsOffscreen() {
780 return true;
783 bool PbufferGLSurfaceGLX::SwapBuffers() {
784 NOTREACHED() << "Attempted to call SwapBuffers on a pbuffer.";
785 return false;
788 gfx::Size PbufferGLSurfaceGLX::GetSize() {
789 return size_;
792 void* PbufferGLSurfaceGLX::GetHandle() {
793 return reinterpret_cast<void*>(pbuffer_);
796 void* PbufferGLSurfaceGLX::GetConfig() {
797 return config_;
800 PbufferGLSurfaceGLX::~PbufferGLSurfaceGLX() {
801 Destroy();
804 } // namespace gfx