]> git.tdb.fi Git - libs/gl.git/blob - source/core/bufferable.cpp
Create specialized versions of SPIR-V modules with default spec values
[libs/gl.git] / source / core / bufferable.cpp
1 #include <stdexcept>
2 #include "bufferable.h"
3 #include "error.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9
10 Bufferable::Bufferable(Bufferable &&other):
11         buffer(other.buffer),
12         offset(other.offset),
13         next_in_buffer(other.next_in_buffer),
14         prev_in_buffer(other.prev_in_buffer),
15         location_dirty(other.location_dirty),
16         dirty(other.dirty)
17 {
18         other.buffer = 0;
19         other.next_in_buffer = 0;
20         other.prev_in_buffer = 0;
21         if(next_in_buffer)
22                 next_in_buffer->prev_in_buffer = this;
23         if(prev_in_buffer)
24                 prev_in_buffer->next_in_buffer = this;
25 }
26
27 Bufferable::~Bufferable()
28 {
29         unlink_from_buffer();
30 }
31
32 void Bufferable::use_buffer(Buffer *buf, Bufferable *prev)
33 {
34         if(prev && buf!=prev->buffer)
35                 throw invalid_argument("Bufferable::use_buffer");
36
37         if(buffer)
38                 unlink_from_buffer();
39
40         buffer = buf;
41         if(buffer)
42         {
43                 prev_in_buffer = prev;
44                 if(prev_in_buffer)
45                 {
46                         next_in_buffer = prev_in_buffer->next_in_buffer;
47                         prev_in_buffer->next_in_buffer = this;
48                 }
49         }
50
51         location_dirty = true;
52         mark_dirty();
53         update_offset();
54 }
55
56 void Bufferable::change_buffer(Buffer *buf)
57 {
58         for(Bufferable *b=this; b; b=b->next_in_buffer)
59         {
60                 b->buffer = buf;
61                 b->location_dirty = true;
62                 b->mark_dirty();
63         }
64         for(Bufferable *b=prev_in_buffer; b; b=b->prev_in_buffer)
65         {
66                 b->buffer = buf;
67                 b->location_dirty = true;
68                 b->mark_dirty();
69         }
70 }
71
72 size_t Bufferable::get_required_buffer_size(bool align) const
73 {
74         const Bufferable *last = this;
75         for(; last->next_in_buffer; last=last->next_in_buffer) ;
76         size_t size = last->offset+last->get_data_size();
77         if(align)
78         {
79                 const Bufferable *first = this;
80                 for(; first->prev_in_buffer; first=first->prev_in_buffer) ;
81                 size_t alignment = first->get_alignment();
82                 size += alignment-1;
83                 size -= size%alignment;
84         }
85         return size;
86 }
87
88 void Bufferable::unlink_from_buffer()
89 {
90         if(prev_in_buffer)
91                 prev_in_buffer->next_in_buffer = next_in_buffer;
92         if(next_in_buffer)
93         {
94                 next_in_buffer->prev_in_buffer = prev_in_buffer;
95                 next_in_buffer->update_offset();
96         }
97         prev_in_buffer = 0;
98         next_in_buffer = 0;
99         buffer = 0;
100         offset = 0;
101 }
102
103 void Bufferable::update_offset()
104 {
105         size_t new_offset = 0;
106         if(prev_in_buffer)
107                 new_offset = prev_in_buffer->offset+prev_in_buffer->get_data_size();
108
109         size_t align = get_alignment();
110         new_offset += align-1;
111         new_offset -= new_offset%align;
112         if(new_offset!=offset)
113         {
114                 offset = new_offset;
115                 location_dirty = true;
116                 mark_dirty();
117         }
118
119         if(next_in_buffer)
120                 next_in_buffer->update_offset();
121         else if(buffer && offset+get_data_size()>buffer->get_size())
122         {
123                 location_dirty = true;
124                 mark_dirty();
125         }
126 }
127
128 void Bufferable::mark_dirty()
129 {
130         dirty = 0xFF;
131 }
132
133 void Bufferable::upload_data(unsigned frame, char *target) const
134 {
135         if(!buffer)
136                 throw invalid_operation("Bufferable::upload_data");
137
138         unsigned multi_buf = buffer->get_multiplicity();
139         frame %= multi_buf;
140         uint8_t mask = 1<<frame;
141         if(!(dirty&mask))
142                 return;
143
144         size_t data_size = get_data_size();
145         if(location_dirty)
146         {
147                 buffer->require_size(offset+data_size);
148                 location_dirty = false;
149         }
150
151         if(target)
152         {
153                 const char *source = reinterpret_cast<const char *>(get_data_pointer());
154                 copy(source, source+data_size, target);
155         }
156         else
157                 buffer->sub_data(frame*buffer->get_size()+offset, data_size, get_data_pointer());
158         dirty &= ~mask;
159         if(!(dirty&((1<<multi_buf)-1)))
160                 dirty = 0;
161 }
162
163 Bufferable::AsyncUpdater *Bufferable::create_async_updater() const
164 {
165         if(!buffer || buffer->get_multiplicity()>1)
166                 throw invalid_operation("Bufferable::create_async_updater");
167         return new AsyncUpdater(*this);
168 }
169
170
171 Bufferable::AsyncUpdater::AsyncUpdater(const Bufferable &b):
172         bufferable(b),
173         transfer(b.buffer->sub_data_async(0, bufferable.get_required_buffer_size()))
174 { }
175
176 void Bufferable::AsyncUpdater::upload_data()
177 {
178         char *mapped_address = static_cast<char *>(transfer.get_address());
179         bufferable.upload_data(0, mapped_address+bufferable.offset);
180         // Update all bufferables in the same buffer at once
181         for(const Bufferable *b=bufferable.prev_in_buffer; b; b=b->prev_in_buffer)
182                 if(b->dirty)
183                         b->upload_data(0, mapped_address+b->offset);
184         for(const Bufferable *b=bufferable.next_in_buffer; b; b=b->next_in_buffer)
185                 if(b->dirty)
186                         b->upload_data(0, mapped_address+b->offset);
187 }
188
189 } // namespace GL
190 } // namespace Msp