├── .gitignore ├── README.md ├── app ├── build.gradle ├── lint.xml └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── wysaid │ │ └── ndkopenglbackdraw │ │ ├── GLHelpFunctions.java │ │ └── MainActivity.java │ ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── NDKOpenGLBackDraw.c │ └── org_wysaid_ndkopenglbackdraw_GLHelpFunctions.h │ └── res │ ├── drawable-nodpi │ └── ic_launcher.png │ ├── layout │ └── activity_main.xml │ ├── menu │ └── main.xml │ ├── values-sw600dp │ └── dimens.xml │ ├── values-sw720dp-land │ └── dimens.xml │ ├── values-v11 │ └── styles.xml │ ├── values-v14 │ └── styles.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── screenshot.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | build/ 7 | /captures 8 | .idea/ 9 | .svn/ 10 | *iml 11 | .idea/ 12 | local/ 13 | libs/ 14 | bin/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NDKOpenGLOffscreenRendering 2 | 简单demo, Android下使用NDK(C++)+GLES2.0进行后台绘图,保存到bitmap并交给java层处理. 在安卓下使用PBuffer创建context并实现在ndk下后台处理 3 | ![https://raw.githubusercontent.com/wysaid/NDKOpenGLOffscreenRendering/master/screenshot.jpg](https://raw.githubusercontent.com/wysaid/NDKOpenGLOffscreenRendering/master/screenshot.jpg) 4 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "org.wysaid.ndkopenglbackdraw" 9 | minSdkVersion 8 10 | targetSdkVersion 22 11 | 12 | ndk { 13 | moduleName "NDKOpenGLBackDraw" 14 | abiFilters "armeabi" 15 | ldLibs "log", "android", "EGL", "GLESv2", "jnigraphics" 16 | } 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/org/wysaid/ndkopenglbackdraw/GLHelpFunctions.java: -------------------------------------------------------------------------------- 1 | package org.wysaid.ndkopenglbackdraw; 2 | 3 | import javax.microedition.khronos.egl.EGL10; 4 | import javax.microedition.khronos.egl.EGLConfig; 5 | import javax.microedition.khronos.egl.EGLContext; 6 | import javax.microedition.khronos.egl.EGLDisplay; 7 | import javax.microedition.khronos.opengles.GL10; 8 | 9 | import android.annotation.SuppressLint; 10 | import android.graphics.Bitmap; 11 | import android.opengl.EGL14; 12 | import android.util.Log; 13 | 14 | public class GLHelpFunctions { 15 | 16 | public static native void getGLBackDrawImage(Bitmap bm); 17 | 18 | // use GLES2.0. 19 | static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 20 | static int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 21 | static private int[] version = new int[2]; 22 | static EGLConfig[] configs = new EGLConfig[1]; 23 | static int[] num_config = new int[1]; 24 | 25 | @SuppressLint("InlinedApi") static int[] configSpec = { EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, 26 | EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, 27 | EGL10.EGL_RED_SIZE, 8, EGL10.EGL_GREEN_SIZE, 8, 28 | EGL10.EGL_BLUE_SIZE, 8, EGL10.EGL_ALPHA_SIZE, 8, EGL10.EGL_NONE }; 29 | // eglCreatePbufferSurface used this config 30 | static int attribListPbuffer[] = { 31 | // The NDK code would never draw to Pbuffer, so it's not neccessary to 32 | // match anything. 33 | EGL10.EGL_WIDTH, 32, EGL10.EGL_HEIGHT, 32, EGL10.EGL_NONE }; 34 | static EGL10 mEgl; 35 | static GL10 gl; 36 | static javax.microedition.khronos.egl.EGLSurface mEglPBSurface; 37 | static EGLContext mEglContext; 38 | static EGLConfig mEglConfig; 39 | static EGLDisplay mEglDisplay; 40 | 41 | static public void initEGL() { 42 | mEgl = (EGL10) EGLContext.getEGL(); 43 | mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 44 | mEgl.eglInitialize(mEglDisplay, version); 45 | mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, num_config); 46 | mEglConfig = configs[0]; 47 | mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, 48 | EGL10.EGL_NO_CONTEXT, attrib_list); 49 | if (mEglContext == EGL10.EGL_NO_CONTEXT) { 50 | Log.d("ERROR:", "eglCreateContext Failed!"); 51 | } 52 | mEglPBSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, 53 | attribListPbuffer); 54 | if (mEglPBSurface == EGL10.EGL_NO_SURFACE) { 55 | Log.d("ERROR:", "eglCreatePbufferSurface Failed!"); 56 | } 57 | 58 | if (!mEgl.eglMakeCurrent(mEglDisplay, mEglPBSurface, mEglPBSurface, mEglContext)) { 59 | Log.d("ERROR:", "eglMakeCurrent failed:" + mEgl.eglGetError()); 60 | } 61 | // You can do some works using OpenGL with java code. But this demo would do that within NDK. 62 | gl = (GL10) mEglContext.getGL(); 63 | } 64 | 65 | static public void enableEGL() { 66 | if (!mEgl.eglMakeCurrent(mEglDisplay, mEglPBSurface, mEglPBSurface, mEglContext)) 67 | { 68 | Log.d("ERROR:", "eglMakeCurrent failed:" + mEgl.eglGetError()); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/org/wysaid/ndkopenglbackdraw/MainActivity.java: -------------------------------------------------------------------------------- 1 | package org.wysaid.ndkopenglbackdraw; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.drawable.BitmapDrawable; 5 | import android.os.Bundle; 6 | import android.annotation.SuppressLint; 7 | import android.app.Activity; 8 | import android.graphics.Bitmap; 9 | import android.view.Menu; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.ImageView; 13 | import android.widget.LinearLayout; 14 | 15 | public class MainActivity extends Activity { 16 | static 17 | { 18 | System.loadLibrary("NDKOpenGLBackDraw"); 19 | } 20 | 21 | @SuppressLint("NewApi") 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_main); 27 | dispalyLayout = (LinearLayout) findViewById(R.id.displayLayout); 28 | displayView = (ImageView) findViewById(R.id.imageView1); 29 | button = (Button) findViewById(R.id.button1); 30 | button.setOnClickListener(clickListener); 31 | GLHelpFunctions.initEGL(); 32 | bitmap = Bitmap.createBitmap(800, 800, Bitmap.Config.ARGB_8888); 33 | 34 | Bitmap displayBitmap = ((BitmapDrawable)displayView.getDrawable()).getBitmap(); 35 | Canvas canvas = new Canvas(bitmap); 36 | for(int i = 0; i < bitmap.getHeight(); i += displayBitmap.getHeight()) { 37 | for(int j = 0; j < bitmap.getWidth(); j += displayBitmap.getWidth()) { 38 | canvas.drawBitmap(displayBitmap, j, i, null); 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public boolean onCreateOptionsMenu(Menu menu) { 45 | // Inflate the menu; this adds items to the action bar if it is present. 46 | getMenuInflater().inflate(R.menu.main, menu); 47 | return true; 48 | } 49 | 50 | android.view.View.OnClickListener clickListener = 51 | new android.view.View.OnClickListener() { 52 | @Override 53 | public void onClick(View view) { 54 | // TODO Auto-generated method stub 55 | GLHelpFunctions.enableEGL(); 56 | GLHelpFunctions.getGLBackDrawImage(bitmap); 57 | displayView.setImageBitmap(bitmap); 58 | } 59 | }; 60 | 61 | ImageView displayView; 62 | LinearLayout dispalyLayout; 63 | Button button; 64 | Bitmap bitmap; 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := NDKOpenGLBackDraw 6 | LOCAL_SRC_FILES := NDKOpenGLBackDraw.c 7 | 8 | LOCAL_LDLIBS := -llog -lGLESv2 -landroid -ljnigraphics 9 | 10 | include $(BUILD_SHARED_LIBRARY) 11 | -------------------------------------------------------------------------------- /app/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_STL := gnustl_static -------------------------------------------------------------------------------- /app/src/main/jni/NDKOpenGLBackDraw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef LOG_TAG 8 | #define LOG_TAG "NDKOpenGLBackDraw" 9 | #endif 10 | 11 | #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 12 | #define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 13 | #define SHADER_STRING(...) #__VA_ARGS__ 14 | 15 | void printGLString(const char* name, GLenum em) 16 | { 17 | const char *s = (const char*)glGetString(em); 18 | LOG_INFO("GL_INFO %s = %s\n", name, s); 19 | } 20 | 21 | void checkGLError(const char* op) 22 | { 23 | GLint error; 24 | for (error = glGetError(); error; error = glGetError()) 25 | { 26 | LOG_INFO("after %s() glError (0x%x)\n", op, error); 27 | } 28 | } 29 | 30 | const char* const g_defaultVertexShaderString = SHADER_STRING 31 | ( 32 | attribute vec2 vPosition; 33 | varying vec2 textureCoordinate; 34 | void main() 35 | { 36 | gl_Position = vec4(vPosition, 0.0, 1.0); 37 | textureCoordinate = (vPosition.xy + 1.0) / 2.0; 38 | } 39 | ); 40 | 41 | const char* const g_defaultFragmentShaderString = SHADER_STRING 42 | ( 43 | precision mediump float; 44 | varying vec2 textureCoordinate; 45 | uniform sampler2D myTexture; 46 | void main() 47 | { 48 | vec4 textureColor = texture2D(myTexture, textureCoordinate); 49 | textureColor.rb += textureCoordinate.xy; 50 | gl_FragColor = textureColor; 51 | } 52 | ); 53 | 54 | const GLfloat g_vertices[] = 55 | { 56 | -1.0f, 1.0f, 57 | 1.0f, 1.0f, 58 | -1.0f, -1.0f, 59 | 1.0f, -1.0f 60 | }; 61 | 62 | void runBackDraw(char* row, int w, int h) 63 | { 64 | GLuint texture, renderBuffer, frameBuffer; 65 | printGLString("Version", GL_VERSION); 66 | printGLString("Vendor", GL_VENDOR); 67 | printGLString("Renderer", GL_RENDERER); 68 | 69 | glActiveTexture(GL_TEXTURE0); 70 | glGenTextures(1, &texture); 71 | LOG_INFO("Input Image Texture id %d\n", texture); 72 | glBindTexture(GL_TEXTURE_2D, texture); 73 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 74 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, row); 75 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 76 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 77 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 78 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 79 | 80 | glGenFramebuffers(1, &frameBuffer); 81 | glGenRenderbuffers(1, &renderBuffer); 82 | glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); 83 | glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer); 84 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, w, h); 85 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 86 | GL_RENDERBUFFER, renderBuffer); 87 | 88 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 89 | { 90 | LOG_ERROR("Image Handler initImageFBO failed!\n"); 91 | } 92 | else 93 | { 94 | glViewport(0, 0, w, h); 95 | 96 | //////////////////////////////////// 97 | GLuint vsh, fsh, program; 98 | vsh = glCreateShader(GL_VERTEX_SHADER); 99 | fsh = glCreateShader(GL_FRAGMENT_SHADER); 100 | program = glCreateProgram(); 101 | glShaderSource(vsh, 1, (const GLchar**)&g_defaultVertexShaderString, NULL); 102 | glShaderSource(fsh, 1, (const GLchar**)&g_defaultFragmentShaderString, NULL); 103 | glCompileShader(vsh); 104 | glCompileShader(fsh); 105 | glAttachShader(program, vsh); 106 | glAttachShader(program, fsh); 107 | glLinkProgram(program); 108 | glDeleteShader(vsh); 109 | glDeleteShader(fsh); 110 | glUseProgram(program); 111 | GLuint vPosition = glGetAttribLocation(program, "vPosition"); 112 | checkGLError("glGetAttribLocation"); 113 | LOG_INFO("glGetAttribLocation(\"vPosition\") = %d\n", vPosition); 114 | glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, g_vertices); 115 | glEnableVertexAttribArray(vPosition); 116 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 117 | 118 | glPixelStorei(GL_PACK_ALIGNMENT, 1); 119 | glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, row); 120 | } 121 | 122 | glDeleteTextures(1, &texture); 123 | glDeleteFramebuffers(1, &frameBuffer); 124 | glDeleteRenderbuffers(1, &renderBuffer); 125 | } 126 | 127 | 128 | JNIEXPORT void JNICALL Java_org_wysaid_ndkopenglbackdraw_GLHelpFunctions_getGLBackDrawImage(JNIEnv *env, jclass cls, jobject bitmap) 129 | { 130 | AndroidBitmapInfo info; 131 | int w, h, ret; 132 | char* row; 133 | 134 | if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) 135 | { 136 | LOG_ERROR("AndroidBitmap_getInfo() failed ! error=%d", ret); 137 | return; 138 | } 139 | 140 | LOG_INFO("color image :: width is %d; height is %d; stride is %d; format is %d;flags is %d", info.width, info.height, info.stride, info.format, info.flags); 141 | 142 | if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) 143 | { 144 | LOG_ERROR("Bitmap format is not RGBA_8888 !"); 145 | return; 146 | } 147 | 148 | w = info.width; 149 | h = info.height; 150 | ret = AndroidBitmap_lockPixels(env, bitmap, (void**) &row); 151 | 152 | if (ret < 0) 153 | { 154 | LOG_ERROR("AndroidBitmap_lockPixels() failed ! error=%d", ret); 155 | return ; 156 | } 157 | 158 | runBackDraw(row, w, h); 159 | LOG_INFO("unlocking pixels"); 160 | AndroidBitmap_unlockPixels(env, bitmap); 161 | } -------------------------------------------------------------------------------- /app/src/main/jni/org_wysaid_ndkopenglbackdraw_GLHelpFunctions.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class org_wysaid_ndkopenglbackdraw_GLHelpFunctions */ 4 | 5 | #ifndef _Included_org_wysaid_ndkopenglbackdraw_GLHelpFunctions 6 | #define _Included_org_wysaid_ndkopenglbackdraw_GLHelpFunctions 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: org_wysaid_ndkopenglbackdraw_GLHelpFunctions 12 | * Method: getGLBackDrawImage 13 | * Signature: (Landroid/graphics/Bitmap;)V 14 | */ 15 | JNIEXPORT void JNICALL Java_org_wysaid_ndkopenglbackdraw_GLHelpFunctions_getGLBackDrawImage 16 | (JNIEnv *, jclass, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wysaid/NDKOpenGLOffscreenRendering/092ca356598974e6fb70ce342e812629a9cf1f06/app/src/main/res/drawable-nodpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | 19 | 24 | 25 |