1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/mesh_block_manager.h"
20 #include "nel/misc/hierarchical_timer.h"
22 using namespace NLMISC
;
32 #define NL3D_MBM_MAX_VBHEAP 255
33 #define NL3D_MBM_VBHEAP_MESH_SHIFT 8
34 #define NL3D_MBM_VBHEAP_MESH_MASK 0xFFFFFF00
35 #define NL3D_MBM_VBHEAP_HEAP_MASK 0x000000FF
38 // ***************************************************************************
39 CMeshBlockManager::CMeshBlockManager()
41 _RenderCtx
.Driver
= NULL
;
42 _RenderCtx
.Scene
= NULL
;
43 _RenderCtx
.RenderTrav
= NULL
;
45 // Allocate at least the 0th heap
46 _VBHeapBlocks
.resize(1);
47 _VBHeapBlocks
[0]= new CVBHeapBlock
;
48 // some reserve, avoiding first reallocation.
49 _VBHeapBlocks
[0]->RdrInstances
.reserve(100);
50 _VBHeapBlocks
[0]->RdrMeshGeoms
.reserve(100);
53 // ***************************************************************************
54 CMeshBlockManager::~CMeshBlockManager()
56 // must release any user heap.
58 // Release the 0th one.
59 delete _VBHeapBlocks
[0];
60 _VBHeapBlocks
.clear();
63 // ***************************************************************************
64 void CMeshBlockManager::addInstance(IMeshGeom
*meshGeom
, CMeshBaseInstance
*inst
, float polygonCount
)
66 // If the meshGeom has never been added to the manager, may do some precalc
67 if(meshGeom
->_MeshBlockManager
==NULL
)
70 meshGeom
->_MeshBlockManager
= this;
71 // try to fit the meshGeom in one of our VBHeap.
72 allocateMeshVBHeap(meshGeom
);
76 /*extern uint TEMP_Yoyo_NInstVBHeap;
77 extern uint TEMP_Yoyo_NInstNoVBHeap;
78 if( meshGeom->_MeshVBHeapId & NL3D_MBM_VBHEAP_HEAP_MASK )
79 TEMP_Yoyo_NInstVBHeap++;
81 TEMP_Yoyo_NInstNoVBHeap++;*/
84 // Choose the HeapBlock to fit in.
85 CVBHeapBlock
*hb
= _VBHeapBlocks
[meshGeom
->_MeshVBHeapId
& NL3D_MBM_VBHEAP_HEAP_MASK
];
87 // If the mesh geom is not added to this manager, add it.
88 if(meshGeom
->_RootInstanceId
==-1)
90 hb
->RdrMeshGeoms
.push_back(meshGeom
);
93 // setup the instance.
94 CInstanceInfo instInfo
;
95 instInfo
.MeshGeom
= meshGeom
;
97 instInfo
.PolygonCount
= polygonCount
;
99 // link to the head of the list.
100 instInfo
.NextInstance
= meshGeom
->_RootInstanceId
;
101 meshGeom
->_RootInstanceId
= (sint32
)hb
->RdrInstances
.size();
104 hb
->RdrInstances
.push_back(instInfo
);
108 // ***************************************************************************
109 void CMeshBlockManager::flush(IDriver
*drv
, CScene
*scene
, CRenderTrav
*renderTrav
)
113 H_AUTO( NL3D_MeshBlockManager
);
116 nlassert(drv
&& scene
&& renderTrav
);
117 _RenderCtx
.Driver
= drv
;
118 _RenderCtx
.Scene
= scene
;
119 _RenderCtx
.RenderTrav
= renderTrav
;
124 // sort by Heap first => small setup of VBs.
125 for(j
=0; j
<_VBHeapBlocks
.size();j
++)
127 CVBHeapBlock
*hb
= _VBHeapBlocks
[j
];
128 // if not the special 0th heap, must activate VB.
131 _RenderCtx
.RenderThroughVBHeap
= false;
135 // set to true => avoid mesh to setup their own VB.
136 _RenderCtx
.RenderThroughVBHeap
= true;
137 // activate current VB in driver
138 #if 0 // todo hulud remove / restore VBHeap
139 hb
->VBHeap
.activate();
140 #endif // todo hulud remove / restore VBHeap
144 // Always sort by MeshGeom, in this heap
145 for(i
=0; i
<hb
->RdrMeshGeoms
.size();i
++)
147 // render the meshGeom and his instances
148 render(hb
, hb
->RdrMeshGeoms
[i
], hb
->RdrInstances
);
156 for(j
=0; j
<_VBHeapBlocks
.size();j
++)
158 CVBHeapBlock
*hb
= _VBHeapBlocks
[j
];
160 // Parse all MehsGeoms, and flag them as Not Added to me
161 for(i
=0; i
<hb
->RdrMeshGeoms
.size();i
++)
163 hb
->RdrMeshGeoms
[i
]->_RootInstanceId
= -1;
167 hb
->RdrInstances
.clear();
168 hb
->RdrMeshGeoms
.clear();
173 // ***************************************************************************
174 void CMeshBlockManager::render(CVBHeapBlock
*vbHeapBlock
, IMeshGeom
*meshGeom
, std::vector
<CInstanceInfo
> &rdrInstances
)
177 /*extern uint TEMP_Yoyo_NMeshVBHeap;
178 extern uint TEMP_Yoyo_NMeshNoVBHeap;
179 if( _RenderCtx.RenderThroughVBHeap )
180 TEMP_Yoyo_NMeshVBHeap++;
182 TEMP_Yoyo_NMeshNoVBHeap++;*/
185 // Start for this mesh.
186 meshGeom
->beginMesh(_RenderCtx
);
189 // sort per material first?
190 if( meshGeom
->sortPerMaterial() )
192 // number of renderPasses for this mesh.
193 uint numRdrPass
= meshGeom
->getNumRdrPassesForMesh();
196 for(uint rdrPass
=0;rdrPass
<numRdrPass
;rdrPass
++)
199 sint32 instId
= meshGeom
->_RootInstanceId
;
202 CInstanceInfo
&instInfo
= rdrInstances
[instId
];
204 // activate this instance
205 meshGeom
->activeInstance(_RenderCtx
, instInfo
.MBI
, instInfo
.PolygonCount
, NULL
);
208 meshGeom
->renderPass(_RenderCtx
, instInfo
.MBI
, instInfo
.PolygonCount
, rdrPass
);
211 instId
= instInfo
.NextInstance
;
215 // else sort per instance first
219 sint32 instId
= meshGeom
->_RootInstanceId
;
222 CInstanceInfo
&instInfo
= rdrInstances
[instId
];
224 // If the meshGeom need to change Some VB (geomorphs...)
225 bool needVBHeapLock
= _RenderCtx
.RenderThroughVBHeap
&& meshGeom
->isActiveInstanceNeedVBFill();
230 #if 0 // todo hulud remove / restore VBHeap
231 vbDst
= vbHeapBlock
->VBHeap
.lock(meshGeom
->_MeshVBHeapIndexStart
);
232 #endif // todo hulud remove / restore VBHeap
235 // activate this instance
236 meshGeom
->activeInstance(_RenderCtx
, instInfo
.MBI
, instInfo
.PolygonCount
, vbDst
);
240 // unlock only what vertices have changed (ATI problem)
241 #if 0 // todo hulud remove / restore VBHeap
242 vbHeapBlock
->VBHeap
.unlock(meshGeom
->_MeshVBHeapIndexStart
,
243 meshGeom
->_MeshVBHeapIndexStart
+ meshGeom
->_MeshVBHeapNumVertices
);
244 #endif // todo hulud remove / restore VBHeap
247 // number of renderPasses for this mesh.
248 uint numRdrPass
= meshGeom
->getNumRdrPassesForInstance(instInfo
.MBI
);
251 for(uint rdrPass
=0;rdrPass
<numRdrPass
;rdrPass
++)
254 meshGeom
->renderPass(_RenderCtx
, instInfo
.MBI
, instInfo
.PolygonCount
, rdrPass
);
258 instId
= instInfo
.NextInstance
;
262 // End for this mesh.
263 meshGeom
->endMesh(_RenderCtx
);
267 // ***************************************************************************
268 // ***************************************************************************
270 // ***************************************************************************
271 // ***************************************************************************
274 // ***************************************************************************
275 void CMeshBlockManager::allocateMeshVBHeap(IMeshGeom
*mesh
)
277 // Get info from mesh.
278 uint vertexFormat
, numVertices
;
279 // if the mesh do not support VBHeap, quit.
280 if( !mesh
->getVBHeapInfo(vertexFormat
, numVertices
) )
287 // try to find a VBHeap with this vertexFormat.
288 TVBHeapMap::iterator it
= _VBHeapMap
.find(vertexFormat
);
289 // if not found, abort
290 if(it
==_VBHeapMap
.end())
293 // access to this VBHeap.
294 uint vbHeapId
= it
->second
;
295 CVBHeapBlock
*vbHeapBlock
= _VBHeapBlocks
[vbHeapId
];
296 // try to allocate sapce into the heap. Fail=> abort.
297 #if 0 // todo hulud remove / restore VBHeap
299 if( !vbHeapBlock
->VBHeap
.allocate(numVertices
, indexStart
) )
301 #endif // todo hulud remove / restore VBHeap
303 // All is Ok here => setup infos.
306 // Keep track of the mesh => allocate.
308 // try to get a free id.
309 if( !vbHeapBlock
->FreeIds
.empty() )
311 meshId
= vbHeapBlock
->FreeIds
.back();
312 vbHeapBlock
->FreeIds
.pop_back();
313 vbHeapBlock
->AllocatedMeshGeoms
[meshId
]= mesh
;
315 // else, must add to the array
318 meshId
= (uint
)vbHeapBlock
->AllocatedMeshGeoms
.size();
319 vbHeapBlock
->AllocatedMeshGeoms
.push_back(mesh
);
322 // info for delete in mesh
323 #if 0 // todo hulud remove / restore VBHeap
324 mesh
->_MeshVBHeapIndexStart
= indexStart
;
325 mesh
->_MeshVBHeapId
= vbHeapId
+ (meshId
<<NL3D_MBM_VBHEAP_MESH_SHIFT
);
326 mesh
->_MeshVBHeapNumVertices
= numVertices
;
327 #endif // todo hulud remove / restore VBHeap
331 #if 0 // todo hulud remove / restore VBHeap
332 uint8
*dst
= vbHeapBlock
->VBHeap
.lock(indexStart
);
333 mesh
->computeMeshVBHeap(dst
, indexStart
);
334 // unlock only what vertices have changed (ATI problem)
335 vbHeapBlock
->VBHeap
.unlock(indexStart
, indexStart
+numVertices
);
336 #endif // todo hulud remove / restore VBHeap
339 // ***************************************************************************
340 void CMeshBlockManager::freeMeshVBHeap(IMeshGeom
*mesh
)
342 nlassert(mesh
->_MeshVBHeapId
);
344 // unpack heap and mesh id.
345 uint vbHeapId
= mesh
->_MeshVBHeapId
& NL3D_MBM_VBHEAP_HEAP_MASK
;
346 uint meshId
= (mesh
->_MeshVBHeapId
& NL3D_MBM_VBHEAP_MESH_MASK
) >> NL3D_MBM_VBHEAP_MESH_SHIFT
;
348 // access to this VBHeap.
349 CVBHeapBlock
*vbHeapBlock
= _VBHeapBlocks
[vbHeapId
];
352 #if 0 // todo hulud remove / restore VBHeap
353 vbHeapBlock
->VBHeap
.free(mesh
->_MeshVBHeapIndexStart
);
354 #endif // todo hulud remove / restore VBHeap
357 nlassert(meshId
<vbHeapBlock
->AllocatedMeshGeoms
.size());
358 vbHeapBlock
->AllocatedMeshGeoms
[meshId
]= NULL
;
359 vbHeapBlock
->FreeIds
.push_back(meshId
);
362 mesh
->_MeshVBHeapId
= 0;
363 mesh
->_MeshVBHeapIndexStart
= 0;
366 // ***************************************************************************
367 void CMeshBlockManager::releaseVBHeaps()
371 // For all blocks but the 0th
372 for(j
=1; j
<_VBHeapBlocks
.size();j
++)
374 CVBHeapBlock
*hb
= _VBHeapBlocks
[j
];
376 // For all allocated mesh of this heap.
377 for(i
=0;i
<hb
->AllocatedMeshGeoms
.size();i
++)
379 IMeshGeom
*mesh
= hb
->AllocatedMeshGeoms
[i
];
380 // if the mesh exist.
383 // free his VBHeap Data.
384 freeMeshVBHeap(mesh
);
385 nlassert( hb
->AllocatedMeshGeoms
[i
] == NULL
);
389 // delete the block. NB: VBHeap auto released
393 // erase all blocks but 0th
394 _VBHeapBlocks
.resize(1);
397 contReset(_VBHeapMap
);
400 // ***************************************************************************
401 bool CMeshBlockManager::addVBHeap(IDriver
*drv
, uint vertexFormat
, uint maxVertices
)
403 return false; // todo hulud remove / restore VBHeap
405 // if find an existing vertexFormat, abort.
406 TVBHeapMap::iterator it
= _VBHeapMap
.find(vertexFormat
);
408 if( it
!=_VBHeapMap
.end() )
412 CVBHeapBlock
*hb
= new CVBHeapBlock
;
414 // allocate vertex space
415 #if 0 // todo hulud remove / restore VBHeap
416 hb
->VBHeap
.init(drv
, vertexFormat
, maxVertices
);
417 #endif // todo hulud remove / restore VBHeap
419 // add an entry to the array, and the map.
420 _VBHeapBlocks
.push_back(hb
);
421 _VBHeapMap
[vertexFormat
]= (uint
)_VBHeapBlocks
.size()-1;