framework2
274 строки · 6.3 Кб
1#include "ofBufferObject.h"
2#include "ofAppRunner.h"
3#include "ofPixels.h"
4#include "ofGLUtils.h"
5
6
7ofBufferObject::Data::Data()
8:id(0)
9,size(0)
10,lastTarget(GL_ARRAY_BUFFER)
11
12#ifdef GLEW_VERSION_4_5
13,isDSA(ofIsGLProgrammableRenderer() && GLEW_ARB_direct_state_access)
14#else
15,isDSA(false)
16#endif
17
18{
19
20// tig: glGenBuffers does not actually create a buffer, it just
21// returns the next available name, and only a subsequent
22// call to bind() will actualy initialize the buffer in
23// memory.
24//
25// This is why, for direct state access, we need to call
26// glCreateBuffers(), so that the buffer is initialized
27// when we pin data to it using setData()
28//
29// see also: https://www.opengl.org/registry/specs/ARB/direct_state_access.txt
30#ifdef GLEW_VERSION_4_5
31if(isDSA) {
32// the above condition is only true if GLEW can provide us
33// with direct state access methods. we use this to test
34// whether the driver is OpenGL 4.5 ready.
35glCreateBuffers(1,&id);
36return;
37}
38#endif
39
40glGenBuffers(1,&id);
41}
42
43ofBufferObject::Data::~Data(){
44glDeleteBuffers(1,&id);
45}
46
47ofBufferObject::ofBufferObject()
48{
49
50}
51
52void ofBufferObject::allocate(){
53data = std::make_shared<Data>();
54}
55
56void ofBufferObject::allocate(GLsizeiptr bytes, GLenum usage){
57allocate();
58setData(bytes,0,usage);
59}
60
61void ofBufferObject::allocate(GLsizeiptr bytes, const void * data, GLenum usage){
62allocate();
63setData(bytes,data,usage);
64}
65
66bool ofBufferObject::isAllocated() const{
67return data.get() != nullptr;
68}
69
70void ofBufferObject::bind(GLenum target) const{
71if(data){
72glBindBuffer(target, data->id);
73data->lastTarget = target;
74data->isBound = true;
75}
76}
77
78void ofBufferObject::unbind(GLenum target) const{
79glBindBuffer(target, 0);
80if(data){
81data->isBound = false;
82}
83}
84
85#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)
86void ofBufferObject::bindBase(GLenum target,GLuint index) const{
87if(data){
88glBindBufferBase(target,index,data->id);
89data->lastTarget = target;
90data->isBound = true;
91}
92}
93
94void ofBufferObject::unbindBase(GLenum target,GLuint index) const{
95glBindBufferBase(target,index,0);
96if(data){
97data->isBound = false;
98}
99}
100
101void ofBufferObject::bindRange(GLenum target,GLuint index, GLintptr offset, GLsizeiptr size) const{
102if(data){
103glBindBufferRange(target,index,data->id,offset,size);
104data->lastTarget = target;
105data->isBound = true;
106}
107}
108
109void ofBufferObject::unbindRange(GLenum target,GLuint index) const{
110glBindBufferBase(target,index,0);
111}
112#endif
113
114GLuint ofBufferObject::getId() const{
115if(data) return data->id;
116else return 0;
117}
118
119void ofBufferObject::setData(GLsizeiptr bytes, const void * data, GLenum usage){
120if(!this->data) return;
121this->data->size = bytes;
122
123#ifdef GLEW_VERSION_4_5
124if(this->data->isDSA) {
125glNamedBufferData(this->data->id, bytes, data, usage);
126return;
127}
128#endif
129
130/// --------| invariant: direct state access is not available
131bind(this->data->lastTarget);
132glBufferData(this->data->lastTarget, bytes, data, usage);
133unbind(this->data->lastTarget);
134}
135
136void ofBufferObject::updateData(GLintptr offset, GLsizeiptr bytes, const void * data){
137if(!this->data) return;
138
139#ifdef GLEW_VERSION_4_5
140if(this->data->isDSA){
141glNamedBufferSubData(this->data->id,offset,bytes,data);
142return;
143}
144#endif
145
146/// --------| invariant: direct state access is not available
147
148bind(this->data->lastTarget);
149glBufferSubData(this->data->lastTarget,offset,bytes,data);
150unbind(this->data->lastTarget);
151}
152
153void ofBufferObject::updateData(GLsizeiptr bytes, const void * data){
154updateData(0,bytes,data);
155}
156
157#ifndef TARGET_OPENGLES
158void * ofBufferObject::map(GLenum access){
159if(!this->data) return nullptr;
160
161#ifdef GLEW_VERSION_4_5
162if(this->data->isDSA) {
163return glMapNamedBuffer(data->id,access);
164}
165#endif
166
167/// --------| invariant: direct state access is not available
168if(!data->isBound){
169// if the buffer wasn't already bound and the operation
170// is one of unpack/pack buffer alternate between the 2
171// since the tipical use is to pack to copy to the buffer
172// then unpack to copy from it.
173// for more advanced usages one can just bind the buffer
174// before mapping
175if(data->lastTarget==GL_PIXEL_PACK_BUFFER){
176data->lastTarget = GL_PIXEL_UNPACK_BUFFER;
177}else if(data->lastTarget == GL_PIXEL_UNPACK_BUFFER){
178data->lastTarget = GL_PIXEL_PACK_BUFFER;
179}
180glBindBuffer(data->lastTarget, data->id);
181}
182
183auto ret = glMapBuffer(data->lastTarget,access);
184
185if(!data->isBound){
186unbind(data->lastTarget);
187}
188
189return ret;
190}
191
192void ofBufferObject::unmap(){
193if(!this->data) return;
194
195#ifdef GLEW_VERSION_4_5
196if(this->data->isDSA) {
197glUnmapNamedBuffer(data->id);
198return;
199}
200#endif
201
202/// --------| invariant: direct state access is not available
203if(!data->isBound){
204glBindBuffer(data->lastTarget, data->id);
205}
206
207glUnmapBuffer(data->lastTarget);
208
209if(!data->isBound){
210unbind(data->lastTarget);
211}
212}
213
214void * ofBufferObject::mapRange(GLintptr offset, GLsizeiptr length, GLenum access){
215if(!this->data) return nullptr;
216
217#ifdef GLEW_VERSION_4_5
218if(this->data->isDSA) {
219return glMapNamedBufferRange(data->id,offset,length,access);
220}
221#endif
222
223/// --------| invariant: direct state access is not available
224
225bind(data->lastTarget);
226return glMapBufferRange(data->lastTarget,offset,length,access);
227}
228
229void ofBufferObject::unmapRange(){
230unmap();
231}
232
233void ofBufferObject::copyTo(ofBufferObject & dstBuffer) const{
234#ifdef GLEW_VERSION_4_5
235if(this->data->isDSA) {
236glCopyNamedBufferSubData(data->id,dstBuffer.getId(),0,0,size());
237return;
238}
239#endif
240
241bind(GL_COPY_READ_BUFFER);
242dstBuffer.bind(GL_COPY_WRITE_BUFFER);
243glCopyBufferSubData(GL_COPY_READ_BUFFER,GL_COPY_WRITE_BUFFER,0,0,size());
244unbind(GL_COPY_READ_BUFFER);
245dstBuffer.unbind(GL_COPY_WRITE_BUFFER);
246}
247
248void ofBufferObject::copyTo(ofBufferObject & dstBuffer, int readOffset, int writeOffset, size_t size) const{
249#ifdef GLEW_VERSION_4_5
250if(this->data->isDSA) {
251glCopyNamedBufferSubData(data->id,dstBuffer.getId(),readOffset,writeOffset,size);
252return;
253}
254#endif
255
256bind(GL_COPY_READ_BUFFER);
257dstBuffer.bind(GL_COPY_WRITE_BUFFER);
258glCopyBufferSubData(GL_COPY_READ_BUFFER,GL_COPY_WRITE_BUFFER,readOffset,writeOffset,size);
259unbind(GL_COPY_READ_BUFFER);
260dstBuffer.unbind(GL_COPY_WRITE_BUFFER);
261}
262
263
264
265void ofBufferObject::invalidate(){
266glInvalidateBufferData(data->id);
267}
268
269#endif
270
271GLsizeiptr ofBufferObject::size() const{
272if (data) return data->size;
273else return 0;
274}
275