]> git.tdb.fi Git - libs/gl.git/blob - source/core/buffer.cpp
Remove the separate allocation step from 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/arb_vertex_buffer_object.h>
6 #include <msp/gl/extensions/khr_debug.h>
7 #include <msp/gl/extensions/oes_mapbuffer.h>
8 #include <msp/strings/format.h>
9 #include "buffer.h"
10 #include "error.h"
11
12 using namespace std;
13
14 namespace Msp {
15 namespace GL {
16
17 Buffer *Buffer::scratch_binding = 0;
18
19 Buffer::Buffer():
20         size(0)
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         if(this==scratch_binding)
33                 unbind_scratch();
34         glDeleteBuffers(1, &id);
35 }
36
37 void Buffer::storage(unsigned sz)
38 {
39         if(size>0)
40         {
41                 if(sz!=size)
42                         throw incompatible_data("Buffer::storage");
43                 return;
44         }
45         if(sz==0)
46                 throw invalid_argument("Buffer::storage");
47
48         size = sz;
49
50         if(ARB_buffer_storage)
51         {
52                 static const int flags = GL_MAP_READ_BIT|GL_MAP_WRITE_BIT|GL_DYNAMIC_STORAGE_BIT;
53                 if(ARB_direct_state_access)
54                         glNamedBufferStorage(id, size, 0, flags);
55                 else
56                 {
57                         bind_scratch();
58                         glBufferStorage(GL_ARRAY_BUFFER, size, 0, flags);
59                 }
60         }
61         else if(ARB_direct_state_access)
62                 glNamedBufferData(id, size, 0, GL_STATIC_DRAW);
63         else
64         {
65                 bind_scratch();
66                 glBufferData(GL_ARRAY_BUFFER, size, 0, GL_STATIC_DRAW);
67         }
68 }
69
70 void Buffer::data(const void *d)
71 {
72         return sub_data(0, size, d);
73 }
74
75 void Buffer::sub_data(unsigned off, unsigned sz, const void *d)
76 {
77         if(size==0)
78                 throw invalid_operation("Buffer::sub_data");
79
80         if(ARB_direct_state_access)
81                 glNamedBufferSubData(id, off, sz, d);
82         else
83         {
84                 bind_scratch();
85                 glBufferSubData(GL_ARRAY_BUFFER, off, sz, d);
86         }
87 }
88
89 void Buffer::require_size(unsigned req_sz) const
90 {
91         if(size<req_sz)
92                 throw buffer_too_small(format("buffer has %d bytes; %d required", size, req_sz));
93 }
94
95 void *Buffer::map()
96 {
97         static Require _req(ARB_map_buffer_range);
98
99         if(ARB_direct_state_access)
100                 return glMapNamedBufferRange(id, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
101         else
102         {
103                 bind_scratch();
104                 void *result = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
105                 return result;
106         }
107 }
108
109 bool Buffer::unmap()
110 {
111         // TODO check if it's mapped
112         if(ARB_direct_state_access)
113                 return glUnmapNamedBuffer(id);
114         else if(OES_mapbuffer)
115         {
116                 bind_scratch();
117                 bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
118                 return result;
119         }
120         else
121                 return true;
122 }
123
124 void Buffer::set_debug_name(const string &name)
125 {
126 #ifdef DEBUG
127         if(KHR_debug)
128                 glObjectLabel(GL_BUFFER, id, name.size(), name.c_str());
129 #else
130         (void)name;
131 #endif
132 }
133
134 void Buffer::bind_scratch()
135 {
136         if(scratch_binding!=this)
137         {
138                 glBindBuffer(GL_ARRAY_BUFFER, id);
139                 scratch_binding = this;
140         }
141 }
142
143 void Buffer::unbind_scratch()
144 {
145         if(scratch_binding)
146         {
147                 glBindBuffer(GL_ARRAY_BUFFER, 0);
148                 scratch_binding = 0;
149         }
150 }
151
152 } // namespace GL
153 } // namespace Msp