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

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