Skip to content

Commit

Permalink
graphics: move out deletion of fbo and vbo outside __dealloc__/gc cal…
Browse files Browse the repository at this point in the history
…l. It seem that gc is sometimes called on a thread, that make everything crash (no opengl call in another thread than main thread. This could resolve the issue of some peoples having crash. Closes #201
  • Loading branch information
Mathieu Virbel committed Aug 4, 2011
1 parent c3120c8 commit e4d702c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 22 deletions.
51 changes: 34 additions & 17 deletions kivy/graphics/fbo.pyx
Expand Up @@ -46,6 +46,7 @@ __all__ = ('Fbo', )
include "config.pxi"
include "opcodes.pxi"

from os import environ
from kivy import Logger
from kivy.graphics.texture cimport Texture
from kivy.graphics.transformation cimport Matrix
Expand All @@ -56,6 +57,9 @@ IF USE_OPENGL_DEBUG == 1:
from instructions cimport RenderContext, Canvas

cdef list fbo_stack = [0]
cdef object _fbo_release_trigger = None
cdef list _fbo_release_list = []



cdef class Fbo(RenderContext):
Expand Down Expand Up @@ -124,27 +128,22 @@ cdef class Fbo(RenderContext):
self.create_fbo()

def __dealloc__(self):
# XXX Cython doc said "not call other class method"
# So just call the minimum
cdef GLuint n
if self._buffer_id != -1:
n = self._buffer_id
glDeleteFramebuffers(1, &n)
if self._depthbuffer_id != -1:
n = self._depthbuffer_id
glDeleteRenderbuffers(1, &n)
# add fbo deletion outside gc call.
if _fbo_release_list is not None:
_fbo_release_list.append((self._buffer_id, self._depthbuffer_id))
if _fbo_release_trigger is not None:
_fbo_release_trigger()

cdef void delete_fbo(self):
# care on this case, if the deletion happen in another thread than main
# thread, we are lost :)
self._texture = None
self._depthbuffer_attached = 0
if self._buffer_id != -1:
glDeleteFramebuffers(1, &self._buffer_id)
self._buffer_id = -1
if self._depthbuffer_id != -1:
glDeleteRenderbuffers(1, &self._depthbuffer_id)
self._depthbuffer_id = -1
# delete in asynchronous way the framebuffers
if _fbo_release_list is not None:
_fbo_release_list.append((self._buffer_id, self._depthbuffer_id))
if _fbo_release_trigger is not None:
_fbo_release_trigger()
self._buffer_id = -1
self._depthbuffer_id = -1

cdef void create_fbo(self):
cdef GLuint f_id
Expand Down Expand Up @@ -297,3 +296,21 @@ cdef class Fbo(RenderContext):
'''
def __get__(self):
return self._texture

# Releasing fbo through GC is problematic. Same as any GL deletion.
def _fbo_release(*largs):
cdef GLuint fbo_id, render_id
if not _fbo_release_list:
return
Logger.trace('FBO: releasing %d fbos' % len(_fbo_release_list))
for l in _fbo_release_list:
fbo_id, render_id = l
if fbo_id != -1:
glDeleteFramebuffers(1, &fbo_id)
if render_id != -1:
glDeleteRenderbuffers(1, &render_id)
del _fbo_release_list[:]

if 'KIVY_DOC_INCLUDE' not in environ:
from kivy.clock import Clock
_fbo_release_trigger = Clock.create_trigger(_fbo_release)
4 changes: 0 additions & 4 deletions kivy/graphics/texture.pyx
Expand Up @@ -853,9 +853,6 @@ cdef class TextureRegion(Texture):
self._id, self.width, self.height)

# Releasing texture through GC is problematic
# GC can happen in a middle of glBegin/glEnd
# So, to prevent that, call the _texture_release
# at flip time.
def _texture_release(*largs):
cdef GLuint texture_id
if not _texture_release_list:
Expand All @@ -866,7 +863,6 @@ def _texture_release(*largs):
del _texture_release_list[:]

if 'KIVY_DOC_INCLUDE' not in environ:
# install tick to release texture every 200ms
from kivy.clock import Clock
_texture_release_trigger = Clock.create_trigger(_texture_release)

25 changes: 24 additions & 1 deletion kivy/graphics/vbo.pyx
Expand Up @@ -13,6 +13,7 @@ __all__ = ('VBO', 'VertexBatch')
include "config.pxi"
include "common.pxi"

from os import environ
from buffer cimport Buffer
from c_opengl cimport *
IF USE_OPENGL_DEBUG == 1:
Expand All @@ -28,6 +29,10 @@ vattr[1] = ['vTexCoords0', 1, 2, GL_FLOAT, sizeof(GLfloat) * 2, 1]
#vertex_attr_list[3] = ['vTexCoords2', 3, 2, GL_FLOAT, sizeof(GLfloat) * 2, 1]
#vertex_attr_list[4] = ['vColor', 4, 2, GL_FLOAT, sizeof(GLfloat) * 4, 0]

cdef object _vbo_release_trigger = None
cdef list _vbo_release_list = []


cdef int vbo_vertex_attr_count():
'''Return the number of vertex attributes used in VBO
'''
Expand All @@ -49,7 +54,11 @@ cdef class VBO:
glGenBuffers(1, &self.id)

def __dealloc__(self):
glDeleteBuffers(1, &self.id)
# Add texture deletion outside GC call.
if _vbo_release_list is not None:
_vbo_release_list.append(self.id)
if _vbo_release_trigger is not None:
_vbo_release_trigger()

def __init__(self, **kwargs):
self.data = Buffer(sizeof(vertex_t))
Expand Down Expand Up @@ -167,3 +176,17 @@ cdef class VertexBatch:

cdef int count(self):
return self.elements.count()

# Releasing vbo through GC is problematic. Same as any GL deletion.
def _vbo_release(*largs):
cdef GLuint vbo_id
if not _vbo_release_list:
return
Logger.trace('VBO: releasing %d vbos' % len(_vbo_release_list))
for vbo_id in _vbo_release_list:
glDeleteBuffers(1, &vbo_id)
del _vbo_release_list[:]

if 'KIVY_DOC_INCLUDE' not in environ:
from kivy.clock import Clock
_vbo_release_trigger = Clock.create_trigger(_vbo_release)

0 comments on commit e4d702c

Please sign in to comment.