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 
createWindow(const sp<IGraphicBufferProducer> & surface)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 
createPbuffer(int width,int height)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 
makeCurrent() const91 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 
eglSetupContext(bool forPbuffer)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 
eglRelease()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.
presentationTime(nsecs_t whenNsec) const182 void EglWindow::presentationTime(nsecs_t whenNsec) const {
183     eglPresentationTimeANDROID(mEglDisplay, mEglSurface, whenNsec);
184 }
185 
186 // Swaps the EGL buffer.
swapBuffers() const187 void EglWindow::swapBuffers() const {
188     eglSwapBuffers(mEglDisplay, mEglSurface);
189 }
190