blob: 928d79005dcff12f0fb3db7a16928393447c2af1 [file] [log] [blame]
// Copyright 2016 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.
#include "remoting/client/jni/egl_thread_context.h"
#include "base/logging.h"
namespace remoting {
EglThreadContext::EglThreadContext() {
DCHECK(thread_checker_.CalledOnValidThread());
CHECK(eglGetCurrentDisplay() == EGL_NO_DISPLAY);
CHECK(eglGetCurrentContext() == EGL_NO_CONTEXT);
display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!display_ || !eglInitialize(display_, NULL, NULL)) {
LOG(FATAL) << "Failed to initialize EGL display: " << eglGetError();
}
if (CreateContextWithClientVersion(EGL_OPENGL_ES3_BIT, GlVersion::ES_3)) {
client_version_ = GlVersion::ES_3;
} else if (CreateContextWithClientVersion(EGL_OPENGL_ES2_BIT,
GlVersion::ES_2)) {
LOG(WARNING) << "OpenGL ES 3 context not supported."
<< "Falled back to OpenGL ES 2";
client_version_ = GlVersion::ES_2;
} else {
LOG(FATAL) << "Failed to create context: " << eglGetError();
}
}
EglThreadContext::~EglThreadContext() {
DCHECK(thread_checker_.CalledOnValidThread());
eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(display_, context_);
if (surface_) {
eglDestroySurface(display_, surface_);
}
eglTerminate(display_);
}
void EglThreadContext::BindToWindow(EGLNativeWindowType window) {
DCHECK(thread_checker_.CalledOnValidThread());
if (surface_) {
eglDestroySurface(display_, surface_);
surface_ = EGL_NO_SURFACE;
}
if (window) {
surface_ = eglCreateWindowSurface(display_, config_, window, NULL);
if (!surface_) {
LOG(FATAL) << "Failed to create window surface: " << eglGetError();
}
} else {
surface_ = EGL_NO_SURFACE;
}
if (!eglMakeCurrent(display_, surface_, surface_, context_)) {
LOG(FATAL) << "Failed to make current: " << eglGetError();
}
}
bool EglThreadContext::IsWindowBound() const {
DCHECK(thread_checker_.CalledOnValidThread());
return surface_ != EGL_NO_SURFACE;
}
bool EglThreadContext::SwapBuffers() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!IsWindowBound()) {
return false;
}
if (!eglSwapBuffers(display_, surface_)) {
// Not fatal since the surface may be destroyed on a different thread
// earlier than the window is unbound. The context can still be reused
// after rebinding to the right window.
LOG(WARNING) << "Failed to swap buffer: " << eglGetError();
return false;
}
return true;
}
bool EglThreadContext::CreateContextWithClientVersion(
int renderable_type,
GlVersion client_version) {
DCHECK(client_version != GlVersion::UNKNOWN);
EGLint config_attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_RENDERABLE_TYPE, renderable_type,
EGL_NONE
};
EGLint num_configs;
if (!eglChooseConfig(display_, config_attribs, &config_, 1, &num_configs)) {
LOG(WARNING) << "Failed to choose config: " << eglGetError();
return false;
}
EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, static_cast<int>(client_version),
EGL_NONE
};
context_ = eglCreateContext(display_, config_, EGL_NO_CONTEXT,
context_attribs);
return context_ != EGL_NO_CONTEXT;
}
} // namespace remoting