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
15 #include <android/native_window.h>
16
17 #include <stdlib.h>
18
19 #include <EGL/egl.h>
20 #include <EGL/eglext.h>
21 #include <GLES2/gl2.h>
22 #include <GLES2/gl2ext.h>
23
24 #include "ContextSwitchRenderer.h"
25 #include <graphics/GLUtils.h>
26
27 #define LOG_TAG "CTS_OPENGL"
28 #define LOG_NDEBUG 0
29 #include <android/log.h>
30 #include <Trace.h>
31
32 static const EGLint contextAttribs[] = {
33 EGL_CONTEXT_CLIENT_VERSION, 2,
34 EGL_NONE };
35
36 static const int NUM_WORKER_CONTEXTS = 7;
37
38 static const int CS_TEXTURE_SIZE = 64;
39
40 static const int CS_NUM_VERTICES = 6;
41
42 static const float CS_VERTICES[CS_NUM_VERTICES * 3] = {
43 0.1f, 0.1f, -0.1f,
44 -0.1f, 0.1f, -0.1f,
45 -0.1f, -0.1f, -0.1f,
46 -0.1f, -0.1f, -0.1f,
47 0.1f, -0.1f, -0.1f,
48 0.1f, 0.1f, -0.1f };
49
50 static const float CS_TEX_COORDS[CS_NUM_VERTICES * 2] = {
51 1.0f, 1.0f,
52 0.0f, 1.0f,
53 0.0f, 0.0f,
54 0.0f, 0.0f,
55 1.0f, 0.0f,
56 1.0f, 1.0f };
57
58 static const char* CS_VERTEX =
59 "attribute vec4 a_Position;"
60 "attribute vec2 a_TexCoord;"
61 "uniform float u_Translate;"
62 "varying vec2 v_TexCoord;"
63 "void main() {"
64 " v_TexCoord = a_TexCoord;"
65 " gl_Position.x = a_Position.x + u_Translate;"
66 " gl_Position.yzw = a_Position.yzw;"
67 "}";
68
69 static const char* CS_FRAGMENT =
70 "precision mediump float;"
71 "uniform sampler2D u_Texture;"
72 "varying vec2 v_TexCoord;"
73 "void main() {"
74 " gl_FragColor = texture2D(u_Texture, v_TexCoord);"
75 "}";
76
ContextSwitchRenderer(ANativeWindow * window,bool offscreen)77 ContextSwitchRenderer::ContextSwitchRenderer(ANativeWindow* window, bool offscreen) :
78 Renderer(window, offscreen), mContexts(NULL), mWorkload(0) {
79 }
80
setUp(int workload)81 bool ContextSwitchRenderer::setUp(int workload) {
82 SCOPED_TRACE();
83 mWorkload = workload;
84 if (!Renderer::setUp(workload)) {
85 return false;
86 }
87
88 // Setup texture.
89 mTextureId = GLUtils::genTexture(CS_TEXTURE_SIZE, CS_TEXTURE_SIZE, GLUtils::RANDOM_FILL);
90 if (mTextureId == 0) {
91 return false;
92 }
93
94 // Create program.
95 mProgramId = GLUtils::createProgram(&CS_VERTEX, &CS_FRAGMENT);
96 if (mProgramId == 0) {
97 return false;
98 }
99 // Bind attributes.
100 mTextureUniformHandle = glGetUniformLocation(mProgramId, "u_Texture");
101 mTranslateUniformHandle = glGetUniformLocation(mProgramId, "u_Translate");
102 mPositionHandle = glGetAttribLocation(mProgramId, "a_Position");
103 mTexCoordHandle = glGetAttribLocation(mProgramId, "a_TexCoord");
104
105 mContexts = new EGLContext[NUM_WORKER_CONTEXTS];
106 mFboIds = new GLuint[NUM_WORKER_CONTEXTS];
107 for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) {
108 // Create the contexts, they share data with the main one.
109 mContexts[i] = eglCreateContext(mEglDisplay, mGlConfig, mEglContext, contextAttribs);
110 if (EGL_NO_CONTEXT == mContexts[i] || EGL_SUCCESS != eglGetError()) {
111 return false;
112 }
113
114 if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i])
115 || EGL_SUCCESS != eglGetError()) {
116 return false;
117 }
118 if (mOffscreen) {
119 // FBOs are not shared across contexts, textures and renderbuffers are though.
120 glGenFramebuffers(1, &mFboIds[i]);
121 glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]);
122
123 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
124 GL_RENDERBUFFER, mFboDepthId);
125
126 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
127 GL_TEXTURE_2D, mFboTexId, 0);
128 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
129 if (status != GL_FRAMEBUFFER_COMPLETE) {
130 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Framebuffer not complete: %d", status);
131 return false;
132 }
133 }
134 }
135 return true;
136 }
137
tearDown()138 bool ContextSwitchRenderer::tearDown() {
139 SCOPED_TRACE();
140 if (mContexts) {
141 // Destroy the contexts, the main one will be handled by Renderer::eglTearDown().
142 for (int i = 0; i < NUM_WORKER_CONTEXTS; i++) {
143 if (mOffscreen) {
144 if (mFboIds[i] != 0) {
145 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]);
146 glDeleteFramebuffers(1, &mFboIds[i]);
147 mFboIds[i] = 0;
148 }
149 }
150 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
151 eglDestroyContext(mEglDisplay, mContexts[i]);
152 }
153 delete[] mContexts;
154 }
155 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
156 if (mTextureId != 0) {
157 glDeleteTextures(1, &mTextureId);
158 mTextureId = 0;
159 }
160 if (!Renderer::tearDown()) {
161 return false;
162 }
163 return true;
164 }
165
drawWorkload()166 void ContextSwitchRenderer::drawWorkload() {
167 SCOPED_TRACE();
168
169 if (mWorkload > 8) {
170 return; // This test does not support higher workloads.
171 }
172
173 // Set the background clear color to black.
174 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
175 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
176 // No culling of back faces
177 glDisable(GL_CULL_FACE);
178 // No depth testing
179 glDisable(GL_DEPTH_TEST);
180
181 EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
182
183 const int TOTAL_NUM_CONTEXTS = NUM_WORKER_CONTEXTS + 1;
184 const float TRANSLATION = 0.9f - (TOTAL_NUM_CONTEXTS * 0.2f);
185 for (int i = 0; i < TOTAL_NUM_CONTEXTS; i++) {
186 eglWaitSyncKHR(mEglDisplay, fence, 0);
187 eglDestroySyncKHR(mEglDisplay, fence);
188 glUseProgram(mProgramId);
189
190 // Set the texture.
191 glActiveTexture (GL_TEXTURE0);
192 glBindTexture(GL_TEXTURE_2D, mTextureId);
193 glUniform1i(mTextureUniformHandle, 0);
194
195 // Set the x translate.
196 glUniform1f(mTranslateUniformHandle, (i * 0.2f) + TRANSLATION);
197
198 glEnableVertexAttribArray(mPositionHandle);
199 glEnableVertexAttribArray(mTexCoordHandle);
200 glVertexAttribPointer(mPositionHandle, 3, GL_FLOAT, false, 0, CS_VERTICES);
201 glVertexAttribPointer(mTexCoordHandle, 2, GL_FLOAT, false, 0, CS_TEX_COORDS);
202
203 glDrawArrays(GL_TRIANGLES, 0, CS_NUM_VERTICES);
204 fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
205
206 // Switch to next context.
207 if (i < (mWorkload - 1)) {
208 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mContexts[i]);
209 // Switch to FBO and re-attach.
210 if (mOffscreen) {
211 glBindFramebuffer(GL_FRAMEBUFFER, mFboIds[i]);
212 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
213 GL_RENDERBUFFER, mFboDepthId);
214 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
215 GL_TEXTURE_2D, mFboTexId, 0);
216 glViewport(0, 0, mFboWidth, mFboHeight);
217 }
218 }
219 GLuint err = glGetError();
220 if (err != GL_NO_ERROR) {
221 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GLError %d in drawWorkload", err);
222 break;
223 }
224 }
225
226 eglWaitSyncKHR(mEglDisplay, fence, 0);
227 eglDestroySyncKHR(mEglDisplay, fence);
228
229 // Switch back to the main context.
230 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
231 if (mOffscreen) {
232 glBindFramebuffer(GL_FRAMEBUFFER, mFboId);
233 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
234 GL_RENDERBUFFER, mFboDepthId);
235 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
236 GL_TEXTURE_2D, mFboTexId, 0);
237 glViewport(0, 0, mFboWidth, mFboHeight);
238 }
239 }
240