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

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