]> git.tdb.fi Git - libs/gl.git/blob - source/core/bufferable.cpp
Compute correct size for SPIR-V structs if the last member is an array
[libs/gl.git] / source / core / bufferable.cpp
1 #include <stdexcept>
2 #include "buffer.h"
3 #include "bufferable.h"
4 #include "error.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace GL {
10
11 Bufferable::~Bufferable()
12 {
13         unlink_from_buffer();
14 }
15
16 void Bufferable::use_buffer(Buffer *buf, Bufferable *prev)
17 {
18         if(prev && buf!=prev->buffer)
19                 throw invalid_argument("Bufferable::use_buffer");
20
21         if(buffer)
22                 unlink_from_buffer();
23
24         buffer = buf;
25         if(buffer)
26         {
27                 prev_in_buffer = prev;
28                 if(prev_in_buffer)
29                 {
30                         next_in_buffer = prev_in_buffer->next_in_buffer;
31                         prev_in_buffer->next_in_buffer = this;
32                 }
33         }
34
35         location_dirty = true;
36         dirty = true;
37         update_offset();
38 }
39
40 void Bufferable::change_buffer(Buffer *buf)
41 {
42         for(Bufferable *b=this; b; b=b->next_in_buffer)
43         {
44                 b->buffer = buf;
45                 b->location_dirty = true;
46                 b->dirty = true;
47         }
48         for(Bufferable *b=prev_in_buffer; b; b=b->prev_in_buffer)
49         {
50                 b->buffer = buf;
51                 b->location_dirty = true;
52                 b->dirty = true;
53         }
54 }
55
56 size_t Bufferable::get_required_buffer_size() const
57 {
58         const Bufferable *last = this;
59         for(; last->next_in_buffer; last=last->next_in_buffer) ;
60         return last->offset+last->get_data_size();
61 }
62
63 void Bufferable::unlink_from_buffer()
64 {
65         if(prev_in_buffer)
66                 prev_in_buffer->next_in_buffer = next_in_buffer;
67         if(next_in_buffer)
68         {
69                 next_in_buffer->prev_in_buffer = prev_in_buffer;
70                 next_in_buffer->update_offset();
71         }
72         prev_in_buffer = 0;
73         next_in_buffer = 0;
74         buffer = 0;
75         offset = 0;
76 }
77
78 void Bufferable::update_offset()
79 {
80         size_t new_offset = 0;
81         if(prev_in_buffer)
82                 new_offset = prev_in_buffer->offset+prev_in_buffer->get_data_size();
83
84         size_t align = get_alignment();
85         new_offset += align-1;
86         new_offset -= new_offset%align;
87         if(new_offset!=offset)
88         {
89                 offset = new_offset;
90                 location_dirty = true;
91                 dirty = true;
92         }
93
94         if(next_in_buffer)
95                 next_in_buffer->update_offset();
96         else if(buffer && offset+get_data_size()>buffer->get_size())
97         {
98                 location_dirty = true;
99                 dirty = true;
100         }
101 }
102
103 void Bufferable::upload_data(char *target) const
104 {
105         if(!buffer)
106                 throw invalid_operation("Bufferable::upload_data");
107
108         size_t data_size = get_data_size();
109         if(location_dirty)
110         {
111                 buffer->require_size(offset+data_size);
112                 location_dirty = false;
113         }
114
115         if(target)
116         {
117                 const char *source = reinterpret_cast<const char *>(get_data_pointer());
118                 copy(source, source+data_size, target);
119         }
120         else
121                 buffer->sub_data(offset, data_size, get_data_pointer());
122         dirty = false;
123 }
124
125
126 Bufferable::AsyncUpdater::AsyncUpdater(const Bufferable &b):
127         bufferable(b)
128 {
129         bufferable.buffer->require_size(bufferable.get_required_buffer_size());
130         mapped_address = reinterpret_cast<char *>(bufferable.buffer->map());
131 }
132
133 Bufferable::AsyncUpdater::~AsyncUpdater()
134 {
135         bufferable.buffer->unmap();
136 }
137
138 void Bufferable::AsyncUpdater::upload_data()
139 {
140         bufferable.upload_data(mapped_address+bufferable.offset);
141         // Update all bufferables in the same buffer at once
142         for(const Bufferable *b=bufferable.prev_in_buffer; b; b=b->prev_in_buffer)
143                 if(b->dirty)
144                         b->upload_data(mapped_address+b->offset);
145         for(const Bufferable *b=bufferable.next_in_buffer; b; b=b->next_in_buffer)
146                 if(b->dirty)
147                         b->upload_data(mapped_address+b->offset);
148 }
149
150 } // namespace GL
151 } // namespace Msp