Axiom3D:Buffer漫谈
在前面数据绑定基本流程,简单说了下,在Axiom中,数据从我们C#的托管环境到下面的OpenGL或是D3D的非托管环境,有个转化过程,相关实现我们可以从BufferBase看起.BufferBase与他的子类集合了相关数据块在托管环境与非托管环境的相关操作. 在BufferBase中,包装了一个重要的类GCHandle,其中托管代码中,因为GC的关系,在运行时所有元素的内存地址也都是变化的,这里在我们需要用到GCHandleType.Pinned,这个会固定我们申请的空间地址,防止GC移动与释放这块内存,当然这块内存的回收也和C++里一样,需要我们手动调用Free方法去释放.GCHandle对象保存了数据块在内存中的位置,而GCHandle里的Ptr(int)保存的是我们在GCHandle内存块里的位置(如申请100字节长度,那么Ptr只能是0-99这100百个数),默认是头0开始,一般用来做偏移地址运算.BufferBase提供一个虚拟方法Pin(),供子类提供数据块固定的指针地址,以便于OpenGL,D3D中非托管环境调用.最后BufferBase里的方法Wrap,用来直接生成一个UnsafeBuffer的对象.
下面针对UnsafeBuffer,我们来先看一段代码:
这段代码里,我们首先用GCHandle.Alloc申请一块buffer大小的空间,在这buffer虽然是object类型,但是因为我们申请的是固定的句柄(GCHandleType.Pinned),这个是不支持引用类型的,就是buffer必需是值类型(值类型也有要求,应该说是准确声明空间长度的值类型),不过在Axiom中,我们一般是传递如int[],float[]这种,所以此处满足.申请后,我们用方法AddrofPinnedObject得到用Pinned方式申请的指针,上面this.Buf是成byte*块,就是字节块,这样主要是为了好做相关地址运算,如下面我传入一个-100.0,-100.0,0.0...的数组,请看下面相关结果.
|
表达式 |
内存地址 |
地址求值 |
|
(float*)this.Buf |
0x01fdfab4 |
*((float*)this.Buf): -100.0 |
|
(float*)this.Buf + 1 |
0x01fdfab8 |
*((float*)this.Buf + 1): -100.0 |
|
(float*)this.Buf + 2 |
0x01fdfabc |
*((float*)this.Buf + 2): 0.0 |
|
(float*)(this.Buf+4) |
0x01fdfab8 |
*((float*)(this.Buf+4)): -100.0 |
|
(float*)(this.Buf+8) |
0x01fdfabc |
*((float*)(this.Buf+8)): 0.0 |
我们知道内存中,数据全是0101这样的bit位,我们的数组buffer保存在内存中也是这样,我们平常定义的什么int,float,byte等只是为了让计算机正确解析位来转换成相应数据.这里转换成byte*,float*,int*的区别也是这样,如果转化成byte位,那么他加1就是一个byte,同理,他转化成int,float,他就加4个byte,也就是4个字节长度.我们知道sizeof计算的长度就是字节来算的,这里转化成byte*就是用了容易对地址进行定义,因为字节是我们数据块用到的最小单位,对应属性Length长度指的也是字节.如上,转化成byte*后,我要得到第二个float就用(float*)(this.Buf+4)或是(float*)this.buf+1,效果一样.我们再来看下面一段代码就很清楚了.

