]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/buffer_backend.cpp
Redesign asynchronous buffer uploads
[libs/gl.git] / source / backends / opengl / buffer_backend.cpp
1 #include <msp/gl/extensions/arb_buffer_storage.h>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_map_buffer_range.h>
4 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
5 #include <msp/gl/extensions/khr_debug.h>
6 #include <msp/gl/extensions/oes_mapbuffer.h>
7 #include "buffer.h"
8 #include "buffer_backend.h"
9 #include "device.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 OpenGLBuffer::OpenGLBuffer()
17 {
18         static Require _req(ARB_vertex_buffer_object);
19
20         if(ARB_direct_state_access)
21                 glCreateBuffers(1, &id);
22         else
23                 glGenBuffers(1, &id);
24 }
25
26 OpenGLBuffer::OpenGLBuffer(OpenGLBuffer &&other):
27         id(other.id)
28 {
29         other.id = 0;
30 }
31
32 OpenGLBuffer::~OpenGLBuffer()
33 {
34         if(this==Device::get_current().get_state().scratch_buffer)
35                 unbind_scratch();
36         if(id)
37                 glDeleteBuffers(1, &id);
38 }
39
40 void OpenGLBuffer::allocate()
41 {
42         size_t size = static_cast<const Buffer *>(this)->get_total_size();
43
44         if(ARB_buffer_storage)
45         {
46                 static const int flags = GL_MAP_READ_BIT|GL_MAP_WRITE_BIT|GL_DYNAMIC_STORAGE_BIT;
47                 if(ARB_direct_state_access)
48                         glNamedBufferStorage(id, size, 0, flags);
49                 else
50                 {
51                         bind_scratch();
52                         glBufferStorage(GL_ARRAY_BUFFER, size, 0, flags);
53                 }
54         }
55         else if(ARB_direct_state_access)
56                 glNamedBufferData(id, size, 0, GL_STATIC_DRAW);
57         else
58         {
59                 bind_scratch();
60                 glBufferData(GL_ARRAY_BUFFER, size, 0, GL_STATIC_DRAW);
61         }
62 }
63
64 void OpenGLBuffer::sub_data(size_t off, size_t sz, const void *d)
65 {
66         if(ARB_direct_state_access)
67                 glNamedBufferSubData(id, off, sz, d);
68         else
69         {
70                 bind_scratch();
71                 glBufferSubData(GL_ARRAY_BUFFER, off, sz, d);
72         }
73 }
74
75 void *OpenGLBuffer::map()
76 {
77         static Require _req(ARB_map_buffer_range);
78
79         size_t size = static_cast<const Buffer *>(this)->size;
80
81         if(ARB_direct_state_access)
82                 return glMapNamedBufferRange(id, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
83         else
84         {
85                 bind_scratch();
86                 void *result = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT|GL_MAP_WRITE_BIT);
87                 return result;
88         }
89 }
90
91 bool OpenGLBuffer::unmap()
92 {
93         if(ARB_direct_state_access)
94                 return glUnmapNamedBuffer(id);
95         else if(OES_mapbuffer)
96         {
97                 bind_scratch();
98                 bool result = glUnmapBuffer(GL_ARRAY_BUFFER);
99                 return result;
100         }
101         else
102                 return true;
103 }
104
105 void OpenGLBuffer::set_debug_name(const string &name)
106 {
107 #ifdef DEBUG
108         if(KHR_debug)
109                 glObjectLabel(GL_BUFFER, id, name.size(), name.c_str());
110 #else
111         (void)name;
112 #endif
113 }
114
115 void OpenGLBuffer::bind_scratch()
116 {
117         const OpenGLBuffer *&scratch_binding = Device::get_current().get_state().scratch_buffer;
118         if(scratch_binding!=this)
119         {
120                 glBindBuffer(GL_ARRAY_BUFFER, id);
121                 scratch_binding = this;
122         }
123 }
124
125 void OpenGLBuffer::unbind_scratch()
126 {
127         const OpenGLBuffer *&scratch_binding = Device::get_current().get_state().scratch_buffer;
128         if(scratch_binding)
129         {
130                 glBindBuffer(GL_ARRAY_BUFFER, 0);
131                 scratch_binding = 0;
132         }
133 }
134
135
136 void Buffer::AsyncTransfer::allocate()
137 {
138         dest_addr = buffer.map();
139 }
140
141 void Buffer::AsyncTransfer::finalize()
142 {
143         buffer.unmap();
144 }
145
146 } // namespace GL
147 } // namespace Msp