1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/gl/gl_context_osmesa.h"
6
7#include <GL/osmesa.h>
8
9#include "base/logging.h"
10#include "ui/gfx/size.h"
11#include "ui/gl/gl_bindings.h"
12#include "ui/gl/gl_surface.h"
13
14namespace gfx {
15
16GLContextOSMesa::GLContextOSMesa(GLShareGroup* share_group)
17    : GLContextReal(share_group),
18      context_(NULL) {
19}
20
21bool GLContextOSMesa::Initialize(GLSurface* compatible_surface,
22                                 GpuPreference gpu_preference) {
23  DCHECK(!context_);
24
25  OSMesaContext share_handle = static_cast<OSMesaContext>(
26      share_group() ? share_group()->GetHandle() : NULL);
27
28  GLuint format = compatible_surface->GetFormat();
29  DCHECK_NE(format, (unsigned)0);
30  context_ = OSMesaCreateContextExt(format,
31                                    0,  // depth bits
32                                    0,  // stencil bits
33                                    0,  // accum bits
34                                    share_handle);
35  if (!context_) {
36    LOG(ERROR) << "OSMesaCreateContextExt failed.";
37    return false;
38  }
39
40  return true;
41}
42
43void GLContextOSMesa::Destroy() {
44  if (context_) {
45    OSMesaDestroyContext(static_cast<OSMesaContext>(context_));
46    context_ = NULL;
47  }
48}
49
50bool GLContextOSMesa::MakeCurrent(GLSurface* surface) {
51  DCHECK(context_);
52
53  gfx::Size size = surface->GetSize();
54
55  ScopedReleaseCurrent release_current;
56  if (!OSMesaMakeCurrent(context_,
57                         surface->GetHandle(),
58                         GL_UNSIGNED_BYTE,
59                         size.width(),
60                         size.height())) {
61    LOG(ERROR) << "OSMesaMakeCurrent failed.";
62    Destroy();
63    return false;
64  }
65
66  // Set this as soon as the context is current, since we might call into GL.
67  SetRealGLApi();
68
69  // Row 0 is at the top.
70  OSMesaPixelStore(OSMESA_Y_UP, 0);
71
72  SetCurrent(surface);
73  if (!InitializeDynamicBindings()) {
74    return false;
75  }
76
77  if (!surface->OnMakeCurrent(this)) {
78    LOG(ERROR) << "Could not make current.";
79    return false;
80  }
81
82  release_current.Cancel();
83  return true;
84}
85
86void GLContextOSMesa::ReleaseCurrent(GLSurface* surface) {
87  if (!IsCurrent(surface))
88    return;
89
90  SetCurrent(NULL);
91  // TODO: Calling with NULL here does not work to release the context.
92  OSMesaMakeCurrent(NULL, NULL, GL_UNSIGNED_BYTE, 0, 0);
93}
94
95bool GLContextOSMesa::IsCurrent(GLSurface* surface) {
96  DCHECK(context_);
97
98  bool native_context_is_current =
99      context_ == OSMesaGetCurrentContext();
100
101  // If our context is current then our notion of which GLContext is
102  // current must be correct. On the other hand, third-party code
103  // using OpenGL might change the current context.
104  DCHECK(!native_context_is_current || (GetRealCurrent() == this));
105
106  if (!native_context_is_current)
107    return false;
108
109  if (surface) {
110    GLint width;
111    GLint height;
112    GLint format;
113    void* buffer = NULL;
114    OSMesaGetColorBuffer(context_, &width, &height, &format, &buffer);
115    if (buffer != surface->GetHandle())
116      return false;
117  }
118
119  return true;
120}
121
122void* GLContextOSMesa::GetHandle() {
123  return context_;
124}
125
126void GLContextOSMesa::SetSwapInterval(int interval) {
127  DCHECK(IsCurrent(NULL));
128}
129
130GLContextOSMesa::~GLContextOSMesa() {
131  Destroy();
132}
133
134}  // namespace gfx
135