Home | History | Annotate | Download | only in screenrecord
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "ScreenRecord"
     18 //#define LOG_NDEBUG 0
     19 #include <utils/Log.h>
     20 
     21 #define EGL_EGLEXT_PROTOTYPES
     22 
     23 #include <gui/BufferQueue.h>
     24 #include <gui/GraphicBufferAlloc.h>
     25 #include <gui/Surface.h>
     26 
     27 #include "EglWindow.h"
     28 
     29 #include <EGL/egl.h>
     30 #include <EGL/eglext.h>
     31 
     32 #include <assert.h>
     33 
     34 using namespace android;
     35 
     36 
     37 status_t EglWindow::createWindow(const sp<IGraphicBufferProducer>& surface) {
     38     if (mEglSurface != EGL_NO_SURFACE) {
     39         ALOGE("surface already created");
     40         return UNKNOWN_ERROR;
     41     }
     42     status_t err = eglSetupContext(false);
     43     if (err != NO_ERROR) {
     44         return err;
     45     }
     46 
     47     // Cache the current dimensions.  We're not expecting these to change.
     48     surface->query(NATIVE_WINDOW_WIDTH, &mWidth);
     49     surface->query(NATIVE_WINDOW_HEIGHT, &mHeight);
     50 
     51     // Output side (EGL surface to draw on).
     52     sp<ANativeWindow> anw = new Surface(surface);
     53     mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, anw.get(),
     54             NULL);
     55     if (mEglSurface == EGL_NO_SURFACE) {
     56         ALOGE("eglCreateWindowSurface error: %#x", eglGetError());
     57         eglRelease();
     58         return UNKNOWN_ERROR;
     59     }
     60 
     61     return NO_ERROR;
     62 }
     63 
     64 status_t EglWindow::createPbuffer(int width, int height) {
     65     if (mEglSurface != EGL_NO_SURFACE) {
     66         ALOGE("surface already created");
     67         return UNKNOWN_ERROR;
     68     }
     69     status_t err = eglSetupContext(true);
     70     if (err != NO_ERROR) {
     71         return err;
     72     }
     73 
     74     mWidth = width;
     75     mHeight = height;
     76 
     77     EGLint pbufferAttribs[] = {
     78             EGL_WIDTH, width,
     79             EGL_HEIGHT, height,
     80             EGL_NONE
     81     };
     82     mEglSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, pbufferAttribs);
     83     if (mEglSurface == EGL_NO_SURFACE) {
     84         ALOGE("eglCreatePbufferSurface error: %#x", eglGetError());
     85         eglRelease();
     86         return UNKNOWN_ERROR;
     87     }
     88 
     89     return NO_ERROR;
     90 }
     91 
     92 status_t EglWindow::makeCurrent() const {
     93     if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
     94         ALOGE("eglMakeCurrent failed: %#x", eglGetError());
     95         return UNKNOWN_ERROR;
     96     }
     97     return NO_ERROR;
     98 }
     99 
    100 status_t EglWindow::eglSetupContext(bool forPbuffer) {
    101     EGLBoolean result;
    102 
    103     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    104     if (mEglDisplay == EGL_NO_DISPLAY) {
    105         ALOGE("eglGetDisplay failed: %#x", eglGetError());
    106         return UNKNOWN_ERROR;
    107     }
    108 
    109     EGLint majorVersion, minorVersion;
    110     result = eglInitialize(mEglDisplay, &majorVersion, &minorVersion);
    111     if (result != EGL_TRUE) {
    112         ALOGE("eglInitialize failed: %#x", eglGetError());
    113         return UNKNOWN_ERROR;
    114     }
    115     ALOGV("Initialized EGL v%d.%d", majorVersion, minorVersion);
    116 
    117     EGLint numConfigs = 0;
    118     EGLint windowConfigAttribs[] = {
    119             EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    120             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    121             EGL_RECORDABLE_ANDROID, 1,
    122             EGL_RED_SIZE, 8,
    123             EGL_GREEN_SIZE, 8,
    124             EGL_BLUE_SIZE, 8,
    125             // no alpha
    126             EGL_NONE
    127     };
    128     EGLint pbufferConfigAttribs[] = {
    129             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
    130             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    131             EGL_RED_SIZE, 8,
    132             EGL_GREEN_SIZE, 8,
    133             EGL_BLUE_SIZE, 8,
    134             EGL_ALPHA_SIZE, 8,
    135             EGL_NONE
    136     };
    137     result = eglChooseConfig(mEglDisplay,
    138             forPbuffer ? pbufferConfigAttribs : windowConfigAttribs,
    139             &mEglConfig, 1, &numConfigs);
    140     if (result != EGL_TRUE) {
    141         ALOGE("eglChooseConfig error: %#x", eglGetError());
    142         return UNKNOWN_ERROR;
    143     }
    144 
    145     EGLint contextAttribs[] = {
    146         EGL_CONTEXT_CLIENT_VERSION, 2,
    147         EGL_NONE
    148     };
    149     mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
    150             contextAttribs);
    151     if (mEglContext == EGL_NO_CONTEXT) {
    152         ALOGE("eglCreateContext error: %#x", eglGetError());
    153         return UNKNOWN_ERROR;
    154     }
    155 
    156     return NO_ERROR;
    157 }
    158 
    159 void EglWindow::eglRelease() {
    160     ALOGV("EglWindow::eglRelease");
    161     if (mEglDisplay != EGL_NO_DISPLAY) {
    162         eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
    163                 EGL_NO_CONTEXT);
    164 
    165         if (mEglContext != EGL_NO_CONTEXT) {
    166             eglDestroyContext(mEglDisplay, mEglContext);
    167         }
    168 
    169         if (mEglSurface != EGL_NO_SURFACE) {
    170             eglDestroySurface(mEglDisplay, mEglSurface);
    171         }
    172     }
    173 
    174     mEglDisplay = EGL_NO_DISPLAY;
    175     mEglContext = EGL_NO_CONTEXT;
    176     mEglSurface = EGL_NO_SURFACE;
    177     mEglConfig = NULL;
    178 
    179     eglReleaseThread();
    180 }
    181 
    182 // Sets the presentation time on the current EGL buffer.
    183 void EglWindow::presentationTime(nsecs_t whenNsec) const {
    184     eglPresentationTimeANDROID(mEglDisplay, mEglSurface, whenNsec);
    185 }
    186 
    187 // Swaps the EGL buffer.
    188 void EglWindow::swapBuffers() const {
    189     eglSwapBuffers(mEglDisplay, mEglSurface);
    190 }
    191