1 #include "graphicsbuffer.h"
6 static GLenum BufferUsageToGLUsage(GraphicsBuffer::BufferUsage buffer_usage)
11 case GraphicsBuffer::BufferUsageStaticDraw:
12 usage = GL_STATIC_DRAW;
14 case GraphicsBuffer::BufferUsageStaticRead:
15 usage = GL_STATIC_READ;
17 case GraphicsBuffer::BufferUsageStaticCopy:
18 usage = GL_STATIC_COPY;
20 case GraphicsBuffer::BufferUsageDynamicDraw:
21 usage = GL_DYNAMIC_DRAW;
23 case GraphicsBuffer::BufferUsageDynamicRead:
24 usage = GL_DYNAMIC_READ;
26 case GraphicsBuffer::BufferUsageDynamicCopy:
27 usage = GL_DYNAMIC_COPY;
29 case GraphicsBuffer::BufferUsageStreamDraw:
30 usage = GL_STREAM_DRAW;
32 case GraphicsBuffer::BufferUsageStreamRead:
33 usage = GL_STREAM_READ;
35 case GraphicsBuffer::BufferUsageStreamCopy:
36 usage = GL_STREAM_COPY;
39 SDL_assert(false && "Unknown buffer usage type."); //WTF?
40 usage = GL_DYNAMIC_DRAW;
45 static GLenum BufferTypeToGLType(GraphicsBuffer::BufferType buffer_type)
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;
64 return GL_COPY_READ_BUFFER;
68 GraphicsBuffer::GraphicsBuffer()
73 m_buffer_shape_dirty = true;
75 m_buffer_usage = BufferUsageDynamicDraw;
77 m_name = "Unnamed Buffer";
78 SetUsage(BufferUsageStaticDraw);
81 GraphicsBuffer::~GraphicsBuffer()
87 glDeleteBuffers(1, &m_buffer_handle);
90 void GraphicsBuffer::SetType(GraphicsBuffer::BufferType bufType)
92 m_buffer_type = bufType;
95 void GraphicsBuffer::SetName(const char *name)
100 void GraphicsBuffer::SetUsage(GraphicsBuffer::BufferUsage bufUsage)
102 if (bufUsage != m_buffer_usage)
104 m_buffer_usage = bufUsage;
105 m_buffer_shape_dirty = true;
109 void GraphicsBuffer::Invalidate()
111 m_invalidated = true;
112 if (!m_buffer_shape_dirty)
114 // Orphan the block of memory we're pointing to.
115 Upload(m_buffer_size, NULL);
117 // Apparently not supported.
118 //glInvalidateBufferData(m_buffer_handle);
121 bool GraphicsBuffer::RecreateBuffer(const void *data)
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;
131 glDeleteBuffers(1, &m_buffer_handle);
133 glGenBuffers(1, &m_buffer_handle);
134 glObjectLabel(GL_BUFFER, m_buffer_handle, -1, m_name);
135 m_buffer_shape_dirty = false;
137 Upload(m_buffer_size, data);
141 void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
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);
148 m_invalidated = true;
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;
157 Warn("Tried to map already mapped buffer!");
160 if (!read && m_buffer_usage == BufferUsage::BufferUsageStaticDraw)
162 m_map_pointer = malloc(m_buffer_size);
164 return m_map_pointer;
171 m_map_pointer = glMapBufferRange(target, 0, m_buffer_size, access);
173 return m_map_pointer;
176 void* GraphicsBuffer::MapRange(int offset, int length, bool read, bool write, bool invalidate)
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);
182 Warn("Tried to map already mapped buffer!");
188 m_map_pointer = glMapBufferRange(target, offset, length, access);
189 return m_map_pointer;
192 void GraphicsBuffer::UnMap()
194 GLenum target = BufferTypeToGLType(m_buffer_type);
196 // If we're not mapped, unmapping is a no-op.
202 Upload(m_buffer_size, m_map_pointer);
204 m_map_pointer = NULL;
205 m_invalidated = false;
206 m_faking_map = false;
211 glUnmapBuffer(target);
212 m_map_pointer = NULL;
213 m_invalidated = false;
216 void GraphicsBuffer::Upload(size_t length, const void* data)
218 GLenum target = BufferTypeToGLType(m_buffer_type);
220 GLenum usage = BufferUsageToGLUsage(m_buffer_usage);
222 m_invalidated = true;
223 m_buffer_size = length;
224 if (!RecreateBuffer(data))
227 glBufferData(target, length, data, usage);
230 m_invalidated = false;
233 void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
235 GLenum target = BufferTypeToGLType(m_buffer_type);
240 glBufferSubData(target, offset, length, data);
241 m_invalidated = false;
244 void GraphicsBuffer::Resize(size_t length)
248 m_buffer_size = length;
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.
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;
268 void GraphicsBuffer::Bind() const
270 if (m_buffer_type == BufferTypeUniform)
271 glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle);
273 glBindBuffer(BufferTypeToGLType(m_buffer_type), m_buffer_handle);
276 void GraphicsBuffer::BindRange(size_t start, size_t size) const
278 glBindBufferRange(BufferTypeToGLType(m_buffer_type), 0, m_buffer_handle, start, size);