• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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