zoukankan      html  css  js  c++  java
  • Ogre源代码浅析——资源管理逻辑结构(二)

           创建好的资源对象指针会被保存在两个地方,第一处是在相应的ResourceManager的mResources容器中或mResourcesWithGroup容器中;第二处是在ResourceGroupManager的ResourceGroup中的loadResourceOrderMap中。

           在之前的ResourceGroupManager::createDeclaredResources()代码中可以看到资源对象由ResourceManager对象调用ResourceManager::create()来创建,此函数又会调用自身的addImpl() 成员函数来保存生成的资源对象的指针,以下是它的代码:

     1 void ResourceManager::addImpl( ResourcePtr& res )
     2 {
     3     OGRE_LOCK_AUTO_MUTEX
     4 
     5     std::pair<ResourceMap::iterator, bool> result;
     6         
     7     if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
     8     {
     9         result = mResources.insert( ResourceMap::value_type( res->getName(), res ) );
    10     }
    11     else
    12     {
    13         ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup());
    14 
    15         // we will create the group if it doesn't exists in our list
    16         if( itGroup == mResourcesWithGroup.end())
    17         {
    18             ResourceMap dummy;
    19             mResourcesWithGroup.insert( ResourceWithGroupMap::value_type( res->getGroup(), dummy ) );
    20             itGroup = mResourcesWithGroup.find(res->getGroup());
    21         }
    22         result = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) );
    23 
    24     }
    25 
    26     if (!result.second)
    27     {
    28         // Attempt to resolve the collision
    29         if(ResourceGroupManager::getSingleton().getLoadingListener())
    30         {
    31             if(ResourceGroupManager::getSingleton().getLoadingListener()->resourceCollision(res.get(), this))
    32             {
    33                 // Try to do the addition again, no seconds attempts to resolve collisions are allowed
    34                 std::pair<ResourceMap::iterator, bool> insertResult;
    35                 if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
    36                 {
    37                     insertResult = mResources.insert( ResourceMap::value_type( res->getName(), res ) );
    38                 }
    39                 else
    40                 {
    41                     ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup());
    42                     insertResult = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) );
    43                 }
    44                 if (!insertResult.second)
    45                 {
    46                         OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the name " + res->getName() + 
    47                             " already exists.", "ResourceManager::add");
    48                 }
    49 
    50                 std::pair<ResourceHandleMap::iterator, bool> resultHandle = 
    51                         mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) );
    52                 if (!resultHandle.second)
    53                 {
    54                         OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " + 
    55                             StringConverter::toString((long) (res->getHandle())) + 
    56                             " already exists.", "ResourceManager::add");
    57                 }
    58             }
    59         }
    60     }
    61     else
    62     {
    63         // Insert the handle
    64         std::pair<ResourceHandleMap::iterator, bool> resultHandle = 
    65             mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) );
    66         if (!resultHandle.second)
    67         {
    68                 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " + 
    69                     StringConverter::toString((long) (res->getHandle())) + 
    70                     " already exists.", "ResourceManager::add");
    71         }
    72     }
    73 }

           mResource被称为“global pool”;mResourceWithGroup则被称为“group pool”。从前面的讨论可知,Ogre的资源对象一般都从属于一个ResourceGroup,每个ResourceGroup类对象有一个成员变量——bool inGlobalPool,在默认情况下生成的ResourceGroup对象的这个值会被设为true。一个资源对象在被创建后,会根据它所属ResourceGroup的inGloablaPool的真值来确定是被保存在ResourceManager的“global pool”中还是“group pool”中。从上面7-10行代码可知,在默认情况下(inGlobal==true),资源对象指针是被保存在“gloabl pool”中的。如果资源要保存到“group pool”中,则稍有些麻烦,这是由mResourceWithGroup造成的,以下是它的定义:

    typedef HashMap< String, ResourcePtr > ResourceMap;
    typedef HashMap< String, ResourceMap > ResourceWithGroupMap;
    ...
    ResourceWithGroupMap mResourcesWithGroup;

          可以看到mResourcesWithGroup用了一个二级散列,这是为了减小collision的概率,但无论如何对mResourcesWithGroup来说,collision始终是可能发生的。如果一个资源对象指针要被保存到“group pool”中,Ogre就会先试着直接存入(13-22行),一旦在存入过程中发生collision(26行),Ogre会先试着向ResourceGroupManager的当前ResourceLoadingListener对象发送“resourceCollision”消息(29-31行),如果发送成功,Ogre会再次重新偿试存放此资源对象指针,如果仍然要被保存到“group pool”中且仍然发生collision,那么Ogre将会抛出弃常并打log(34-48行)。

          资源对象指针在被成功地存入到“group pool”或“global pool”后,Ogre还会以对象句柄为key,将其在mResourcesByHandle容器中再做一个备份(50-51行及64-65行)。这样做的目的显然是为了提高资源访问的效率。下面是相关的定义:

    typedef unsigned long long int ResourceHandle;
    ...
    typedef map<ResourceHandle, ResourcePtr>::type ResourceHandleMap;
    ...
    ResourceHandleMap mResourcesByHandle;

           以上就是资源对象指针在ResourceManager中的存储过程。

          在前面列出的ResourceGroupManager::createDeclaredResources()代码中可以看到,ResourceManager在创建了相应的资源对象并对其加以保存后,紧接着会把此资源对象的指针保存到其所属的ResourceGroup的loadResourceOrderMap中。 之前的ResourceGroup结构声明中已看到了loadResourceOrderMap定义,这里再专门列出其定义相关的所有代码:

    typedef list<ResourcePtr>::type LoadUnloadResourceList;
    ...
    typedef map<Real, LoadUnloadResourceList*>::type LoadResourceOrderMap;
    LoadResourceOrderMap loadResourceOrderMap;

          loadResourceOrderMap是一个以实数为key的map容器,这个key是用来区分资源类型的。通过前面的讨论可知,一个group包含了各种类型的资源对象,当以group为单元对这些资源对象进行操作时,如何对资源进行分门别类地管理就成了必须的了。Oger在ResourceManager中定义了一个变量,Real mLoadOrder,从ResourceManager中派生的资源管理器在创建时,会初始化这个mLoadOrder变量。各资源管理器的这个值是固定的,而且各不相同,具体值可以在相应的资源管理器的构造函数中找到。下面列出其中的一部分:

    TextureManager      mLoadOrder=25.0
    GpuProgramManager   mLoadOrder=50.0
    MaterialManager     mLoadOrder=100.0
    CompositionManager  mLoadOrder=110.0
    FontManager         mLoadOrder=200.0
    SkeletonManager     mLoadOrder=300

         资源对象指针在被保存到所属的ResourceGroup中时,会先根据mLoadOrder值在mLoadOrder中找到相应的list(如果没找到,就直接创建一个),然后将资源对象指针保存到此list中去。这样一来,ResourceGroupManager对象在进行资源访问时,就可以先通过mLoadOrder找到相应类型的资源list,然后再遍历此list找到需要的资源对象了。

    -----------------------------------------------------------------------------------------------------------------------------------

         存疑:在ResourceGroupManager::createDeclaredResources()中有以下调用:

    ResourceManager* mgr = _getResourceManager(dcl.resourceType);
    // Create the resource
    ResourcePtr res = mgr->create(dcl.resourceName, grp->name,
                    dcl.loader != 0, dcl.loader, &dcl.parameters);

         其中ResourceManager的create方法为:

    ResourcePtr ResourceManager::create(const String& name, const String& group, 
            bool isManual, ManualResourceLoader* loader, const NameValuePairList* params)
    {
        // Call creation implementation
        ResourcePtr ret = ResourcePtr(
                createImpl(name, getNextHandle(), group, isManual, loader, params));
           if (params)
               ret->setParameterList(*params);
    
        addImpl(ret);
        // Tell resource group manager
        ResourceGroupManager::getSingleton()._notifyResourceCreated(ret);
        return ret;
    
    }

          而被调用的ResourceGroupManager::_notifyResourceCreated(ret)又会调用ResourceGroupManager::addCreatedResource(),其代码为:

    void ResourceGroupManager::addCreatedResource(ResourcePtr& res, ResourceGroup& grp)
    {
            OGRE_LOCK_MUTEX(grp.OGRE_AUTO_MUTEX_NAME)
        Real order = res->getCreator()->getLoadingOrder();
    
        ResourceGroup::LoadResourceOrderMap::iterator i = grp.loadResourceOrderMap.find(order);
        LoadUnloadResourceList* loadList;
        if (i == grp.loadResourceOrderMap.end())
        {
            loadList = OGRE_NEW_T(LoadUnloadResourceList, MEMCATEGORY_RESOURCE)();
            grp.loadResourceOrderMap[order] = loadList;
        }
        else
        {
            loadList = i->second;
        }
        loadList->push_back(res);
    }

         也就是说,在调用ResourceManager::create()时,会将所创建的资源对象指针保存到loadResourceOrderMap中,而ResourceGroupManager::createDeclaredResources()函数会在创建完资源对象后,也将其指针保存到相应的ResourceGroup的loadResourceOrderMap中。这会造成资源对象在ResourceGroup中的重复保存吗?

    作者:yzwalkman
    转载请注明出处。
  • 相关阅读:
    预处理器宏指令(Macro)
    汇编语言中macro的用法
    USB设备的VID与PID
    前端工具 | JS编译器Monaco使用教程
    vue + ts中的shimsvue.d.ts文件的作用,在ts中引入vueecharts等vue文件 TypeScript 导入 JSON Module resolveJsonModule
    Jenkins自动打包并部署到远程服务器
    如何获取设备的VID,PID?
    TypeScript装饰器(decorators)
    MACRO指令
    IE6左右边框断线现象
  • 原文地址:https://www.cnblogs.com/yzwalkman/p/2830862.html
Copyright © 2011-2022 走看看