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/Surface.h> 25 26 #include "EglWindow.h" 27 28 #include <EGL/egl.h> 29 #include <EGL/eglext.h> 30 31 #include <assert.h> 32 33 using namespace android; 34 35 36 status_t EglWindow::createWindow(const sp<IGraphicBufferProducer>& surface) { 37 if (mEglSurface != EGL_NO_SURFACE) { 38 ALOGE("surface already created"); 39 return UNKNOWN_ERROR; 40 } 41 status_t err = eglSetupContext(false); 42 if (err != NO_ERROR) { 43 return err; 44 } 45 46 // Cache the current dimensions. We're not expecting these to change. 47 surface->query(NATIVE_WINDOW_WIDTH, &mWidth); 48 surface->query(NATIVE_WINDOW_HEIGHT, &mHeight); 49 50 // Output side (EGL surface to draw on). 51 sp<ANativeWindow> anw = new Surface(surface); 52 mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, anw.get(), 53 NULL); 54 if (mEglSurface == EGL_NO_SURFACE) { 55 ALOGE("eglCreateWindowSurface error: %#x", eglGetError()); 56 eglRelease(); 57 return UNKNOWN_ERROR; 58 } 59 60 return NO_ERROR; 61 } 62 63 status_t EglWindow::createPbuffer(int width, int height) { 64 if (mEglSurface != EGL_NO_SURFACE) { 65 ALOGE("surface already created"); 66 return UNKNOWN_ERROR; 67 } 68 status_t err = eglSetupContext(true); 69 if (err != NO_ERROR) { 70 return err; 71 } 72 73 mWidth = width; 74 mHeight = height; 75 76 EGLint pbufferAttribs[] = { 77 EGL_WIDTH, width, 78 EGL_HEIGHT, height, 79 EGL_NONE 80 }; 81 mEglSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, pbufferAttribs); 82 if (mEglSurface == EGL_NO_SURFACE) { 83 ALOGE("eglCreatePbufferSurface error: %#x", eglGetError()); 84 eglRelease(); 85 return UNKNOWN_ERROR; 86 } 87 88 return NO_ERROR; 89 } 90 91 status_t EglWindow::makeCurrent() const { 92 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { 93 ALOGE("eglMakeCurrent failed: %#x", eglGetError()); 94 return UNKNOWN_ERROR; 95 } 96 return NO_ERROR; 97 } 98 99 status_t EglWindow::eglSetupContext(bool forPbuffer) { 100 EGLBoolean result; 101 102 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 103 if (mEglDisplay == EGL_NO_DISPLAY) { 104 ALOGE("eglGetDisplay failed: %#x", eglGetError()); 105 return UNKNOWN_ERROR; 106 } 107 108 EGLint majorVersion, minorVersion; 109 result = eglInitialize(mEglDisplay, &majorVersion, &minorVersion); 110 if (result != EGL_TRUE) { 111 ALOGE("eglInitialize failed: %#x", eglGetError()); 112 return UNKNOWN_ERROR; 113 } 114 ALOGV("Initialized EGL v%d.%d", majorVersion, minorVersion); 115 116 EGLint numConfigs = 0; 117 EGLint windowConfigAttribs[] = { 118 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 119 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 120 EGL_RECORDABLE_ANDROID, 1, 121 EGL_RED_SIZE, 8, 122 EGL_GREEN_SIZE, 8, 123 EGL_BLUE_SIZE, 8, 124 // no alpha 125 EGL_NONE 126 }; 127 EGLint pbufferConfigAttribs[] = { 128 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, 129 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 130 EGL_RED_SIZE, 8, 131 EGL_GREEN_SIZE, 8, 132 EGL_BLUE_SIZE, 8, 133 EGL_ALPHA_SIZE, 8, 134 EGL_NONE 135 }; 136 result = eglChooseConfig(mEglDisplay, 137 forPbuffer ? pbufferConfigAttribs : windowConfigAttribs, 138 &mEglConfig, 1, &numConfigs); 139 if (result != EGL_TRUE) { 140 ALOGE("eglChooseConfig error: %#x", eglGetError()); 141 return UNKNOWN_ERROR; 142 } 143 144 EGLint contextAttribs[] = { 145 EGL_CONTEXT_CLIENT_VERSION, 2, 146 EGL_NONE 147 }; 148 mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, 149 contextAttribs); 150 if (mEglContext == EGL_NO_CONTEXT) { 151 ALOGE("eglCreateContext error: %#x", eglGetError()); 152 return UNKNOWN_ERROR; 153 } 154 155 return NO_ERROR; 156 } 157 158 void EglWindow::eglRelease() { 159 ALOGV("EglWindow::eglRelease"); 160 if (mEglDisplay != EGL_NO_DISPLAY) { 161 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 162 EGL_NO_CONTEXT); 163 164 if (mEglContext != EGL_NO_CONTEXT) { 165 eglDestroyContext(mEglDisplay, mEglContext); 166 } 167 168 if (mEglSurface != EGL_NO_SURFACE) { 169 eglDestroySurface(mEglDisplay, mEglSurface); 170 } 171 } 172 173 mEglDisplay = EGL_NO_DISPLAY; 174 mEglContext = EGL_NO_CONTEXT; 175 mEglSurface = EGL_NO_SURFACE; 176 mEglConfig = NULL; 177 178 eglReleaseThread(); 179 } 180 181 // Sets the presentation time on the current EGL buffer. 182 void EglWindow::presentationTime(nsecs_t whenNsec) const { 183 eglPresentationTimeANDROID(mEglDisplay, mEglSurface, whenNsec); 184 } 185 186 // Swaps the EGL buffer. 187 void EglWindow::swapBuffers() const { 188 eglSwapBuffers(mEglDisplay, mEglSurface); 189 } 190