Circles (ellipses) have been added (filled only)
[ipdf/code.git] / src / graphicsbuffer.cpp
1 #include "graphicsbuffer.h"
2 #include "log.h"
3
4 using namespace IPDF;
5
6 static GLenum BufferUsageToGLUsage(GraphicsBuffer::BufferUsage buffer_usage)
7 {
8         GLenum usage;
9         switch (buffer_usage)
10         {
11         case GraphicsBuffer::BufferUsageStaticDraw:
12                 usage = GL_STATIC_DRAW;
13                 break;
14         case GraphicsBuffer::BufferUsageStaticRead:
15                 usage = GL_STATIC_READ;
16                 break;
17         case GraphicsBuffer::BufferUsageStaticCopy:
18                 usage = GL_STATIC_COPY;
19                 break;
20         case GraphicsBuffer::BufferUsageDynamicDraw:
21                 usage = GL_DYNAMIC_DRAW;
22                 break;
23         case GraphicsBuffer::BufferUsageDynamicRead:
24                 usage = GL_DYNAMIC_READ;
25                 break;
26         case GraphicsBuffer::BufferUsageDynamicCopy:
27                 usage = GL_DYNAMIC_COPY;
28                 break;
29         case GraphicsBuffer::BufferUsageStreamDraw:
30                 usage = GL_STREAM_DRAW;
31                 break;
32         case GraphicsBuffer::BufferUsageStreamRead:
33                 usage = GL_STREAM_READ;
34                 break;
35         case GraphicsBuffer::BufferUsageStreamCopy:
36                 usage = GL_STREAM_COPY;
37                 break;
38         default:
39                 SDL_assert(false && "Unknown buffer usage type.");
40                 usage = GL_DYNAMIC_DRAW;
41         }
42         return usage;
43 }
44
45 static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type)
46 {
47         switch (buffer_type)
48         {
49         case GraphicsBuffer::BufferTypeVertex:
50                 return GL_ARRAY_BUFFER;
51         case GraphicsBuffer::BufferTypeIndex:
52                 return GL_ELEMENT_ARRAY_BUFFER;
53         case GraphicsBuffer::BufferTypePixelPack:
54                 return GL_PIXEL_PACK_BUFFER;
55         case GraphicsBuffer::BufferTypePixelUnpack:
56                 return GL_PIXEL_UNPACK_BUFFER;
57         case GraphicsBuffer::BufferTypeUniform:
58                 return GL_UNIFORM_BUFFER;
59         case GraphicsBuffer::BufferTypeDrawIndirect:
60                 return GL_DRAW_INDIRECT_BUFFER;
61         default:
62                 return GL_COPY_READ_BUFFER;
63         }
64 }
65
66 GraphicsBuffer::GraphicsBuffer()
67 {
68         m_invalidated = true;
69         m_map_pointer = nullptr;
70         m_buffer_size = 0;
71         m_buffer_shape_dirty = true;
72         m_buffer_handle = 0;
73         m_buffer_usage = BufferUsageDynamicDraw;
74         m_faking_map = false;
75         SetUsage(BufferUsageStaticDraw);
76 }
77
78 GraphicsBuffer::~GraphicsBuffer()
79 {
80         if (m_map_pointer)
81         {
82                 UnMap();
83         }
84         glDeleteBuffers(1, &m_buffer_handle);
85 }
86
87 void GraphicsBuffer::SetType(GraphicsBuffer::BufferType bufType)
88 {
89         m_buffer_type = bufType;
90 }
91
92 void GraphicsBuffer::SetUsage(GraphicsBuffer::BufferUsage bufUsage)
93 {
94         if (bufUsage != m_buffer_usage)
95         {
96                 m_buffer_usage = bufUsage;
97                 m_buffer_shape_dirty = true;
98         }
99 }
100
101 void GraphicsBuffer::Invalidate()
102 {
103         m_invalidated = true;
104         if (!m_buffer_shape_dirty)
105         {
106                 // Orphan the block of memory we're pointing to.
107                 Upload(m_buffer_size, nullptr);
108         }
109         // Apparently not supported.
110         //glInvalidateBufferData(m_buffer_handle);
111 }
112
113 bool GraphicsBuffer::RecreateBuffer(const void *data)
114 {
115         // If the buffer is not dirty, don't recreate it.
116         if (!m_buffer_shape_dirty) return false;
117         // If the buffer is mapped, don't recreate it.
118         if (!m_faking_map && m_map_pointer) return false;
119         // If the buffer has data in it we need, don't recreate it.
120         if (!m_invalidated) return false;
121         if (m_buffer_handle)
122         {
123                 glDeleteBuffers(1, &m_buffer_handle);
124         }
125         glGenBuffers(1, &m_buffer_handle);
126         m_buffer_shape_dirty = false;
127         if (m_buffer_size)
128                 Upload(m_buffer_size, data);
129         return true;
130 }
131
132 void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
133 {
134         GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_BUFFER_BIT:0);
135         GLenum target = BufferTypeToGLType(m_buffer_type);
136
137         if (invalidate)
138         {
139                 m_invalidated = true;
140
141                 // Intel's Mesa driver does not rename the buffer when we map with GL_MAP_INVALIDATE_BUFFER_BIT,
142                 // resulting in the CPU stalling waiting for rendering from the buffer to complete on the GPU.
143                 // We manually force the buffer to be renamed here to avoid this.
144                 m_buffer_shape_dirty = true;
145         }
146
147         if (m_map_pointer)
148                 Warn("Tried to map already mapped buffer!");    
149
150
151         if (!read && m_buffer_usage == BufferUsage::BufferUsageStaticDraw)
152         {
153                 m_map_pointer = malloc(m_buffer_size);
154                 m_faking_map = true;
155                 return m_map_pointer;
156         }
157
158         RecreateBuffer();
159
160         Bind();
161         
162         m_map_pointer = glMapBufferRange(target, 0, m_buffer_size, access);
163         
164         return m_map_pointer;
165 }
166
167 void* GraphicsBuffer::MapRange(int offset, int length, bool read, bool write, bool invalidate)
168 {
169         GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_RANGE_BIT:0);
170         GLenum target = BufferTypeToGLType(m_buffer_type);
171
172         if (m_map_pointer)
173                 Warn("Tried to map already mapped buffer!");    
174
175         RecreateBuffer();
176
177         Bind();
178         
179         m_map_pointer = glMapBufferRange(target, offset, length, access);
180         return m_map_pointer;
181 }
182
183 void GraphicsBuffer::UnMap()
184 {
185         GLenum target = BufferTypeToGLType(m_buffer_type);
186
187         if (m_faking_map)
188         {
189                 Upload(m_buffer_size, m_map_pointer);
190                 free(m_map_pointer);
191                 m_map_pointer = nullptr;
192                 m_invalidated = false;
193                 m_faking_map = false;
194                 return;
195         }
196         
197         Bind();
198         glUnmapBuffer(target);
199         m_map_pointer = nullptr;
200         m_invalidated = false;
201 }
202
203 void GraphicsBuffer::Upload(size_t length, const void* data)
204 {
205         GLenum target = BufferTypeToGLType(m_buffer_type);
206         
207         GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
208
209         m_invalidated = true;
210         m_buffer_size = length;
211         if (!RecreateBuffer(data))
212         {
213                 Bind();
214                 glBufferData(target, length, data, usage);
215         }
216         if (data != nullptr)
217                 m_invalidated = false;
218 }
219
220 void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
221 {
222         GLenum target = BufferTypeToGLType(m_buffer_type);
223
224         RecreateBuffer();
225         
226         Bind();
227         glBufferSubData(target, offset, length, data);
228         m_invalidated = false;
229 }
230
231 void GraphicsBuffer::Resize(size_t length)
232 {
233         if (m_invalidated)
234         {
235                 m_buffer_size = length;
236         }
237         else
238         {
239                 // Create a new buffer and copy the old data into it.
240                 UnMap();
241                 GLuint old_buffer = m_buffer_handle;    
242                 glGenBuffers(1, &m_buffer_handle);
243                 Upload(length, nullptr);
244                 glBindBuffer(GL_COPY_READ_BUFFER, old_buffer);
245                 glBindBuffer(GL_COPY_WRITE_BUFFER, m_buffer_handle);
246                 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, m_buffer_size);
247                 glDeleteBuffers(1, &old_buffer);
248                 m_buffer_size = length;
249         }
250 }
251
252 void GraphicsBuffer::Bind() const
253 {
254         if (m_buffer_type == BufferTypeUniform)
255                 glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle);
256         else
257                 glBindBuffer(BufferTypeToGLType(m_buffer_type), m_buffer_handle);
258 }
259

UCC git Repository :: git.ucc.asn.au