1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14 #include "Renderer.h"
15 #include <graphics/GLUtils.h>
16
17 #define LOG_TAG "CTS_OPENGL"
18 #define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <Trace.h>
22
23 // Used to center the grid on the screen.
24 #define CENTER_GRID(x) ((((x) * 2.0 + 1) - OFFSCREEN_GRID_SIZE) / OFFSCREEN_GRID_SIZE)
25
26 static const int FBO_NUM_VERTICES = 6;
27
28 static const float FBO_VERTICES[FBO_NUM_VERTICES * 3] = {
29 0.1f, 0.1f, -0.1f,
30 -0.1f, 0.1f, -0.1f,
31 -0.1f, -0.1f, -0.1f,
32 -0.1f, -0.1f, -0.1f,
33 0.1f, -0.1f, -0.1f,
34 0.1f, 0.1f, -0.1f };
35 static const float FBO_TEX_COORDS[FBO_NUM_VERTICES * 2] = {
36 1.0f, 1.0f,
37 0.0f, 1.0f,
38 0.0f, 0.0f,
39 0.0f, 0.0f,
40 1.0f, 0.0f,
41 1.0f, 1.0f };
42
43 static const char* FBO_VERTEX =
44 "attribute vec4 a_Position;"
45 "attribute vec2 a_TexCoord;"
46 "uniform float u_XOffset;"
47 "uniform float u_YOffset;"
48 "varying vec2 v_TexCoord;"
49 "void main() {"
50 " v_TexCoord = a_TexCoord;"
51 " gl_Position.x = a_Position.x + u_XOffset;"
52 " gl_Position.y = a_Position.y + u_YOffset;"
53 " gl_Position.zw = a_Position.zw;"
54 "}";
55
56 static const char* FBO_FRAGMENT =
57 "precision mediump float;"
58 "uniform sampler2D u_Texture;"
59 "varying vec2 v_TexCoord;"
60 "void main() {"
61 " gl_FragColor = texture2D(u_Texture, v_TexCoord);"
62 "}";
63
64 static const EGLint contextAttribs[] = {
65 EGL_CONTEXT_CLIENT_VERSION, 2,
66 EGL_NONE };
67
68 static const EGLint configAttribs[] = {
69 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
70 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
71 EGL_RED_SIZE, 8,
72 EGL_GREEN_SIZE, 8,
73 EGL_BLUE_SIZE, 8,
74 EGL_ALPHA_SIZE, 8,
75 EGL_DEPTH_SIZE, 16,
76 EGL_STENCIL_SIZE, 8,
77 EGL_NONE };
78
79 static const int FBO_SIZE = 128;
80
Renderer(ANativeWindow * window,bool offscreen,int workload)81 Renderer::Renderer(ANativeWindow* window, bool offscreen, int workload) :
82 mOffscreen(offscreen), mWindow(window), mEglDisplay(EGL_NO_DISPLAY),
83 mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT), mWorkload(workload) {
84 }
85
setUp()86 bool Renderer::setUp() {
87 SCOPED_TRACE();
88 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
89 if (EGL_NO_DISPLAY == mEglDisplay || EGL_SUCCESS != eglGetError()) {
90 return false;
91 }
92
93 EGLint major;
94 EGLint minor;
95 if (!eglInitialize(mEglDisplay, &major, &minor) || EGL_SUCCESS != eglGetError()) {
96 return false;
97 }
98
99 EGLint numConfigs = 0;
100 if (!eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
101 || EGL_SUCCESS != eglGetError()) {
102 return false;
103 }
104
105 mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mWindow, NULL);
106 if (EGL_NO_SURFACE == mEglSurface || EGL_SUCCESS != eglGetError()) {
107 return false;
108 }
109
110 mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, contextAttribs);
111 if (EGL_NO_CONTEXT == mEglContext || EGL_SUCCESS != eglGetError()) {
112 return false;
113 }
114
115 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
116 || EGL_SUCCESS != eglGetError()) {
117 return false;
118 }
119
120 if (!eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth)
121 || EGL_SUCCESS != eglGetError()) {
122 return false;
123 }
124 if (!eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight)
125 || EGL_SUCCESS != eglGetError()) {
126 return false;
127 }
128
129 if (mOffscreen) {
130 mFboWidth = FBO_SIZE;
131 mFboHeight = FBO_SIZE;
132
133 glGenFramebuffers(1, &mFboId);
134 glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
135
136 glGenRenderbuffers(1, &mFboDepthId);
137 glBindRenderbuffer(GL_RENDERBUFFER, mFboDepthId);
138 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mFboWidth, mFboHeight);
139 glBindRenderbuffer(GL_RENDERBUFFER, 0);
140 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
141 GL_RENDERBUFFER, mFboDepthId);
142
143 mFboTexId = GLUtils::genTexture(mFboWidth, mFboHeight, 0);
144 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboTexId, 0);
145
146 GLuint err = glGetError();
147 if (err != GL_NO_ERROR) {
148 ALOGE("GLError %d", err);
149 return false;
150 }
151
152 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
153 if (status != GL_FRAMEBUFFER_COMPLETE) {
154 ALOGE("Framebuffer not complete: %d", status);
155 return false;
156 }
157 // Create fbo program.
158 mFboProgId = GLUtils::createProgram(&FBO_VERTEX, &FBO_FRAGMENT);
159 if (mFboProgId == 0) {
160 return false;
161 }
162 // Bind attributes.
163 mFboTexUniformHandle = glGetUniformLocation(mFboProgId, "u_Texture");
164 mFboXOffsetUniformHandle = glGetUniformLocation(mFboProgId, "u_XOffset");
165 mFboYOffsetUniformHandle = glGetUniformLocation(mFboProgId, "u_YOffset");
166 mFboPositionHandle = glGetAttribLocation(mFboProgId, "a_Position");
167 mFboTexCoordHandle = glGetAttribLocation(mFboProgId, "a_TexCoord");
168 } else {
169 mFboWidth = 0;
170 mFboHeight = 0;
171 mFboId = 0;
172 mFboDepthId = 0;
173 mFboTexId = 0;
174 }
175
176 GLuint err = glGetError();
177 if (err != GL_NO_ERROR) {
178 ALOGE("GLError %d in setUp", err);
179 return false;
180 }
181 return true;
182 }
183
tearDown()184 bool Renderer::tearDown() {
185 SCOPED_TRACE();
186 if (mOffscreen) {
187 if (mFboId != 0) {
188 glDeleteFramebuffers(1, &mFboId);
189 mFboId = 0;
190 }
191 if (mFboDepthId != 0) {
192 glDeleteRenderbuffers(1, &mFboDepthId);
193 mFboDepthId = 0;
194 }
195 if (mFboTexId != 0) {
196 glDeleteTextures(1, &mFboTexId);
197 mFboTexId = 0;
198 }
199 }
200 GLuint err = glGetError();
201 if (err != GL_NO_ERROR) {
202 ALOGE("GLError %d in tearDown", err);
203 return false;
204 }
205 if (mEglContext != EGL_NO_CONTEXT) {
206 eglDestroyContext(mEglDisplay, mEglContext);
207 mEglContext = EGL_NO_CONTEXT;
208 }
209 if (mEglSurface != EGL_NO_SURFACE) {
210 eglDestroySurface(mEglDisplay, mEglSurface);
211 mEglSurface = EGL_NO_SURFACE;
212 }
213 if (mEglDisplay != EGL_NO_DISPLAY) {
214 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
215 eglTerminate(mEglDisplay);
216 mEglDisplay = EGL_NO_DISPLAY;
217 }
218
219 return EGL_SUCCESS == eglGetError();
220 }
221
draw()222 bool Renderer::draw() {
223 SCOPED_TRACE();
224 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
225 || EGL_SUCCESS != eglGetError()) {
226 return false;
227 }
228
229 glBindFramebuffer(GL_FRAMEBUFFER, 0);
230 glViewport(0, 0, mWidth, mHeight);
231
232 if (mOffscreen) {
233 // Set the background clear color to black.
234 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
235 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
236 for (int i = 0; i < OFFSCREEN_INNER_FRAMES; i++) {
237 // Switch to FBO and re-attach.
238 glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
239 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
240 GL_RENDERBUFFER, mFboDepthId);
241 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
242 GL_TEXTURE_2D, mFboTexId, 0);
243 glViewport(0, 0, mFboWidth, mFboHeight);
244
245 // Render workload.
246 drawWorkload();
247 glFlush();
248
249 // Switch back to display.
250 glBindFramebuffer(GL_FRAMEBUFFER, 0);
251 glViewport(0, 0, mWidth, mHeight);
252
253 // No culling of back faces
254 glDisable (GL_CULL_FACE);
255 // No depth testing
256 glDisable (GL_DEPTH_TEST);
257 // No blending
258 glDisable (GL_BLEND);
259
260 glUseProgram(mFboProgId);
261
262 // Set the texture.
263 glActiveTexture (GL_TEXTURE0);
264 glBindTexture(GL_TEXTURE_2D, mFboTexId);
265 glUniform1i(mFboTexUniformHandle, 0);
266
267 // Set the offsets
268 glUniform1f(mFboXOffsetUniformHandle, CENTER_GRID(i / OFFSCREEN_GRID_SIZE));
269 glUniform1f(mFboYOffsetUniformHandle, CENTER_GRID(i % OFFSCREEN_GRID_SIZE));
270
271 glEnableVertexAttribArray(mFboPositionHandle);
272 glEnableVertexAttribArray(mFboTexCoordHandle);
273 glVertexAttribPointer(mFboPositionHandle, 3, GL_FLOAT, false, 0, FBO_VERTICES);
274 glVertexAttribPointer(mFboTexCoordHandle, 2, GL_FLOAT, false, 0, FBO_TEX_COORDS);
275
276 // Render FBO to display.
277 glDrawArrays(GL_TRIANGLES, 0, FBO_NUM_VERTICES);
278 }
279 } else {
280 // Render workload.
281 drawWorkload();
282 }
283
284 GLuint err = glGetError();
285 if (err != GL_NO_ERROR) {
286 ALOGE("GLError %d in draw", err);
287 return false;
288 }
289
290 return eglSwapBuffers(mEglDisplay, mEglSurface);
291 }
292