我们知道,long是8个字节,而index是指单位为字节的长度,那么转化成对应的long数组里对应的long的索引应该是index*8,例如index是10,那么long数组对应值应该是对应字节块的初地址加上80的偏移量.对应的如ITypePointer<byte>,ITypePointer<short>,ITypePointer<int,float>,ITypePointer<double>分别是index,index*2,index*4,index*8.
而同属BufferBase的子类的ManagedBuffer,不同于UnsafeBuffer管理的byte*,他管理的是byte[],好吧,这二个也是一样,相关的索引器也是在对byte索引的偏移计算,同UnsafeBuffer逻辑一样,不同的是,UnsafeBuffer中的GCHandle.Alloc操作是在初始化的时候.而ManagedBuffer是发生在调用方法Pin时,才会执行GCHandle.Alloc操作.注意,不管是UnsafeBuffer还是ManagedBuffer,Pin方法指向的指针位置是当前内存块的头地址(GCHandle.AddrofPinnedObject())加上偏移地址(BufferBase.Ptr).
同样如ManagedBufferCol3b等,都是在原来类的基础上增加一个对应的索引器.
在前面Axiom3D:数据绑定基本流程可以看到顶点数据(VertexData),索引数据(IndexData),他们都有HardwareBuffer对象,这个对象用来与BufferBase互动.HardwareBuffer与BufferBase的关系有些类似AnimationTrack与KeyFrame,他们的具体实现交给子类,抽象互动都由本身来实现.前面我们说了BufferBase,主要是提供一个数据块空间,这个空间的位置,对这个空间的索引,相关子类对应托管环境与非托管环境的实现.而HardwareBuffer如下方法WriteData,ReadData,Copy分别提供对BufferBase的写入,读取,复制数据一些操作的包装.针对GL的环境,我们来看下HardwareBuffer的子类GLHardwareVertexBuffer,其WriteData,ReadData就是调用glBufferData,glGetBufferData分别把BufferBase里的数据块写入到显存,或从显存中读取出来.不用显存,DefaultHardwareVertexBuffer提供针对内存中BufferBase的相关操作,不像GLHardwareVertexBuffer需要把数据从CPU到GPU的过程,DefaultHardwareVertexBuffer里的读取,写入,复制操作就是把BufferBase的数据块从一个地方复制到另一个地方,直接用的就是对应的BufferBase的Copy操作.
还有一个地方,数据也是一块一块的包装在一个位置的,就是纹理,我们知道纹理图片里的每个像素点都是各个类型的RGBA元素组合而成,那么在我们内存或显存中,图片就是一个数据块区域,知道了这个数据块区域的格式,如RGBA8B,那么我们就能正确的解析成相应的像素点集合,然后就能正确的在显示器上显示成对应图像了.通过纹理我们能利用GPU强大的并行功能,因为纹理就是数据块,就是数组.具体可以参看GPGPU基本运算与乒乓技术.
如同顶点对应HardwareVertexBuffer,顶点索引对应HardwareIndexBuffer,图片也有自己的HardwareBuffer对应类HardwarePixelBuffer.在介绍这个类时,先看下类BasicBox与PixelBox,其中PixelBox是BasicBox的子类,BasicBox差不多就是针对一个描述一个立方体,有6面,分别是前后左右上下6面(一般情况下,默认宽度Width指左右距离,高度Height指上下距离,深度Depth指前后距离).而PixelBox描述的是图片(包含一维至三维,一维用宽度Width,二维增加高度Height,三维增加深度Depth).在BasicBox的上面增加一个BufferBase用来表示像素数据,其中PixelBox有个比较重要的属性PixelFormat,其实这个类就相当于VertexDeclaration,一个是指明像素是如何组成的,如SHORT_RBG.而VertexDeclaration指明顶点是如何组成,如T2fN3fV3f.有了PixelFormat,我们才能正确序列化PixelBox里的数据块BufferBase里的信息.在PixelConverter这个类中提供了二个PixelBox互相操作的方法,例如从一张图片中提取他的R通道数据,调用PixelConverter的BulkPixeConversion方法就可.有兴趣可以看一下具体实现,本质还是对BufferBase根据PixelFormat与索引得到偏移赋值操作.
而HardwarePixelBuffer提供二个抽象方法,一个是BlitFormMemory,把PixelBox中的像素数据取出放到新的内存或显存.另一个是BlitToMemory,把显存和内存里的数据取出.这二个函数分别在GL的环境中的子类GLHardwareBuffer与他的子类GLTextureBuffer中的实现如下,BlitFormMemory就是调用GL的API如glTexImage2D这类把数据,而BlitToMemory就是调用glGetTexImage,这样就很容易理解了.
下图是上面类的关系,突出像素HardwarePixelBuffer与BufferBase的关系。

