]> git.tdb.fi Git - libs/gl.git/blob - source/buffer.cpp
a502190f82058c5b67aa4b53dada321bbec95cbf
[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 "misc.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12
13 const Buffer *Buffer::bound[5] = { 0, 0, 0, 0, 0 };
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         glDeleteBuffers(1, &id);
28 }
29
30 void Buffer::require_buffer_type(BufferType type)
31 {
32         static Require _req_vbo(ARB_vertex_buffer_object);
33         if(type==PIXEL_PACK_BUFFER || type==PIXEL_UNPACK_BUFFER)
34                 static Require _req_pbo(ARB_pixel_buffer_object);
35         else if(type==UNIFORM_BUFFER)
36                 static Require _req_ubo(ARB_uniform_buffer_object);
37 }
38
39 void Buffer::set_usage(BufferUsage u)
40 {
41         usage = u;
42 }
43
44 void Buffer::data(unsigned sz, const void *d)
45 {
46         const Buffer *old = current(type);
47         bind();
48         glBufferData(type, sz, d, usage);
49         size = sz;
50         restore(old, type);
51 }
52
53 void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
54 {
55         const Buffer *old = current(type);
56         bind();
57         glBufferSubData(type, off, sz, d);
58         restore(old, type);
59 }
60
61 BufferRange *Buffer::create_range(unsigned s, unsigned o)
62 {
63         return new BufferRange(*this, s, o);
64 }
65
66 void Buffer::bind_to(BufferType t) const
67 {
68         if(t!=type)
69                 require_buffer_type(t);
70         if(set_current(t, this))
71                 glBindBuffer(t, id);
72 }
73
74 void Buffer::unbind_from(BufferType type)
75 {
76         if(set_current(type, 0))
77                 glBindBuffer(type, 0);
78 }
79
80 const Buffer *&Buffer::binding(BufferType type)
81 {
82         switch(type)
83         {
84         case ARRAY_BUFFER:         return bound[0];
85         case ELEMENT_ARRAY_BUFFER: return bound[1];
86         case PIXEL_PACK_BUFFER:    return bound[2];
87         case PIXEL_UNPACK_BUFFER:  return bound[3];
88         case UNIFORM_BUFFER:       return bound[4];
89         default: throw invalid_argument("Buffer::binding");
90         }
91 }
92
93 bool Buffer::set_current(BufferType type, const Buffer *buf)
94 {
95         const Buffer *&ptr = binding(type);
96         if(ptr==buf)
97                 return false;
98
99         ptr = buf;
100         return true;
101 }
102
103 void Buffer::restore(const Buffer *buf, BufferType type)
104 {
105         if(buf!=current(type))
106         {
107                 if(buf)
108                         buf->bind_to(type);
109                 else
110                         unbind_from(type);
111         }
112 }
113
114
115 vector<const BufferRange *> BufferRange::bound_uniform;
116
117 BufferRange::BufferRange(Buffer &b, unsigned o, unsigned s):
118         buffer(b),
119         offset(o),
120         size(s)
121 {
122         if(o>buffer.get_size() || o+s>buffer.get_size())
123                 throw out_of_range("BufferRange::BufferRange");
124 }
125
126 void BufferRange::data(const void *d)
127 {
128         buffer.sub_data(offset, size, d);
129 }
130
131 void BufferRange::bind_to(BufferType t, unsigned i)
132 {
133         if(t!=buffer.type)
134                 Buffer::require_buffer_type(t);
135         // Intentionally using bitwise | to avoid short-circuiting
136         if(Buffer::set_current(t, &buffer) | set_current(t, i, this))
137                 glBindBufferRange(t, i, buffer.id, offset, size);
138 }
139
140 void BufferRange::unbind_from(BufferType t, unsigned i)
141 {
142         if(set_current(t, i, 0))
143         {
144                 Buffer::set_current(t, 0);
145                 glBindBufferBase(t, i, 0);
146         }
147 }
148
149 const BufferRange *&BufferRange::binding(BufferType type, unsigned index)
150 {
151         if(type==UNIFORM_BUFFER)
152         {
153                 if(index>=get_n_uniform_buffer_bindings())
154                         throw out_of_range("BufferRange::binding");
155                 if(bound_uniform.size()<=index)
156                         bound_uniform.resize(index+1);
157                 return bound_uniform[index];
158         }
159         else
160                 throw invalid_argument("BufferRange::binding");
161 }
162
163 bool BufferRange::set_current(BufferType type, unsigned index, const BufferRange *buf)
164 {
165         const BufferRange *&ptr = binding(type, index);
166         if(ptr==buf)
167                 return false;
168
169         ptr = buf;
170         return true;
171 }
172
173 unsigned BufferRange::get_n_uniform_buffer_bindings()
174 {
175         static unsigned count = get_i(GL_MAX_UNIFORM_BUFFER_BINDINGS);
176         return count;
177 }
178
179 unsigned BufferRange::get_uniform_buffer_alignment()
180 {
181         static unsigned align = get_i(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
182         return align;
183 }
184
185 } // namespace GL
186 } // namespace Msp