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