Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / index_buffer.cpp
blobe99b1e1e39f1acb0070f353651b413a7a6c08d0c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
17 #include "std3d.h"
19 #include "nel/3d/index_buffer.h"
20 #include "nel/3d/driver.h"
21 #include "nel/misc/stream.h"
22 #include "nel/misc/fast_mem.h"
24 using namespace NLMISC;
26 #ifdef DEBUG_NEW
27 #define new DEBUG_NEW
28 #endif
30 namespace NL3D
32 // ***************************************************************************
33 // IIBDrvInfos
34 // ***************************************************************************
36 IIBDrvInfos::~IIBDrvInfos()
38 _Driver->removeIBDrvInfoPtr(_DriverIterator);
41 // ***************************************************************************
42 // CIndexBuffer
43 // ***************************************************************************
45 CIndexBuffer::CIndexBuffer()
47 /* ***********************************************
48 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
49 * It can be loaded/called through CAsyncFileManager for instance
50 * ***********************************************/
52 _Capacity = 0;
53 _NbIndexes = 0;
54 _InternalFlags = 0;
55 _LockCounter = 0;
56 _LockedBuffer = NULL;
57 _PreferredMemory = RAMPreferred;
58 _Location = NotResident;
59 _ResidentSize = 0;
60 _KeepLocalMemory = false;
61 _Format = Indices32;
64 // ***************************************************************************
66 CIndexBuffer::CIndexBuffer(const CIndexBuffer &vb) : CRefCount()
68 /* ***********************************************
69 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
70 * It can be loaded/called through CAsyncFileManager for instance
71 * ***********************************************/
72 _Capacity = 0;
73 _NbIndexes = 0;
74 _LockCounter = 0;
75 _LockedBuffer = NULL;
76 _PreferredMemory = RAMPreferred;
77 _Location = NotResident;
78 _ResidentSize = 0;
79 _KeepLocalMemory = false;
80 operator=(vb);
83 // ***************************************************************************
84 CIndexBuffer::CIndexBuffer(const char *name)
86 /* ***********************************************
87 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
88 * It can be loaded/called through CAsyncFileManager for instance
89 * ***********************************************/
90 _Capacity = 0;
91 _NbIndexes = 0;
92 _InternalFlags = 0;
93 _LockCounter = 0;
94 _LockedBuffer = NULL;
95 _PreferredMemory = RAMPreferred;
96 _Location = NotResident;
97 _ResidentSize = 0;
98 _KeepLocalMemory = false;
99 _Name = name;
102 // ***************************************************************************
104 CIndexBuffer::~CIndexBuffer()
106 /* ***********************************************
107 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
108 * It can be loaded/called through CAsyncFileManager for instance
109 * ***********************************************/
111 // Single value
112 if (DrvInfos)
113 DrvInfos->IndexBufferPtr = NULL; // Tell the driver info to not restore memory when it will die
115 // Must kill the drv mirror of this VB.
116 DrvInfos.kill();
119 // ***************************************************************************
121 CIndexBuffer &CIndexBuffer::operator=(const CIndexBuffer &vb)
123 nlassertex (!isLocked(), ("The index buffer is locked."));
124 // Single value
125 _InternalFlags = vb._InternalFlags;
126 _NbIndexes = vb._NbIndexes;
127 _Capacity = vb._Capacity;
128 _NonResidentIndexes = vb._NonResidentIndexes;
129 _PreferredMemory = vb._PreferredMemory;
130 _KeepLocalMemory = vb._KeepLocalMemory;
131 _Format = vb._Format;
133 // Set touch flags
134 _InternalFlags |= TouchedAll;
135 _Location = NotResident;
136 _ResidentSize = 0;
138 return *this;
141 // ***************************************************************************
143 void CIndexBuffer::setPreferredMemory (TPreferredMemory preferredMemory, bool keepLocalMemory)
145 if ((_PreferredMemory != preferredMemory) || (_KeepLocalMemory != keepLocalMemory))
147 _PreferredMemory = preferredMemory;
148 _KeepLocalMemory = keepLocalMemory;
150 // Force non resident
151 restoreNonResidentMemory();
155 // ***************************************************************************
157 void CIndexBuffer::reserve(uint32 n)
159 nlassert (!isLocked());
160 if (_Capacity != n)
162 _Capacity= n;
163 _NbIndexes=std::min (_NbIndexes,_Capacity);
165 // Force non resident
166 restoreNonResidentMemory();
170 // ***************************************************************************
172 void CIndexBuffer::setNumIndexes(uint32 n)
174 if(_Capacity<n)
176 reserve(n);
178 if(_NbIndexes != n)
180 _InternalFlags |= TouchedNumIndexes;
181 _NbIndexes=n;
185 // ***************************************************************************
187 void CIndexBuffer::setFormat(TFormat format)
189 if (format == _Format) return;
190 uint numIndexes = getNumIndexes();
191 deleteAllIndexes();
192 _Format = format;
193 setNumIndexes(numIndexes);
196 // ***************************************************************************
198 void CIndexBuffer::deleteAllIndexes()
200 if (_Capacity)
202 nlassert (!isLocked());
203 // free memory.
204 contReset(_NonResidentIndexes);
205 _Capacity= 0;
206 if(_NbIndexes!=0)
208 _NbIndexes=0;
209 _InternalFlags |= TouchedNumIndexes;
212 // Force non resident
213 restoreNonResidentMemory();
215 // Delete driver info
216 nlassert (DrvInfos == NULL);
220 // ***************************************************************************
222 void CIndexBuffer::setLocation (TLocation newLocation)
224 // Upload ?
225 if (newLocation != NotResident)
227 // The driver must have setuped the driver info
228 nlassert (DrvInfos);
230 // Current size of the buffer
231 const uint size = ((_PreferredMemory==RAMVolatile)||(_PreferredMemory==AGPVolatile))?_NbIndexes:_Capacity;
233 // The buffer must not be resident
234 if (_Location != NotResident)
235 setLocation (NotResident);
237 // Copy the buffer content
238 void *dest = DrvInfos->lock (0, size, false);
239 nlassert (_NonResidentIndexes.size() / getIndexNumBytes() == _Capacity); // Internal buffer must have the good size
240 if (_Capacity != 0)
241 memcpy (dest, &(_NonResidentIndexes[0]), size*getIndexNumBytes());
242 DrvInfos->unlock(0, 0);
244 // Reset the non resident container if not a static preferred memory and not put in RAM
245 if ((_PreferredMemory != StaticPreferred) && (_Location != RAMResident) && !_KeepLocalMemory)
246 contReset(_NonResidentIndexes);
248 // Clear touched flags
249 resetTouchFlags ();
251 _Location = newLocation;
252 _ResidentSize = _Capacity;
254 else
256 // Resize the non resident buffer
257 _NonResidentIndexes.resize (_Capacity * getIndexNumBytes());
259 // If resident in RAM, backup the data in non resident memory
260 if ((_Location == RAMResident) && (_PreferredMemory != RAMVolatile) && (_PreferredMemory != AGPVolatile) && !_KeepLocalMemory)
262 // The driver must have setuped the driver info
263 nlassert (DrvInfos);
265 // Copy the old buffer data
266 const void *src = DrvInfos->lock (0, _ResidentSize, true);
267 uint size = std::min ((uint)(_Capacity*getIndexNumBytes()), (uint)(_ResidentSize*getIndexNumBytes()));
268 if (size)
269 memcpy (&(_NonResidentIndexes[0]), src, size);
270 DrvInfos->unlock(0, 0);
273 _Location = NotResident;
274 _ResidentSize = 0;
276 // Touch the buffer
277 _InternalFlags |= TouchedAll;
281 // ***************************************************************************
283 void CIndexBuffer::restoreNonResidentMemory()
285 setLocation (NotResident);
287 if (DrvInfos)
288 DrvInfos->IndexBufferPtr = NULL; // Tell the driver info to not restore memory when it will die
290 // Must kill the drv mirror of this VB.
291 DrvInfos.kill();
295 // ***************************************************************************
296 void CIndexBuffer::buildSerialVector(std::vector<uint32> &dest) const
298 dest.resize(getNumIndexes());
299 if (_Format == Indices16)
301 const uint16 *src = (const uint16 *) &_NonResidentIndexes[0];
302 // convert to 32 bits
303 for(uint k = 0; k < getNumIndexes(); ++k)
305 dest[k] = *src ++;
308 else
310 // direct copy
311 memcpy(&dest[0], &_NonResidentIndexes[0], sizeof(uint32) * getNumIndexes());
315 // ***************************************************************************
316 void CIndexBuffer::restoreFromSerialVector(const std::vector<uint32> &src)
318 // for now, just convert to wanted format
319 if (_Format == Indices16)
321 _NonResidentIndexes.resize(sizeof(uint16) * src.size());
322 uint16 *dest = (uint16 *) &_NonResidentIndexes[0];
323 for(uint k = 0; k < src.size(); ++k)
325 nlassert(src[k] <= 0xffff);
326 *dest++ = (uint16) src[k];
329 else
331 nlassert(_Format == Indices32);
332 _NonResidentIndexes.resize(sizeof(uint32) * src.size());
333 memcpy(&_NonResidentIndexes[0], &src[0], sizeof(uint32) * src.size());
337 // ***************************************************************************
338 void CIndexBuffer::serial(NLMISC::IStream &f)
340 /* ***********************************************
341 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
342 * It can be loaded/called through CAsyncFileManager for instance
343 * ***********************************************/
345 /** Version 2 : no more write only flags
346 * Version 1 : index buffer
347 * Version 0 : primitive block
350 sint ver = f.serialVersion(2);
352 // Primitive block?
353 if (ver < 1)
355 uint32 nb, capacity;
356 std::vector<uint32> indexes;
358 // Skip lines
359 f.serial(nb, capacity);
360 f.serialCont(indexes);
362 // Read tri
363 // NB : for backward compatibility, indices are always saved in 32 bit format
364 std::vector<uint32> nonResidentIndexes;
365 if (!f.isReading())
367 buildSerialVector(nonResidentIndexes);
369 f.serial(nb, capacity);
370 _NbIndexes = nb*3;
371 _Capacity = capacity*3;
372 f.serialCont(nonResidentIndexes);
374 if (f.isReading())
376 restoreFromSerialVector(nonResidentIndexes);
379 // Skip quads
380 f.serial(nb, capacity);
381 f.serialCont(indexes);
384 // Index buffer?
385 if (ver >= 1)
387 // NB : for backward compatibility, indices are always saved in 32 bit format
388 std::vector<uint32> nonResidentIndexes;
389 if (!f.isReading())
391 buildSerialVector(nonResidentIndexes);
393 f.serial(_NbIndexes, _Capacity);
394 f.serialCont(nonResidentIndexes);
395 f.serialEnum(_PreferredMemory);
396 if (f.isReading())
398 restoreFromSerialVector(nonResidentIndexes);
400 // Read the old format
401 if (ver == 1)
403 uint i;
404 bool temp;
405 for (i=0; i<PreferredCount; i++)
406 f.serial(temp);
410 // Loaded ?
411 if (f.isReading())
413 // Force non resident
414 restoreNonResidentMemory();
418 // ***************************************************************************
420 void CIndexBuffer::fillBuffer ()
422 if (DrvInfos && _KeepLocalMemory)
424 // Copy the local memory in local memory
425 nlassert ((_NbIndexes * getIndexNumBytes()) <=_NonResidentIndexes.size());
426 void *dest = DrvInfos->lock (0, _NbIndexes, false);
427 NLMISC::CFastMem::memcpy (dest, &(_NonResidentIndexes[0]), _NbIndexes*getIndexNumBytes());
428 DrvInfos->unlock(0, _NbIndexes);
432 // ***************************************************************************
434 } // namespace NL3D