root/OpenSceneGraph/trunk/include/osgDB/ImagePager @ 13144

Revision 13144, 5.1 kB (checked in by robert, 25 hours ago)

From Jannik Heller, "I've hit what I believe to be a bug (or at the very least, an unintuitive behaviour) in the osg::Geometry copy constructor. I noticed it when using osg::clone on a Geometry with vertex buffer objects, and the copy flags DEEP_COPY_ARRAYS. To be precise, I add a Geometry to an osgUtil::IncrementalCompileOperation?, then osg::clone the Geometry. I was getting reports from users of random crashes happening.

I believe the offending lines are in the osg::Geometry copy constructor:

if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS))
{

if (_useVertexBufferObjects)
{

// copying of arrays doesn't set up buffer objects so we'll need to force
// Geometry to assign these, we'll do this by switching off VBO's then renabling them.
setUseVertexBufferObjects(false);
setUseVertexBufferObjects(true);

}

}

Toggling the vertex buffer objects off then on again actually touches not only the arrays controlled by DEEP_COPY_ARRAYS, but also the PrimitiveSets? which are controlled by DEEP_COPY_PRIMITIVES. This means if the user has copyflags of only DEEP_COPY_ARRAYS, we are modifying arrays that belong to the original const Geometry& we are copying from. I believe this shouldn't be allowed to happen because we are using a const& specifier for the original Geometry.

In my case the osgUtil::IncrementalCompileOperation? was trying to compile the geometry, while in the main thread a clone operation toggled the VBO's off and on, a crash ensues.

In the attached patch, you will find a more efficient handling of VBO's in the osg::Geometry copy constructor, so that only the Arrays that were actually deep copied have their VBO assigned, and no changes are made to Arrays that already had a valid VBO assigned. In addition, the DEEP_COPY_PRIMITIVES flag is now honored so that VBO's are set up correctly should a user copy a Geometry with only that flag.
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#ifndef OSGDB_IMAGEPAGER
15#define OSGDB_IMAGEPAGER 1
16
17#include <osg/Image>
18#include <osg/NodeVisitor>
19#include <osg/observer_ptr>
20#include <osg/OperationThread>
21#include <osg/FrameStamp>
22
23#include <OpenThreads/Mutex>
24
25#include <osgDB/ReaderWriter>
26#include <osgDB/Options>
27
28namespace osgDB
29{
30
31class OSGDB_EXPORT ImagePager : public osg::NodeVisitor::ImageRequestHandler
32{
33    public:
34
35        ImagePager();
36
37        class OSGDB_EXPORT ImageThread : public osg::Referenced, public OpenThreads::Thread
38        {
39        public:
40
41            enum Mode
42            {
43                HANDLE_ALL_REQUESTS,
44                HANDLE_NON_HTTP,
45                HANDLE_ONLY_HTTP
46            };
47
48            ImageThread(ImagePager* pager, Mode mode, const std::string& name);
49
50            ImageThread(const ImageThread& dt, ImagePager* pager);
51
52            void setDone(bool done) { _done = done; }
53            bool getDone() const { return _done; }
54
55            virtual int cancel();
56
57            virtual void run();
58
59        protected:
60
61            virtual ~ImageThread();
62
63            bool            _done;
64            Mode            _mode;
65            ImagePager*     _pager;
66            std::string     _name;
67        };
68
69
70        ImageThread* getImageThread(unsigned int i) { return _imageThreads[i].get(); }
71
72        const ImageThread* getImageThread(unsigned int i) const { return _imageThreads[i].get(); }
73
74        unsigned int getNumImageThreads() const { return _imageThreads.size(); }
75
76
77        void setPreLoadTime(double preLoadTime) { _preLoadTime=preLoadTime; }
78        virtual double getPreLoadTime() const { return _preLoadTime; }
79
80        virtual osg::Image* readImageFile(const std::string& fileName);
81
82        virtual void requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp* framestamp);
83
84
85        /** Return true if there are pending updates to the scene graph that require a call to updateSceneGraph(double). */
86        virtual bool requiresUpdateSceneGraph() const;
87
88        /** Merge the changes to the scene graph. */
89        virtual void updateSceneGraph(const osg::FrameStamp &frameStamp);
90
91        int cancel();
92
93    protected:
94
95        virtual ~ImagePager();
96        // forward declare
97        struct RequestQueue;
98
99        struct SortFileRequestFunctor;
100        friend struct SortFileRequestFunctor;
101
102        struct ImageRequest : public osg::Referenced
103        {
104            ImageRequest():
105                osg::Referenced(true),
106                _timeToMergeBy(0.0),
107                _attachmentIndex(-1) {}
108
109            double                              _timeToMergeBy;
110            std::string                         _fileName;
111            osg::ref_ptr<Options> _loadOptions;
112            osg::observer_ptr<osg::Object>      _attachmentPoint;
113            int                                 _attachmentIndex;
114            osg::ref_ptr<osg::Image>            _loadedImage;
115            RequestQueue*                       _requestQueue;
116
117        };
118
119        struct RequestQueue : public osg::Referenced
120        {
121            typedef std::vector< osg::ref_ptr<ImageRequest> > RequestList;
122
123            void sort();
124
125            unsigned int size() const;
126
127            RequestList         _requestList;
128            mutable OpenThreads::Mutex  _requestMutex;
129        };
130
131
132        struct ReadQueue : public RequestQueue
133        {
134            ReadQueue(ImagePager* pager, const std::string& name);
135
136            void block() { _block->block(); }
137
138            void release() { _block->release(); }
139
140            void updateBlock()
141            {
142                _block->set((!_requestList.empty() || !_pager->_databasePagerThreadPaused));
143            }
144
145            void clear();
146
147            void add(ImageRequest* imageRequest);
148
149            void takeFirst(osg::ref_ptr<ImageRequest>& databaseRequest);
150
151            osg::ref_ptr<osg::RefBlock> _block;
152
153            ImagePager*                 _pager;
154            std::string                 _name;
155        };
156
157        OpenThreads::Mutex          _run_mutex;
158        bool                        _startThreadCalled;
159
160        bool                        _done;
161        bool                        _databasePagerThreadPaused;
162
163        osg::ref_ptr<ReadQueue>     _readQueue;
164
165        typedef std::vector< osg::ref_ptr<ImageThread> > ImageThreads;
166        ImageThreads                _imageThreads;
167
168        osg::ref_ptr<RequestQueue>  _completedQueue;
169
170        double                      _preLoadTime;
171};
172
173
174}
175
176#endif
177
Note: See TracBrowser for help on using the browser.