Source code for arcade.gl.query

from typing import TYPE_CHECKING
import weakref

from pyglet import gl

if TYPE_CHECKING:
    from arcade.gl import Context


[docs]class Query: """ A query object to perform low level measurements of OpenGL rendering calls. The best way to create a program instance is through :py:meth:`arcade.gl.Context.query` Example usage:: query = ctx.query() with query: geometry.render(..) print('samples_passed:', query.samples_passed) print('time_elapsed:', query.time_elapsed) print('primitives_generated:', query.primitives_generated) """ __slots__ = ( "_ctx", "_glo_samples_passed", "_glo_time_elapsed", "_glo_primitives_generated", "__weakref__", "_samples_enabled", "_time_enabled", "_primitives_enabled", "_samples", "_time", "_primitives", ) def __init__(self, ctx: "Context", samples=True, time=True, primitives=True): # TODO: Support querying a subset of these queries (faster) # TODO: Evalute of this query should be included # gl.GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN # gl.GL_ANY_SAMPLES_PASSED self._ctx = ctx self._samples_enabled = samples self._time_enabled = time self._primitives_enabled = primitives self._samples = 0 self._time = 0 self._primitives = 0 glos = [] self._glo_samples_passed = glo_samples_passed = gl.GLuint() if self._samples_enabled: gl.glGenQueries(1, self._glo_samples_passed) glos.append(glo_samples_passed) self._glo_time_elapsed = glo_time_elapsed = gl.GLuint() if self._time_enabled: gl.glGenQueries(1, self._glo_time_elapsed) glos.append(glo_time_elapsed) self._glo_primitives_generated = glo_primitives_generated = gl.GLuint() if self._primitives_enabled: gl.glGenQueries(1, self._glo_primitives_generated) glos.append(glo_primitives_generated) self.ctx.stats.incr("query") if self._ctx.gc_mode == "auto": weakref.finalize(self, Query.delete_glo, self._ctx, glos) def __del__(self): if self._ctx.gc_mode == "context_gc": self._ctx.objects.append(self) @property def ctx(self) -> "Context": """ The context this query object belongs to :type: :py:class:`arcade.gl.Context` """ return self._ctx @property def samples_passed(self) -> int: """ How many samples was written. These are per component (RGBA) :type: int """ return self._samples @property def time_elapsed(self) -> int: """ The time elapsed in nanoseconds :type: int """ return self._time @property def primitives_generated(self) -> int: """ How many primitives a vertex or geometry shader processed. When using a geometry shader this only counts the primitives actually emitted. :type: int """ return self._primitives def __enter__(self): if self._samples_enabled: gl.glBeginQuery(gl.GL_SAMPLES_PASSED, self._glo_samples_passed) if self._time_enabled: gl.glBeginQuery(gl.GL_TIME_ELAPSED, self._glo_time_elapsed) if self._primitives_enabled: gl.glBeginQuery(gl.GL_PRIMITIVES_GENERATED, self._glo_primitives_generated) def __exit__(self, exc_type, exc_val, exc_tb): if self._samples_enabled: gl.glEndQuery(gl.GL_SAMPLES_PASSED) value = gl.GLint() gl.glGetQueryObjectiv(self._glo_samples_passed, gl.GL_QUERY_RESULT, value) self._samples = value.value if self._time_enabled: gl.glEndQuery(gl.GL_TIME_ELAPSED) value = gl.GLint() gl.glGetQueryObjectiv(self._glo_time_elapsed, gl.GL_QUERY_RESULT, value) self._time = value.value if self._primitives_enabled: gl.glEndQuery(gl.GL_PRIMITIVES_GENERATED) value = gl.GLint() gl.glGetQueryObjectiv(self._glo_primitives_generated, gl.GL_QUERY_RESULT, value) self._primitives = value.value
[docs] def delete(self): """ Destroy the underlying OpenGL resource. Don't use this unless you know exactly what you are doing. """ Query.delete_glo( self._ctx, [ self._glo_samples_passed, self._glo_time_elapsed, self._glo_primitives_generated, ] )
[docs] @staticmethod def delete_glo(ctx, glos) -> None: """ Delete this query object. This is automatically called when the object is garbage collected. """ if gl.current_context is None: return for glo in glos: gl.glDeleteQueries(1, glo) ctx.stats.decr("query")