Android GPUImage

1.文章介绍

不甘落后,就努力充实自己。
根据自己的学习计划,最近看了看Android平台上的图片处理相关构架。发现无论是glide-transformations,还是Picasso TransformationsFresco Processors等主流的开源项目都基于GPUImage实现图片特效的渲染。借此机会自己也记录下部分学习内容。

2.干货

一.核心类

1.GPUImage.java
Android OpenGLES核心实现类,配合GLSurfaceView和GPUImageFilter实现渲染。

    /**
     * Sets the GLSurfaceView which will display the preview.
     *
     * @param view the GLSurfaceView
     */
    public void setGLSurfaceView(final GLSurfaceView view) {
        mGlSurfaceView = view;
        mGlSurfaceView.setEGLContextClientVersion(2);
        mGlSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        mGlSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
        mGlSurfaceView.setRenderer(mRenderer);
        mGlSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
        mGlSurfaceView.requestRender();
    }

    /**
     * Sets the filter which should be applied to the image which was (or will
     * be) set by setImage(...).
     *
     * @param filter the new filter
     */
    public void setFilter(final GPUImageFilter filter) {
        mFilter = filter;
        mRenderer.setFilter(mFilter);
        requestRender();
    }

    /**
     * Request the preview to be rendered again.
     */
    public void requestRender() {
        if (mGlSurfaceView != null) {
            mGlSurfaceView.requestRender();
        }
    }

比如渲染一张图片:

/**
     * Sets the image on which the filter should be applied.
     *
     * @param bitmap the new image
     */
    public void setImage(final Bitmap bitmap) {
        mCurrentBitmap = bitmap;
        mRenderer.setImageBitmap(bitmap, false);
        requestRender();
    }

2.GPUImageView.java

对GPUImage的进一步封装,实际上是一个包含了GPUImageGLSurfaceView的FrameLayout,使用时通过配合使用GPUImageFilter调整参数即可。
这里释放下程序员天赋技能(搬砖),以下是ActivityGallery.java的源码,通过GPUImageView和Filter直接实现渲染效果:

