安卓下多线程OpenGL共享Context (三)

上一节中我们介绍了多线程OpenGL绘制方案,但是如果需要在Java线程不断修改纹理数据,会由于并发访问导致Unity线程出现访问非法内存而崩溃。因此,考虑在Java线程加载数据,然后在unity线程调用OpenGL操作更新纹理。这样所有的OpenGL操作都在Unity绘制线程完成,从而避免了多线程OpenGL引入的各种问题。为了能够从Java线程切换到Unity线程执行,我们获取到Unity线程的Looper,然后使用该Looper实例化一个Handler,这样就可以通过往上发送消息或者Runnable在Unity线程执行任务了。Java代码如下:

 1 package com.thornbirds.unity;
 2
 3 import android.graphics.Bitmap;
 4 import android.graphics.BitmapFactory;
 5 import android.opengl.GLES10;
 6 import android.opengl.GLES11Ext;
 7 import android.opengl.GLES20;
 8 import android.opengl.GLUtils;
 9 import android.os.Handler;
10 import android.os.Looper;
11 import android.util.Log;
12
13 import java.util.concurrent.ExecutorService;
14 import java.util.concurrent.Executors;
15
16 public class PluginTexture {
17     private static final String TAG = "PluginTexture";
18
19     private int mTextureID = 0;
20     private int mTextureWidth = 0;
21     private int mTextureHeight = 0;
22
23     // 创建单线程池,用于加载图片资源
24     private final ExecutorService mJavaThread = Executors.newSingleThreadExecutor();
25     // 使用Unity线程Looper的Handler,用于执行Java层的OpenGL操作
26     private Handler mUnityRenderHandler;
27
28     public int getStreamTextureWidth() {
29         return mTextureWidth;
30     }
31
32     public int getStreamTextureHeight() {
33         return mTextureHeight;
34     }
35
36     public int getStreamTextureID() {
37         return mTextureID;
38     }
39
40     public PluginTexture() {
41     }
42
43     private void glLogE(String msg) {
44         Log.e(TAG, msg + ", err=" + GLES10.glGetError());
45     }
46
47     public void setupOpenGL() {
48         // 注意:该调用一定是从Unity绘制线程发起
49         if (Looper.myLooper() == null) {
50             Looper.prepare();
51         }
52         mUnityRenderHandler = new Handler(Looper.myLooper());
53         // 生成OpenGL纹理ID
54         int textures[] = new int[1];
55         GLES20.glGenTextures(1, textures, 0);
56         if (textures[0] == 0) {
57             glLogE("glGenTextures failed");
58             return;
59         }
60         mTextureID = textures[0];
61         mTextureWidth = 640;
62         mTextureHeight = 360;
63     }
64
65     public void updateTexture() {
66         mJavaThread.execute(new Runnable() {
67             @Override
68             public void run() {
69                 // 加载图片资源
70                 String imageFilePath = "/sdcard/test/image.png";
71                 final Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);
72                 // 切换到Unity绘制线程更新纹理
73                 mUnityRenderHandler.post(new Runnable() {
74                     @Override
75                     public void run() {
76                         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
77                         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
78                         GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
79                         GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
80                         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
81                         bitmap.recycle();
82                     }
83                 });
84             }
85         });
86     }
87
88     public void destroy() {
89         mJavaThread.shutdownNow();
90         mUnityRenderHandler.removeCallbacksAndMessages(null);
91     }
92 }

至此,我们完整介绍了Unity3D开发中在Android Java Plugin中进行纹理更新的方案和实现方法。基于相同的原理,我们可以很方便地给出iOS Object-C Plugin的实现,此处不在赘述。

时间: 2024-11-03 03:41:59

安卓下多线程OpenGL共享Context (三)的相关文章

安卓下多线程OpenGL共享Context (二)

