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// This file implements the GLContextWGL and PbufferGLContext classes.
6
7#include "ui/gl/gl_context_wgl.h"
8
9#include "base/debug/trace_event.h"
10#include "base/logging.h"
11#include "ui/gl/gl_bindings.h"
12#include "ui/gl/gl_implementation.h"
13#include "ui/gl/gl_surface_wgl.h"
14
15namespace gfx {
16
17GLContextWGL::GLContextWGL(GLShareGroup* share_group)
18    : GLContextReal(share_group),
19      context_(NULL) {
20}
21
22GLContextWGL::~GLContextWGL() {
23  Destroy();
24}
25
26std::string GLContextWGL::GetExtensions() {
27  const char* extensions = NULL;
28  if (g_driver_wgl.fn.wglGetExtensionsStringARBFn)
29    extensions = wglGetExtensionsStringARB(GLSurfaceWGL::GetDisplayDC());
30  else if (g_driver_wgl.fn.wglGetExtensionsStringEXTFn)
31    extensions = wglGetExtensionsStringEXT();
32
33  if (extensions)
34    return GLContext::GetExtensions() + " " + extensions;
35
36  return GLContext::GetExtensions();
37}
38
39bool GLContextWGL::Initialize(
40    GLSurface* compatible_surface, GpuPreference gpu_preference) {
41  // Get the handle of another initialized context in the share group _before_
42  // setting context_. Otherwise this context will be considered initialized
43  // and could potentially be returned by GetHandle.
44  HGLRC share_handle = static_cast<HGLRC>(share_group()->GetHandle());
45
46  context_ = wglCreateContext(
47      static_cast<HDC>(compatible_surface->GetHandle()));
48  if (!context_) {
49    LOG(ERROR) << "Failed to create GL context.";
50    Destroy();
51    return false;
52  }
53
54  if (share_handle) {
55    if (!wglShareLists(share_handle, context_)) {
56      LOG(ERROR) << "Could not share GL contexts.";
57      Destroy();
58      return false;
59    }
60  }
61
62  return true;
63}
64
65void GLContextWGL::Destroy() {
66  if (context_) {
67    wglDeleteContext(context_);
68    context_ = NULL;
69  }
70}
71
72bool GLContextWGL::MakeCurrent(GLSurface* surface) {
73  DCHECK(context_);
74  if (IsCurrent(surface))
75    return true;
76
77  ScopedReleaseCurrent release_current;
78  TRACE_EVENT0("gpu", "GLContextWGL::MakeCurrent");
79
80  if (!wglMakeCurrent(static_cast<HDC>(surface->GetHandle()), context_)) {
81    LOG(ERROR) << "Unable to make gl context current.";
82    return false;
83  }
84
85  // Set this as soon as the context is current, since we might call into GL.
86  SetRealGLApi();
87
88  SetCurrent(surface);
89  if (!InitializeDynamicBindings()) {
90    return false;
91  }
92
93  if (!surface->OnMakeCurrent(this)) {
94    LOG(ERROR) << "Could not make current.";
95    return false;
96  }
97
98  release_current.Cancel();
99  return true;
100}
101
102void GLContextWGL::ReleaseCurrent(GLSurface* surface) {
103  if (!IsCurrent(surface))
104    return;
105
106  SetCurrent(NULL);
107  wglMakeCurrent(NULL, NULL);
108}
109
110bool GLContextWGL::IsCurrent(GLSurface* surface) {
111  bool native_context_is_current =
112      wglGetCurrentContext() == context_;
113
114  // If our context is current then our notion of which GLContext is
115  // current must be correct. On the other hand, third-party code
116  // using OpenGL might change the current context.
117  DCHECK(!native_context_is_current || (GetRealCurrent() == this));
118
119  if (!native_context_is_current)
120    return false;
121
122  if (surface) {
123    if (wglGetCurrentDC() != surface->GetHandle())
124      return false;
125  }
126
127  return true;
128}
129
130void* GLContextWGL::GetHandle() {
131  return context_;
132}
133
134void GLContextWGL::SetSwapInterval(int interval) {
135  DCHECK(IsCurrent(NULL));
136  if (gfx::g_driver_wgl.ext.b_WGL_EXT_swap_control) {
137    wglSwapIntervalEXT(interval);
138  } else {
139      LOG(WARNING) <<
140          "Could not disable vsync: driver does not "
141          "support WGL_EXT_swap_control";
142  }
143}
144
145}  // namespace gfx
146