/* 
 * Copyright (C) 2012 CyberAgent 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
 
package jp.co.cyberagent.android.gpuimage.sample.activity; 
 
import jp.co.cyberagent.android.gpuimage.GPUImageFilter; 
import jp.co.cyberagent.android.gpuimage.GPUImageView; 
import jp.co.cyberagent.android.gpuimage.GPUImageView.OnPictureSavedListener; 
import jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools; 
import jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools.FilterAdjuster; 
import jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools.OnGpuImageFilterChosenListener; 
import jp.co.cyberagent.android.gpuimage.sample.R; 
import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.SeekBar; 
import android.widget.SeekBar.OnSeekBarChangeListener; 
import android.widget.Toast; 
 
public class ActivityGallery extends Activity implements OnSeekBarChangeListener, 
        OnClickListener, OnPictureSavedListener { 
 
    private static final int REQUEST_PICK_IMAGE = 1; 
    private GPUImageFilter mFilter; 
    private FilterAdjuster mFilterAdjuster; 
    private GPUImageView mGPUImageView; 
 
    @Override 
    public void onCreate(final Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_gallery); 
        ((SeekBar) findViewById(R.id.seekBar)).setOnSeekBarChangeListener(this); 
        findViewById(R.id.button_choose_filter).setOnClickListener(this); 
        findViewById(R.id.button_save).setOnClickListener(this); 
 
        mGPUImageView = (GPUImageView) findViewById(R.id.gpuimage); 
 
        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); 
        photoPickerIntent.setType("image/*"); 
        startActivityForResult(photoPickerIntent, REQUEST_PICK_IMAGE); 
    } 
 
    @Override 
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { 
        switch (requestCode) { 
            case REQUEST_PICK_IMAGE: 
                if (resultCode == RESULT_OK) { 
                    handleImage(data.getData()); 
                } else { 
                    finish(); 
                } 
                break; 
 
            default: 
                super.onActivityResult(requestCode, resultCode, data); 
                break; 
        } 
    } 
 
    @Override 
    public void onClick(final View v) { 
        switch (v.getId()) { 
            case R.id.button_choose_filter: 
                GPUImageFilterTools.showDialog(this, new OnGpuImageFilterChosenListener() { 
 
                    @Override 
                    public void onGpuImageFilterChosenListener(final GPUImageFilter filter) { 
                        switchFilterTo(filter); 
                        mGPUImageView.requestRender(); 
                    } 
 
                }); 
                break; 
            case R.id.button_save: 
                saveImage(); 
                break; 
 
            default: 
                break; 
        } 
 
    } 
 
    @Override 
    public void onPictureSaved(final Uri uri) { 
        Toast.makeText(this, "Saved: " + uri.toString(), Toast.LENGTH_SHORT).show(); 
    } 
 
    private void saveImage() { 
        String fileName = System.currentTimeMillis() + ".jpg"; 
        mGPUImageView.saveToPictures("GPUImage", fileName, this); 
//        mGPUImageView.saveToPictures("GPUImage", fileName, 1600, 1600, this); 
    } 
 
    private void switchFilterTo(final GPUImageFilter filter) { 
        if (mFilter == null 
                || (filter != null && !mFilter.getClass().equals(filter.getClass()))) { 
            mFilter = filter; 
            mGPUImageView.setFilter(mFilter); 
            mFilterAdjuster = new FilterAdjuster(mFilter); 
 
            findViewById(R.id.seekBar).setVisibility( 
                    mFilterAdjuster.canAdjust() ? View.VISIBLE : View.GONE); 
        } 
    } 
 
    @Override 
    public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) { 
        if (mFilterAdjuster != null) { 
            mFilterAdjuster.adjust(progress); 
        } 
        mGPUImageView.requestRender(); 
    } 
 
    @Override 
    public void onStartTrackingTouch(final SeekBar seekBar) { 
    } 
 
    @Override 
    public void onStopTrackingTouch(final SeekBar seekBar) { 
    } 
 
    private void handleImage(final Uri selectedImage) { 
        mGPUImageView.setImage(selectedImage); 
    } 
} 

3.GPUImageFilter.java

GPUImageFilter是用来配置OpenGLES渲染的主类,所谓VERTEX,就是顶点,FRAGMENT就是片元,这都涉及到OpenGL的渲染相关知识,多少需要了解。

   public static final String NO_FILTER_VERTEX_SHADER = "" +
            "attribute vec4 position;\n" +
            "attribute vec4 inputTextureCoordinate;\n" +
            " \n" +
            "varying vec2 textureCoordinate;\n" +
            " \n" +
            "void main()\n" +
            "{\n" +
            "    gl_Position = position;\n" +
            "    textureCoordinate = inputTextureCoordinate.xy;\n" +
            "}";
    public static final String NO_FILTER_FRAGMENT_SHADER = "" +
            "varying highp vec2 textureCoordinate;\n" +
            " \n" +
            "uniform sampler2D inputImageTexture;\n" +
            " \n" +
            "void main()\n" +
            "{\n" +
            "     gl_FragColor = texture2D(inputImageTexture, textureCoordinate);\n" +
            "}";

    public GPUImageFilter() {
        this(NO_FILTER_VERTEX_SHADER, NO_FILTER_FRAGMENT_SHADER);
    }

    public GPUImageFilter(final String vertexShader, final String fragmentShader) {
        mRunOnDraw = new LinkedList<Runnable>();
        mVertexShader = vertexShader;
        mFragmentShader = fragmentShader;
    }

    public final void init() {
        onInit();
        mIsInitialized = true;
        onInitialized();
    }

    public void onInit() {
        mGLProgId = OpenGlUtils.loadProgram(mVertexShader, mFragmentShader);
        mGLAttribPosition = GLES20.glGetAttribLocation(mGLProgId, "position");
        mGLUniformTexture = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture");
        mGLAttribTextureCoordinate = GLES20.glGetAttribLocation(mGLProgId,
                "inputTextureCoordinate");
        mIsInitialized = true;
    }

上面一段代码是对OpenGL不配置任何效果,即按原始图片效果渲染图片;若需要自定义渲染效果,可以根据JAVA的继承特性扩展一个继承于GPUImageFilter的子类即可,因此在GPUImage的源码中你可以看到很多类似GPUImageAlphaBlendFilter、GPUImageBoxBlurFilter等渲染特效的子类。

4.GPUImageRenderer.java

GPUImageRenderer是接口类Renderer的实现,在OpenGLES中如何理解Renderer呢?其实Renderer是GLSurfaceView(继承于SurfaceView)定义的一个接口类,作用就是实现事件回调

    public interface Renderer { 
        /** 
         * Called when the surface is created or recreated. 
         * <p> 
         * Called when the rendering thread 
         * starts and whenever the EGL context is lost. The EGL context will typically 
         * be lost when the Android device awakes after going to sleep. 
         * <p> 
         * Since this method is called at the beginning of rendering, as well as 
         * every time the EGL context is lost, this method is a convenient place to put 
         * code to create resources that need to be created when the rendering 
         * starts, and that need to be recreated when the EGL context is lost. 
         * Textures are an example of a resource that you might want to create 
         * here. 
         * <p> 
         * Note that when the EGL context is lost, all OpenGL resources associated 
         * with that context will be automatically deleted. You do not need to call 
         * the corresponding "glDelete" methods such as glDeleteTextures to 
         * manually delete these lost resources. 
         * <p> 
         * @param gl the GL interface. Use <code>instanceof</code> to 
         * test if the interface supports GL11 or higher interfaces. 
         * @param config the EGLConfig of the created surface. Can be used 
         * to create matching pbuffers. 
         */ 
        void onSurfaceCreated(GL10 gl, EGLConfig config); 
 
        /** 
         * Called when the surface changed size. 
         * <p> 
         * Called after the surface is created and whenever 
         * the OpenGL ES surface size changes. 
         * <p> 
         * Typically you will set your viewport here. If your camera 
         * is fixed then you could also set your projection matrix here: 
         * <pre class="prettyprint"> 
         * void onSurfaceChanged(GL10 gl, int width, int height) { 
         *     gl.glViewport(0, 0, width, height); 
         *     // for a fixed camera, set the projection too 
         *     float ratio = (float) width / height; 
         *     gl.glMatrixMode(GL10.GL_PROJECTION); 
         *     gl.glLoadIdentity(); 
         *     gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 
         * } 
         * </pre> 
         * @param gl the GL interface. Use <code>instanceof</code> to 
         * test if the interface supports GL11 or higher interfaces. 
         * @param width 
         * @param height 
         */ 
        void onSurfaceChanged(GL10 gl, int width, int height); 
 
        /** 
         * Called to draw the current frame. 
         * <p> 
         * This method is responsible for drawing the current frame. 
         * <p> 
         * The implementation of this method typically looks like this: 
         * <pre class="prettyprint"> 
         * void onDrawFrame(GL10 gl) { 
         *     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
         *     //... other gl calls to render the scene ... 
         * } 
         * </pre> 
         * @param gl the GL interface. Use <code>instanceof</code> to 
         * test if the interface supports GL11 or higher interfaces. 
         */ 
        void onDrawFrame(GL10 gl); 
    }

5.GPUImageNativeLibrary.java

仅仅是对YUV和ARGB数据互转进行的封装,应该是考虑C代码的效率会更高。

package jp.co.cyberagent.android.gpuimage;

public class GPUImageNativeLibrary {
    static {
        System.loadLibrary("gpuimage-library");
    }

    public static native void YUVtoRBGA(byte[] yuv, int width, int height, int[] out);

    public static native void YUVtoARBG(byte[] yuv, int width, int height, int[] out);
}
/*
*yuv-decoder.c
*/
#include <jni.h> 
#include <android/log.h> 
 