为了在Java线程进行OpenGL调用,需要为java线程初始化OpenGL环境,initOpenGL函数展示了初始化OpenGL环境的过程.在setupOpenGL方法中,在线程上先执行该调用即可.Java代码示例如下: 1 package com.thornbirds.unity; 2 3 public class PluginTexture { 4 5 private EGLDisplay mEGLDisplay; 6 private EGLConfig mEglConfig; 7 pri

安卓下多线程OpenGL共享Context (四)

之前的方案假定Java层更新纹理时使用的是RGB或RBGA格式的数据,但是在播放视频这种应用场景下,解码器解码出来的数据如果是YUV格式,渲染起来就比较麻烦了.一种方式是使用CPU进行YUV转RGB,然后再进行渲染,但是这种方式性能极差:另一种方式是使用GPU进行转换,利用GPU的并行计算能力加速转换.我们需要编写Shader来实现.如前文所述,Unity只需要Java层的纹理ID,当使用Shader进行YUV转RGB时,怎么实现更新该纹理的数据呢?答案是Render to Texture (参

安卓下多线程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.BitmapF

安卓笔记2——安卓下的测试和数据存储方式

今天开始介绍安卓的另一个基础知识,安卓下的测试和数据存储的几种方式. 以后后同步发出对应笔记.老规矩,用一张图来介绍今天的内容. 图片看不清的话可以右键新窗口打开. 一.测试 1,分类 黑盒测试: 是以用户的角度,从输入数据与输出数据的对应关系出发进行测试的. 白盒测试: 又称结构测试.透明盒测试.逻辑驱动测试或基于代码的测试. 单元测试: 又称模块测试,是开发者编写的一小段代码,用于检验被测代码的一个很小的.很明确的功能是否正确. 功能测试: 根据产品特性.操作描述和用户方案,测试一个产品的特

linux下多线程编程

最近研究mysql源码,各种锁,各种互斥,好在我去年认真学了<unix环境高级编程>, 虽然已经忘得差不多了,但是学过始终是学过,拿起来也快.写这篇文章的目的就是总结linux 下多线程编程,作为日后的参考资料. 本文将介绍linux系统下多线程编程中,线程同步的各种方法.包括: 互斥量(mutex) 读写锁 条件变量 信号量 文件互斥 在介绍不同的线程同步的方法之前,先简单的介绍一下进程和线程的概念, 它们的优缺点,线程相关的API,读者——写者问题和哲学家就餐问题. 基础知识 1. 进程和

用redis实现tomcat集群下的session共享

上篇实现了 LINUX中NGINX反向代理下的TOMCAT集群(http://www.cnblogs.com/yuanjava/p/6850764.html) 这次我们在上篇的基础上实现session 共享问题 Nginx机器:192.168.1.108 两台tomcat机器分别是:192.168.1.168 192.168.1.178 一:测试session共享问题 在原index.jsp页面添加如下代码 SessionId:<%= session.getId() %> <% Stri

c++11 多线程间共享数据 &lt;c++ concurrency in action&gt;

本章主要描述多线程之间共享数据的方法.存在问题.解决方案. 第一部分:mutex在保护共享数据中的使用 1.最简单使用: #include<mutex> std::mutex some_mutex; void func(){ some_mutex.lock(); //访问共享数据 .... some_mutex.unlock(); } 2.向lock_guard推进: 但是不推荐直接使用lock.unlock,因为unlock一定要调用,如果由于你的疏忽或前面的异常将会导致问题,再次利用RAI

【OPENGL】第三章 着色器基础(一)

在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互. 首先我们先来看看什么叫着色器. Shader(着色器)是用来实现图像渲染的,用来替代固定渲染管线的可编程程序. 着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编程性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制.这极大的提高了图像的画质. 在上一篇文章( http://www.cnblog

NeHe OpenGL教程 第三十七课:卡通映射

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十七课:卡通映射 卡通映射: 什么是卡通了,一个轮廓加上少量的几种颜色.使用一维纹理映射,你也可以实现这种效果. 看到人们仍然e-mail我请求在文章中使用我方才在GameDev.net上写的源代码,还看到文章的第二版(在那每一