转:Ogre源码剖析1
初学Ogre 貌似看到一些套路(ajohn)
1 Ogre的编译
获得最新的Ogre 1.71 和之前的Ogre比起来,除了sampler集成之外,最大的改变就是编译过程加入了Cmake,这个东西其实就是检测你电脑上装了些什么?
比如说是否安装DX_SDK 如果没有装,就不会有RenderSystem_DXXXX的工程,如果有装,检测DXSDK是什么版本的,相应产生
RenderSystem_DX9 RenderSystem_DX10 RenderSystem_DX11工程到你的解决方案中
还有就是boost,如果你安装了一定版本的boost(太低了不行)便会加入多线程
网上看到一个评估程序员能力的文章:
说对于工程的编译的最高境界,就是写相关的编译脚本,让我想起了linux的工程的编译,不禁感叹生在Windows是多么得幸福,
俺的工程编译的境界还停留在初期阶段,顶多就是把VS玩来玩去,而且VS的工程设置的每个选项还不一定都知道。- -!
1 内存管理
之前分析过U3的内存管理以及其GC机制,所以一上来就看内存,Ogre没有GC,有的是比
System new和delete效率更高,速度更快的nedmalloc的封装。
nedmalloc是一个免费的第三方支持多线程并且速度在同类产品中很快的内存管理库。
Ogre对nedmalloc的封装可以说是一波三折,并且提供内存泄露检测工具类,
先从底层看OgreMemoryNedPooling.h
NedPoolingImpl 接口类,适配模式,提供allocBytes,deallocBytes,具体实现便是对nedmalloc的调用
NedPoolingPolicy Alloc的分配策略,也是简单提供allocateBytes和deallcateBytes,具体通过NedPoolingImpl来操作
接下来在OgreMemoryAllocatorConfig.h中提供一个模板类
template <MemoryCategory Cat> class CategorisedAllocPolicy : public NedPoolingPolicy{};
似乎没做什么,其实意义很大,目的是可以通过模板实例化来定义不同的AllocPolicy。
typedef CategorisedAllocPolicy<Ogre::MEMCATEGORY_GENERAL> GeneralAllocPolicy; 通用分配器
typedef CategorisedAllocPolicy<Ogre::MEMCATEGORY_GEOMETRY> GeometryAllocPolicy; 几何图元分配器
typedef CategorisedAllocPolicy<Ogre::MEMCATEGORY_RESOURCE> ResourceAllocPolicy;
.
.
这些其实都是一样的东西,但是类名不一样
转到OgreMemoryAllcatedObject.h 的 templete<class Alloc> class AllocatedObject 模板类
提供operator new, operator delete, operator new[], operator delete[]。
里面的操作就是通过模板类型Alloc的 allocateBytes 和 deallocateBytes来分配内存.
再回头看OgreMemoryAllocatorConfig.h
typedef AllocatedObject<GeneralAllocPolicy> GeneralAllocatedObject; 通用分对象
typedef AllocatedObject<GeometryAllocPolicy> GeometryAllocatedObject; 集合图元分配对象
typedef AllocatedObject<ResourceAllocPolicy> ResourceAllocatedObject;
.
.
还没完。。。。Ogre似乎为大部分常用的类(或者说sizeof(该类)很大)都定义了一个具体的名字:
typedef ResourceAllocatedObject ResourceAlloc;
typedef SceneObjAllocatedObject SubEntityAlloc;
typedef ResourceAllocatedObject SubMeshAlloc;
typedef RenderSysAllocatedObject BufferAlloc;
看Resource类的申明:
class Resource : public StringInterface, public ResourceAlloc
所以,当你new Resource或者Resource的派生类的时候,内存的分配通过ResourceAlloc -> ResourceAllocatedObject
-> operator new -> ResourceAllocPolicy::allocateBytes -> NedPoolingPolicy::allocateBytes
-> NedPoolingImpl::allocaBytes -> nedmalloc的C函数开辟内存(->不是指的函数调用)
当某些类或者资源没有派生自这些Alloc的时候,怎样用nedmalloc来处理?
Ogre提供很多宏来用nedmalloc操作内存:
OGRE_MALLOC (等同于malloc) OGRE_ALLOC_T(等同于malloc) OGRE_FREE(等同于free)
OGRE_NEW_T (等同于new)OGRE_NEW_ARRAY_T(等同于new[])
OGRE_DELETE_T (等同于delete) OGRE_DELETE_ARRAY_T(等同于delete[])。
最后提下内存跟踪和泄露:
参看OgreMemoryNedPooling.cpp
在NedPoolingImpl的allocBytes和deAllocBytes中,如果定义了OGRE_MEMORY_TRACKER宏,便会把当前的
内存分配信息交给MemoryTracker处理,MemoryTracker是单件,里面用哈希表
typedef HashMap<void*, Alloc> AllocationMap; AllocationMap mAllocations;
来存储这些内存分配和释放信息,计算是使用HashMap,速度还是慢,测试了一下,
没有内存跟踪和有内存跟踪的性能比为 38::5
2 SharedPtr
纯粹模仿boost::shared_ptr。
基类实现几个重要的操作接口:
SharedPtr() 对象指针和计数指针都为NULL。
explicit SharedPtr(Y* rep)对象指针->rep 计数指针->+1
SharedPtr(const SharedPtr& r)对象指针->r的对象指针 计数指针->r的计数指针并+1
SharedPtr& operator=(const SharedPtr& r)有点复杂,自己跟代码
而每个资源型的类,貌似都附带一个该类的Ptr,
1 直接定义 有的直接def SharedPtr<SomeClass> SomeClassPtr;
2 继承 有的是class SomeClassPtr : public SharedPtr<SomeClass>。
分析一下TexturePtr说明为什么有继承的存在:
TexturePtr 新加入了2个函数:
TexturePtr(const ResourcePtr& r) 把资源指针看成纹理
TexturePtr& operator=(const ResourcePtr& r) 同上
索迪斯内
3 Manager
凡有很多对象需要管理,比如说Resource , SceneNode, 等 都会配套实现一个该类的Manager
如ResourceManager SceneManager
虽然所有的Manager都是单件,但是并不是真正意义上的单件!一般说来,单件是不允许new出来的,即
sigleton基类的构造函数是protected的,
而Ogre的sigleton的构造函数是public,这样就允许new SomeManager出来。
这样做的目的是为了实现Plugin机制(抽象工厂模式)。
比如说有个TextureManager(抽象类) createImpl创建的产品是 TexturePtr
而D3D9TextureManager(具体实现类) createImpl创建的产品是 D3D9TexturePtr
GLTextureManager(具体实现类) createImpl创建的产品是 GLTexturePtr
OgreMain中给用户的只有TextureManager接口,那么它到底是哪个具体实现类?
所以必须new出来,so,就有了这个不标准的sigleton
例举Resource。关键步骤如下
class D3D9Resource
{
//不做任何事情,相应派生自改类的做事情
virtual void notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device) {}
//当创建一个需要管理的对象的时候,通知合适的Manager做处理 一般说来就是加入到manager的自身列表
D3D9Resource::D3D9Resource()
{
D3D9RenderSystem::getResourceManager()->_notifyResourceCreated(static_cast<D3D9Resource*>(this));
}
//当销毁一个需要管理的对象的时候,通知合适的Manager做处理,一般说来就是从manager的自身列表中删除
D3D9Resource::~D3D9Resource()
{
D3D9RenderSystem::getResourceManager()->_notifyResourceDestroyed(static_cast<D3D9Resource*>(this));
}
};
class D3D9RespirceManager
{
//加入列表
void _notifyOnDeviceCreate (IDirect3DDevice9* d3d9Device)
{
mResources.push_back(pResource);
}
//从列表中找到该对象,并且删除
void _notifyResourceDestroyed(D3D9Resource* pResource)
{
OGRE_LOCK_MUTEX(mResourcesMutex)
ResourceContainerIterator it = mResources.begin();
while (it != mResources.end())
{
if ((*it) == pResource)
{
mResources.erase(it);
break;
}
++it;
}
}
//注意,保存的是指针。
//这里用的vector,因为删除,查找操作不常见,否则会用map,比如说SceneManager
typedef vector<D3D9Resource*>::type ResourceContainer;
}
4, Plugin
就RenderSystem_DX9来详细说明一下
基本流程如下:
1,OgreMain 定义基本接口 RenderSystem Texture HardwareVertexBuffer HardwareIndexBuffer
其中RenderSystem代表抽象出的渲染接口 其他类代表是渲染资源
2,Plugins 写各种基于改基本接口的扩展类的dll 提供 D3D9RenderSystem D3D9Texture D3D9HardwareVertexBuffer HardwareIndexBuffer
3,配置文件制定那种dll,就动态链接动态链接库,来找到扩展类的实现
逆向分析RenderSystem_DX9的实现,先了解Plugin的思路。
Ogre运行,
new Root();
跟入代码发现root() -> loadPlugins() -> loadPlugin() -> pFunc().
仔细跟一下代码发现pFunc()是Dll的extern "C"的导出函数,如果你当前的Plugin是RenderSystemn_DX9的话
会进入到OgreD3D9EngineDll.cpp -> dllstartPlugin中 改dllstartPlugin做的事情是:构建D3D9Plugin对象
然后通知Root维护该对象,并且调用plugin->install().进入到OgreD3DPlugin::install,构建D3D9RenderSystem
然后通知Root维护改RenderSystem。
over
Plugin的机制就是以dll的方式来隐藏具体的实现,比如说D3D9Device,D3D9IB D3D9VB D3D9Textuer
Ogremain提供基本的抽象,比如说3D引擎都有渲染器,便抽象出RenderSystem以及里面的接口,如针对DX9的Device提供的函数的
各种具体操作:如_useLights _setDepthBias _setfog _setTexture _setWorldMatrix等等
用户(使用Ogre的民工)只需要面对Ogreman的接口,无须关心DX的具体实现,
对于资源型接口,如HardwareVertexBuffer HardwareIndexBuffer Texture来说,也是同理,
分析一下Texture的创建过程,根据套路2,Manager的思路,在root初始化之后写下如下代码调试跟进。
Ogre::TexturePtr pt = Ogre::TextureManager::getSingleton().create("danteng.jpg","danteng");
会发现,最终由D3D9TextureManager负责创建一个D3D9Texture,然后返回其基类TexturePtr的智能指针
D3D9TextureManager是继承自TextureManager,并且是单件,根据抽象工厂设计模式的概念来理解
一般单件都不是new出来的,而是getsingleton出来的,但是Ogre为了保证抽象工厂,必须注册一个具体的Manager。
这个初始化过程在root->initialize() -> mActiveRenderer->_initialise() -> mTextureManager = new D3D9TextureManager();
注意这个mTextureManager是RenderSystem接口的成员。
于是乎,,D3D9Texture透明化了,用户能看到的只有Texture
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shenghanzhouyou/archive/2010/05/05/5559730.aspx