Move buffer management into its own class

This commit is contained in:
Kovid Goyal 2017-08-21 22:53:13 +05:30
parent 4fdb55e260
commit f35bf7f1ba
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 54 additions and 20 deletions

View File

@ -581,19 +581,19 @@ GetBufferSubData(PyObject UNUSED *self, PyObject *args) {
static PyObject*
replace_or_create_buffer(PyObject UNUSED *self, PyObject *args) {
int usage;
int usage, buftype;
unsigned long size, prev_sz, target;
PyObject *address;
if (!PyArg_ParseTuple(args, "kkkO!i", &target, &size, &prev_sz, &PyLong_Type, &address, &usage)) return NULL;
if (!PyArg_ParseTuple(args, "kkkO!ii", &target, &size, &prev_sz, &PyLong_Type, &address, &usage, &buftype)) return NULL;
void *data = PyLong_AsVoidPtr(address);
if (data == NULL) { PyErr_SetString(PyExc_TypeError, "Not a valid data pointer"); return NULL; }
glBindBuffer(GL_TEXTURE_BUFFER, target);
glBindBuffer(buftype, target);
Py_BEGIN_ALLOW_THREADS;
if (prev_sz == 0 || prev_sz != size) glBufferData(GL_TEXTURE_BUFFER, size, data, usage);
else glBufferSubData(GL_TEXTURE_BUFFER, 0, size, data);
if (prev_sz == 0 || prev_sz != size) glBufferData(buftype, size, data, usage);
else glBufferSubData(buftype, 0, size, data);
Py_END_ALLOW_THREADS;
CHECK_ERROR;
glBindBuffer(GL_TEXTURE_BUFFER, 0);
glBindBuffer(buftype, 0);
Py_RETURN_NONE;
}

View File

@ -4,7 +4,6 @@
import os
import sys
from collections import defaultdict
from ctypes import addressof, sizeof
from functools import lru_cache
from threading import Lock
@ -45,6 +44,50 @@ def load_shaders(name):
return vert, frag
class BufferManager: # {{{
def __init__(self):
self.buffers = {}
self.sizes = {}
self.types = {}
self.name_count = 0
def create(self, name=None, for_use=GL_TEXTURE_BUFFER):
if name is None:
name = self.name_count
self.name_count += 1
self.buffers[name] = buf_id = glGenBuffers(1)
self.types[name] = for_use
self.sizes.pop(buf_id, None)
return name
def delete(self, name):
buf_id = self.buffers.get(name)
if name is not None:
glDeleteBuffer(buf_id)
self.sizes.pop(buf_id, None)
def set_data(self, name, data, usage=GL_STREAM_DRAW, verify=False):
prev_sz = self.sizes.get(name, 0)
new_sz = sizeof(data)
replace_or_create_buffer(self.buffers[name], new_sz, prev_sz, addressof(data), usage, self.types[name])
self.sizes[name] = new_sz
if verify:
verify_data = type(data)()
glGetBufferSubData(self.buffers[name], new_sz, 0, addressof(verify_data))
if list(data) != list(verify_data):
raise RuntimeError('OpenGL failed to upload to buffer')
def bind(self, name):
buf_id = self.buffers[name]
glBindBuffer(GL_TEXTURE_BUFFER, buf_id)
return buf_id
buffer_manager = BufferManager()
# }}}
class Sprites:
''' Maintain sprite sheets of all rendered characters on the GPU as a texture
array with each texture being a sprite sheet. '''
@ -53,7 +96,6 @@ class Sprites:
# extensions one they become available.
def __init__(self):
self.prev_sprite_map_sizes = defaultdict(lambda: 0)
self.xnum = self.ynum = 1
self.first_cell_cache = {}
self.second_cell_cache = {}
@ -169,29 +211,21 @@ class Sprites:
self.buffer_texture_id = glGenTextures(1)
def add_sprite_map(self):
return glGenBuffers(1)
return buffer_manager.create()
def set_sprite_map(self, buf_id, data, usage=GL_STREAM_DRAW):
prev_sz = self.prev_sprite_map_sizes[buf_id]
new_sz = sizeof(data)
if new_sz // 4 > self.max_texture_buffer_size:
raise RuntimeError(('The OpenGL implementation on your system has a max_texture_buffer_size of {} which'
' is insufficient for the sprite_map').format(self.max_texture_buffer_size))
replace_or_create_buffer(buf_id, new_sz, prev_sz, addressof(data), usage)
self.prev_sprite_map_sizes[buf_id] = new_sz
if False:
verify_data = type(data)()
glGetBufferSubData(buf_id, new_sz, 0, addressof(verify_data))
if list(data) != list(verify_data):
raise RuntimeError('OpenGL failed to upload to buffer')
buffer_manager.set_data(buf_id, data, usage)
def bind_sprite_map(self, buf_id):
glBindBuffer(GL_TEXTURE_BUFFER, buf_id)
buf_id = buffer_manager.bind(buf_id)
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, buf_id)
def destroy_sprite_map(self, buf_id):
glDeleteBuffer(buf_id)
self.prev_sprite_map_sizes.pop(buf_id, None)
buffer_manager.delete(buf_id)
def __enter__(self):
self.ensure_state()