blob: 520b4cac1017a5d20165dc48f519cde3a8525301 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file implements the GLContextWGL and PbufferGLContext classes.
#include "ui/gl/gl_context_wgl.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/trace_event/trace_event.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface_wgl.h"
namespace gl {
GLContextWGL::GLContextWGL(GLShareGroup* share_group)
: GLContextReal(share_group), context_(nullptr) {
}
bool GLContextWGL::Initialize(GLSurface* compatible_surface,
const GLContextAttribs& attribs) {
// webgl_compatibility_context and disabling bind_generates_resource are not
// supported.
DCHECK(!attribs.webgl_compatibility_context &&
attribs.bind_generates_resource);
// Get the handle of another initialized context in the share group _before_
// setting context_. Otherwise this context will be considered initialized
// and could potentially be returned by GetHandle.
HGLRC share_handle = static_cast<HGLRC>(share_group()->GetHandle());
HDC device_context = static_cast<HDC>(compatible_surface->GetHandle());
bool has_wgl_create_context_arb =
strstr(wglGetExtensionsStringARB(device_context),
"WGL_ARB_create_context") != nullptr;
bool create_core_profile = has_wgl_create_context_arb &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableES3GLContext);
if (create_core_profile) {
std::pair<int, int> attempt_versions[] = {
{4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2},
};
for (const auto& version : attempt_versions) {
const int attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB,
version.first,
WGL_CONTEXT_MINOR_VERSION_ARB,
version.second,
WGL_CONTEXT_PROFILE_MASK_ARB,
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0,
0,
};
context_ =
wglCreateContextAttribsARB(device_context, share_handle, attribs);
if (context_) {
break;
}
}
}
if (!context_) {
context_ = wglCreateContext(device_context);
}
if (!context_) {
LOG(ERROR) << "Failed to create GL context.";
Destroy();
return false;
}
if (share_handle) {
if (!wglShareLists(share_handle, context_)) {
LOG(ERROR) << "Could not share GL contexts.";
Destroy();
return false;
}
}
return true;
}
void GLContextWGL::Destroy() {
if (context_) {
wglDeleteContext(context_);
context_ = nullptr;
}
}
bool GLContextWGL::MakeCurrent(GLSurface* surface) {
DCHECK(context_);
if (IsCurrent(surface))
return true;
ScopedReleaseCurrent release_current;
TRACE_EVENT0("gpu", "GLContextWGL::MakeCurrent");
if (!wglMakeCurrent(static_cast<HDC>(surface->GetHandle()), context_)) {
LOG(ERROR) << "Unable to make gl context current.";
return false;
}
// Set this as soon as the context is current, since we might call into GL.
BindGLApi();
SetCurrent(surface);
InitializeDynamicBindings();
if (!surface->OnMakeCurrent(this)) {
LOG(ERROR) << "Could not make current.";
return false;
}
release_current.Cancel();
return true;
}
void GLContextWGL::ReleaseCurrent(GLSurface* surface) {
if (!IsCurrent(surface))
return;
SetCurrent(nullptr);
wglMakeCurrent(nullptr, nullptr);
}
bool GLContextWGL::IsCurrent(GLSurface* surface) {
bool native_context_is_current =
wglGetCurrentContext() == context_;
// If our context is current then our notion of which GLContext is
// current must be correct. On the other hand, third-party code
// using OpenGL might change the current context.
DCHECK(!native_context_is_current || (GetRealCurrent() == this));
if (!native_context_is_current)
return false;
if (surface) {
if (wglGetCurrentDC() != surface->GetHandle())
return false;
}
return true;
}
void* GLContextWGL::GetHandle() {
return context_;
}
void GLContextWGL::OnSetSwapInterval(int interval) {
DCHECK(IsCurrent(nullptr));
if (g_driver_wgl.ext.b_WGL_EXT_swap_control) {
wglSwapIntervalEXT(interval);
} else {
LOG(WARNING) <<
"Could not disable vsync: driver does not "
"support WGL_EXT_swap_control";
}
}
GLContextWGL::~GLContextWGL() {
Destroy();
}
} // namespace gl