mirror of https://github.com/kivy/kivy.git
clock: implement rfps (real frame displayed on screen)
base: display and flip only when needed (might be have some bugs.)
This commit is contained in:
parent
dd91a1f940
commit
e838e13e96
|
@ -6,7 +6,8 @@ from kivy.lang import Builder
|
||||||
|
|
||||||
class KvApp(App):
|
class KvApp(App):
|
||||||
def _print_fps(self, *largs):
|
def _print_fps(self, *largs):
|
||||||
print 'FPS:', Clock.get_fps()
|
print 'FPS: %2.4f (real draw: %d)' % (
|
||||||
|
Clock.get_fps(), Clock.get_rfps())
|
||||||
def build(self):
|
def build(self):
|
||||||
Clock.schedule_interval(self._print_fps, 1)
|
Clock.schedule_interval(self._print_fps, 1)
|
||||||
return Builder.load_file(self.options['filename'])
|
return Builder.load_file(self.options['filename'])
|
||||||
|
|
|
@ -12,6 +12,7 @@ from kivy.logger import Logger
|
||||||
from kivy.exceptions import ExceptionManager
|
from kivy.exceptions import ExceptionManager
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.input import TouchFactory, kivy_postproc_modules
|
from kivy.input import TouchFactory, kivy_postproc_modules
|
||||||
|
from kivy.graphics import GraphicContext
|
||||||
|
|
||||||
# private vars
|
# private vars
|
||||||
EventLoop = None
|
EventLoop = None
|
||||||
|
@ -211,7 +212,9 @@ class EventLoopBase(object):
|
||||||
self.dispatch_input()
|
self.dispatch_input()
|
||||||
|
|
||||||
window = self.window
|
window = self.window
|
||||||
if window:
|
need_redraw = GraphicContext.instance().need_redraw
|
||||||
|
if window and need_redraw:
|
||||||
|
Clock.tick_draw()
|
||||||
window.dispatch('on_draw')
|
window.dispatch('on_draw')
|
||||||
window.dispatch('on_flip')
|
window.dispatch('on_flip')
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ cdef class GraphicContext:
|
||||||
cdef readonly int need_flush
|
cdef readonly int need_flush
|
||||||
cdef Shader _default_shader
|
cdef Shader _default_shader
|
||||||
cdef object _default_texture
|
cdef object _default_texture
|
||||||
cdef int need_redraw
|
cdef int _need_redraw
|
||||||
|
|
||||||
cpdef post_update(self)
|
cpdef post_update(self)
|
||||||
cpdef finish_frame(self)
|
cpdef finish_frame(self)
|
||||||
|
|
|
@ -45,18 +45,22 @@ cdef class GraphicContext:
|
||||||
self.journal = set()
|
self.journal = set()
|
||||||
self.need_flush = 0
|
self.need_flush = 0
|
||||||
self._default_shader = None
|
self._default_shader = None
|
||||||
|
self._need_redraw = 1
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# create initial state
|
# create initial state
|
||||||
self.reset()
|
self.reset()
|
||||||
self.save()
|
self.save()
|
||||||
self.need_redraw = 1
|
|
||||||
|
property need_redraw:
|
||||||
|
def __get__(self):
|
||||||
|
return self._need_redraw
|
||||||
|
|
||||||
cpdef post_update(self):
|
cpdef post_update(self):
|
||||||
self.need_redraw = 1
|
self._need_redraw = 1
|
||||||
|
|
||||||
cpdef finish_frame(self):
|
cpdef finish_frame(self):
|
||||||
self.need_redraw = 0
|
self._need_redraw = 0
|
||||||
err = glGetError()
|
err = glGetError()
|
||||||
if err:
|
if err:
|
||||||
Logger.warning('GContext: GL Error while drawing frame: %d' % err)
|
Logger.warning('GContext: GL Error while drawing frame: %d' % err)
|
||||||
|
|
|
@ -17,8 +17,9 @@ If the callback return False, the schedule will be removed.
|
||||||
|
|
||||||
__all__ = ('Clock', )
|
__all__ = ('Clock', )
|
||||||
|
|
||||||
import time
|
from time import time, sleep
|
||||||
from kivy.weakmethod import WeakMethod
|
from kivy.weakmethod import WeakMethod
|
||||||
|
from kivy.config import Config
|
||||||
|
|
||||||
class _Event(object):
|
class _Event(object):
|
||||||
|
|
||||||
|
@ -63,16 +64,19 @@ class _Event(object):
|
||||||
|
|
||||||
class ClockBase(object):
|
class ClockBase(object):
|
||||||
'''A clock object, that support events'''
|
'''A clock object, that support events'''
|
||||||
__slots__ = ('_dt', '_last_fps_tick', '_last_tick', '_fps',
|
__slots__ = ('_dt', '_last_fps_tick', '_last_tick', '_fps', '_rfps',
|
||||||
'_fps_counter', '_events')
|
'_fps_counter', '_rfps_counter', '_events', '_max_fps')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._dt = 0.0001
|
self._dt = 0.0001
|
||||||
self._last_tick = time.time()
|
self._last_tick = time()
|
||||||
self._fps = 0
|
self._fps = 0
|
||||||
|
self._rfps = 0
|
||||||
self._fps_counter = 0
|
self._fps_counter = 0
|
||||||
|
self._rfps_counter = 0
|
||||||
self._last_fps_tick = None
|
self._last_fps_tick = None
|
||||||
self._events = []
|
self._events = []
|
||||||
|
self._max_fps = float(Config.getint('graphics', 'fps'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def frametime(self):
|
def frametime(self):
|
||||||
|
@ -83,8 +87,16 @@ class ClockBase(object):
|
||||||
def tick(self):
|
def tick(self):
|
||||||
'''Advance clock to the next step. Must be called every frame.
|
'''Advance clock to the next step. Must be called every frame.
|
||||||
The default clock have the tick() function called by Kivy'''
|
The default clock have the tick() function called by Kivy'''
|
||||||
|
|
||||||
|
# do we need to sleep ?
|
||||||
|
if self._max_fps > 0:
|
||||||
|
fps = self._max_fps
|
||||||
|
s = 1 / fps - (time() - self._last_tick)
|
||||||
|
if s > 0:
|
||||||
|
sleep(s)
|
||||||
|
|
||||||
# tick the current time
|
# tick the current time
|
||||||
current = time.time()
|
current = time()
|
||||||
self._dt = current - self._last_tick
|
self._dt = current - self._last_tick
|
||||||
self._fps_counter += 1
|
self._fps_counter += 1
|
||||||
self._last_tick = current
|
self._last_tick = current
|
||||||
|
@ -93,19 +105,37 @@ class ClockBase(object):
|
||||||
if self._last_fps_tick == None:
|
if self._last_fps_tick == None:
|
||||||
self._last_fps_tick = current
|
self._last_fps_tick = current
|
||||||
elif current - self._last_fps_tick > 1:
|
elif current - self._last_fps_tick > 1:
|
||||||
self._fps = self._fps_counter / float(current - self._last_fps_tick)
|
d = float(current - self._last_fps_tick)
|
||||||
|
self._fps = self._fps_counter / d
|
||||||
|
self._rfps = self._rfps_counter
|
||||||
self._last_fps_tick = current
|
self._last_fps_tick = current
|
||||||
self._fps_counter = 0
|
self._fps_counter = 0
|
||||||
|
self._rfps_counter = 0
|
||||||
|
|
||||||
# process event
|
# process event
|
||||||
self._process_events()
|
self._process_events()
|
||||||
|
|
||||||
return self._dt
|
return self._dt
|
||||||
|
|
||||||
|
def tick_draw(self):
|
||||||
|
'''Tick the drawing counter
|
||||||
|
'''
|
||||||
|
self._rfps_counter += 1
|
||||||
|
|
||||||
def get_fps(self):
|
def get_fps(self):
|
||||||
'''Get the current FPS calculated by the clock'''
|
'''Get the current FPS calculated by the clock
|
||||||
|
'''
|
||||||
return self._fps
|
return self._fps
|
||||||
|
|
||||||
|
def get_rfps(self):
|
||||||
|
'''Get the current "real" FPS calculated by the clock.
|
||||||
|
This counter reflect the real frame displayed on the screen.
|
||||||
|
|
||||||
|
In contrary to get_fps(), this function return a counter of the number
|
||||||
|
of frame, not a average of frame per seconds
|
||||||
|
'''
|
||||||
|
return self._rfps
|
||||||
|
|
||||||
def get_time(self):
|
def get_time(self):
|
||||||
'''Get the last tick made by the clock'''
|
'''Get the last tick made by the clock'''
|
||||||
return self._last_tick
|
return self._last_tick
|
||||||
|
|
|
@ -7,7 +7,6 @@ __all__ = ('WindowPygame', )
|
||||||
from . import WindowBase
|
from . import WindowBase
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from time import sleep, time
|
|
||||||
from kivy.config import Config
|
from kivy.config import Config
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.exceptions import ExceptionManager
|
from kivy.exceptions import ExceptionManager
|
||||||
|
@ -138,17 +137,6 @@ class WindowPygame(WindowBase):
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
super(WindowPygame, self).flip()
|
super(WindowPygame, self).flip()
|
||||||
|
|
||||||
# do software vsync if asked
|
|
||||||
# FIXME: vsync is surely not 60 for everyone
|
|
||||||
# this is not a real vsync. this must be done by driver...
|
|
||||||
# but pygame can't do vsync on X11, and some people
|
|
||||||
# use hack to make it work under darwin...
|
|
||||||
fps = self._fps
|
|
||||||
if fps > 0:
|
|
||||||
s = 1 / fps - (time() - Clock.get_time())
|
|
||||||
if s > 0:
|
|
||||||
sleep(s)
|
|
||||||
|
|
||||||
def toggle_fullscreen(self):
|
def toggle_fullscreen(self):
|
||||||
if self.flags & pygame.FULLSCREEN:
|
if self.flags & pygame.FULLSCREEN:
|
||||||
self.flags &= ~pygame.FULLSCREEN
|
self.flags &= ~pygame.FULLSCREEN
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
source: 'data/images/button.png'
|
source: 'data/images/button.png'
|
||||||
Label:
|
Label:
|
||||||
text: root.text
|
text: root.text
|
||||||
font_size: 18
|
font_size: 12
|
||||||
canvas:
|
canvas:
|
||||||
Color:
|
Color:
|
||||||
rgb: (1, 1, 1)
|
rgb: (1, 1, 1)
|
||||||
|
|
Loading…
Reference in New Issue