fe5ae1c4600d339e5858defaaf2a38c09583328c
[ipdf/code.git] / src / graphicsbuffer.cpp
1 #include "graphicsbuffer.h"
2 #include "log.h"
3 #define GL_GLEXT_PROTOTYPES
4 #include <SDL_opengl.h>
5 #include <GL/glext.h>
6
7 using namespace IPDF;
8
9 static GLenum BufferUsageToGLUsage(GraphicsBuffer::BufferUsage buffer_usage)
10 {
11         GLenum usage;
12         switch (buffer_usage)
13         {
14         case GraphicsBuffer::BufferUsageStaticDraw:
15                 usage = GL_STATIC_DRAW;
16                 break;
17         case GraphicsBuffer::BufferUsageStaticRead:
18                 usage = GL_STATIC_READ;
19                 break;
20         case GraphicsBuffer::BufferUsageStaticCopy:
21                 usage = GL_STATIC_COPY;
22                 break;
23         case GraphicsBuffer::BufferUsageDynamicDraw:
24                 usage = GL_DYNAMIC_DRAW;
25                 break;
26         case GraphicsBuffer::BufferUsageDynamicRead:
27                 usage = GL_DYNAMIC_READ;
28                 break;
29         case GraphicsBuffer::BufferUsageDynamicCopy:
30                 usage = GL_DYNAMIC_COPY;
31                 break;
32         case GraphicsBuffer::BufferUsageStreamDraw:
33                 usage = GL_STREAM_DRAW;
34                 break;
35         case GraphicsBuffer::BufferUsageStreamRead:
36                 usage = GL_STREAM_READ;
37                 break;
38         case GraphicsBuffer::BufferUsageStreamCopy:
39                 usage = GL_STREAM_COPY;
40                 break;
41         default:
42                 SDL_assert(false && "Unknown buffer usage type.");
43                 usage = GL_DYNAMIC_DRAW;
44         }
45         return usage;
46 }
47
48 static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type)
49 {
50         switch (buffer_type)
51         {
52         case GraphicsBuffer::BufferTypeVertex:
53                 return GL_ARRAY_BUFFER;
54         case GraphicsBuffer::BufferTypeIndex:
55                 return GL_ELEMENT_ARRAY_BUFFER;
56         case GraphicsBuffer::BufferTypePixelPack:
57                 return GL_PIXEL_PACK_BUFFER;
58         case GraphicsBuffer::BufferTypePixelUnpack:
59                 return GL_PIXEL_UNPACK_BUFFER;
60         case GraphicsBuffer::BufferTypeUniform:
61                 return GL_UNIFORM_BUFFER;
62         case GraphicsBuffer::BufferTypeDrawIndirect:
63                 return GL_DRAW_INDIRECT_BUFFER;
64         default:
65                 return GL_COPY_READ_BUFFER;
66         }
67 }
68
69 GraphicsBuffer::GraphicsBuffer()
70 {
71         m_invalidated = true;
72         m_map_pointer = nullptr;
73         m_buffer_size = 0;
74         m_buffer_shape_dirty = true;
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         // Apparently not supported.
105         //glInvalidateBufferData(m_buffer_handle);
106 }
107
108 void GraphicsBuffer::RecreateBuffer()
109 {
110         // If the buffer is not dirty, don't recreate it.
111         if (!m_buffer_shape_dirty) return;
112         // If the buffer is mapped, don't recreate it.
113         if (m_map_pointer) return;
114         // If the buffer has data in it we need, don't recreate it.
115         if (!m_invalidated) return;
116         if (m_buffer_handle)
117         {
118                 glDeleteBuffers(1, &m_buffer_handle);
119         }
120         glGenBuffers(1, &m_buffer_handle);
121         m_buffer_shape_dirty = false;
122         if (m_buffer_size)
123                 Upload(m_buffer_size, nullptr);
124 }
125
126 void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
127 {
128         GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_BUFFER_BIT:0);
129         GLenum target = BufferTypeToGLType(m_buffer_type);
130
131         if (invalidate)
132                m_invalidated = true;
133
134         if (m_map_pointer)
135                 Warn("Tried to map already mapped buffer!");    
136
137         RecreateBuffer();
138
139         Bind();
140         
141         m_map_pointer = glMapBufferRange(target, 0, m_buffer_size, access);
142         
143         return m_map_pointer;
144 }
145
146 void* GraphicsBuffer::MapRange(int offset, int length, bool read, bool write, bool invalidate)
147 {
148         GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_RANGE_BIT:0);
149         GLenum target = BufferTypeToGLType(m_buffer_type);
150
151         if (m_map_pointer)
152                 Warn("Tried to map already mapped buffer!");    
153
154         RecreateBuffer();
155
156         Bind();
157         
158         m_map_pointer = glMapBufferRange(target, offset, length, access);
159         return m_map_pointer;
160 }
161
162 void GraphicsBuffer::UnMap()
163 {
164         GLenum target = BufferTypeToGLType(m_buffer_type);
165         
166         Bind();
167         glUnmapBuffer(target);
168         m_map_pointer = nullptr;
169 }
170
171 void GraphicsBuffer::Upload(size_t length, const void* data)
172 {
173         GLenum target = BufferTypeToGLType(m_buffer_type);
174         
175         GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
176
177         m_invalidated = true;
178         RecreateBuffer();
179         
180         Bind();
181         glBufferData(target, length, data, usage);
182         m_buffer_size = length;
183 }
184
185 void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
186 {
187         GLenum target = BufferTypeToGLType(m_buffer_type);
188
189         RecreateBuffer();
190         
191         Bind();
192         glBufferSubData(target, offset, length, data);
193 }
194
195 void GraphicsBuffer::Resize(size_t length)
196 {
197         if (m_invalidated)
198         {
199                 m_buffer_size = length;
200                 RecreateBuffer();       
201         }
202         else
203         {
204                 // Create a new buffer and copy the old data into it.
205                 UnMap();
206                 GLuint old_buffer = m_buffer_handle;    
207                 glGenBuffers(1, &m_buffer_handle);
208                 Upload(length, nullptr);
209                 glBindBuffer(GL_COPY_READ_BUFFER, old_buffer);
210                 glBindBuffer(GL_COPY_WRITE_BUFFER, m_buffer_handle);
211                 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, m_buffer_size);
212                 glDeleteBuffers(1, &old_buffer);
213                 m_buffer_size = length;
214         }
215 }
216
217 void GraphicsBuffer::Bind()
218 {
219         if (m_buffer_type == BufferTypeUniform)
220                 glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle);
221         else
222                 glBindBuffer(BufferTypeToGLType(m_buffer_type), m_buffer_handle);
223 }
224

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