JNIEXPORT void JNICALL Java_jp_co_cyberagent_android_gpuimage_GPUImageNativeLibrary_YUVtoRBGA(JNIEnv * env, jobject obj, jbyteArray yuv420sp, jint width, jint height, jintArray rgbOut) 
{ 
    int             sz; 
    int             i; 
    int             j; 
    int             Y; 
    int             Cr = 0; 
    int             Cb = 0; 
    int             pixPtr = 0; 
    int             jDiv2 = 0; 
    int             R = 0; 
    int             G = 0; 
    int             B = 0; 
    int             cOff; 
    int w = width; 
    int h = height; 
    sz = w * h; 
 
    jint *rgbData = (jint*) ((*env)->GetPrimitiveArrayCritical(env, rgbOut, 0)); 
    jbyte* yuv = (jbyte*) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, 0); 
 
    for(j = 0; j < h; j++) { 
             pixPtr = j * w; 
             jDiv2 = j >> 1; 
             for(i = 0; i < w; i++) { 
                     Y = yuv[pixPtr]; 
                     if(Y < 0) Y += 255; 
                     if((i & 0x1) != 1) { 
                             cOff = sz + jDiv2 * w + (i >> 1) * 2; 
                             Cb = yuv[cOff]; 
                             if(Cb < 0) Cb += 127; else Cb -= 128; 
                             Cr = yuv[cOff + 1]; 
                             if(Cr < 0) Cr += 127; else Cr -= 128; 
                     } 
                      
                     //ITU-R BT.601 conversion 
                     // 
                     //R = 1.164*(Y-16) + 2.018*(Cr-128); 
                     //G = 1.164*(Y-16) - 0.813*(Cb-128) - 0.391*(Cr-128); 
                     //B = 1.164*(Y-16) + 1.596*(Cb-128); 
                     // 
                     Y = Y + (Y >> 3) + (Y >> 5) + (Y >> 7); 
                     R = Y + (Cr << 1) + (Cr >> 6); 
                     if(R < 0) R = 0; else if(R > 255) R = 255; 
                     G = Y - Cb + (Cb >> 3) + (Cb >> 4) - (Cr >> 1) + (Cr >> 3); 
                     if(G < 0) G = 0; else if(G > 255) G = 255; 
                     B = Y + Cb + (Cb >> 1) + (Cb >> 4) + (Cb >> 5); 
                     if(B < 0) B = 0; else if(B > 255) B = 255; 
                     rgbData[pixPtr++] = 0xff000000 + (R << 16) + (G << 8) + B; 
             } 
    } 
 
    (*env)->ReleasePrimitiveArrayCritical(env, rgbOut, rgbData, 0); 
    (*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, 0); 
} 
 
JNIEXPORT void JNICALL Java_jp_co_cyberagent_android_gpuimage_GPUImageNativeLibrary_YUVtoARBG(JNIEnv * env, jobject obj, jbyteArray yuv420sp, jint width, jint height, jintArray rgbOut) 
{ 
    int             sz; 
    int             i; 
    int             j; 
    int             Y; 
    int             Cr = 0; 
    int             Cb = 0; 
    int             pixPtr = 0; 
    int             jDiv2 = 0; 
    int             R = 0; 
    int             G = 0; 
    int             B = 0; 
    int             cOff; 
    int w = width; 
    int h = height; 
    sz = w * h; 
 
    jint *rgbData = (jint*) ((*env)->GetPrimitiveArrayCritical(env, rgbOut, 0)); 
    jbyte* yuv = (jbyte*) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, 0); 
 
    for(j = 0; j < h; j++) { 
             pixPtr = j * w; 
             jDiv2 = j >> 1; 
             for(i = 0; i < w; i++) { 
                     Y = yuv[pixPtr]; 
                     if(Y < 0) Y += 255; 
                     if((i & 0x1) != 1) { 
                             cOff = sz + jDiv2 * w + (i >> 1) * 2; 
                             Cb = yuv[cOff]; 
                             if(Cb < 0) Cb += 127; else Cb -= 128; 
                             Cr = yuv[cOff + 1]; 
                             if(Cr < 0) Cr += 127; else Cr -= 128; 
                     } 
                      
                     //ITU-R BT.601 conversion 
                     // 
                     //R = 1.164*(Y-16) + 2.018*(Cr-128); 
                     //G = 1.164*(Y-16) - 0.813*(Cb-128) - 0.391*(Cr-128); 
                     //B = 1.164*(Y-16) + 1.596*(Cb-128); 
                     // 
                     Y = Y + (Y >> 3) + (Y >> 5) + (Y >> 7); 
                     R = Y + (Cr << 1) + (Cr >> 6); 
                     if(R < 0) R = 0; else if(R > 255) R = 255; 
                     G = Y - Cb + (Cb >> 3) + (Cb >> 4) - (Cr >> 1) + (Cr >> 3); 
                     if(G < 0) G = 0; else if(G > 255) G = 255; 
                     B = Y + Cb + (Cb >> 1) + (Cb >> 4) + (Cb >> 5); 
                     if(B < 0) B = 0; else if(B > 255) B = 255; 
                     rgbData[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R; 
             } 
    } 
 
    (*env)->ReleasePrimitiveArrayCritical(env, rgbOut, rgbData, 0); 
    (*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, 0); 
}

6.OpenGlUtils.java

直接使用Android OpenGLES API,相当与对OpenGLES的一层封装,简化了OpenGLES复杂的编程。

   public static int loadTexture(final Bitmap img, final int usedTexId, final boolean recycle) {
        int textures[] = new int[1];
        if (usedTexId == NO_TEXTURE) {
            GLES20.glGenTextures(1, textures, 0);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
                    GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img, 0);
        } else {
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId);
            GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, img);
            textures[0] = usedTexId;
        }
        if (recycle) {
            img.recycle();
        }
        return textures[0];
    }

GLES20.java是自动生成的代码,通过jni调用到OpenGLES库实现。

package android.opengl; 
 
/**
* OpenGL ES 2.0 
*/ 
public class GLES20 { 
    ...
    native private static void _nativeClassInit(); 
    static { 
        _nativeClassInit(); 
    } 
    // C function void glActiveTexture ( GLenum texture ) 
 
    public static native void glActiveTexture( 
        int texture 
    ); 
 
    // C function void glAttachShader ( GLuint program, GLuint shader ) 
 
    public static native void glAttachShader( 
        int program, 
        int shader 
    ); 
   ...
} 

GLUtils是Android已经封装好的OpenGL ES工具类:

