From 23a844024c8354d9846cb124a3a6054ac48901cd Mon Sep 17 00:00:00 2001 From: Dexer <73297572+DexerBR@users.noreply.github.com> Date: Sat, 14 Oct 2023 13:51:19 -0300 Subject: [PATCH] Introduce `clear_stencil` option in `StencilPush`, to allow disabling stencil clearing and improve GPU performance when using Stencil Instructions (#8405) * add clear_stencil option to StencilPush * add docs --- kivy/graphics/stencil_instructions.pxd | 1 + kivy/graphics/stencil_instructions.pyx | 31 +++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/kivy/graphics/stencil_instructions.pxd b/kivy/graphics/stencil_instructions.pxd index 549beb23e..3a1b613ff 100644 --- a/kivy/graphics/stencil_instructions.pxd +++ b/kivy/graphics/stencil_instructions.pxd @@ -5,6 +5,7 @@ cdef void restore_stencil_state(dict state) cdef void reset_stencil_state() cdef class StencilPush(Instruction): + cdef int _clear_stencil cdef int apply(self) except -1 cdef class StencilPop(Instruction): diff --git a/kivy/graphics/stencil_instructions.pyx b/kivy/graphics/stencil_instructions.pyx index 7cb485ce8..36bf07bba 100644 --- a/kivy/graphics/stencil_instructions.pyx +++ b/kivy/graphics/stencil_instructions.pyx @@ -105,7 +105,9 @@ cdef dict DEFAULT_STATE = { "level": 0, "in_push": False, "op": None, - "gl_stencil_func": None} + "gl_stencil_func": None, + "clear_stencil": True +} cdef dict _stencil_state = DEFAULT_STATE.copy() @@ -156,10 +158,11 @@ cdef void stencil_apply_state(dict state, restore_only): if state["level"] == 1: cgl.glStencilMask(0xff) log_gl_error('StencilPush.apply-glStencilMask') - cgl.glClearStencil(0) - log_gl_error('StencilPush.apply-glClearStencil') - cgl.glClear(GL_STENCIL_BUFFER_BIT) - log_gl_error('StencilPush.apply-glClear(GL_STENCIL_BUFFER_BIT)') + if state["clear_stencil"]: + cgl.glClearStencil(0) + log_gl_error('StencilPush.apply-glClearStencil') + cgl.glClear(GL_STENCIL_BUFFER_BIT) + log_gl_error('StencilPush.apply-glClear(GL_STENCIL_BUFFER_BIT)') elif state["level"] > 128: raise Exception('Cannot push more than 128 level of stencil.' ' (stack overflow)') @@ -221,9 +224,27 @@ cdef void stencil_apply_state(dict state, restore_only): cdef class StencilPush(Instruction): '''Push the stencil stack. See the module documentation for more information. + + .. versionadded:: 2.3.0 + ``clear_stencil`` was added to allow disabling stencil clearing in the + ``StencilPush`` phase. This option essentially disables the invocation + of the functions ``cgl.glClearStencil(0)`` and ``cgl.glClear(GL_STENCIL_BUFFER_BIT).`` + + .. note:: + It is **highly recommended** to set ``clear_stencil=False`` for improved + performance and reduced GPU usage. However, if any side effects (such as + artifacts or inaccurate functioning of ``StencilPush``) occur, it is + advisable to re-enable the clearing instructions with ``clear_stencil=True.`` + ''' + + def __init__(self, **kwargs): + super(StencilPush, self).__init__(**kwargs) + self._clear_stencil = kwargs.get('clear_stencil', True) + cdef int apply(self) except -1: _stencil_state["op"] = "push" + _stencil_state["clear_stencil"] = self._clear_stencil stencil_apply_state(_stencil_state, False) return 0