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 <android/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 // Leave a good error message if something fails.
26 #define EGL_RESULT_CHECK(X) do { \
27 EGLint error = eglGetError(); \
28 if (!(X) || error != EGL_SUCCESS) { \
29 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
30 "EGL error '%d' at %s:%d", error, __FILE__, __LINE__);\
31 return false; \
32 } \
33 } while (0)
34
35 static const int FBO_NUM_VERTICES = 6;
36
37 static const float FBO_VERTICES[FBO_NUM_VERTICES * 3] = {
38 0.1f, 0.1f, -0.1f,
39 -0.1f, 0.1f, -0.1f,
40 -0.1f, -0.1f, -0.1f,
41 -0.1f, -0.1f, -0.1f,
42 0.1f, -0.1f, -0.1f,
43 0.1f, 0.1f, -0.1f };
44 static const float FBO_TEX_COORDS[FBO_NUM_VERTICES * 2] = {
45 1.0f, 1.0f,
46 0.0f, 1.0f,
47 0.0f, 0.0f,
48 0.0f, 0.0f,
49 1.0f, 0.0f,
50 1.0f, 1.0f };
51
52 static const char* FBO_VERTEX =
53 "attribute vec4 a_Position;"
54 "attribute vec2 a_TexCoord;"
55 "uniform float u_XOffset;"
56 "uniform float u_YOffset;"
57 "varying vec2 v_TexCoord;"
58 "void main() {"
59 " v_TexCoord = a_TexCoord;"
60 " gl_Position.x = a_Position.x + u_XOffset;"
61 " gl_Position.y = a_Position.y + u_YOffset;"
62 " gl_Position.zw = a_Position.zw;"
63 "}";
64
65 static const char* FBO_FRAGMENT =
66 "precision mediump float;"
67 "uniform sampler2D u_Texture;"
68 "varying vec2 v_TexCoord;"
69 "void main() {"
70 " gl_FragColor = texture2D(u_Texture, v_TexCoord);"
71 "}";
72
73 static const EGLint contextAttribs[] = {
74 EGL_CONTEXT_CLIENT_VERSION, 2,
75 EGL_NONE };
76
77 static const EGLint configAttribs[] = {
78 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
79 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
80 EGL_RED_SIZE, 8,
81 EGL_GREEN_SIZE, 8,
82 EGL_BLUE_SIZE, 8,
83 EGL_ALPHA_SIZE, 8,
84 EGL_DEPTH_SIZE, 16,
85 EGL_STENCIL_SIZE, 8,
86 EGL_NONE };
87
88 static const int FBO_SIZE = 128;
89
Renderer(EGLNativeWindowType window,bool offscreen)90 Renderer::Renderer(EGLNativeWindowType window, bool offscreen) :
91 mOffscreen(offscreen), mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE),
92 mEglContext(EGL_NO_CONTEXT), mWindow(window) {
93 }
94
eglSetUp()95 bool Renderer::eglSetUp() {
96 SCOPED_TRACE();
97 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
98 EGL_RESULT_CHECK(mEglDisplay != EGL_NO_DISPLAY);
99
100 EGLint major;
101 EGLint minor;
102 EGL_RESULT_CHECK(eglInitialize(mEglDisplay, &major, &minor));
103
104 EGLint numConfigs = 0;
105 EGL_RESULT_CHECK(eglChooseConfig(mEglDisplay, configAttribs, &mGlConfig, 1, &numConfigs)
106 && (numConfigs > 0));
107
108 mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mWindow, NULL);
109 EGL_RESULT_CHECK(mEglSurface != EGL_NO_SURFACE);
110
111 mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, contextAttribs);
112 EGL_RESULT_CHECK(mEglContext != EGL_NO_CONTEXT);
113
114 EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
115 EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &mWidth));
116 EGL_RESULT_CHECK(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &mHeight));
117
118 return true;
119 }
120
eglTearDown()121 void Renderer::eglTearDown() {
122 SCOPED_TRACE();
123 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
124
125 if (mEglContext != EGL_NO_CONTEXT) {
126 eglDestroyContext(mEglDisplay, mEglContext);
127 mEglContext = EGL_NO_CONTEXT;
128 }
129
130 if (mEglSurface != EGL_NO_SURFACE) {
131 mEglSurface = EGL_NO_SURFACE;
132 }
133
134 if (mEglDisplay != EGL_NO_DISPLAY) {
135 eglTerminate(mEglDisplay);
136 mEglDisplay = EGL_NO_DISPLAY;
137 }
138 }
139
setUp(int)140 bool Renderer::setUp(int /*workload*/) {
141 SCOPED_TRACE();
142
143 EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
144
145 if (mOffscreen) {
146 mFboWidth = FBO_SIZE;
147 mFboHeight = FBO_SIZE;
148
149 glGenFramebuffers(1, &mFboId);
150 glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
151
152 glGenRenderbuffers(1, &mFboDepthId);
153 glBindRenderbuffer(GL_RENDERBUFFER, mFboDepthId);
154 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mFboWidth, mFboHeight);
155 glBindRenderbuffer(GL_RENDERBUFFER, 0);
156 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
157 GL_RENDERBUFFER, mFboDepthId);
158
159 mFboTexId = GLUtils::genTexture(mFboWidth, mFboHeight, 0);
160 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFboTexId, 0);
161
162 GLuint err = glGetError();
163 if (err != GL_NO_ERROR) {
164 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d", err);
165 return false;
166 }
167
168 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
169 if (status != GL_FRAMEBUFFER_COMPLETE) {
170 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Framebuffer not complete: %d", status);
171 return false;
172 }
173 // Create fbo program.
174 mFboProgId = GLUtils::createProgram(&FBO_VERTEX, &FBO_FRAGMENT);
175 if (mFboProgId == 0) {
176 return false;
177 }
178 // Bind attributes.
179 mFboTexUniformHandle = glGetUniformLocation(mFboProgId, "u_Texture");
180 mFboXOffsetUniformHandle = glGetUniformLocation(mFboProgId, "u_XOffset");
181 mFboYOffsetUniformHandle = glGetUniformLocation(mFboProgId, "u_YOffset");
182 mFboPositionHandle = glGetAttribLocation(mFboProgId, "a_Position");
183 mFboTexCoordHandle = glGetAttribLocation(mFboProgId, "a_TexCoord");
184 } else {
185 mFboWidth = 0;
186 mFboHeight = 0;
187 mFboId = 0;
188 mFboDepthId = 0;
189 mFboTexId = 0;
190 }
191
192 GLuint err = glGetError();
193 if (err != GL_NO_ERROR) {
194 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in setUp", err);
195 return false;
196 }
197
198 return true;
199 }
200
tearDown()201 bool Renderer::tearDown() {
202 SCOPED_TRACE();
203 if (mOffscreen) {
204 if (mFboId != 0) {
205 glDeleteFramebuffers(1, &mFboId);
206 mFboId = 0;
207 }
208 if (mFboDepthId != 0) {
209 glDeleteRenderbuffers(1, &mFboDepthId);
210 mFboDepthId = 0;
211 }
212 if (mFboTexId != 0) {
213 glDeleteTextures(1, &mFboTexId);
214 mFboTexId = 0;
215 }
216 }
217 GLuint err = glGetError();
218 if (err != GL_NO_ERROR) {
219 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in tearDown", err);
220 return false;
221 }
222
223 return true;
224 }
225
draw()226 bool Renderer::draw() {
227 SCOPED_TRACE();
228
229 EGL_RESULT_CHECK(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext));
230
231 glBindFramebuffer(GL_FRAMEBUFFER, 0);
232 glViewport(0, 0, mWidth, mHeight);
233
234 if (mOffscreen) {
235 // Set the background clear color to black.
236 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
237 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
238 for (int i = 0; i < OFFSCREEN_INNER_FRAMES; i++) {
239 // Switch to FBO and re-attach.
240 glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
241 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
242 GL_RENDERBUFFER, mFboDepthId);
243 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
244 GL_TEXTURE_2D, mFboTexId, 0);
245 glViewport(0, 0, mFboWidth, mFboHeight);
246
247 // Render workload.
248 drawWorkload();
249 glFlush();
250
251 // Switch back to display.
252 glBindFramebuffer(GL_FRAMEBUFFER, 0);
253 glViewport(0, 0, mWidth, mHeight);
254
255 // No culling of back faces
256 glDisable (GL_CULL_FACE);
257 // No depth testing
258 glDisable (GL_DEPTH_TEST);
259 // No blending
260 glDisable (GL_BLEND);
261
262 glUseProgram(mFboProgId);
263
264 // Set the texture.
265 glActiveTexture (GL_TEXTURE0);
266 glBindTexture(GL_TEXTURE_2D, mFboTexId);
267 glUniform1i(mFboTexUniformHandle, 0);
268
269 // Set the offsets
270 glUniform1f(mFboXOffsetUniformHandle, CENTER_GRID(i / OFFSCREEN_GRID_SIZE));
271 glUniform1f(mFboYOffsetUniformHandle, CENTER_GRID(i % OFFSCREEN_GRID_SIZE));
272
273 glEnableVertexAttribArray(mFboPositionHandle);
274 glEnableVertexAttribArray(mFboTexCoordHandle);
275 glVertexAttribPointer(mFboPositionHandle, 3, GL_FLOAT, false, 0, FBO_VERTICES);
276 glVertexAttribPointer(mFboTexCoordHandle, 2, GL_FLOAT, false, 0, FBO_TEX_COORDS);
277
278 // Render FBO to display.
279 glDrawArrays(GL_TRIANGLES, 0, FBO_NUM_VERTICES);
280 }
281 } else {
282 // Render workload.
283 drawWorkload();
284 }
285
286 GLuint err = glGetError();
287 if (err != GL_NO_ERROR) {
288 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in draw", err);
289 return false;
290 }
291
292 EGL_RESULT_CHECK(eglSwapBuffers(mEglDisplay, mEglSurface));
293 return true;
294 }
295