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  if (!OSMesaMakeCurrent(context_,
56                         surface->GetHandle(),
57                         GL_UNSIGNED_BYTE,
58                         size.width(),
59                         size.height())) {
60    LOG(ERROR) << "OSMesaMakeCurrent failed.";
61    Destroy();
62    return false;
63  }
64
65  // Set this as soon as the context is current, since we might call into GL.
66  SetRealGLApi();
67
68  // Row 0 is at the top.
69  OSMesaPixelStore(OSMESA_Y_UP, 0);
70
71  SetCurrent(surface);
72  if (!InitializeExtensionBindings()) {
73    ReleaseCurrent(surface);
74    return false;
75  }
76
77  if (!surface->OnMakeCurrent(this)) {
78    LOG(ERROR) << "Could not make current.";
79    return false;
80  }
81
82  return true;
83}
84
85void GLContextOSMesa::ReleaseCurrent(GLSurface* surface) {
86  if (!IsCurrent(surface))
87    return;
88
89  SetCurrent(NULL);
90  OSMesaMakeCurrent(NULL, NULL, GL_UNSIGNED_BYTE, 0, 0);
91}
92
93bool GLContextOSMesa::IsCurrent(GLSurface* surface) {
94  DCHECK(context_);
95
96  bool native_context_is_current =
97      context_ == OSMesaGetCurrentContext();
98
99  // If our context is current then our notion of which GLContext is
100  // current must be correct. On the other hand, third-party code
101  // using OpenGL might change the current context.
102  DCHECK(!native_context_is_current || (GetRealCurrent() == this));
103
104  if (!native_context_is_current)
105    return false;
106
107  if (surface) {
108    GLint width;
109    GLint height;
110    GLint format;
111    void* buffer = NULL;
112    OSMesaGetColorBuffer(context_, &width, &height, &format, &buffer);
113    if (buffer != surface->GetHandle())
114      return false;
115  }
116
117  return true;
118}
119
120void* GLContextOSMesa::GetHandle() {
121  return context_;
122}
123
124void GLContextOSMesa::SetSwapInterval(int interval) {
125  DCHECK(IsCurrent(NULL));
126}
127
128GLContextOSMesa::~GLContextOSMesa() {
129  Destroy();
130}
131
132}  // namespace gfx
133