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