安卓下多线程OpenGL共享Context

Posted 荆棘鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓下多线程OpenGL共享Context 相关的知识,希望对你有一定的参考价值。

    最近在研究Unity3D开发中使用Java Plugin进行纹理更新,想法很简单,在Java线程更新纹理数据,然后Unity场景中的纹理将自动更新。

首先,创建Java类,定义创建纹理及获取纹理参数的接口,并创建单线程池用于进行加载Bitmap并绑定纹理数据等OpenGL操作。Java代码示例:

 1 package com.thornbirds.unity;
 2 
 3 import android.graphics.Bitmap;
 4 import android.graphics.BitmapFactory;
 5 import android.opengl.GLES11Ext;
 6 import android.opengl.GLES20;
 7 import android.opengl.GLUtils;
 8 import android.util.Log;
 9 
10 import java.util.concurrent.ExecutorService;
11 import java.util.concurrent.Executors;
12 
13 public class PluginTexture {
14     private static final String TAG = "PluginTexture";
15     private int mTextureID = 0;
16     private int mTextureWidth = 0;
17     private int mTextureHeight = 0;
18 
19     // 创建单线程池,用于处理OpenGL纹理
20     private final ExecutorService mRenderThread = Executors.newSingleThreadExecutor();
21 
22     public int getStreamTextureWidth() {
23         return mTextureWidth;
24     }
25 
26     public int getStreamTextureHeight() {
27         return mTextureHeight;
28     }
29 
30     public int getStreamTextureID() {
31         return mTextureID;
32     }
33 
34     public PluginTexture() {
35     }
36 
37     public void setupOpenGL() {
38         mRenderThread.execute(new Runnable() {
39             @Override
40             public void run() {
41                 // 生成OpenGL纹理ID
42                 int textures[] = new int[1];
43                 GLES20.glGenTextures(1, textures, 0);
44                 if (textures[0] == 0) {
45                     Log.e(TAG, "glGenTextures failed");
46                     return;
47                 }
48                 mTextureID = textures[0];
49                 mTextureWidth = 640;
50                 mTextureHeight = 360;
51             }
52         });
53     }
54 
55     public void updateTexture() {
56         mRenderThread.execute(new Runnable() {
57             @Override
58             public void run() {
59                 String imageFilePath = "/sdcard/test/image.png";
60                 final Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);
61 
62                 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
63                 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
64                 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
65                 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
66                 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
67 
68                 bitmap.recycle();
69             }
70         });
71     }
72 
73     public void destroy() {
74         mRenderThread.shutdownNow();
75     }
76 }

    然后,创建C#脚本,在脚本中示例化Java对象,并调用Java方法初始化OpenGL;为了展示更新纹理,需获取到Java生成的纹理ID,并将其与脚本当前GameObject绑定。C#代码示例:

 1 public class PluginTestureDemo : MonoBehaviour {
 2     private AndroidJavaObject mPluginTexture; 
 3     private int mTextureId;
 4     private int mWidth;
 5     private int mHeight;
 6 
 7     void Start () {
 8         // 实例化com.thornbirds.unity.PluginTexture类的对象
 9         mPluginTexture = new AndroidJavaObject ("com.thornbirds.unity.PluginTexture");
10         // 初始化OpenGL
11         mPluginTexture.Call ("setupOpenGL");
12     }
13 
14     void BindTexture () {
15         // 获取JavaPlugin生成的纹理ID
16         mTextureId = mPluginTexture.Call<int> ("getPluginTextureID");
17         if (mTextureId == 0) {
18             Debug.LogError ("getPluginTextureID failed");
19             return;
20         }
21         mWidth = mPluginTexture.Call<int> ("getPluginTextureWidth");
22         mHeight = mPluginTexture.Call<int> ("getPluginTextureHeight");
23         // 将纹理ID与当前GameObject绑定
24         GetComponent<MeshRenderer> ().material.mainTexture = Texture2D.CreateExternalTexture 
25             (mWidth, mHeight, TextureFormat.ARGB32, false, false, (IntPtr) mTextureId);
26         // 更新纹理数据
27         mPluginTexture.Call ("updateTexture");
28     }
29 }

注意:C#中使用了方法名调用Java方法,因此需要防止编译Jar包时Java类及其public方法被混淆。在Proguard文件中加入如下代码:

1 -keep class com.thornbirds.unity.PluginTexture {
2     public *;
3 }

    该方案存在一个问题,在Java线程中访问进行OpenGL操作,会报Missing GLContext,需要为Java线程初始化OpenGL绘制环境。下回继续。

 

以上是关于安卓下多线程OpenGL共享Context 的主要内容,如果未能解决你的问题,请参考以下文章

安卓下多线程OpenGL共享Context

安卓下多线程OpenGL共享Context

安卓和Unity线程共享context

安卓和Unity线程共享context

OpenGL ES 可不可以实现多线程共享 纹理

OpenGL 多线程共享纹理