Axiom3D:Buffer漫谈的更多相关文章
- Axiom3D:Ogre地形组件代码解析
大致流程. 这里简单介绍下,Axiom中采用的Ogre的地形组件的一些概念与如何生成地形. 先说下大致流程,然后大家再往下看.(只说如何生成地形与LOD,除高度纹理图外别的纹理暂时不管.) 1.生成T ...
- Axiom3D:数据绑定基本流程
在前面我们学习OpenGL时,不管绘制如球,立方体,平面,地面,动画模型中最常用的几个操作有创建缓冲区,写入缓冲区.在Axiom中,相关的操作被整合与组织到VertexData,IndexData中, ...
- MySQL · 性能优化· InnoDB buffer pool flush策略漫谈
MySQL · 性能优化· InnoDB buffer pool flush策略漫谈 背景 我们知道InnoDB使用buffer pool来缓存从磁盘读取到内存的数据页.buffer pool通常由数 ...
- 【转载】MySQL · 性能优化· InnoDB buffer pool flush策略漫谈
背景 我们知道InnoDB使用buffer pool来缓存从磁盘读取到内存的数据页.buffer pool通常由数个内存块加上一组控制结构体对象组成.内存块的个数取决于buffer pool inst ...
- 【转】漫谈linux文件IO--io流程讲的很清楚
[转]漫谈linux文件IO--io流程讲的很清楚 这篇文章写的比较全面,也浅显易懂,备份下.转载自:http://blog.chinaunix.net/uid-27105712-id-3270102 ...
- Axiom3D写游戏:用Overlay实现Mesh浏览.
从网上找了些资源,大多搜Ogre,Mesh资源,然后为了方便查看各个Mesh,以及对应骨骼动画.为了实用性,考虑放在原游戏窗口里实现.最开始打算窗口新建viewport来实现,后发现这种方式的局限性, ...
- (转)漫谈JVM
漫谈JVM 原文:https://liuzhengyang.github.io/2016/10/05/gossip-jvm/ 背景介绍 JVM已经是Java开发的必备技能了,JVM相当于Java的操作 ...
- 分布式系统漫谈一 —— Google三驾马车: GFS,mapreduce,Bigtable
分布式系统学习必读文章!!!! 原文:http://blog.sina.com.cn/s/blog_4ed630e801000bi3.html 分布式系统漫谈一 —— Google三驾马车: GFS, ...
- [Alink漫谈之三] AllReduce通信模型
[Alink漫谈之三] AllReduce通信模型 目录 [Alink漫谈之三] AllReduce通信模型 0x00 摘要 0x01 MPI是什么 0x02 Alink 实现MPI的思想 0x03 ...
随机推荐
- c++ STL map 结构体
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候 ...
- 如何将git本地创建的项目推送到github仓库
除了集中式的版本控制系统CVS和SVN外,还有目前世界上最先进的分布式版本控制系统Git,它的创始人是创建了linux的大神 - linus.GitHub网站与2008年开始服役,为开源项目免费提供G ...
- python(59):yield 函数
可迭代对象: 当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象: >>> mylist = [1, 2, 3] >>> for i in myli ...
- spring 过滤器
Spring的web包中中有很多过滤器,这些过滤器位于org.springframework.web.filter并且理所当然地实现了javax.servlet.Filter,不过实现的方式有以下几类 ...
- 什么是POP3、SMTP和IMAP?
POP3 POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议.它是因特网电子邮件的第 ...
- 基于HTML5手机上下滑动翻页特效
基于HTML5手机上下滑动翻页特效.这是一款手机移动端触屏滑动翻页代码下载.效果图如下: 在线预览 源码下载 实现的代码. html代码: <section class="u-al ...
- 自己动手写Android框架-数据库框架
大家在工作中基本上都有使用到数据库框架 关系型:ORMLite,GreenDao 对象型:DB4O,Perst 这些数据库用起来都非常的简单,对于我们Android上来说这些数据库足够我们使用了,但是 ...
- 编写js语句结束时保持良好的习惯-源于身边例子
记录以下信息,源于一件事情,一位同事,每次我改他的js代码,发现语句结束都不使用分号作为结束.长长的一串,读起来比较吃力.即便语句的结束不使用分号结束,代码仍然不会报错,正常运行,所以不少程序员懒得去 ...
- 【Unity】使用Resources类管理资源
最近参考了各位大神的资源,初步学习了Unity的资源管理模式,包括在编辑器管理(使用AssetDatabase)和在运行时管理(使用Resources和AssetBundle).在此简单总结运行时用R ...
- mongo源码学习(三)请求接收传输层
在上一篇博客中(mongo源码学习(二)db.cpp之mongoDbMain方法分析),我们把db.cpp中的mongoDbMain的执行过程分析了一下,最后会调用initAndListen(serv ...