/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "ScreenRecord" //#define LOG_NDEBUG 0 #include <utils/Log.h> #define EGL_EGLEXT_PROTOTYPES #include <gui/BufferQueue.h> #include <gui/Surface.h> #include "EglWindow.h" #include <EGL/egl.h> #include <EGL/eglext.h> #include <assert.h> using namespace android; status_t EglWindow::createWindow(const sp<IGraphicBufferProducer>& surface) { if (mEglSurface != EGL_NO_SURFACE) { ALOGE("surface already created"); return UNKNOWN_ERROR; } status_t err = eglSetupContext(false); if (err != NO_ERROR) { return err; } // Cache the current dimensions. We're not expecting these to change. surface->query(NATIVE_WINDOW_WIDTH, &mWidth); surface->query(NATIVE_WINDOW_HEIGHT, &mHeight); // Output side (EGL surface to draw on). sp<ANativeWindow> anw = new Surface(surface); mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, anw.get(), NULL); if (mEglSurface == EGL_NO_SURFACE) { ALOGE("eglCreateWindowSurface error: %#x", eglGetError()); eglRelease(); return UNKNOWN_ERROR; } return NO_ERROR; } status_t EglWindow::createPbuffer(int width, int height) { if (mEglSurface != EGL_NO_SURFACE) { ALOGE("surface already created"); return UNKNOWN_ERROR; } status_t err = eglSetupContext(true); if (err != NO_ERROR) { return err; } mWidth = width; mHeight = height; EGLint pbufferAttribs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE }; mEglSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, pbufferAttribs); if (mEglSurface == EGL_NO_SURFACE) { ALOGE("eglCreatePbufferSurface error: %#x", eglGetError()); eglRelease(); return UNKNOWN_ERROR; } return NO_ERROR; } status_t EglWindow::makeCurrent() const { if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { ALOGE("eglMakeCurrent failed: %#x", eglGetError()); return UNKNOWN_ERROR; } return NO_ERROR; } status_t EglWindow::eglSetupContext(bool forPbuffer) { EGLBoolean result; mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mEglDisplay == EGL_NO_DISPLAY) { ALOGE("eglGetDisplay failed: %#x", eglGetError()); return UNKNOWN_ERROR; } EGLint majorVersion, minorVersion; result = eglInitialize(mEglDisplay, &majorVersion, &minorVersion); if (result != EGL_TRUE) { ALOGE("eglInitialize failed: %#x", eglGetError()); return UNKNOWN_ERROR; } ALOGV("Initialized EGL v%d.%d", majorVersion, minorVersion); EGLint numConfigs = 0; EGLint windowConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RECORDABLE_ANDROID, 1, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, // no alpha EGL_NONE }; EGLint pbufferConfigAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; result = eglChooseConfig(mEglDisplay, forPbuffer ? pbufferConfigAttribs : windowConfigAttribs, &mEglConfig, 1, &numConfigs); if (result != EGL_TRUE) { ALOGE("eglChooseConfig error: %#x", eglGetError()); return UNKNOWN_ERROR; } EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, contextAttribs); if (mEglContext == EGL_NO_CONTEXT) { ALOGE("eglCreateContext error: %#x", eglGetError()); return UNKNOWN_ERROR; } return NO_ERROR; } void EglWindow::eglRelease() { ALOGV("EglWindow::eglRelease"); if (mEglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (mEglContext != EGL_NO_CONTEXT) { eglDestroyContext(mEglDisplay, mEglContext); } if (mEglSurface != EGL_NO_SURFACE) { eglDestroySurface(mEglDisplay, mEglSurface); } } mEglDisplay = EGL_NO_DISPLAY; mEglContext = EGL_NO_CONTEXT; mEglSurface = EGL_NO_SURFACE; mEglConfig = NULL; eglReleaseThread(); } // Sets the presentation time on the current EGL buffer. void EglWindow::presentationTime(nsecs_t whenNsec) const { eglPresentationTimeANDROID(mEglDisplay, mEglSurface, whenNsec); } // Swaps the EGL buffer. void EglWindow::swapBuffers() const { eglSwapBuffers(mEglDisplay, mEglSurface); }