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 34using namespace android; 35 36 37status_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 64status_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 92status_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 100status_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 159void 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. 183void EglWindow::presentationTime(nsecs_t whenNsec) const { 184 eglPresentationTimeANDROID(mEglDisplay, mEglSurface, whenNsec); 185} 186 187// Swaps the EGL buffer. 188void EglWindow::swapBuffers() const { 189 eglSwapBuffers(mEglDisplay, mEglSurface); 190} 191