diff --git a/kivy/core/text/__init__.py b/kivy/core/text/__init__.py index 2ac21a603..4fb11b671 100644 --- a/kivy/core/text/__init__.py +++ b/kivy/core/text/__init__.py @@ -431,7 +431,6 @@ class LabelBase(object): # If the text is 1px width, usually, the data is black. # Don't blit that kind of data, otherwise, you have a little black bar. if data is not None and data.width > 1: - print 'XXXXXXXXX BLIT DATA ON ', texture texture.blit_data(data) def _texture_refresh(self, *l): diff --git a/kivy/graphics/instructions.pxd b/kivy/graphics/instructions.pxd index 31ef856ec..236cd236d 100644 --- a/kivy/graphics/instructions.pxd +++ b/kivy/graphics/instructions.pxd @@ -27,6 +27,7 @@ cdef class Instruction: cdef void flag_update(self, int do_parent=?) cdef void flag_update_done(self) cdef void set_parent(self, Instruction parent) + cdef void reload(self) cdef void radd(self, InstructionGroup ig) cdef void rinsert(self, InstructionGroup ig, int index) @@ -37,6 +38,7 @@ cdef class InstructionGroup(Instruction): cdef InstructionGroup compiled_children cdef GraphicsCompiler compiler cdef void build(self) + cdef void reload(self) cpdef add(self, Instruction c) cpdef insert(self, int index, Instruction c) cpdef remove(self, Instruction c) @@ -80,8 +82,10 @@ cdef class CanvasBase(InstructionGroup): pass cdef class Canvas(CanvasBase): + cdef object __weakref__ cdef CanvasBase _before cdef CanvasBase _after + cdef void reload(self) cpdef clear(self) cpdef add(self, Instruction c) cpdef remove(self, Instruction c) @@ -89,8 +93,6 @@ cdef class Canvas(CanvasBase): cdef class RenderContext(Canvas): - cdef object __weakref__ - cdef Shader _shader cdef dict state_stacks #cdef TextureManager texture_manager diff --git a/kivy/graphics/instructions.pyx b/kivy/graphics/instructions.pyx index 9a7e8647c..59d49cffa 100644 --- a/kivy/graphics/instructions.pyx +++ b/kivy/graphics/instructions.pyx @@ -24,15 +24,15 @@ from weakref import ref cdef int _need_reset_gl = 1 cdef int _active_texture = -1 -cdef list rc_list = [] +cdef list canvas_list = [] cdef void gl_rcs_gc(): - rc_list[:] = [x for x in rc_list if x() is not None] + canvas_list[:] = [x for x in canvas_list if x() is not None] cdef void gl_rcs_reload(): - cdef RenderContext rc + cdef Canvas rc gl_rcs_gc() - for item in rc_list: + for item in canvas_list: rc = item() if not rc: continue @@ -91,6 +91,11 @@ cdef class Instruction: cdef void set_parent(self, Instruction parent): self.parent = parent + cdef void reload(self): + self.flags |= GI_NEEDS_UPDATE + self.flags &= ~GI_NO_APPLY_ONCE + self.flags &= ~GI_IGNORE + property needs_redraw: def __get__(self): if (self.flags & GI_NEEDS_UPDATE) > 0: @@ -187,6 +192,12 @@ cdef class InstructionGroup(Instruction): cdef Instruction c return [c for c in self.children if c.group == groupname] + cdef void reload(self): + Instruction.reload(self) + cdef Instruction c + for c in self.children: + c.reload() + cdef class ContextInstruction(Instruction): '''The ContextInstruction class is the base for the creation of instructions @@ -498,10 +509,22 @@ cdef class Canvas(CanvasBase): ''' def __init__(self, **kwargs): + canvas_list.append(ref(self)) CanvasBase.__init__(self, **kwargs) self._before = None self._after = None + cdef void reload(self): + return + cdef Canvas c + if self._before is not None: + c = self._before + c.reload() + CanvasBase.reload(self) + if self._after is not None: + c = self._after + c.reload() + cpdef clear(self): cdef Instruction c for c in self.children[:]: @@ -599,7 +622,6 @@ cdef class RenderContext(Canvas): - The state stack (color, texture, matrix...) ''' def __init__(self, *args, **kwargs): - rc_list.append(ref(self)) cdef str key self.bind_texture = dict() Canvas.__init__(self, **kwargs) @@ -705,6 +727,7 @@ cdef class RenderContext(Canvas): cdef void reload(self): pushActiveContext(self) reset_gl_context() + Canvas.reload(self) popActiveContext() def __setitem__(self, key, val): diff --git a/kivy/graphics/opengl_utils.pyx b/kivy/graphics/opengl_utils.pyx index d0353c66a..9188105d0 100644 --- a/kivy/graphics/opengl_utils.pyx +++ b/kivy/graphics/opengl_utils.pyx @@ -189,7 +189,7 @@ cpdef int gl_has_texture_format(str fmt): return gl_has_texture_conversion(fmt) cdef int gl_context = 1 -from kivy.graphics.vbo cimport gl_vbos_reload +from kivy.graphics.vbo cimport gl_vbos_reload, gl_batchs_reload from kivy.graphics.shader cimport gl_shaders_reload from kivy.graphics.texture cimport gl_textures_reload from kivy.graphics.instructions cimport gl_rcs_reload @@ -202,12 +202,15 @@ def gl_reload(): gl_context += 1 print '--> reload initiated' - print ' > vbos' - gl_vbos_reload() - print ' > shaders' - gl_shaders_reload() print ' > textures' gl_textures_reload() + print ' > vbos' + gl_vbos_reload() + print ' > vertex batches' + gl_batchs_reload() + print ' > shaders' + gl_shaders_reload() print ' > render contexts' gl_rcs_reload() + print ' > force recompilation.' print '<-- reload done' diff --git a/kivy/graphics/shader.pyx b/kivy/graphics/shader.pyx index 750d3e60e..e050c7208 100644 --- a/kivy/graphics/shader.pyx +++ b/kivy/graphics/shader.pyx @@ -174,7 +174,7 @@ cdef class Shader: glUseProgram(0) self.vertex_shader = None self.fragment_shader = None - self.uniform_values = dict() + #self.uniform_values = dict() self.uniform_locations = dict() self._success = 0 self.program = glCreateProgram() @@ -188,15 +188,16 @@ cdef class Shader: glUseProgram(self.program) for k,v in self.uniform_values.iteritems(): self.upload_uniform(k, v) - # XXX Very very weird bug. On virtualbox / win7 / glew, if we don't call - # glFlush or glFinish or glGetIntegerv(GL_CURRENT_PROGRAM, ...), it seem - # that the pipeline is broken, and we have glitch issue. In order to - # prevent that on possible other hardware, i've (mathieu) prefered to - # include a glFlush here. However, it could be nice to know exactly what - # is going on. Even the glGetIntegerv() is not working here. Broken - # driver on virtualbox / win7 ???? - # FIXME maybe include that instruction for glew usage only. - glFlush() + IF USE_GLEW == 1: + # XXX Very very weird bug. On virtualbox / win7 / glew, if we don't call + # glFlush or glFinish or glGetIntegerv(GL_CURRENT_PROGRAM, ...), it seem + # that the pipeline is broken, and we have glitch issue. In order to + # prevent that on possible other hardware, i've (mathieu) prefered to + # include a glFlush here. However, it could be nice to know exactly what + # is going on. Even the glGetIntegerv() is not working here. Broken + # driver on virtualbox / win7 ???? + # FIXME maybe include that instruction for glew usage only. + glFlush() cdef void stop(self): '''Stop using the shader diff --git a/kivy/graphics/texture.pxd b/kivy/graphics/texture.pxd index e28dc71c3..0d6dff12c 100644 --- a/kivy/graphics/texture.pxd +++ b/kivy/graphics/texture.pxd @@ -5,7 +5,7 @@ cdef void gl_textures_reload() cdef class Texture: cdef object __weakref__ - cdef str _source + cdef object _source cdef float _tex_coords[8] cdef int _width cdef int _height @@ -26,13 +26,18 @@ cdef class Texture: cdef int _nofree cdef list observers - cdef update_tex_coords(self) - cdef set_min_filter(self, str x) - cdef set_mag_filter(self, str x) - cdef set_wrap(self, str x) - cdef reload(self) + cdef void update_tex_coords(self) + cdef void set_min_filter(self, str x) + cdef void set_mag_filter(self, str x) + cdef void set_wrap(self, str x) + cdef void reload(self) cpdef flip_vertical(self) cpdef get_region(self, x, y, width, height) cpdef bind(self) +cdef class TextureRegion(Texture): + cdef int x + cdef int y + cdef Texture owner + cdef void reload(self) diff --git a/kivy/graphics/texture.pyx b/kivy/graphics/texture.pyx index 2fe1a1eaa..fc59deb74 100644 --- a/kivy/graphics/texture.pyx +++ b/kivy/graphics/texture.pyx @@ -170,13 +170,11 @@ cdef GLuint GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1 cdef GLuint GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2 cdef GLuint GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3 -cdef object _texture_release_trigger = None -cdef list _texture_release_list = [] +cdef object texture_release_trigger = None +cdef list texture_release_list = [] cdef list texture_list = [] -cdef void gl_textures_gc(): - # Remove all the vbos not weakref - texture_list[:] = [x for x in texture_list if x() is not None] + cdef void gl_textures_reload(): # Force reloading of textures @@ -184,8 +182,8 @@ cdef void gl_textures_reload(): cdef list l Cache.remove('kv.image') Cache.remove('kv.texture') - gl_textures_gc() - del _texture_release_list[:] + texture_list[:] = [x for x in texture_list if x() is not None] + del texture_release_list[:] # duplicate the current list, new texture might be created l = texture_list[:] @@ -193,16 +191,13 @@ cdef void gl_textures_reload(): # First step, prevent double loading by setting everything to -1 # We do this because texture might be loaded in seperate texture at first, # then merged from the cache cause of the same source - print '------- texture reload phase 0' for item in l: texture = item() if texture is None: continue - print ' -', texture texture._id = -1 # First time, only reload base texture - print '------- texture reload phase 1' for item in l: texture = item() if texture is None or isinstance(texture, TextureRegion): @@ -210,16 +205,12 @@ cdef void gl_textures_reload(): texture.reload() # Second time, update texture region id - print '------- texture reload phase 2' for item in l: texture = item() if texture is None or not isinstance(texture, TextureRegion): continue texture.reload() - print '------- texture reload ended' - - cdef dict _gl_color_fmt = { 'rgba': GL_RGBA, 'bgra': GL_BGRA, 'rgb': GL_RGB, 'bgr': GL_BGR, @@ -228,17 +219,20 @@ cdef dict _gl_color_fmt = { 's3tc_dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 's3tc_dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT } + cdef dict _gl_buffer_fmt = { 'ubyte': GL_UNSIGNED_BYTE, 'ushort': GL_UNSIGNED_SHORT, 'uint': GL_UNSIGNED_INT, 'byte': GL_BYTE, 'short': GL_SHORT, 'int': GL_INT, 'float': GL_FLOAT } + cdef dict _gl_buffer_size = { 'ubyte': sizeof(GLubyte), 'ushort': sizeof(GLushort), 'uint': sizeof(GLuint), 'byte': sizeof(GLbyte), 'short': sizeof(GLshort), 'int': sizeof(GLint), 'float': sizeof(GLfloat) } + cdef dict _gl_texture_min_filter = { 'nearest': GL_NEAREST, 'linear': GL_LINEAR, 'nearest_mipmap_nearest': GL_NEAREST_MIPMAP_NEAREST, @@ -247,7 +241,6 @@ cdef dict _gl_texture_min_filter = { 'linear_mipmap_linear': GL_LINEAR_MIPMAP_LINEAR } - cdef inline int _nearest_pow2(int v): # From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 # Credit: Sean Anderson @@ -440,7 +433,7 @@ cdef _texture_create(int width, int height, str colorfmt, str bufferfmt, make_npot = 0 # depending if npot is available, use the real size or pot size - if make_npot and gl_has_capability(GLCAP_NPOT): + if make_npot and gl_has_capability(c_GLCAP_NPOT): texture_width = width texture_height = height else: @@ -543,8 +536,6 @@ def texture_create(size=None, colorfmt=None, bufferfmt=None, mipmap=False): def texture_create_from_data(im, mipmap=False): '''Create a texture from an ImageData class ''' - print ' create texture from data', im - cdef int width = im.width cdef int height = im.height cdef int allocate = 1 @@ -598,18 +589,19 @@ cdef class Texture: self._source = source self._nofree = 0 self.update_tex_coords() - print 'create texture', self, texture_list def __dealloc__(self): # Add texture deletion outside GC call. # This case happen if some texture have been not deleted # before application exit... - if _texture_release_list is not None and self._id != -1 and self._nofree == 0: - _texture_release_list.append(self._id) - if _texture_release_trigger is not None: - _texture_release_trigger() + if self.__class__ is not Texture: + return + if texture_release_list is not None and self._id != -1 and self._nofree == 0: + texture_release_list.append(self._id) + if texture_release_trigger is not None: + texture_release_trigger() - cdef update_tex_coords(self): + cdef void update_tex_coords(self): self._tex_coords[0] = self._uvx self._tex_coords[1] = self._uvy self._tex_coords[2] = self._uvx + self._uvw @@ -644,17 +636,17 @@ cdef class Texture: '''Bind the texture to current opengl state''' glBindTexture(self._target, self._id) - cdef set_min_filter(self, str x): + cdef void set_min_filter(self, str x): cdef GLuint _value = _str_to_gl_texture_min_filter(x) glTexParameteri(self._target, GL_TEXTURE_MIN_FILTER, _value) self._min_filter = x - cdef set_mag_filter(self, str x): + cdef void set_mag_filter(self, str x): cdef GLuint _value = _str_to_gl_texture_mag_filter(x) glTexParameteri(self._target, GL_TEXTURE_MAG_FILTER, _value) self._mag_filter = x - cdef set_wrap(self, str x): + cdef void set_wrap(self, str x): cdef GLuint _value = _str_to_gl_texture_wrap(x) glTexParameteri(self._target, GL_TEXTURE_WRAP_S, _value) glTexParameteri(self._target, GL_TEXTURE_WRAP_T, _value) @@ -745,38 +737,34 @@ cdef class Texture: if _mipmap_generation: glGenerateMipmap(target) - cdef reload(self): + cdef void reload(self): cdef Texture texture - print ' - want to reload texture', self.id, self._source - print ' ', isinstance(self, Texture), isinstance(self, TextureRegion) if self._id != -1: - print ' -< abort, already reloaded.', self._id return if self._source is None: - print ' -< Unable to reload this texture automatically, call observers' # manual texture recreation texture = texture_create(self.size, self.colorfmt, self.bufferfmt, self.mipmap) self._id = texture.id - self._nofree = 1 + texture._nofree = 1 # then update content again for cb in self.observers: cb(self) + return - print ' reloading...' from kivy.core.image import Image image = Image(self._source) - print ' reloading give image', image - print ' reloading give texture', image.texture self._id = image.texture.id texture = image.texture texture._nofree = 1 - print ' reloading give new id', self._id - + # then update content again + for cb in self.observers: + cb(self) def __str__(self): - return '' % ( - self._id, self.width, self.height, self._source, self.observers) + return '' % ( + id(self), self._id, self.size, self.colorfmt, self.bufferfmt, + self._source, len(self.observers)) property size: '''Return the (width, height) of the texture (readonly) @@ -927,28 +915,7 @@ cdef class TextureRegion(Texture): '''Handle a region of a Texture class. Useful for non power-of-2 texture handling.''' - cdef int x - cdef int y - cdef Texture owner - def __init__(self, int x, int y, int width, int height, Texture origin): - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN' - print' TEXTURE REGIONNNNNNNNNNNNNNNNNNNNNNNNNNNN', origin Texture.__init__(self, width, height, origin.target, origin.id) self._is_allocated = 1 self._mipmap = origin._mipmap @@ -967,20 +934,33 @@ cdef class TextureRegion(Texture): self.update_tex_coords() def __str__(self): - return '' % ( - self._id, self.width, self.height) + return '' % ( + self.owner, id(self), self._id, self.size, self.colorfmt, + self.bufferfmt, self._source, len(self.observers)) + + cdef void reload(self): + # texture region are reloaded _after_ normal texture + # so that could work, except if it's a region of region + # it's safe to retrigger a reload, since the owner texture will be not + # really reloaded if its id is not -1. + self.owner.reload() + self._id = self.owner.id + + # then update content again + for cb in self.observers: + cb(self) # Releasing texture through GC is problematic def _texture_release(*largs): cdef GLuint texture_id - if not _texture_release_list: + if not texture_release_list: return - Logger.trace('Texture: releasing %d textures' % len(_texture_release_list)) - for texture_id in _texture_release_list: + Logger.trace('Texture: releasing %d textures' % len(texture_release_list)) + for texture_id in texture_release_list: glDeleteTextures(1, &texture_id) - del _texture_release_list[:] + del texture_release_list[:] if 'KIVY_DOC_INCLUDE' not in environ: from kivy.clock import Clock - _texture_release_trigger = Clock.create_trigger(_texture_release) + texture_release_trigger = Clock.create_trigger(_texture_release) diff --git a/kivy/graphics/vbo.pxd b/kivy/graphics/vbo.pxd index 7c19e93dc..631941601 100644 --- a/kivy/graphics/vbo.pxd +++ b/kivy/graphics/vbo.pxd @@ -5,6 +5,7 @@ from vertex cimport vertex_t, vertex_attr_t cdef int vbo_vertex_attr_count() cdef vertex_attr_t *vbo_vertex_attr_list() cdef void gl_vbos_reload() +cdef void gl_batchs_reload() cdef class VBO: cdef object __weakref__ @@ -29,6 +30,8 @@ cdef class VBO: cdef class VertexBatch: + cdef object __weakref__ + cdef VBO vbo cdef Buffer elements cdef Buffer vbo_index @@ -48,3 +51,4 @@ cdef class VertexBatch: cdef void set_mode(self, str mode) cdef str get_mode(self) cdef int count(self) + cdef void reload(self) diff --git a/kivy/graphics/vbo.pyx b/kivy/graphics/vbo.pyx index 8fb6043c1..306f8b1da 100644 --- a/kivy/graphics/vbo.pyx +++ b/kivy/graphics/vbo.pyx @@ -31,11 +31,16 @@ vattr[1] = ['vTexCoords0', 1, 2, GL_FLOAT, sizeof(GLfloat) * 2, 1] cdef object _vbo_release_trigger = None cdef list _vbo_release_list = [] cdef list vbo_list = [] +cdef list batch_list = [] cdef gl_vbos_gc(): # Remove all the vbos not weakref. vbo_list[:] = [x for x in vbo_list if x() is not None] +cdef gl_batchs_gc(): + # Remove all the vbos not weakref. + batch_list[:] = [x for x in batch_list if x() is not None] + cdef void gl_vbos_reload(): # Force reloading of vbos @@ -47,6 +52,16 @@ cdef void gl_vbos_reload(): continue vbo.reload() +cdef void gl_batchs_reload(): + # Force reloading of Batchs + cdef VertexBatch batch + gl_batchs_gc() + for item in batch_list: + batch = item() + if not batch: + continue + batch.reload() + cdef int vbo_vertex_attr_count(): '''Return the number of vertex attributes used in VBO @@ -129,6 +144,7 @@ cdef class VBO: cdef class VertexBatch: def __init__(self, **kwargs): + batch_list.append(ref(self)) self.usage = GL_DYNAMIC_DRAW cdef object lushort = sizeof(unsigned short) self.vbo = kwargs.get('vbo') @@ -150,6 +166,11 @@ cdef class VertexBatch: if _vbo_release_trigger is not None: _vbo_release_trigger() + cdef void reload(self): + self.need_upload = 1 + self.elements_size = 0 + glGenBuffers(1, &self.id) + cdef void clear_data(self): # clear old vertices from vbo and then reset index buffer self.vbo.remove_vertex_data(self.vbo_index.pointer(),