1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2011 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Bitmap;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.opengl.GLES20;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.opengl.GLUtils;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.os.Looper;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteOrder;
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * TODO: Make this package-private as RenderTarget and TextureSource should suffice as public
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * facing OpenGL utilities.
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @hide
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class GLToolbox {
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int textureNone() {
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return 0;
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static boolean isTexture(int texId) {
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return GLES20.glIsTexture(texId);
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void deleteTexture(int texId) {
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] textures = new int[] { texId };
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        assertNonUiThread("glDeleteTextures");
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDeleteTextures(1, textures, 0);
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glDeleteTextures");
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void deleteFbo(int fboId) {
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] fbos = new int[] { fboId };
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        assertNonUiThread("glDeleteFramebuffers");
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDeleteFramebuffers(1, fbos, 0);
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glDeleteFramebuffers");
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int generateTexture() {
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] textures = new int[1];
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glGenTextures(1, textures, 0);
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glGenTextures");
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return textures[0];
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int generateFbo() {
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] fbos = new int[1];
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glGenFramebuffers(1, fbos, 0);
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glGenFramebuffers");
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return fbos[0];
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void readFbo(int fboId, ByteBuffer pixels, int width, int height) {
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixels);
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glReadPixels");
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void readTarget(RenderTarget target, ByteBuffer pixels, int width, int height) {
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        target.focus();
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixels);
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glReadPixels");
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int attachedTexture(int fboId) {
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] params = new int[1];
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glGetFramebufferAttachmentParameteriv(
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.GL_FRAMEBUFFER,
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.GL_COLOR_ATTACHMENT0,
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GLES20.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            params, 0);
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glGetFramebufferAttachmentParameteriv");
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return params[0];
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void attachTextureToFbo(int texId, int fboId) {
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      GLES20.GL_COLOR_ATTACHMENT0,
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      GLES20.GL_TEXTURE_2D,
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      texId,
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      0);
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glFramebufferTexture2D");
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void allocateTexturePixels(int texId, int target, int width, int height) {
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setTexturePixels(texId, target, (ByteBuffer)null, width, height);
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void setTexturePixels(int texId, int target, Bitmap bitmap) {
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glBindTexture(target, texId);
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLUtils.texImage2D(target, 0, bitmap, 0);
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glTexImage2D");
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setDefaultTexParams();
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void setTexturePixels(int texId, int target, ByteBuffer pixels,
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                        int width, int height) {
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glBindTexture(target, texId);
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // For some devices, "pixels" being null causes system error.
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (pixels == null) {
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            pixels = ByteBuffer.allocateDirect(width * height * 4);
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glTexImage2D(target, 0, GLES20.GL_RGBA, width, height, 0,
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixels);
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glTexImage2D");
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setDefaultTexParams();
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void setDefaultTexParams() {
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                               GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                               GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                               GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                               GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glTexParameteri");
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int vboNone() {
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return 0;
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static int generateVbo() {
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] vbos = new int[1];
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glGenBuffers(1, vbos, 0);
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glGenBuffers");
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return vbos[0];
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void setVboData(int vboId, ByteBuffer data) {
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, data.remaining(), data, GLES20.GL_STATIC_DRAW);
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glBufferData");
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void setVboFloats(int vboId, float[] values) {
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int len = values.length * 4;
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ByteBuffer buffer = ByteBuffer.allocateDirect(len).order(ByteOrder.nativeOrder());
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        setVboData(vboId, buffer);
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static boolean isVbo(int vboId) {
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return GLES20.glIsBuffer(vboId);
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void deleteVbo(int vboId) {
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] buffers = new int[] { vboId };
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GLES20.glDeleteBuffers(1, buffers, 0);
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkGlError("glDeleteBuffers");
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static void checkGlError(String operation) {
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int error;
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("GL Operation '" + operation + "' caused error "
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + Integer.toHexString(error) + "!");
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Make sure we are not operating in the UI thread.
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * It is often tricky to track down bugs that happen when issuing GL commands in the UI thread.
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is especially true when releasing GL resources. Often this will cause errors much later
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * on. Therefore we make sure we do not do these dangerous operations on the UI thread.
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static void assertNonUiThread(String operation) {
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Attempting to perform GL operation '" + operation
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "' on UI thread!");
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
195