/*                                   GLUtils.java
 * Copyright (C) 2006 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
 
package android.opengl; 
 
import android.graphics.Bitmap; 
 
import javax.microedition.khronos.egl.EGL10; 
import javax.microedition.khronos.egl.EGL11; 
 
/** 
 * 
 * Utility class to help bridging OpenGL ES and Android APIs. 
 * 
 */ 
 
public final class GLUtils { 
 
    private GLUtils() { 
    } 
 
    /** 
     * return the internal format as defined by OpenGL ES of the supplied bitmap. 
     * @param bitmap 
     * @return the internal format of the bitmap. 
     */ 
    public static int getInternalFormat(Bitmap bitmap) { 
        if (bitmap == null) { 
            throw new NullPointerException("getInternalFormat can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        int result = native_getInternalFormat(bitmap); 
        if (result < 0) { 
            throw new IllegalArgumentException("Unknown internalformat"); 
        } 
        return result; 
    } 
 
    /** 
     * Return the type as defined by OpenGL ES of the supplied bitmap, if there 
     * is one. If the bitmap is stored in a compressed format, it may not have 
     * a valid OpenGL ES type. 
     * @throws IllegalArgumentException if the bitmap does not have a type. 
     * @param bitmap 
     * @return the OpenGL ES type of the bitmap. 
     */ 
    public static int getType(Bitmap bitmap) { 
        if (bitmap == null) { 
            throw new NullPointerException("getType can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        int result = native_getType(bitmap); 
        if (result < 0) { 
            throw new IllegalArgumentException("Unknown type"); 
        } 
        return result; 
    } 
 
    /** 
     * Calls glTexImage2D() on the current OpenGL context. If no context is 
     * current the behavior is the same as calling glTexImage2D() with  no 
     * current context, that is, eglGetError() will return the appropriate 
     * error. 
     * Unlike glTexImage2D() bitmap cannot be null and will raise an exception 
     * in that case. 
     * All other parameters are identical to those used for glTexImage2D(). 
     * 
     * NOTE: this method doesn't change GL_UNPACK_ALIGNMENT, you must make 
     * sure to set it properly according to the supplied bitmap. 
     * 
     * Whether or not bitmap can have non power of two dimensions depends on 
     * the current OpenGL context. Always check glGetError() some time 
     * after calling this method, just like when using OpenGL directly. 
     * 
     * @param target 
     * @param level 
     * @param internalformat 
     * @param bitmap 
     * @param border 
     */ 
    public static void texImage2D(int target, int level, int internalformat, 
            Bitmap bitmap, int border) { 
        if (bitmap == null) { 
            throw new NullPointerException("texImage2D can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) { 
            throw new IllegalArgumentException("invalid Bitmap format"); 
        } 
    } 
 
    /** 
     * A version of texImage2D() that takes an explicit type parameter 
     * as defined by the OpenGL ES specification. The actual type and 
     * internalformat of the bitmap must be compatible with the specified 
     * type and internalformat parameters. 
     * 
     * @param target 
     * @param level 
     * @param internalformat 
     * @param bitmap 
     * @param type 
     * @param border 
     */ 
    public static void texImage2D(int target, int level, int internalformat, 
            Bitmap bitmap, int type, int border) { 
        if (bitmap == null) { 
            throw new NullPointerException("texImage2D can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        if (native_texImage2D(target, level, internalformat, bitmap, type, border)!=0) { 
            throw new IllegalArgumentException("invalid Bitmap format"); 
        } 
    } 
 
    /** 
     * A version of texImage2D that determines the internalFormat and type 
     * automatically. 
     * 
     * @param target 
     * @param level 
     * @param bitmap 
     * @param border 
     */ 
    public static void texImage2D(int target, int level, Bitmap bitmap, 
            int border) { 
        if (bitmap == null) { 
            throw new NullPointerException("texImage2D can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        if (native_texImage2D(target, level, -1, bitmap, -1, border)!=0) { 
            throw new IllegalArgumentException("invalid Bitmap format"); 
        } 
    } 
 
    /** 
     * Calls glTexSubImage2D() on the current OpenGL context. If no context is 
     * current the behavior is the same as calling glTexSubImage2D() with  no 
     * current context, that is, eglGetError() will return the appropriate 
     * error. 
     * Unlike glTexSubImage2D() bitmap cannot be null and will raise an exception 
     * in that case. 
     * All other parameters are identical to those used for glTexSubImage2D(). 
     * 
     * NOTE: this method doesn't change GL_UNPACK_ALIGNMENT, you must make 
     * sure to set it properly according to the supplied bitmap. 
     * 
     * Whether or not bitmap can have non power of two dimensions depends on 
     * the current OpenGL context. Always check glGetError() some time 
     * after calling this method, just like when using OpenGL directly. 
     * 
     * @param target 
     * @param level 
     * @param xoffset 
     * @param yoffset 
     * @param bitmap 
     */ 
    public static void texSubImage2D(int target, int level, int xoffset, int yoffset, 
            Bitmap bitmap) { 
        if (bitmap == null) { 
            throw new NullPointerException("texSubImage2D can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        int type = getType(bitmap); 
        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, -1, type)!=0) { 
            throw new IllegalArgumentException("invalid Bitmap format"); 
        } 
    } 
 
    /** 
     * A version of texSubImage2D() that takes an explicit type parameter 
     * as defined by the OpenGL ES specification. 
     * 
     * @param target 
     * @param level 
     * @param xoffset 
     * @param yoffset 
     * @param bitmap 
     * @param type 
     */ 
    public static void texSubImage2D(int target, int level, int xoffset, int yoffset, 
            Bitmap bitmap, int format, int type) { 
        if (bitmap == null) { 
            throw new NullPointerException("texSubImage2D can't be used with a null Bitmap"); 
        } 
        if (bitmap.isRecycled()) { 
            throw new IllegalArgumentException("bitmap is recycled"); 
        } 
        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, format, type)!=0) { 
            throw new IllegalArgumentException("invalid Bitmap format"); 
        } 
    } 
 
    /** 
     * Return a string for the EGL error code, or the hex representation 
     * if the error is unknown. 
     * 
     * @param error The EGL error to convert into a String. 
     * 
     * @return An error string corresponding to the EGL error code. 
     */ 
    public static String getEGLErrorString(int error) { 
        switch (error) { 
            case EGL10.EGL_SUCCESS: 
                return "EGL_SUCCESS"; 
            case EGL10.EGL_NOT_INITIALIZED: 
                return "EGL_NOT_INITIALIZED"; 
            case EGL10.EGL_BAD_ACCESS: 
                return "EGL_BAD_ACCESS"; 
            case EGL10.EGL_BAD_ALLOC: 
                return "EGL_BAD_ALLOC"; 
            case EGL10.EGL_BAD_ATTRIBUTE: 
                return "EGL_BAD_ATTRIBUTE"; 
            case EGL10.EGL_BAD_CONFIG: 
                return "EGL_BAD_CONFIG"; 
            case EGL10.EGL_BAD_CONTEXT: 
                return "EGL_BAD_CONTEXT"; 
            case EGL10.EGL_BAD_CURRENT_SURFACE: 
                return "EGL_BAD_CURRENT_SURFACE"; 
            case EGL10.EGL_BAD_DISPLAY: 
                return "EGL_BAD_DISPLAY"; 
            case EGL10.EGL_BAD_MATCH: 
                return "EGL_BAD_MATCH"; 
            case EGL10.EGL_BAD_NATIVE_PIXMAP: 
                return "EGL_BAD_NATIVE_PIXMAP"; 
            case EGL10.EGL_BAD_NATIVE_WINDOW: 
                return "EGL_BAD_NATIVE_WINDOW"; 
            case EGL10.EGL_BAD_PARAMETER: 
                return "EGL_BAD_PARAMETER"; 
            case EGL10.EGL_BAD_SURFACE: 
                return "EGL_BAD_SURFACE"; 
            case EGL11.EGL_CONTEXT_LOST: 
                return "EGL_CONTEXT_LOST"; 
            default: 
                return "0x" + Integer.toHexString(error); 
        } 
    } 
 
    /** 
     * Set OpenGL Tracing level for this application. 
     * @hide 
     */ 
    native public static void setTracingLevel(int level); 
 
    native private static int native_getInternalFormat(Bitmap bitmap); 
    native private static int native_getType(Bitmap bitmap); 
    native private static int native_texImage2D(int target, int level, int internalformat, 
            Bitmap bitmap, int type, int border); 
    native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset, 
            Bitmap bitmap, int format, int type); 
} 

7.Filter子类
扩展OpenGLES渲染特效的实现类,主要封装对OpenGL
的配置,以简单的GPUImageBrightnessFilter为例来说明:

public class GPUImageBrightnessFilter extends GPUImageFilter {
    public static final String BRIGHTNESS_FRAGMENT_SHADER = "" +
            "varying highp vec2 textureCoordinate;\n" +
            " \n" +
            " uniform sampler2D inputImageTexture;\n" +
            " uniform lowp float brightness;\n" +
            " \n" +
            " void main()\n" +
            " {\n" +
            "     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" +
            "     \n" +
            "     gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);\n" +
            " }";
    private int mBrightnessLocation;
    private float mBrightness;

    public GPUImageBrightnessFilter() {
        this(0.0f);
    }

    public GPUImageBrightnessFilter(final float brightness) {
        super(NO_FILTER_VERTEX_SHADER, BRIGHTNESS_FRAGMENT_SHADER);
        mBrightness = brightness;
    }

    @Override
    public void onInit() {
        super.onInit();
        mBrightnessLocation = GLES20.glGetUniformLocation(getProgram(), "brightness");
    }

   @Override
    public void onInitialized() {
        super.onInitialized();
        setBrightness(mBrightness);
    }

    public void setBrightness(final float brightness) {
        mBrightness = brightness;
        setFloat(mBrightnessLocation, mBrightness);
    }
}

很好理解的渲染实现参考,仅仅是配置了片元的渲染BRIGHTNESS_FRAGMENT_SHADER是具体的配置语法,涉及到OpenGL的编程,本文不作扩展说明。

二.关于OpenGLES API的自动生成分析

首先看frameworks\native\opengl\tools\glgen下的gen

#!/bin/bash
set -u
set -e
rm -rf out generated

mkdir out

# Create dummy Java files for Android APIs that are used by the code we generate.
# This allows us to test the generated code without building the rest of Android.

mkdir -p out/javax/microedition/khronos/opengles
mkdir -p out/com/google/android/gles_jni
mkdir -p out/android/app
mkdir -p out/android/graphics
mkdir -p out/android/view
mkdir -p out/android/opengl
mkdir -p out/android/content
mkdir -p out/android/content/pm
mkdir -p out/android/os
mkdir -p out/android/util

echo "package android.graphics;" > out/android/graphics/Canvas.java
echo "public interface Canvas {}" >> out/android/graphics/Canvas.java

echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java
# echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags, java.lang.String userId) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;};    }" > out/android/os/Build.java
echo "package android.os; public class UserHandle {public static String myUserId() { return \"\"; } }" > out/android/os/UserHandle.java
echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java
echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java

echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java


echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java
echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java
echo "package android.view;" > out/android/view/SurfaceView.java
echo "public interface SurfaceView { SurfaceHolder getHolder(); }" >> out/android/view/SurfaceView.java
echo "package android.view;" > out/android/view/Surface.java
echo "public interface Surface {}" >> out/android/view/Surface.java
echo "package android.view;" > out/android/view/SurfaceHolder.java
echo "public interface SurfaceHolder { Surface getSurface(); }" >> out/android/view/SurfaceHolder.java

cp static/egl/*.java out/android/opengl/

GLFILE=out/javax/microedition/khronos/opengles/GL.java
cp stubs/jsr239/GLHeader.java-if $GLFILE

GLGEN_FILES="CFunc.java CType.java CodeEmitter.java EGLCodeEmitter.java GenerateEGL.java GenerateGL.java GenerateGLES.java GLESCodeEmitter.java JFunc.java JniCodeEmitter.java JType.java Jsr239CodeEmitter.java ParameterChecker.java"

pushd src > /dev/null
javac ${GLGEN_FILES}
JAVAC_RESULT=$?
if [ $JAVAC_RESULT -ne 0 ]; then
    echo "Could not compile glgen."
    exit $JAVAC_RESULT
fi
popd > /dev/null

echo "Generating JSR239-like APIs"
java -classpath src GenerateGL -c specs/jsr239/glspec-1.0 \
                                  specs/jsr239/glspec-1.0ext \
                                  specs/jsr239/glspec-1.1 \
                                  specs/jsr239/glspec-1.1ext \
                                  specs/jsr239/glspec-1.1extpack \
                                  specs/jsr239/glspec-checks
JAVA_RESULT=$?
if [ $JAVA_RESULT -ne 0 ]; then
    echo "Could not run GenerateGL."
    exit $JAVA_RESULT
fi

echo "Generating static OpenGLES bindings"
java -classpath src GenerateGLES
JAVA_RESULT=$?
if [ $JAVA_RESULT -ne 0 ]; then
    echo "Could not run GenerateGLES."
    exit $JAVA_RESULT
fi

echo "Generating static EGL bindings"
java -classpath src GenerateEGL
JAVA_RESULT=$?
if [ $JAVA_RESULT -ne 0 ]; then
    echo "Could not run GenerateEGL."
    exit $JAVA_RESULT
fi

rm src/*.class

pushd out > /dev/null
mkdir classes
javac -d classes    android/opengl/EGL14.java \
                    android/opengl/EGLExt.java \
                    com/google/android/gles_jni/GLImpl.java \
                    javax/microedition/khronos/opengles/GL10.java \
                    javax/microedition/khronos/opengles/GL10Ext.java \
                    javax/microedition/khronos/opengles/GL11.java \
                    javax/microedition/khronos/opengles/GL11Ext.java \
                    javax/microedition/khronos/opengles/GL11ExtensionPack.java \
                    android/opengl/GLES10.java \
                    android/opengl/GLES10Ext.java \
                    android/opengl/GLES11.java \
                    android/opengl/GLES11Ext.java \
                    android/opengl/GLES20.java \
                    android/opengl/GLES30.java
popd > /dev/null
JAVA_RESULT=$?
if [ $JAVA_RESULT -ne 0 ]; then
    echo "Could not compile generated classes."
    exit $JAVA_RESULT
fi

rm -rf generated
mkdir -p generated/C
cp out/com_google_android_gles_jni_GLImpl.cpp generated/C
cp -r out/com generated
cp -r out/javax generated

cp out/android_opengl_*.cpp generated/C
mkdir -p generated/android/opengl
cp -r out/android/opengl generated/android

rm -rf out
KEEP_GENERATED=0
SAID_PLEASE=0

# compareGenerated destDir generatedDir file
compareGenerated() {
    if cmp -s $1/$3 $2/$3 ; then
        echo "#    " $3 unchanged
    else
        echo "#    " $3 changed
        if [ $SAID_PLEASE == "0" ] ; then
            echo Please evaluate the following commands:
            echo
            SAID_PLEASE=1
        fi
        echo "    cp $2/$3 $1"
        echo "    (cd $1; git add $3)"
        KEEP_GENERATED=1
    fi
}

compareGenerated ../../../../base/core/jni generated/C com_google_android_gles_jni_GLImpl.cpp
compareGenerated ../../../../base/opengl/java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java

for x in GL.java GL10.java GL10Ext.java GL11.java GL11Ext.java GL11ExtensionPack.java
do
    compareGenerated ../../../../base/opengl/java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x
done

for x in EGL14 EGLExt GLES10 GLES10Ext GLES11 GLES11Ext GLES20 GLES30
do
    compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java
    compareGenerated ../../../../base/core/jni generated/C android_opengl_${x}.cpp
done

for x in EGLConfig EGLContext EGLDisplay EGLObjectHandle EGLSurface
do
    compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java
done

if [ $KEEP_GENERATED == "0" ] ; then
    rm -rf generated
fi

基本可以看出来是如何实现自动生成文件的了吧。
1.创建编译GL相关引用文件,比如SurfaceView 、Surface 等

echo "public interface SurfaceTexture {}" >> out/android/graphics/SurfaceTexture.java

2.自动生成GL接口类的核心逻辑实现,如GenerateGL.java GenerateGLES.java等

GLGEN_FILES="CFunc.java CType.java CodeEmitter.java EGLCodeEmitter.java GenerateEGL.java GenerateGL.java GenerateGLES.java GLESCodeEmitter.java JFunc.java JniCodeEmitter.java JType.java Jsr239CodeEmitter.java ParameterChecker.java"

pushd src > /dev/null
javac ${GLGEN_FILES}
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;

public class GenerateGLES {

    static void copy(String filename, PrintStream out) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(filename));
        String s;
        while ((s = br.readLine()) != null) {
            out.println(s);
        }
    }

    private static void emit(GLESCodeEmitter emitter,
                             BufferedReader specReader,
                             PrintStream glStream,
                             PrintStream cStream) throws Exception {
        String s = null;
        while ((s = specReader.readLine()) != null) {
            if (s.trim().startsWith("//")) {
                continue;
            }

            CFunc cfunc = CFunc.parseCFunc(s);
            String fname = cfunc.getName();
            String stubRoot = "stubs/gles11/" + fname;
            String javaPath = stubRoot + ".java";
            File f = new File(javaPath);
            if (f.exists()) {
                System.out.println("Special-casing function " + fname);
                copy(javaPath, glStream);
                copy(stubRoot + ".cpp", cStream);

                // Register native function names
                // This should be improved to require fewer discrete files
                String filename = stubRoot + ".nativeReg";
                BufferedReader br =
                    new BufferedReader(new FileReader(filename));
                String nfunc;
                while ((nfunc = br.readLine()) != null) {
                    emitter.addNativeRegistration(nfunc);
                }
            } else {
                emitter.emitCode(cfunc, s);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        int aidx = 0;
        while ((aidx < args.length) && (args[aidx].charAt(0) == '-')) {
            switch (args[aidx].charAt(1)) {
            default:
                System.err.println("Unknown flag: " + args[aidx]);
                System.exit(1);
            }

            aidx++;
        }

        BufferedReader checksReader =
            new BufferedReader(new FileReader("specs/gles11/checks.spec"));
        ParameterChecker checker = new ParameterChecker(checksReader);

        // Generate files
        for(String suffix: new String[] {"GLES10", "GLES10Ext",
                "GLES11", "GLES11Ext", "GLES20", "GLES30"})
        {
            BufferedReader spec11Reader =
                new BufferedReader(new FileReader("specs/gles11/"
                        + suffix + ".spec"));
            String gl11Filename = "android/opengl/" + suffix + ".java";
            String gl11cFilename = "android_opengl_" + suffix + ".cpp";
            PrintStream gl11Stream =
                new PrintStream(new FileOutputStream("out/" + gl11Filename));
            PrintStream gl11cStream =
                new PrintStream(new FileOutputStream("out/" + gl11cFilename));
            copy("stubs/gles11/" + suffix + "Header.java-if", gl11Stream);
            copy("stubs/gles11/" + suffix + "cHeader.cpp", gl11cStream);
            copy("stubs/gles11/common.cpp", gl11cStream);
            GLESCodeEmitter emitter = new GLESCodeEmitter(
                    "android/opengl/" + suffix,
                    checker, gl11Stream, gl11cStream);
            emit(emitter, spec11Reader, gl11Stream, gl11cStream);
            emitter.emitNativeRegistration("register_android_opengl_jni_"
                    + suffix);
            gl11Stream.println("}");
            gl11Stream.close();
            gl11cStream.close();
        }
    }
}

从上面的代码片段:

        // Generate files
        for(String suffix: new String[] {"GLES10", "GLES10Ext",
                "GLES11", "GLES11Ext", "GLES20", "GLES30"})
        {
            BufferedReader spec11Reader =
                new BufferedReader(new FileReader("specs/gles11/"
                        + suffix + ".spec"));
            String gl11Filename = "android/opengl/" + suffix + ".java";
            String gl11cFilename = "android_opengl_" + suffix + ".cpp";
            PrintStream gl11Stream =
                new PrintStream(new FileOutputStream("out/" + gl11Filename));
            PrintStream gl11cStream =new PrintStream(new FileOutputStream("out/" + gl11cFilename));
            copy("stubs/gles11/" + suffix + "Header.java-if", gl11Stream);
            copy("stubs/gles11/" + suffix + "cHeader.cpp", gl11cStream);
            copy("stubs/gles11/common.cpp", gl11cStream);
            GLESCodeEmitter emitter = new GLESCodeEmitter(
                    "android/opengl/" + suffix,
                    checker, gl11Stream, gl11cStream);
            emit(emitter, spec11Reader, gl11Stream, gl11cStream);
            emitter.emitNativeRegistration("register_android_opengl_jni_"
                    + suffix);
            gl11Stream.println("}");
            gl11Stream.close();
            gl11cStream.close();
        }

可以看出GLES10,GLES10Ext、GLES20等都是由specs/gles11/目录下的对应文件.spec描述生成规则的,比如GLES20对应的GLES20.spec:

void glActiveTexture ( GLenum texture )
void glAttachShader ( GLuint program, GLuint shader )
void glBindAttribLocation ( GLuint program, GLuint index, const char *name )
void glBindBuffer ( GLenum target, GLuint buffer )
void glBindFramebuffer ( GLenum target, GLuint framebuffer )
void glBindRenderbuffer ( GLenum target, GLuint renderbuffer )
void glBindTexture ( GLenum target, GLuint texture )
void glBlendColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
void glBlendEquation ( GLenum mode )
void glBlendEquationSeparate ( GLenum modeRGB, GLenum modeAlpha )
void glBlendFunc ( GLenum sfactor, GLenum dfactor )
void glBlendFuncSeparate ( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha )
void glBufferData ( GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage )
void glBufferSubData ( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data )
GLenum glCheckFramebufferStatus ( GLenum target )
void glClear ( GLbitfield mask )
void glClearColor ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
void glClearDepthf ( GLclampf depth )
void glClearStencil ( GLint s )
void glColorMask ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha )
void glCompileShader ( GLuint shader )
void glCompressedTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data )
void glCompressedTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data )
void glCopyTexImage2D ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border )
void glCopyTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height )
GLuint glCreateProgram ( void )
GLuint glCreateShader ( GLenum type )
void glCullFace ( GLenum mode )
void glDeleteBuffers ( GLsizei n, const GLuint *buffers )
void glDeleteFramebuffers ( GLsizei n, const GLuint *framebuffers )
void glDeleteProgram ( GLuint program )
void glDeleteRenderbuffers ( GLsizei n, const GLuint *renderbuffers )
void glDeleteShader ( GLuint shader )
void glDeleteTextures ( GLsizei n, const GLuint *textures )
void glDepthFunc ( GLenum func )
void glDepthMask ( GLboolean flag )
void glDepthRangef ( GLclampf zNear, GLclampf zFar )
void glDetachShader ( GLuint program, GLuint shader )
void glDisable ( GLenum cap )
void glDisableVertexAttribArray ( GLuint index )
void glDrawArrays ( GLenum mode, GLint first, GLsizei count )
void glDrawElements ( GLenum mode, GLsizei count, GLenum type, GLint offset )
void glDrawElements ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices )
void glEnable ( GLenum cap )
void glEnableVertexAttribArray ( GLuint index )
void glFinish ( void )
void glFlush ( void )
void glFramebufferRenderbuffer ( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer )
void glFramebufferTexture2D ( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level )
void glFrontFace ( GLenum mode )
void glGenBuffers ( GLsizei n, GLuint *buffers )
void glGenerateMipmap ( GLenum target )
void glGenFramebuffers ( GLsizei n, GLuint *framebuffers )
void glGenRenderbuffers ( GLsizei n, GLuint *renderbuffers )
void glGenTextures ( GLsizei n, GLuint *textures )
void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
void glGetAttachedShaders ( GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders )
GLint glGetAttribLocation ( GLuint program, const char *name )
void glGetBooleanv ( GLenum pname, GLboolean *params )
void glGetBufferParameteriv ( GLenum target, GLenum pname, GLint *params )
GLenum glGetError ( void )
void glGetFloatv ( GLenum pname, GLfloat *params )
void glGetFramebufferAttachmentParameteriv ( GLenum target, GLenum attachment, GLenum pname, GLint *params )
void glGetIntegerv ( GLenum pname, GLint *params )
void glGetProgramiv ( GLuint program, GLenum pname, GLint *params )
void glGetProgramInfoLog ( GLuint program, GLsizei bufsize, GLsizei *length, char *infolog )
void glGetRenderbufferParameteriv ( GLenum target, GLenum pname, GLint *params )
void glGetShaderiv ( GLuint shader, GLenum pname, GLint *params )
void glGetShaderInfoLog ( GLuint shader, GLsizei bufsize, GLsizei *length, char *infolog )
void glGetShaderPrecisionFormat ( GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision )
void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source )
const GLubyte * glGetString ( GLenum name )
void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params )
void glGetTexParameteriv ( GLenum target, GLenum pname, GLint *params )
void glGetUniformfv ( GLuint program, GLint location, GLfloat *params )
void glGetUniformiv ( GLuint program, GLint location, GLint *params )
GLint glGetUniformLocation ( GLuint program, const char *name )
void glGetVertexAttribfv ( GLuint index, GLenum pname, GLfloat *params )
void glGetVertexAttribiv ( GLuint index, GLenum pname, GLint *params )
// void glGetVertexAttribPointerv ( GLuint index, GLenum pname, void **pointer )
void glHint ( GLenum target, GLenum mode )
GLboolean glIsBuffer ( GLuint buffer )
GLboolean glIsEnabled ( GLenum cap )
GLboolean glIsFramebuffer ( GLuint framebuffer )
GLboolean glIsProgram ( GLuint program )
GLboolean glIsRenderbuffer ( GLuint renderbuffer )
GLboolean glIsShader ( GLuint shader )
GLboolean glIsTexture ( GLuint texture )
void glLineWidth ( GLfloat width )
void glLinkProgram ( GLuint program )
void glPixelStorei ( GLenum pname, GLint param )
void glPolygonOffset ( GLfloat factor, GLfloat units )
void glReadPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels )
void glReleaseShaderCompiler ( void )
void glRenderbufferStorage ( GLenum target, GLenum internalformat, GLsizei width, GLsizei height )
void glSampleCoverage ( GLclampf value, GLboolean invert )
void glScissor ( GLint x, GLint y, GLsizei width, GLsizei height )
void glShaderBinary ( GLsizei n, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length )
void glShaderSource ( GLuint shader )
void glStencilFunc ( GLenum func, GLint ref, GLuint mask )
void glStencilFuncSeparate ( GLenum face, GLenum func, GLint ref, GLuint mask )
void glStencilMask ( GLuint mask )
void glStencilMaskSeparate ( GLenum face, GLuint mask )
void glStencilOp ( GLenum fail, GLenum zfail, GLenum zpass )
void glStencilOpSeparate ( GLenum face, GLenum fail, GLenum zfail, GLenum zpass )
void glTexImage2D ( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels )
void glTexParameterf ( GLenum target, GLenum pname, GLfloat param )
void glTexParameterfv ( GLenum target, GLenum pname, const GLfloat *params )
void glTexParameteri ( GLenum target, GLenum pname, GLint param )
void glTexParameteriv ( GLenum target, GLenum pname, const GLint *params )
void glTexSubImage2D ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels )
void glUniform1f ( GLint location, GLfloat x )
void glUniform1fv ( GLint location, GLsizei count, const GLfloat *v )
void glUniform1i ( GLint location, GLint x )
void glUniform1iv ( GLint location, GLsizei count, const GLint *v )
void glUniform2f ( GLint location, GLfloat x, GLfloat y )
void glUniform2fv ( GLint location, GLsizei count, const GLfloat *v )
void glUniform2i ( GLint location, GLint x, GLint y )
void glUniform2iv ( GLint location, GLsizei count, const GLint *v )
void glUniform3f ( GLint location, GLfloat x, GLfloat y, GLfloat z )
void glUniform3fv ( GLint location, GLsizei count, const GLfloat *v )
void glUniform3i ( GLint location, GLint x, GLint y, GLint z )
void glUniform3iv ( GLint location, GLsizei count, const GLint *v )
void glUniform4f ( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
void glUniform4fv ( GLint location, GLsizei count, const GLfloat *v )
void glUniform4i ( GLint location, GLint x, GLint y, GLint z, GLint w )
void glUniform4iv ( GLint location, GLsizei count, const GLint *v )
void glUniformMatrix2fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
void glUniformMatrix3fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
void glUniformMatrix4fv ( GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
void glUseProgram ( GLuint program )
void glValidateProgram ( GLuint program )
void glVertexAttrib1f ( GLuint indx, GLfloat x )
void glVertexAttrib1fv ( GLuint indx, const GLfloat *values )
void glVertexAttrib2f ( GLuint indx, GLfloat x, GLfloat y )
void glVertexAttrib2fv ( GLuint indx, const GLfloat *values )
void glVertexAttrib3f ( GLuint indx, GLfloat x, GLfloat y, GLfloat z )
void glVertexAttrib3fv ( GLuint indx, const GLfloat *values )
void glVertexAttrib4f ( GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
void glVertexAttrib4fv ( GLuint indx, const GLfloat *values )
void glVertexAttribPointer ( GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLint offset )
void glVertexAttribPointer ( GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *ptr )
void glViewport ( GLint x, GLint y, GLsizei width, GLsizei height )

然后根据stubs/gles11/目录下对应的Header.java-if和cHeader.cpp以及common.cpp来拼凑成一个完成的类文件,jni也是同样道理.

3.根据specs/jsr239/glspec*的规则自动生成JSR239 APIs
4.生成static OpenGLES bindings
5.生成static EGL bindings
6.自动生成OpenGLES APIs,比如GLES20.java
7.创建类似Android framework的目录,准备拷贝API到该目录
8.最后是校验自动生成的文件和拷贝到Android framework的API是否一致

3.结束语

最近发生一些事情,烦恼中,没什么好说的了,就这点IT痴汉的怪脾气。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容