Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreHardwareBufferManager.cpp @ 5

Last change on this file since 5 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

File size: 20.4 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreHardwareBufferManager.h"
31#include "OgreVertexIndexData.h"
32#include "OgreLogManager.h"
33
34
35namespace Ogre {
36
37    //-----------------------------------------------------------------------
38    template<> HardwareBufferManager* Singleton<HardwareBufferManager>::ms_Singleton = 0;
39    HardwareBufferManager* HardwareBufferManager::getSingletonPtr(void)
40    {
41        return ms_Singleton;
42    }
43    HardwareBufferManager& HardwareBufferManager::getSingleton(void)
44    { 
45        assert( ms_Singleton );  return ( *ms_Singleton ); 
46    }
47    // Free temporary vertex buffers every 5 minutes on 100fps
48    const size_t HardwareBufferManager::UNDER_USED_FRAME_THRESHOLD = 30000;
49    const size_t HardwareBufferManager::EXPIRED_DELAY_FRAME_THRESHOLD = 5;
50    //-----------------------------------------------------------------------
51    HardwareBufferManager::HardwareBufferManager()
52        : mUnderUsedFrameCount(0)
53    {
54    }
55    //-----------------------------------------------------------------------
56    HardwareBufferManager::~HardwareBufferManager()
57    {
58        // Clear vertex/index buffer list first, avoid destroyed notify do
59        // unnecessary work, and we'll destroy everything here.
60                mVertexBuffers.clear();
61                mIndexBuffers.clear();
62
63        // Destroy everything
64        destroyAllDeclarations();
65        destroyAllBindings();
66        // No need to destroy main buffers - they will be destroyed by removal of bindings
67
68        // No need to destroy temp buffers - they will be destroyed automatically.
69    }
70    //-----------------------------------------------------------------------
71    VertexDeclaration* HardwareBufferManager::createVertexDeclaration(void)
72    {
73        VertexDeclaration* decl = createVertexDeclarationImpl();
74                OGRE_LOCK_MUTEX(mVertexDeclarationsMutex)
75        mVertexDeclarations.insert(decl);
76        return decl;
77    }
78    //-----------------------------------------------------------------------
79    void HardwareBufferManager::destroyVertexDeclaration(VertexDeclaration* decl)
80    {
81                OGRE_LOCK_MUTEX(mVertexDeclarationsMutex)
82        mVertexDeclarations.erase(decl);
83        destroyVertexDeclarationImpl(decl);
84    }
85    //-----------------------------------------------------------------------
86        VertexBufferBinding* HardwareBufferManager::createVertexBufferBinding(void)
87        {
88                VertexBufferBinding* ret = createVertexBufferBindingImpl();
89                OGRE_LOCK_MUTEX(mVertexBufferBindingsMutex)
90                mVertexBufferBindings.insert(ret);
91                return ret;
92        }
93    //-----------------------------------------------------------------------
94        void HardwareBufferManager::destroyVertexBufferBinding(VertexBufferBinding* binding)
95        {
96                OGRE_LOCK_MUTEX(mVertexBufferBindingsMutex)
97                mVertexBufferBindings.erase(binding);
98                destroyVertexBufferBindingImpl(binding);
99        }
100    //-----------------------------------------------------------------------
101    VertexDeclaration* HardwareBufferManager::createVertexDeclarationImpl(void)
102    {
103        return new VertexDeclaration();
104    }
105    //-----------------------------------------------------------------------
106    void HardwareBufferManager::destroyVertexDeclarationImpl(VertexDeclaration* decl)
107    {
108        delete decl;
109    }
110    //-----------------------------------------------------------------------
111        VertexBufferBinding* HardwareBufferManager::createVertexBufferBindingImpl(void)
112        {
113                return new VertexBufferBinding();
114        }
115    //-----------------------------------------------------------------------
116        void HardwareBufferManager::destroyVertexBufferBindingImpl(VertexBufferBinding* binding)
117        {
118                delete binding;
119        }
120    //-----------------------------------------------------------------------
121    void HardwareBufferManager::destroyAllDeclarations(void)
122    {
123                OGRE_LOCK_MUTEX(mVertexDeclarationsMutex)
124        VertexDeclarationList::iterator decl;
125        for (decl = mVertexDeclarations.begin(); decl != mVertexDeclarations.end(); ++decl)
126        {
127            destroyVertexDeclarationImpl(*decl);
128        }
129        mVertexDeclarations.clear();
130    }
131    //-----------------------------------------------------------------------
132    void HardwareBufferManager::destroyAllBindings(void)
133    {
134                OGRE_LOCK_MUTEX(mVertexBufferBindingsMutex)
135        VertexBufferBindingList::iterator bind;
136        for (bind = mVertexBufferBindings.begin(); bind != mVertexBufferBindings.end(); ++bind)
137        {
138            destroyVertexBufferBindingImpl(*bind);
139        }
140        mVertexBufferBindings.clear();
141    }
142        //-----------------------------------------------------------------------
143    void HardwareBufferManager::registerVertexBufferSourceAndCopy(
144                        const HardwareVertexBufferSharedPtr& sourceBuffer,
145                        const HardwareVertexBufferSharedPtr& copy)
146        {
147                OGRE_LOCK_MUTEX(mTempBuffersMutex)
148                // Add copy to free temporary vertex buffers
149        mFreeTempVertexBufferMap.insert(
150            FreeTemporaryVertexBufferMap::value_type(sourceBuffer.get(), copy));
151        }
152        //-----------------------------------------------------------------------
153    HardwareVertexBufferSharedPtr
154    HardwareBufferManager::allocateVertexBufferCopy(
155        const HardwareVertexBufferSharedPtr& sourceBuffer, 
156        BufferLicenseType licenseType, HardwareBufferLicensee* licensee,
157        bool copyData)
158    {
159                OGRE_LOCK_MUTEX(mTempBuffersMutex)
160        HardwareVertexBufferSharedPtr vbuf;
161
162        // Locate existing buffer copy in temporary vertex buffers
163        FreeTemporaryVertexBufferMap::iterator i = 
164            mFreeTempVertexBufferMap.find(sourceBuffer.get());
165        if (i == mFreeTempVertexBufferMap.end())
166        {
167            // copy buffer, use shadow buffer and make dynamic
168            vbuf = makeBufferCopy(
169                sourceBuffer, 
170                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, 
171                true);
172        }
173        else
174        {
175            // Allocate existing copy
176            vbuf = i->second;
177            mFreeTempVertexBufferMap.erase(i);
178        }
179
180        // Copy data?
181        if (copyData)
182        {
183            vbuf->copyData(*(sourceBuffer.get()), 0, 0, sourceBuffer->getSizeInBytes(), true);
184        }
185
186        // Insert copy into licensee list
187        mTempVertexBufferLicenses.insert(
188            TemporaryVertexBufferLicenseMap::value_type(
189                vbuf.get(),
190                VertexBufferLicense(sourceBuffer.get(), licenseType, EXPIRED_DELAY_FRAME_THRESHOLD, vbuf, licensee)));
191
192        return vbuf;
193    }
194    //-----------------------------------------------------------------------
195    void HardwareBufferManager::releaseVertexBufferCopy(
196        const HardwareVertexBufferSharedPtr& bufferCopy)
197    {
198                OGRE_LOCK_MUTEX(mTempBuffersMutex)
199
200                TemporaryVertexBufferLicenseMap::iterator i =
201            mTempVertexBufferLicenses.find(bufferCopy.get());
202        if (i != mTempVertexBufferLicenses.end())
203        {
204            const VertexBufferLicense& vbl = i->second;
205
206            vbl.licensee->licenseExpired(vbl.buffer.get());
207
208            mFreeTempVertexBufferMap.insert(
209                FreeTemporaryVertexBufferMap::value_type(vbl.originalBufferPtr, vbl.buffer));
210            mTempVertexBufferLicenses.erase(i);
211        }
212    }
213    //-----------------------------------------------------------------------
214    void HardwareBufferManager::touchVertexBufferCopy(
215            const HardwareVertexBufferSharedPtr& bufferCopy)
216    {
217                OGRE_LOCK_MUTEX(mTempBuffersMutex)
218        TemporaryVertexBufferLicenseMap::iterator i =
219            mTempVertexBufferLicenses.find(bufferCopy.get());
220        if (i != mTempVertexBufferLicenses.end())
221        {
222            VertexBufferLicense& vbl = i->second;
223            assert(vbl.licenseType == BLT_AUTOMATIC_RELEASE);
224
225            vbl.expiredDelay = EXPIRED_DELAY_FRAME_THRESHOLD;
226        }
227    }
228    //-----------------------------------------------------------------------
229    void HardwareBufferManager::_freeUnusedBufferCopies(void)
230    {
231                OGRE_LOCK_MUTEX(mTempBuffersMutex)
232        size_t numFreed = 0;
233
234        // Free unused temporary buffers
235        FreeTemporaryVertexBufferMap::iterator i;
236        i = mFreeTempVertexBufferMap.begin();
237        while (i != mFreeTempVertexBufferMap.end())
238        {
239            FreeTemporaryVertexBufferMap::iterator icur = i++;
240            // Free the temporary buffer that referenced by ourself only.
241            // TODO: Some temporary buffers are bound to vertex buffer bindings
242            // but not checked out, need to sort out method to unbind them.
243            if (icur->second.useCount() <= 1)
244            {
245                ++numFreed;
246                mFreeTempVertexBufferMap.erase(icur);
247            }
248        }
249
250        StringUtil::StrStreamType str;
251        if (numFreed)
252        {
253            str << "HardwareBufferManager: Freed " << numFreed << " unused temporary vertex buffers.";
254        }
255        else
256        {
257            str << "HardwareBufferManager: No unused temporary vertex buffers found.";
258        }
259        LogManager::getSingleton().logMessage(str.str(), LML_TRIVIAL);
260    }
261    //-----------------------------------------------------------------------
262    void HardwareBufferManager::_releaseBufferCopies(bool forceFreeUnused)
263    {
264                OGRE_LOCK_MUTEX(mTempBuffersMutex)
265        size_t numUnused = mFreeTempVertexBufferMap.size();
266        size_t numUsed = mTempVertexBufferLicenses.size();
267
268        // Erase the copies which are automatic licensed out
269        TemporaryVertexBufferLicenseMap::iterator i;
270        i = mTempVertexBufferLicenses.begin(); 
271        while (i != mTempVertexBufferLicenses.end()) 
272        {
273            TemporaryVertexBufferLicenseMap::iterator icur = i++;
274            VertexBufferLicense& vbl = icur->second;
275            if (vbl.licenseType == BLT_AUTOMATIC_RELEASE &&
276                (forceFreeUnused || --vbl.expiredDelay <= 0))
277            {
278                                vbl.licensee->licenseExpired(vbl.buffer.get());
279
280                mFreeTempVertexBufferMap.insert(
281                    FreeTemporaryVertexBufferMap::value_type(vbl.originalBufferPtr, vbl.buffer));
282                mTempVertexBufferLicenses.erase(icur);
283            }
284        }
285
286        // Check whether or not free unused temporary vertex buffers.
287        if (forceFreeUnused)
288        {
289            _freeUnusedBufferCopies();
290            mUnderUsedFrameCount = 0;
291        }
292        else
293        {
294            if (numUsed < numUnused)
295            {
296                // Free temporary vertex buffers if too many unused for a long time.
297                // Do overall temporary vertex buffers instead of per source buffer
298                // to avoid overhead.
299                ++mUnderUsedFrameCount;
300                if (mUnderUsedFrameCount >= UNDER_USED_FRAME_THRESHOLD)
301                {
302                    _freeUnusedBufferCopies();
303                    mUnderUsedFrameCount = 0;
304                }
305            }
306            else
307            {
308                mUnderUsedFrameCount = 0;
309            }
310        }
311    }
312    //-----------------------------------------------------------------------
313    void HardwareBufferManager::_forceReleaseBufferCopies(
314        const HardwareVertexBufferSharedPtr& sourceBuffer)
315    {
316        _forceReleaseBufferCopies(sourceBuffer.get());
317    }
318    //-----------------------------------------------------------------------
319    void HardwareBufferManager::_forceReleaseBufferCopies(
320        HardwareVertexBuffer* sourceBuffer)
321    {
322                OGRE_LOCK_MUTEX(mTempBuffersMutex)
323        // Erase the copies which are licensed out
324        TemporaryVertexBufferLicenseMap::iterator i;
325        i = mTempVertexBufferLicenses.begin();
326        while (i != mTempVertexBufferLicenses.end()) 
327        {
328            TemporaryVertexBufferLicenseMap::iterator icur = i++;
329            const VertexBufferLicense& vbl = icur->second;
330            if (vbl.originalBufferPtr == sourceBuffer)
331            {
332                // Just tell the owner that this is being released
333                vbl.licensee->licenseExpired(vbl.buffer.get());
334
335                mTempVertexBufferLicenses.erase(icur);
336            }
337        }
338
339        // Erase the free copies
340        //
341        // Why we need this unusual code? It's for resolve reenter problem.
342        //
343        // Using mFreeTempVertexBufferMap.erase(sourceBuffer) directly will
344        // cause reenter into here because vertex buffer destroyed notify.
345        // In most time there are no problem. But when sourceBuffer is the
346        // last item of the mFreeTempVertexBufferMap, some STL multimap
347        // implementation (VC and STLport) will call to clear(), which will
348        // causing intermediate state of mFreeTempVertexBufferMap, in that
349        // time destroyed notify back to here cause illegal accessing in
350        // the end.
351        //
352        // For safely reason, use following code to resolve reenter problem.
353        //
354        typedef FreeTemporaryVertexBufferMap::iterator _Iter;
355        std::pair<_Iter, _Iter> range = mFreeTempVertexBufferMap.equal_range(sourceBuffer);
356        if (range.first != range.second)
357        {
358            std::list<HardwareVertexBufferSharedPtr> holdForDelayDestroy;
359            for (_Iter it = range.first; it != range.second; ++it)
360            {
361                if (it->second.useCount() <= 1)
362                {
363                    holdForDelayDestroy.push_back(it->second);
364                }
365            }
366
367            mFreeTempVertexBufferMap.erase(range.first, range.second);
368
369            // holdForDelayDestroy will destroy auto.
370        }
371    }
372        //-----------------------------------------------------------------------
373        void HardwareBufferManager::_notifyVertexBufferDestroyed(HardwareVertexBuffer* buf)
374        {
375                OGRE_LOCK_MUTEX(mVertexBuffersMutex)
376
377                VertexBufferList::iterator i = mVertexBuffers.find(buf);
378                if (i != mVertexBuffers.end())
379                {
380            // release vertex buffer copies
381                        mVertexBuffers.erase(i);
382            _forceReleaseBufferCopies(buf);
383                }
384        }
385        //-----------------------------------------------------------------------
386        void HardwareBufferManager::_notifyIndexBufferDestroyed(HardwareIndexBuffer* buf)
387        {
388                OGRE_LOCK_MUTEX(mIndexBuffersMutex)
389
390                IndexBufferList::iterator i = mIndexBuffers.find(buf);
391                if (i != mIndexBuffers.end())
392                {
393                        mIndexBuffers.erase(i);
394                }
395        }
396    //-----------------------------------------------------------------------
397    HardwareVertexBufferSharedPtr
398    HardwareBufferManager::makeBufferCopy(
399        const HardwareVertexBufferSharedPtr& source,
400        HardwareBuffer::Usage usage, bool useShadowBuffer)
401    {
402        return this->createVertexBuffer(
403            source->getVertexSize(), 
404            source->getNumVertices(),
405            usage, useShadowBuffer);
406    }
407    //-----------------------------------------------------------------------------
408    //-----------------------------------------------------------------------------
409    //-----------------------------------------------------------------------------
410    TempBlendedBufferInfo::~TempBlendedBufferInfo(void)
411    {
412        // check that temp buffers have been released
413        HardwareBufferManager &mgr = HardwareBufferManager::getSingleton();
414        if (!destPositionBuffer.isNull())
415            mgr.releaseVertexBufferCopy(destPositionBuffer);
416        if (!destNormalBuffer.isNull())
417            mgr.releaseVertexBufferCopy(destNormalBuffer);
418
419    }
420    //-----------------------------------------------------------------------------
421    void TempBlendedBufferInfo::extractFrom(const VertexData* sourceData)
422    {
423        // Release old buffer copies first
424        HardwareBufferManager &mgr = HardwareBufferManager::getSingleton();
425        if (!destPositionBuffer.isNull())
426        {
427            mgr.releaseVertexBufferCopy(destPositionBuffer);
428            assert(destPositionBuffer.isNull());
429        }
430        if (!destNormalBuffer.isNull())
431        {
432            mgr.releaseVertexBufferCopy(destNormalBuffer);
433            assert(destNormalBuffer.isNull());
434        }
435
436        VertexDeclaration* decl = sourceData->vertexDeclaration;
437        VertexBufferBinding* bind = sourceData->vertexBufferBinding;
438        const VertexElement *posElem = decl->findElementBySemantic(VES_POSITION);
439        const VertexElement *normElem = decl->findElementBySemantic(VES_NORMAL);
440
441        assert(posElem && "Positions are required");
442
443        posBindIndex = posElem->getSource();
444        srcPositionBuffer = bind->getBuffer(posBindIndex);
445
446        if (!normElem)
447        {
448            posNormalShareBuffer = false;
449            srcNormalBuffer.setNull();
450        }
451        else
452        {
453            normBindIndex = normElem->getSource();
454            if (normBindIndex == posBindIndex)
455            {
456                posNormalShareBuffer = true;
457                srcNormalBuffer.setNull();
458            }
459            else
460            {
461                posNormalShareBuffer = false;
462                srcNormalBuffer = bind->getBuffer(normBindIndex);
463            }
464        }
465    }
466    //-----------------------------------------------------------------------------
467    void TempBlendedBufferInfo::checkoutTempCopies(bool positions, bool normals)
468    {
469        bindPositions = positions;
470        bindNormals = normals;
471
472        HardwareBufferManager &mgr = HardwareBufferManager::getSingleton();
473
474        if (positions && destPositionBuffer.isNull())
475        {
476            destPositionBuffer = mgr.allocateVertexBufferCopy(srcPositionBuffer, 
477                HardwareBufferManager::BLT_AUTOMATIC_RELEASE, this);
478        }
479        if (normals && !posNormalShareBuffer && !srcNormalBuffer.isNull() && destNormalBuffer.isNull())
480        {
481            destNormalBuffer = mgr.allocateVertexBufferCopy(srcNormalBuffer, 
482                HardwareBufferManager::BLT_AUTOMATIC_RELEASE, this);
483        }
484    }
485        //-----------------------------------------------------------------------------
486        bool TempBlendedBufferInfo::buffersCheckedOut(bool positions, bool normals) const
487        {
488        HardwareBufferManager &mgr = HardwareBufferManager::getSingleton();
489
490        if (positions || (normals && posNormalShareBuffer))
491        {
492            if (destPositionBuffer.isNull())
493                return false;
494
495            mgr.touchVertexBufferCopy(destPositionBuffer);
496        }
497
498        if (normals && !posNormalShareBuffer)
499        {
500            if (destNormalBuffer.isNull())
501                return false;
502
503            mgr.touchVertexBufferCopy(destNormalBuffer);
504        }
505
506                return true;
507        }
508    //-----------------------------------------------------------------------------
509    void TempBlendedBufferInfo::bindTempCopies(VertexData* targetData, bool suppressHardwareUpload)
510    {
511        this->destPositionBuffer->suppressHardwareUpdate(suppressHardwareUpload);
512        targetData->vertexBufferBinding->setBinding(
513            this->posBindIndex, this->destPositionBuffer);
514        if (bindNormals && !posNormalShareBuffer && !destNormalBuffer.isNull())
515        {
516            this->destNormalBuffer->suppressHardwareUpdate(suppressHardwareUpload);
517            targetData->vertexBufferBinding->setBinding(
518                this->normBindIndex, this->destNormalBuffer);
519        }
520    }
521    //-----------------------------------------------------------------------------
522    void TempBlendedBufferInfo::licenseExpired(HardwareBuffer* buffer)
523    {
524        assert(buffer == destPositionBuffer.get()
525            || buffer == destNormalBuffer.get());
526
527        if (buffer == destPositionBuffer.get())
528            destPositionBuffer.setNull();
529        if (buffer == destNormalBuffer.get())
530            destNormalBuffer.setNull();
531
532    }
533
534}
Note: See TracBrowser for help on using the repository browser.