]> git.tdb.fi Git - libs/gl.git/blob - source/bufferable.cpp
Improve performance of Bufferable::update_buffer_data
[libs/gl.git] / source / bufferable.cpp
1 #include <stdexcept>
2 #include "buffer.h"
3 #include "bufferable.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 Bufferable::Bufferable():
11         buffer(0),
12         buffer_offset(0),
13         next_in_buffer(0),
14         prev_in_buffer(0),
15         dirty(false)
16 { }
17
18 Bufferable::~Bufferable()
19 {
20         unlink_from_buffer();
21 }
22
23 void Bufferable::use_buffer(Buffer *buf, Bufferable *prev)
24 {
25         if(prev && buf!=prev->buffer)
26                 throw invalid_argument("Bufferable::use_buffer");
27
28         if(buffer)
29                 unlink_from_buffer();
30
31         buffer = buf;
32         if(buffer)
33         {
34                 prev_in_buffer = prev;
35                 if(prev_in_buffer)
36                         prev_in_buffer->next_in_buffer = this;
37         }
38
39         update_buffer_offset();
40 }
41
42 void Bufferable::unlink_from_buffer()
43 {
44         if(prev_in_buffer)
45                 prev_in_buffer->next_in_buffer = next_in_buffer;
46         if(next_in_buffer)
47         {
48                 next_in_buffer->prev_in_buffer = prev_in_buffer;
49                 next_in_buffer->update_buffer_offset();
50         }
51         prev_in_buffer = 0;
52         next_in_buffer = 0;
53 }
54
55 void Bufferable::update_buffer_offset()
56 {
57         unsigned offset = 0;
58         if(prev_in_buffer)
59                 offset = prev_in_buffer->buffer_offset+prev_in_buffer->get_data_size();
60
61         if(offset!=buffer_offset)
62         {
63                 buffer_offset = offset;
64                 dirty = true;
65                 offset_changed();
66         }
67
68         if(next_in_buffer)
69                 next_in_buffer->update_buffer_offset();
70
71         /* Do not resize the buffer here, as the offsets may change multiple times
72         before the buffer is actually used */
73 }
74
75 void Bufferable::update_buffer_data() const
76 {
77         if(buffer_offset+get_data_size()>=buffer->get_size())
78         {
79                 const Bufferable *last = this;
80                 for(; last->next_in_buffer; last=last->next_in_buffer) ;
81
82                 unsigned total_size = last->buffer_offset+last->get_data_size();
83
84                 if(total_size>buffer->get_size())
85                 {
86                         buffer->data(total_size, 0);
87                         /* Resizing the buffer invalidates its contents.  Non-dirty data may
88                         be in use, so reupload it. */
89                         for(const Bufferable *b=last; b; b=b->prev_in_buffer)
90                                 if(!b->dirty)
91                                         b->upload_data();
92                 }
93         }
94
95         upload_data();
96         dirty = false;
97 }
98
99 } // namespace GL
100 } // namespace Msp