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