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