转: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
转:Ogre源码剖析1的更多相关文章
- 转:Ogre源码剖析 - 场景管理之Octree
由于本人的引擎ProjectGaia服务于08年创新杯的游戏项目 – 3D太空游戏,所以理所应当加入Octree(八叉树 – 已经周宁学长发帖介绍过)场景管理器.参考了无数Octree的代码,发现还是 ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
- Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现
声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析
项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...
- STL"源码"剖析-重点知识总结
STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段.在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过serv ...
- 自己实现多线程的socket,socketserver源码剖析
1,IO多路复用 三种多路复用的机制:select.poll.epoll 用的多的两个:select和epoll 简单的说就是:1,select和poll所有平台都支持,epoll只有linux支持2 ...
- Java多线程9:ThreadLocal源码剖析
ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...
随机推荐
- MySQL C API的一个让我头疼的问题,获得一行记录中包括NULL
遇到过几次错误,通过gdb来查看错误对战,发现错误居然是atoi调用出错,除非atoi(NULL) 才会报这种错误.说明 row[0]==NULL. (gdb) bt #0 0x00007f82c66 ...
- 企业高并发的成熟解决方案(一)----搭建LVS负载均衡
企业整个架构分析 1. App服务器上边部署应用,如果是java的话,一般是tomcat: 2. 负载均衡服务器负责转发请求,这种既有主机又有备机的负载均衡成为高可用(HA): 3. 一般web服务器 ...
- ubuntu下nodejs开发环境搭建
1.安装nodejs sudo apt install -y nodejs 2.更新npm到最新版本 sudo npm i -g npm 3.npm配置为淘宝镜像 sudo npm config se ...
- Building LinkedIn’s Real-time Activity Data Pipeline
转自:http://blog.163.com/guaiguai_family/blog/static/20078414520138911393767/ http://sites.computer.or ...
- php学习笔记之动态生成一组单选button
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 从头来之【iOS及历史版本特性介绍】
iOS是apple公司的移动操作系统,在iPhone,iPad,iPod中应用,该名最初为Cisco的网络设备操作系统,后授权于Apple公司使用.下面介绍历史版本的特性. iOS1 最大特性是具有其 ...
- Linux 远程和本地的一些解决方式
有的小伙伴想Linux 远程登录 两台机器同一时候root登录.事实上能够同一时候多个用户的. Linux是多用户的多任务系统,能够同一时候多个用户登录到系统,也能够一个用户通过不同终端登录到一个系 ...
- 【转】Java抽象类与接口的区别
很多常见的面试题都会出诸如抽象类和接口有什么区别,什么情况下会使用抽象类和什么情况你会使用接口这样的问题.本文我们将仔细讨论这些话题. 在讨论它们之间的不同点之前,我们先看看抽象类.接口各自的特性. ...
- Binary Search二分法搜索C++程序
二分法基本上学计算机的都听过,但是有人不知道的就是其实二分法是减治法的思想. 所谓减治法和分治法有一个主要差别就是减治法是减去一般,就是分治之后只需要解决原问题的一半就可以了得到全局问题的解了.所以速 ...
- 茶道(tea)
#include<iostream> #include<string> #include<stdio.h> #include<algorithm> #i ...