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

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

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

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

原文地址:https://www.cnblogs.com/moderate-fish/p/6890749.html