Slightly better kerning maybe?
[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."); //WTF?
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::BufferTypeTexture:
60                 return GL_TEXTURE_BUFFER;
61         case GraphicsBuffer::BufferTypeDrawIndirect:
62                 return GL_DRAW_INDIRECT_BUFFER;
63         default:
64                 return GL_COPY_READ_BUFFER;
65         }
66 }
67
68 GraphicsBuffer::GraphicsBuffer()
69 {
70         m_invalidated = true;
71         m_map_pointer = NULL;
72         m_buffer_size = 0;
73         m_buffer_shape_dirty = true;
74         m_buffer_handle = 0;
75         m_buffer_usage = BufferUsageDynamicDraw;
76         m_faking_map = false;
77         m_name = "Unnamed Buffer";
78         SetUsage(BufferUsageStaticDraw);
79 }
80
81 GraphicsBuffer::~GraphicsBuffer()
82 {
83         if (m_map_pointer)
84         {
85                 UnMap();
86         }
87         glDeleteBuffers(1, &m_buffer_handle);
88 }
89
90 void GraphicsBuffer::SetType(GraphicsBuffer::BufferType bufType)
91 {
92         m_buffer_type = bufType;
93 }
94
95 void GraphicsBuffer::SetName(const char *name)
96 {
97         m_name = name;
98 }
99
100 void GraphicsBuffer::SetUsage(GraphicsBuffer::BufferUsage bufUsage)
101 {
102         if (bufUsage != m_buffer_usage)
103         {
104                 m_buffer_usage = bufUsage;
105                 m_buffer_shape_dirty = true;
106         }
107 }
108
109 void GraphicsBuffer::Invalidate()
110 {
111         m_invalidated = true;
112         if (!m_buffer_shape_dirty)
113         {
114                 // Orphan the block of memory we're pointing to.
115                 Upload(m_buffer_size, NULL);
116         }
117         // Apparently not supported.
118         //glInvalidateBufferData(m_buffer_handle);
119 }
120
121 bool GraphicsBuffer::RecreateBuffer(const void *data)
122 {
123         // If the buffer is not dirty, don't recreate it.
124         if (!m_buffer_shape_dirty) return false;
125         // If the buffer is mapped, don't recreate it.
126         if (!m_faking_map && m_map_pointer) return false;
127         // If the buffer has data in it we need, don't recreate it.
128         if (!m_invalidated) return false;
129         if (m_buffer_handle)
130         {
131                 glDeleteBuffers(1, &m_buffer_handle);
132         }
133         glGenBuffers(1, &m_buffer_handle);
134         glObjectLabel(GL_BUFFER, m_buffer_handle, -1, m_name);
135         m_buffer_shape_dirty = false;
136         if (m_buffer_size)
137                 Upload(m_buffer_size, data);
138         return true;
139 }
140
141 void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
142 {
143         GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_BUFFER_BIT:0);
144         GLenum target = BufferTypeToGLType(m_buffer_type);
145
146         if (invalidate)
147         {
148                 m_invalidated = true;
149
150                 // Intel's Mesa driver does not rename the buffer when we map with GL_MAP_INVALIDATE_BUFFER_BIT,
151                 // resulting in the CPU stalling waiting for rendering from the buffer to complete on the GPU.
152                 // We manually force the buffer to be renamed here to avoid this.
153                 m_buffer_shape_dirty = true;
154         }
155
156         if (m_map_pointer)
157                 Warn("Tried to map already mapped buffer!");    
158
159
160         if (!read && m_buffer_usage == BufferUsage::BufferUsageStaticDraw)
161         {
162                 m_map_pointer = malloc(m_buffer_size);
163                 m_faking_map = true;
164                 return m_map_pointer;
165         }
166
167         RecreateBuffer();
168
169         Bind();
170         
171         m_map_pointer = glMapBufferRange(target, 0, m_buffer_size, access);
172         
173         return m_map_pointer;
174 }
175
176 void* GraphicsBuffer::MapRange(int offset, int length, bool read, bool write, bool invalidate)
177 {
178         GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_RANGE_BIT:0);
179         GLenum target = BufferTypeToGLType(m_buffer_type);
180
181         if (m_map_pointer)
182                 Warn("Tried to map already mapped buffer!");    
183
184         RecreateBuffer();
185
186         Bind();
187         
188         m_map_pointer = glMapBufferRange(target, offset, length, access);
189         return m_map_pointer;
190 }
191
192 void GraphicsBuffer::UnMap()
193 {
194         GLenum target = BufferTypeToGLType(m_buffer_type);
195         
196         // If we're not mapped, unmapping is a no-op.
197         if (!m_map_pointer)
198                 return;
199
200         if (m_faking_map)
201         {
202                 Upload(m_buffer_size, m_map_pointer);
203                 free(m_map_pointer);
204                 m_map_pointer = NULL;
205                 m_invalidated = false;
206                 m_faking_map = false;
207                 return;
208         }
209         
210         Bind();
211         glUnmapBuffer(target);
212         m_map_pointer = NULL;
213         m_invalidated = false;
214 }
215
216 void GraphicsBuffer::Upload(size_t length, const void* data)
217 {
218         GLenum target = BufferTypeToGLType(m_buffer_type);
219         
220         GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
221
222         m_invalidated = true;
223         m_buffer_size = length;
224         if (!RecreateBuffer(data))
225         {
226                 Bind();
227                 glBufferData(target, length, data, usage);
228         }
229         if (data != NULL)
230                 m_invalidated = false;
231 }
232
233 void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
234 {
235         GLenum target = BufferTypeToGLType(m_buffer_type);
236
237         RecreateBuffer();
238         
239         Bind();
240         glBufferSubData(target, offset, length, data);
241         m_invalidated = false;
242 }
243
244 void GraphicsBuffer::Resize(size_t length)
245 {
246         if (m_invalidated)
247         {
248                 m_buffer_size = length;
249         }
250         else
251         {
252                 glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Resizing buffer.");
253                 glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, NULL, GL_TRUE);
254                 // Create a new buffer and copy the old data into it.
255                 UnMap();
256                 GLuint old_buffer = m_buffer_handle;    
257                 glGenBuffers(1, &m_buffer_handle);
258                 Upload(length, NULL);
259                 glBindBuffer(GL_COPY_READ_BUFFER, old_buffer);
260                 glBindBuffer(GL_COPY_WRITE_BUFFER, m_buffer_handle);
261                 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, m_buffer_size);
262                 glDeleteBuffers(1, &old_buffer);
263                 m_buffer_size = length;
264                 glPopDebugGroup();
265         }
266 }
267
268 void GraphicsBuffer::Bind() const
269 {
270         if (m_buffer_type == BufferTypeUniform)
271                 glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle);
272         else
273                 glBindBuffer(BufferTypeToGLType(m_buffer_type), m_buffer_handle);
274 }
275
276 void GraphicsBuffer::BindRange(size_t start, size_t size) const
277 {
278         glBindBufferRange(BufferTypeToGLType(m_buffer_type), 0, m_buffer_handle, start, size);
279 }

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