source: OGRE/trunk/ogrenew/OgreMain/src/OgreHardwareBufferManager.cpp @ 692

Revision 692, 20.1 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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