]> git.tdb.fi Git - libs/gl.git/blob - source/core/buffer.cpp
Add support for integer vertex attributes
[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():
19         size(0),
20         allocated(false)
21 {
22         static Require _req(ARB_vertex_buffer_object);
23
24         if(ARB_direct_state_access)
25                 glCreateBuffers(1, &id);
26         else
27                 glGenBuffers(1, &id);
28 }
29
30 Buffer::~Buffer()
31 {
32         glDeleteBuffers(1, &id);
33 }
34
35 void Buffer::storage(unsigned sz)
36 {
37         if(size>0)
38         {
39                 if(sz!=size)
40                         throw incompatible_data("Buffer::storage");
41                 return;
42         }
43         if(sz==0)
44                 throw invalid_argument("Buffer::storage");
45
46         size = sz;
47 }
48
49 void Buffer::allocate()
50 {
51         if(size==0)
52                 throw invalid_operation("Buffer::allocate");
53         if(allocated)
54                 return;
55
56         if(ARB_buffer_storage)
57         {
58                 static const int flags = GL_MAP_READ_BIT|GL_MAP_WRITE_BIT|GL_DYNAMIC_STORAGE_BIT;
59                 if(ARB_direct_state_access)
60                         glNamedBufferStorage(id, size, 0, flags);
61                 else
62                 {
63                         glBindBuffer(GL_ARRAY_BUFFER, id);
64                         glBufferStorage(GL_ARRAY_BUFFER, size, 0, flags);
65                         glBindBuffer(GL_ARRAY_BUFFER, 0);
66                 }
67
68                 allocated = true;
69         }
70         else
71                 data(0);
72 }
73
74 void Buffer::set_usage(BufferUsage)
75 {
76 }
77
78 void Buffer::data(const void *d)
79 {
80         if(size==0)
81                 throw invalid_operation("Buffer::data");
82
83         if(ARB_buffer_storage)
84                 return sub_data(0, size, d);
85
86         if(ARB_direct_state_access)
87                 glNamedBufferData(id, size, d, STATIC_DRAW);
88         else
89         {
90                 glBindBuffer(GL_ARRAY_BUFFER, id);
91                 glBufferData(GL_ARRAY_BUFFER, size, d, STATIC_DRAW);
92                 glBindBuffer(GL_ARRAY_BUFFER, 0);
93         }
94
95         allocated = true;
96 }
97
98 void Buffer::data(unsigned sz, const void *d)
99 {
100         if(size==0)
101                 storage(sz);
102         else if(sz!=size)
103                 throw incompatible_data("Buffer::data");
104
105         data(d);
106 }
107
108 void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
109 {
110         if(size==0)
111                 throw invalid_operation("Buffer::sub_data");
112
113         allocate();
114
115         if(ARB_direct_state_access)
116                 glNamedBufferSubData(id, off, sz, d);
117         else
118         {
119                 glBindBuffer(GL_ARRAY_BUFFER, id);
120                 glBufferSubData(GL_ARRAY_BUFFER, off, sz, d);
121                 glBindBuffer(GL_ARRAY_BUFFER, 0);
122         }
123 }
124
125 void Buffer::require_size(unsigned req_sz) const
126 {
127         if(size<req_sz)
128                 throw buffer_too_small(format("buffer has %d bytes; %d required", size, req_sz));
129 }
130
131 void *Buffer::map()
132 {
133         static Require _req(ARB_map_buffer_range);
134
135         allocate();
136         if(ARB_direct_state_access)
137                 return glMapNamedBufferRange(id, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
138         else
139         {
140                 glBindBuffer(GL_ARRAY_BUFFER, id);
141                 void *result = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
142                 glBindBuffer(GL_ARRAY_BUFFER, 0);
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                 glBindBuffer(GL_ARRAY_BUFFER, id);
155                 bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
156                 glBindBuffer(GL_ARRAY_BUFFER, 0);
157                 return result;
158         }
159         else
160                 return true;
161 }
162
163 void Buffer::set_debug_name(const string &name)
164 {
165 #ifdef DEBUG
166         if(KHR_debug)
167                 glObjectLabel(GL_BUFFER, id, name.size(), name.c_str());
168 #else
169         (void)name;
170 #endif
171 }
172
173 } // namespace GL
174 } // namespace Msp