[go: nahoru, domu]

1/*
2 * Copyright (C) 2015 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 */
16package com.android.test.uibench.opengl;
17
18import android.content.res.Resources;
19import android.graphics.Bitmap;
20import android.graphics.BitmapFactory;
21import android.graphics.SurfaceTexture;
22import android.opengl.GLUtils;
23import android.util.Log;
24
25import com.android.test.uibench.R;
26
27import java.nio.ByteBuffer;
28import java.nio.ByteOrder;
29import java.nio.FloatBuffer;
30
31import javax.microedition.khronos.egl.EGL10;
32import javax.microedition.khronos.egl.EGLConfig;
33import javax.microedition.khronos.egl.EGLContext;
34import javax.microedition.khronos.egl.EGLDisplay;
35import javax.microedition.khronos.egl.EGLSurface;
36
37import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
38import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
39import static android.opengl.GLES20.GL_COMPILE_STATUS;
40import static android.opengl.GLES20.GL_FLOAT;
41import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
42import static android.opengl.GLES20.GL_LINEAR;
43import static android.opengl.GLES20.GL_LINK_STATUS;
44import static android.opengl.GLES20.GL_NO_ERROR;
45import static android.opengl.GLES20.GL_RGBA;
46import static android.opengl.GLES20.GL_TEXTURE0;
47import static android.opengl.GLES20.GL_TEXTURE_2D;
48import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
49import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
50import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
51import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
52import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
53import static android.opengl.GLES20.GL_TRUE;
54import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
55import static android.opengl.GLES20.GL_VERTEX_SHADER;
56import static android.opengl.GLES20.glActiveTexture;
57import static android.opengl.GLES20.glAttachShader;
58import static android.opengl.GLES20.glBindTexture;
59import static android.opengl.GLES20.glClear;
60import static android.opengl.GLES20.glClearColor;
61import static android.opengl.GLES20.glCompileShader;
62import static android.opengl.GLES20.glCreateProgram;
63import static android.opengl.GLES20.glCreateShader;
64import static android.opengl.GLES20.glDeleteProgram;
65import static android.opengl.GLES20.glDeleteShader;
66import static android.opengl.GLES20.glDrawArrays;
67import static android.opengl.GLES20.glEnableVertexAttribArray;
68import static android.opengl.GLES20.glGenTextures;
69import static android.opengl.GLES20.glGetAttribLocation;
70import static android.opengl.GLES20.glGetError;
71import static android.opengl.GLES20.glGetProgramInfoLog;
72import static android.opengl.GLES20.glGetProgramiv;
73import static android.opengl.GLES20.glGetShaderInfoLog;
74import static android.opengl.GLES20.glGetShaderiv;
75import static android.opengl.GLES20.glGetUniformLocation;
76import static android.opengl.GLES20.glLinkProgram;
77import static android.opengl.GLES20.glShaderSource;
78import static android.opengl.GLES20.glTexParameteri;
79import static android.opengl.GLES20.glUniform1i;
80import static android.opengl.GLES20.glUseProgram;
81import static android.opengl.GLES20.glVertexAttribPointer;
82
83public class ImageFlipRenderThread extends Thread {
84    public static final String LOG_TAG = "GLTextureView";
85
86    static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
87    static final int EGL_OPENGL_ES2_BIT = 4;
88
89    private volatile boolean mFinished;
90
91    private final Resources mResources;
92    private final SurfaceTexture mSurface;
93
94    private EGL10 mEgl;
95    private EGLDisplay mEglDisplay;
96    private EGLConfig mEglConfig;
97    private EGLContext mEglContext;
98    private EGLSurface mEglSurface;
99
100    public ImageFlipRenderThread(Resources resources, SurfaceTexture surface) {
101        mResources = resources;
102        mSurface = surface;
103    }
104
105    private static final String sSimpleVS =
106            "attribute vec4 position;\n" +
107                    "attribute vec2 texCoords;\n" +
108                    "varying vec2 outTexCoords;\n" +
109                    "\nvoid main(void) {\n" +
110                    "    outTexCoords = texCoords;\n" +
111                    "    gl_Position = position;\n" +
112                    "}\n\n";
113    private static final String sSimpleFS =
114            "precision mediump float;\n\n" +
115                    "varying vec2 outTexCoords;\n" +
116                    "uniform sampler2D texture;\n" +
117                    "\nvoid main(void) {\n" +
118                    "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
119                    "}\n\n";
120
121    private static final int FLOAT_SIZE_BYTES = 4;
122    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
123    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
124    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
125    private final float[] mTriangleVerticesData = {
126            // X, Y, Z, U, V
127            -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
128            1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
129            -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
130            1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
131    };
132
133    @Override
134    public void run() {
135        initGL();
136
137        FloatBuffer triangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
138                * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
139        triangleVertices.put(mTriangleVerticesData).position(0);
140
141        int texture = loadTexture(R.drawable.large_photo);
142        int program = buildProgram(sSimpleVS, sSimpleFS);
143
144        int attribPosition = glGetAttribLocation(program, "position");
145        checkGlError();
146
147        int attribTexCoords = glGetAttribLocation(program, "texCoords");
148        checkGlError();
149
150        int uniformTexture = glGetUniformLocation(program, "texture");
151        checkGlError();
152
153        glBindTexture(GL_TEXTURE_2D, texture);
154        checkGlError();
155
156        glUseProgram(program);
157        checkGlError();
158
159        glEnableVertexAttribArray(attribPosition);
160        checkGlError();
161
162        glEnableVertexAttribArray(attribTexCoords);
163        checkGlError();
164
165        glUniform1i(uniformTexture, 0);
166        checkGlError();
167
168        // drawQuad
169        triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
170        glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
171                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
172        checkGlError();
173
174        triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
175        glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
176                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
177        checkGlError();
178
179        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
180        checkGlError();
181
182        while (!mFinished) {
183            checkCurrent();
184
185            glClear(GL_COLOR_BUFFER_BIT);
186            checkGlError();
187
188            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
189            checkGlError();
190
191            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
192                throw new RuntimeException("Cannot swap buffers");
193            }
194            checkEglError();
195
196            try {
197                Thread.sleep(2000);
198            } catch (InterruptedException e) {
199                // Ignore
200            }
201        }
202
203        finishGL();
204    }
205
206    private int loadTexture(int resource) {
207        int[] textures = new int[1];
208
209        glActiveTexture(GL_TEXTURE0);
210        glGenTextures(1, textures, 0);
211        checkGlError();
212
213        int texture = textures[0];
214        glBindTexture(GL_TEXTURE_2D, texture);
215        checkGlError();
216
217        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
218        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
219
220        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
221        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
222
223        Bitmap bitmap = BitmapFactory.decodeResource(mResources, resource);
224
225        GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
226        checkGlError();
227
228        bitmap.recycle();
229
230        return texture;
231    }
232
233    private static int buildProgram(String vertex, String fragment) {
234        int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
235        if (vertexShader == 0) return 0;
236
237        int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
238        if (fragmentShader == 0) return 0;
239
240        int program = glCreateProgram();
241        glAttachShader(program, vertexShader);
242        checkGlError();
243
244        glAttachShader(program, fragmentShader);
245        checkGlError();
246
247        glLinkProgram(program);
248        checkGlError();
249
250        int[] status = new int[1];
251        glGetProgramiv(program, GL_LINK_STATUS, status, 0);
252        if (status[0] != GL_TRUE) {
253            String error = glGetProgramInfoLog(program);
254            Log.d(LOG_TAG, "Error while linking program:\n" + error);
255            glDeleteShader(vertexShader);
256            glDeleteShader(fragmentShader);
257            glDeleteProgram(program);
258            return 0;
259        }
260
261        return program;
262    }
263
264    private static int buildShader(String source, int type) {
265        int shader = glCreateShader(type);
266
267        glShaderSource(shader, source);
268        checkGlError();
269
270        glCompileShader(shader);
271        checkGlError();
272
273        int[] status = new int[1];
274        glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
275        if (status[0] != GL_TRUE) {
276            String error = glGetShaderInfoLog(shader);
277            Log.d(LOG_TAG, "Error while compiling shader:\n" + error);
278            glDeleteShader(shader);
279            return 0;
280        }
281
282        return shader;
283    }
284
285    private void checkEglError() {
286        int error = mEgl.eglGetError();
287        if (error != EGL10.EGL_SUCCESS) {
288            Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error));
289        }
290    }
291
292    private static void checkGlError() {
293        int error = glGetError();
294        if (error != GL_NO_ERROR) {
295            Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
296        }
297    }
298
299    private void finishGL() {
300        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
301        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
302    }
303
304    private void checkCurrent() {
305        if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
306                !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
307            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
308                throw new RuntimeException("eglMakeCurrent failed "
309                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
310            }
311        }
312    }
313
314    private void initGL() {
315        mEgl = (EGL10) EGLContext.getEGL();
316
317        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
318        if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
319            throw new RuntimeException("eglGetDisplay failed "
320                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
321        }
322
323        int[] version = new int[2];
324        if (!mEgl.eglInitialize(mEglDisplay, version)) {
325            throw new RuntimeException("eglInitialize failed " +
326                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
327        }
328
329        mEglConfig = chooseEglConfig();
330        if (mEglConfig == null) {
331            throw new RuntimeException("eglConfig not initialized");
332        }
333
334        mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
335
336        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);
337
338        if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
339            int error = mEgl.eglGetError();
340            if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
341                Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
342                return;
343            }
344            throw new RuntimeException("createWindowSurface failed "
345                    + GLUtils.getEGLErrorString(error));
346        }
347
348        if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
349            throw new RuntimeException("eglMakeCurrent failed "
350                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
351        }
352    }
353
354
355    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
356        int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
357        return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
358    }
359
360    private EGLConfig chooseEglConfig() {
361        int[] configsCount = new int[1];
362        EGLConfig[] configs = new EGLConfig[1];
363        int[] configSpec = getConfig();
364        if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
365            throw new IllegalArgumentException("eglChooseConfig failed " +
366                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
367        } else if (configsCount[0] > 0) {
368            return configs[0];
369        }
370        return null;
371    }
372
373    private static int[] getConfig() {
374        return new int[]{
375                EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
376                EGL10.EGL_RED_SIZE, 8,
377                EGL10.EGL_GREEN_SIZE, 8,
378                EGL10.EGL_BLUE_SIZE, 8,
379                EGL10.EGL_ALPHA_SIZE, 8,
380                EGL10.EGL_DEPTH_SIZE, 0,
381                EGL10.EGL_STENCIL_SIZE, 0,
382                EGL10.EGL_NONE
383        };
384    }
385
386    public void finish() {
387        mFinished = true;
388    }
389}
390