]> git.tdb.fi Git - libs/gl.git/blob - source/core/buffer.cpp
Use a scratch binding to modify textures and buffers
[libs/gl.git] / source / core / buffer.cpp
1 #include <stdexcept>
2 #include <msp/gl/extensions/arb_buffer_storage.h>
3 #include <msp/gl/extensions/arb_direct_state_access.h>
4 #include <msp/gl/extensions/arb_map_buffer_range.h>
5 #include <msp/gl/extensions/khr_debug.h>
6 #include <msp/strings/format.h>
7 #include "buffer.h"
8 #include "deviceinfo.h"
9 #include "error.h"
10 #include "misc.h"
11 #include "vertexsetup.h"
12
13 using namespace std;
14
15 namespace Msp {
16 namespace GL {
17
18 Buffer *Buffer::scratch_binding = 0;
19
20 Buffer::Buffer():
21         size(0),
22         allocated(false)
23 {
24         static Require _req(ARB_vertex_buffer_object);
25
26         if(ARB_direct_state_access)
27                 glCreateBuffers(1, &id);
28         else
29                 glGenBuffers(1, &id);
30 }
31
32 Buffer::~Buffer()
33 {
34         if(this==scratch_binding)
35                 unbind_scratch();
36         glDeleteBuffers(1, &id);
37 }
38
39 void Buffer::storage(unsigned sz)
40 {
41         if(size>0)
42         {
43                 if(sz!=size)
44                         throw incompatible_data("Buffer::storage");
45                 return;
46         }
47         if(sz==0)
48                 throw invalid_argument("Buffer::storage");
49
50         size = sz;
51 }
52
53 void Buffer::allocate()
54 {
55         if(size==0)
56                 throw invalid_operation("Buffer::allocate");
57         if(allocated)
58                 return;
59
60         if(ARB_buffer_storage)
61         {
62                 static const int flags = GL_MAP_READ_BIT|GL_MAP_WRITE_BIT|GL_DYNAMIC_STORAGE_BIT;
63                 if(ARB_direct_state_access)
64                         glNamedBufferStorage(id, size, 0, flags);
65                 else
66                 {
67                         bind_scratch();
68                         glBufferStorage(GL_ARRAY_BUFFER, size, 0, flags);
69                 }
70
71                 allocated = true;
72         }
73         else
74                 data(0);
75 }
76
77 void Buffer::set_usage(BufferUsage)
78 {
79 }
80
81 void Buffer::data(const void *d)
82 {
83         if(size==0)
84                 throw invalid_operation("Buffer::data");
85
86         if(ARB_buffer_storage)
87                 return sub_data(0, size, d);
88
89         if(ARB_direct_state_access)
90                 glNamedBufferData(id, size, d, STATIC_DRAW);
91         else
92         {
93                 bind_scratch();
94                 glBufferData(GL_ARRAY_BUFFER, size, d, STATIC_DRAW);
95         }
96
97         allocated = true;
98 }
99
100 void Buffer::data(unsigned sz, const void *d)
101 {
102         if(size==0)
103                 storage(sz);
104         else if(sz!=size)
105                 throw incompatible_data("Buffer::data");
106
107         data(d);
108 }
109
110 void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
111 {
112         if(size==0)
113                 throw invalid_operation("Buffer::sub_data");
114
115         allocate();
116
117         if(ARB_direct_state_access)
118                 glNamedBufferSubData(id, off, sz, d);
119         else
120         {
121                 bind_scratch();
122                 glBufferSubData(GL_ARRAY_BUFFER, off, sz, d);
123         }
124 }
125
126 void Buffer::require_size(unsigned req_sz) const
127 {
128         if(size<req_sz)
129                 throw buffer_too_small(format("buffer has %d bytes; %d required", size, req_sz));
130 }
131
132 void *Buffer::map()
133 {
134         static Require _req(ARB_map_buffer_range);
135
136         allocate();
137         if(ARB_direct_state_access)
138                 return glMapNamedBufferRange(id, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
139         else
140         {
141                 bind_scratch();
142                 void *result = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
143                 return result;
144         }
145 }
146
147 bool Buffer::unmap()
148 {
149         // TODO check if it's mapped
150         if(ARB_direct_state_access)
151                 return glUnmapNamedBuffer(id);
152         else if(OES_mapbuffer)
153         {
154                 bind_scratch();
155                 bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
156                 return result;
157         }
158         else
159                 return true;
160 }
161
162 void Buffer::set_debug_name(const string &name)
163 {
164 #ifdef DEBUG
165         if(KHR_debug)
166                 glObjectLabel(GL_BUFFER, id, name.size(), name.c_str());
167 #else
168         (void)name;
169 #endif
170 }
171
172 void Buffer::bind_scratch()
173 {
174         if(scratch_binding!=this)
175         {
176                 glBindBuffer(GL_ARRAY_BUFFER, id);
177                 scratch_binding = this;
178         }
179 }
180
181 void Buffer::unbind_scratch()
182 {
183         if(scratch_binding)
184         {
185                 glBindBuffer(GL_ARRAY_BUFFER, 0);
186                 scratch_binding = 0;
187         }
188 }
189
190 } // namespace GL
191 } // namespace Msp