在前面数据绑定基本流程,简单说了下,在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漫谈的更多相关文章

  1. Axiom3D:Ogre地形组件代码解析

    大致流程. 这里简单介绍下,Axiom中采用的Ogre的地形组件的一些概念与如何生成地形. 先说下大致流程,然后大家再往下看.(只说如何生成地形与LOD,除高度纹理图外别的纹理暂时不管.) 1.生成T ...

  2. Axiom3D:数据绑定基本流程

    在前面我们学习OpenGL时,不管绘制如球,立方体,平面,地面,动画模型中最常用的几个操作有创建缓冲区,写入缓冲区.在Axiom中,相关的操作被整合与组织到VertexData,IndexData中, ...

  3. MySQL · 性能优化· InnoDB buffer pool flush策略漫谈

    MySQL · 性能优化· InnoDB buffer pool flush策略漫谈 背景 我们知道InnoDB使用buffer pool来缓存从磁盘读取到内存的数据页.buffer pool通常由数 ...

  4. 【转载】MySQL · 性能优化· InnoDB buffer pool flush策略漫谈

    背景 我们知道InnoDB使用buffer pool来缓存从磁盘读取到内存的数据页.buffer pool通常由数个内存块加上一组控制结构体对象组成.内存块的个数取决于buffer pool inst ...

  5. 【转】漫谈linux文件IO--io流程讲的很清楚

    [转]漫谈linux文件IO--io流程讲的很清楚 这篇文章写的比较全面,也浅显易懂,备份下.转载自:http://blog.chinaunix.net/uid-27105712-id-3270102 ...

  6. Axiom3D写游戏:用Overlay实现Mesh浏览.

    从网上找了些资源,大多搜Ogre,Mesh资源,然后为了方便查看各个Mesh,以及对应骨骼动画.为了实用性,考虑放在原游戏窗口里实现.最开始打算窗口新建viewport来实现,后发现这种方式的局限性, ...

  7. (转)漫谈JVM

    漫谈JVM 原文:https://liuzhengyang.github.io/2016/10/05/gossip-jvm/ 背景介绍 JVM已经是Java开发的必备技能了,JVM相当于Java的操作 ...

  8. 分布式系统漫谈一 —— Google三驾马车: GFS,mapreduce,Bigtable

    分布式系统学习必读文章!!!! 原文:http://blog.sina.com.cn/s/blog_4ed630e801000bi3.html 分布式系统漫谈一 —— Google三驾马车: GFS, ...

  9. [Alink漫谈之三] AllReduce通信模型

    [Alink漫谈之三] AllReduce通信模型 目录 [Alink漫谈之三] AllReduce通信模型 0x00 摘要 0x01 MPI是什么 0x02 Alink 实现MPI的思想 0x03 ...

随机推荐

  1. 基于 Promise 的 HTTP 请求客户端 axios

    基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 node.js 中使用 功能特性 在浏览器中发送 XMLHttpRequests 请求 在 node.js 中发送 http请求 支持 ...

  2. Chrome多线程下载

    https://github.com/jae-jae/camtd https://aria2.github.io/ 切换到解压目录D:\Tools\aria2-1.34.0-win-64bit中,打开 ...

  3. Postman调用WebService,包括头验证部分

    Postman调用WebService时,Body中选择Raw,最右端选择XML(txt/xml),然后把某个方法显示在页面的xml拷贝到请求框中即可,如下图: 以下是postman中的设置,

  4. su 和 su -

    单纯使用su切揣到root,读取变量的方式 是non-login shell,这种方式下很多的变量都 不会改变,尤其是PATH,所以root用的很多命令都只能用绝对路径来执行,这种方式只是切换到roo ...

  5. FFmpeg(11)-基于FFmpeg进行音频重采样(swr_init(), swr_convert())

    一.包含头文件和库文件 修改CMakeLists # swresample add_library(swresample SHARED IMPORTED) set_target_properties( ...

  6. 每日英语:Researchers Study How Excess Fat Cells Interfere With Organ Function, Metabolism

    Why are some obese people healthy, apparently protected from the damaging effects of excess fat on t ...

  7. 将docker的image转移到数据盘

    1. 将 /var/lib/docker 移至数据盘 原因: docker运行中产生较大文件,以及pull下来的images会占用很多空间: 注意:在执行前确认docker已经启动,sudo dock ...

  8. Mac上把python源文件编译成so文件

    把python源文件编译成so文件 前言 实际上属于一种代码混淆/加密的技术,大家知道python的源文件放在那里,大家是都可以看的,不像C语言编译出来可以拿编译后的东西去运行,所以就出现了这种需求. ...

  9. 【Ubuntu】任务管理器loadruner

    linux1 准备工作   可以通过两种方法验证服务器上是否配置了rstatd守护程序:    ①使用rup命令,它用于报告计算机的各种统计信息,其中就包括rstatd的配置信息.使用命令rup 10 ...

  10. 为什么说Thunderbird是最好的桌面RSS阅读器

    也许现在再讨论RSS阅读器似乎已经过时了,毕竟随着社交网络服务的发展,通过一个带有大众评分能力的社交网络(比如reddit),相比RSS的固定订阅而言,也许你能更快地在你所关心的话题上更快地获得新的资 ...