]> git.tdb.fi Git - libs/gl.git/blob - source/buffer.cpp
Don't consider the current buffer in deciding whether to bind BufferRange
[libs/gl.git] / source / buffer.cpp
1 #include <stdexcept>
2 #include <msp/gl/extensions/arb_pixel_buffer_object.h>
3 #include <msp/gl/extensions/arb_uniform_buffer_object.h>
4 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
5 #include "buffer.h"
6 #include "error.h"
7 #include "mesh.h"
8 #include "misc.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 const Buffer *Buffer::bound[5] = { 0, 0, 0, 0, 0 };
16 BufferType buffer_types[] = { ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, PIXEL_PACK_BUFFER, PIXEL_UNPACK_BUFFER, UNIFORM_BUFFER };
17
18 Buffer::Buffer(BufferType t):
19         type(t),
20         usage(STATIC_DRAW),
21         size(0)
22 {
23         require_buffer_type(type);
24
25         glGenBuffers(1, &id);
26 }
27
28 Buffer::~Buffer()
29 {
30         for(unsigned i=0; i<5; ++i)
31                 if(bound[i]==this)
32                         unbind_from(buffer_types[i]);
33         glDeleteBuffers(1, &id);
34 }
35
36 void Buffer::require_buffer_type(BufferType type)
37 {
38         static Require _req_vbo(ARB_vertex_buffer_object);
39         if(type==PIXEL_PACK_BUFFER || type==PIXEL_UNPACK_BUFFER)
40                 static Require _req_pbo(ARB_pixel_buffer_object);
41         else if(type==UNIFORM_BUFFER)
42                 static Require _req_ubo(ARB_uniform_buffer_object);
43 }
44
45 void Buffer::set_usage(BufferUsage u)
46 {
47         usage = u;
48 }
49
50 void Buffer::data(unsigned sz, const void *d)
51 {
52         BindRestore _bind(this, type);
53         glBufferData(type, sz, d, usage);
54         size = sz;
55 }
56
57 void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
58 {
59         BindRestore _bind(this, type);
60         glBufferSubData(type, off, sz, d);
61 }
62
63 BufferRange *Buffer::create_range(unsigned s, unsigned o)
64 {
65         return new BufferRange(*this, s, o);
66 }
67
68 void *Buffer::map(BufferAccess access)
69 {
70         BindRestore _bind(this, type);
71         return glMapBuffer(type, access);
72 }
73
74 bool Buffer::unmap()
75 {
76         BindRestore _bind(this, type);
77         return glUnmapBuffer(type);
78 }
79
80 void Buffer::bind_to(BufferType t) const
81 {
82         if(t!=type)
83                 require_buffer_type(t);
84         if(t==ELEMENT_ARRAY_BUFFER)
85                 if(const Mesh *m = Mesh::current())
86                 {
87                         // Don't change the binding in a mesh's vertex array object
88                         if(this==m->get_index_buffer())
89                                 return;
90                         throw invalid_operation("Buffer::bind_to(ELEMENT_ARRAY_BUFFER)");
91                 }
92         if(set_current(t, this))
93                 glBindBuffer(t, id);
94 }
95
96 const Buffer *Buffer::current(BufferType t)
97 {
98         if(t==ELEMENT_ARRAY_BUFFER)
99                 if(const Mesh *m = Mesh::current())
100                         return m->get_index_buffer();
101         return binding(t);
102 }
103
104 void Buffer::unbind_from(BufferType type)
105 {
106         if(type==ELEMENT_ARRAY_BUFFER && Mesh::current())
107                 throw invalid_operation("Buffer::unbind_from(ELEMENT_ARRAY_BUFFER)");
108         if(set_current(type, 0))
109                 glBindBuffer(type, 0);
110 }
111
112 const Buffer *&Buffer::binding(BufferType type)
113 {
114         switch(type)
115         {
116         case ARRAY_BUFFER:         return bound[0];
117         case ELEMENT_ARRAY_BUFFER: return bound[1];
118         case PIXEL_PACK_BUFFER:    return bound[2];
119         case PIXEL_UNPACK_BUFFER:  return bound[3];
120         case UNIFORM_BUFFER:       return bound[4];
121         default: throw invalid_argument("Buffer::binding");
122         }
123 }
124
125 bool Buffer::set_current(BufferType type, const Buffer *buf)
126 {
127         const Buffer *&ptr = binding(type);
128         if(ptr==buf)
129                 return false;
130
131         ptr = buf;
132         return true;
133 }
134
135
136 vector<const BufferRange *> BufferRange::bound_uniform;
137
138 BufferRange::BufferRange(Buffer &b, unsigned o, unsigned s):
139         buffer(b),
140         offset(o),
141         size(s)
142 {
143         if(o>buffer.get_size() || o+s>buffer.get_size())
144                 throw out_of_range("BufferRange::BufferRange");
145 }
146
147 BufferRange::~BufferRange()
148 {
149         for(unsigned i=0; i<bound_uniform.size(); ++i)
150                 if(bound_uniform[i]==this)
151                         unbind_from(UNIFORM_BUFFER, i);
152 }
153
154 void BufferRange::data(const void *d)
155 {
156         buffer.sub_data(offset, size, d);
157 }
158
159 void BufferRange::bind_to(BufferType t, unsigned i)
160 {
161         if(t!=buffer.type)
162                 Buffer::require_buffer_type(t);
163         if(set_current(t, i, this))
164         {
165                 // The buffer gets bound as a side effect
166                 Buffer::set_current(t, &buffer);
167                 glBindBufferRange(t, i, buffer.id, offset, size);
168         }
169 }
170
171 void BufferRange::unbind_from(BufferType t, unsigned i)
172 {
173         if(set_current(t, i, 0))
174         {
175                 Buffer::set_current(t, 0);
176                 glBindBufferBase(t, i, 0);
177         }
178 }
179
180 const BufferRange *&BufferRange::binding(BufferType type, unsigned index)
181 {
182         if(type==UNIFORM_BUFFER)
183         {
184                 if(index>=get_n_uniform_buffer_bindings())
185                         throw out_of_range("BufferRange::binding");
186                 if(bound_uniform.size()<=index)
187                         bound_uniform.resize(index+1);
188                 return bound_uniform[index];
189         }
190         else
191                 throw invalid_argument("BufferRange::binding");
192 }
193
194 bool BufferRange::set_current(BufferType type, unsigned index, const BufferRange *buf)
195 {
196         const BufferRange *&ptr = binding(type, index);
197         if(ptr==buf)
198                 return false;
199
200         ptr = buf;
201         return true;
202 }
203
204 unsigned BufferRange::get_n_uniform_buffer_bindings()
205 {
206         static unsigned count = get_i(GL_MAX_UNIFORM_BUFFER_BINDINGS);
207         return count;
208 }
209
210 unsigned BufferRange::get_uniform_buffer_alignment()
211 {
212         static unsigned align = get_i(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
213         return align;
214 }
215
216 } // namespace GL
217 } // namespace Msp