To give quick visibility to the things going on relating to clipping and
culling this adds some more CLIPPING debug notes to clutter-actor.c and
clutter-stage.c
This implements a variation of frustum culling whereby we convert screen
space clip rectangles into eye space mini-frustums so that we don't have
to repeatedly transform actor paint-volumes all the way into screen
coordinates to perform culling, we just have to apply the modelview
transform and then determine each points distance from the planes that
make up the clip frustum.
By avoiding the projective transform, perspective divide and viewport
scale for each point culled this makes culling much cheaper.
This simplifies the implementation of the ClutterStage apply_transform
vfunc by using the new cogl_matrix_view_2d_in_perspective utility API
which can setup up a view transform for a given perspective so that a
cross section of the view frustum at an arbitrary depth can be mapped
directly to 2D stage coordinates with (0,0) at the top left.
Firstly Clutter shouldn't be using OpenGL directly so this needed
changing but also conceptually it doesn't make sense for
clutter_stage_read_pixels to validate the requested area to read against
the viewport it would make more sense to compare against the window
size. Finally checking that the width of the area is less than the
viewport or window width without considering the x isn't enough to know
if the area extends outside the windows bounds. (same for the height)
This patch removes the validation of the read area from
clutter_stage_read_pixels and instead we now simply rely on the
semantics of cogl_read_pixels for reading areas outside the window
bounds.
OpenGL < 4.0 only supports integer based viewports and internally we
have a mixture of code using floats and integers for viewports. This
patch switches all viewports throughout clutter and cogl to be
represented using floats considering that in the future we may want to
take advantage of floating point viewports with modern hardware/drivers.
Once upon a time, the land of Clutter had a stage singleton. It was
created automatically at initialization time and stayed around even
after the main loop was terminated. The singleton was content in
being all there was. There also was a global API to handle the
configuration of the stage singleton that would affect the behaviour
on other classes, signals and properties.
Then, an evil wizard came along and locked the stage singleton in his
black tower, and twisted it until it was possible to create new stages.
These new stages were pesky, and didn't have the same semantics of the
singleton: they didn't stay around when closed, or terminate the main
loop on delete events.
The evil wizard also started moving all the stage-related API from the
global context into class-specific methods.
Finally, the evil wizard cast a spell, and the stage singleton was
demoted to creation on demand - and until somebody called the
clutter_stage_get_default() function, the singleton remained in a limbo
of NULL pointers and undefined memory areas.
There was a last bit - literally - of information still held by the
global API; a tiny, little flag that disabled per-actor motion events.
The evil wizard added private accessors for it, and stored it inside the
stage private structure, in preparation for a deprecation that would
come in a future development cycle.
The evil wizard looked down upon the land of Clutter from the height of
his black tower; the lay of the land had been reshaped into a crucible
of potential, and the last dregs of the original force of creation were
either molted into new, useful shapes, or blasted away by the sheer fury
of his will.
All was good.
The _clutter_do_redraw() function should really be moved inside
ClutterStage, since all it does is calling private stage and
backend functions. This also allows us to change a long-standing
issue with a global fps counter for all stages, instead of a\
per-stage one.
Since we realize on creation we need to unrealize on destruction. This
makes sure that the ClutterStageWindow implementation can tear down any
resource set up during the realization phase.
http://bugzilla.clutter-project.org/show_bug.cgi?id=2559
The GQueue that stores the global events queue is handled all over the
place:
• the structure is created in _clutter_backend_init_events();
• the queue is handled in clutter-event.c, clutter-stage.c and
clutter-backend.c;
• ClutterStage::dispose cleans up the events associated with
the stage being destroyed;
• the queue is destroyed in ClutterBackend::dispose.
Since we need to have access to it in different places we cannot put it
inside ClutterBackendPrivate, hence it should stay in ClutterMainContext;
but we should still manage it from just one place - preferably by the
ClutterEvent API only.
Clutter should just require that the windowing system used by a backend
adds a device to the stage when the device enters, and removes it from
the stage when the device leaves; with this information, we can
synthesize every crossing event and update the device state without
other intervention from the backend-specific code.
The generation of additional crossing events for actors that are
covering the stage at the coordinates of the crossing event should be
delegated to the event processing code.
The x11 and win32 backends need to be modified to relay the enter and
leave events from the windowing system.
Allow the developer to set whether the Stage should receive key focus
when mapped. The implementation is fully backend-dependent. The default
value is TRUE because that's what we've been expecting so far.
http://bugzilla.clutter-project.org/show_bug.cgi?id=2500
If an actor is (unfortunately) queuing a relayout in relayout, you would
end up with (ClutterActor*)stage->needs_allocation set to TRUE and
stage->relayout_pending set to TRUE. But if then in the same cycle, an
actor calls clutter_actor_get_allocation_box, that will trigger another
(recursive) _clutter_stage_maybe_relayout, which will wrongly reset the
relayout pending to FALSE, while not actually performing a new relayout
because of the re-entrancy protection.
http://bugzilla.clutter-project.org/show_bug.cgi?id=2503
The stage has a dirty flag to record whenever the viewport and
projection matrices need to be flushed. However after flushing these
the flags were never cleared so it would always redundantly update the
state.
http://bugzilla.clutter-project.org/show_bug.cgi?id=2480
In clutter_stage_real_queue_redraw we were checking to see if the
backend will ignore any subsequent redraw_clip so we can avoid the cost
of projecting the paint-volume of an actor into stage coordinates, but
we weren't ensuring that a full redraw would be queued instead we just
bailed out immediately. This makes sure to call
_clutter_stage_window_add_redraw_clip (stage_window, NULL) in this case
to make sure the backend will do an un-clipped redraw.
Previously we were leaving it up to the default implementation of
get_paint_volume in ClutterGroup to handle the stage by determining the
bounding box of all contained children. This isn't the true bounding box
of the stage though since the stage is responsible for clearing the
entire framebuffer at the start of the frame. This adds a
get_paint_volume implementation for ClutterStage which simply returns
False which means Clutter has to assume it covers everything.
Once an actor had _clutter_stage_queue_redraw_entry_invalidate()
called on it once, then priv->queue_redraw_entry would point to
an entry with entry->actor NULL. _clutter_stage_queue_actor_redraw()
doesn't handle this case and no further redraws would be queued.
To fix this, NULL out priv->queue_redraw_entry() and then make sure
we free the invalidated entry in
_clutter_stage_maybe_finish_queue_redraws() just as we do for
still valid entries.
http://bugzilla.clutter-project.org/show_bug.cgi?id=2389
* private-cleanup:
Add copyright notices
Clean up clutter-private.h/6
Clean up clutter-private.h/5
Clean up clutter-private.h/4
Clean up clutter-private.h/3
Clean up clutter-private.h/2
Clean up clutter-private.h/1
When handling an allocation on the stage, Clutter uses the oppurtunity
to inform Cogl of the new size of the framebuffer so that it can
handle the viewport correctly. It queries the size of the window
implementation using a backend virtual function. However it was doing
this before letting the backend handle the allocation so on Win32 it
would end up using the previous framebuffer size. This wasn't
affecting the X11 backend because in that case the resizes are
asynchronous so setting the stage size causes one allocation which
ends up sending a window size request. Eventually a ConfigureNotify is
received which causes the size of the stage to be set again and
another allocation is fired meaning the framebuffer size will be set
again this time with the correct size. In Win32 the resizes are
synchronous so we don't have this second allocation.
Move the private Backend API to a separate header.
This also allows us to finally move the class vtable and instance
structure to a separate file and plug the visibility hole that left
the Backend class bare for everyone to poke into.
In the case that an unclipped redraw of an actor is queued after a
clipped we should update any existing ClutterStageQueueRedrawEntry
so entry->has_clip = FALSE and free the previous clip.
The clutter stage has a list of entries of actors waiting to be redrawn.
Each entry has a "clip" ClutterPaintVolume member which represents which
how much of the actor needs to get redrawn. It's possible for there to
be no clip associated with the entry. In this case, the clip member is
invalid, the has_clip member should be set to false.
This commit fixes a bug where the has_clip member was not being
initially, explicitly set to false for new entries, and not being
explicitly set to false in the event the clip associated with the entry
is freed.
http://bugzilla.clutter-project.org/show_bug.cgi?id=2350
Signed-off-by: Robert Bragg <robert@linux.intel.com>
During destruction, the StageWindow implementation associated to a Stage
might be NULL. We need to add more checks for a) the IN_DESTRUCTION flag
being set and b) the StageWindow pointer being NULL. Otherwise, we will
get warnings during the destruction of the Stage.
Instead of immediately, recursively emitting the "queue-redraw" signal
when clutter_actor_queue_redraw is called we now defer this process
until all stage updates are complete. This allows us to aggregate
repeated _queue_redraw requests for the same actor avoiding redundant
paint volume transformations. By deferring we also increase the
likelihood that the actor will have a valid paint volume since it will
have an up to date allocation; this in turn means we will more often be
able to automatically queue clipped redraws which can have a big impact
on performance.
Here's an outline of the actor queue redraw mechanism:
The process starts in clutter_actor_queue_redraw or
_clutter_actor_queue_redraw_with_clip.
These functions queue an entry in a list associated with the stage which
is a list of actors that queued a redraw while updating the timelines,
performing layouting and processing other mainloop sources before the
next paint starts.
We aim to minimize the processing done at this point because there is a
good chance other events will happen while updating the scenegraph that
would invalidate any expensive work we might otherwise try to do here.
For example we don't try and resolve the screen space bounding box of an
actor at this stage so as to minimize how much of the screen redraw
because it's possible something else will happen which will force a full
redraw anyway.
When all updates are complete and we come to paint the stage (see
_clutter_stage_do_update) then we iterate this list and actually emit
the "queue-redraw" signals for each of the listed actors which will
bubble up to the stage for each actor and at that point we will
transform the actors paint volume into screen coordinates to determine
the clip region for what needs to be redrawn in the next paint.
Note: actors are allowed to queue a redraw in reseponse to a
queue-redraw signal so we repeat the processing of the list until it
remains empty. An example of when this happens is for Clone actors or
clutter_texture_new_from_actor actors which need to queue a redraw if
their source queues a redraw.
In clutter_stage_allocate at the end we were always querying the latest
allocation set and using the geometry to assert the viewport and then
kicking a full redraw. These only need to be done when the allocation
really changes, so we now read the previous allocation at the start of
the function and compare at the end. This was stopping clipped redraws
from being used in a lot of cases.
Since clutter_actor_queue_redraw now automatically clips redraws
according to the paint volume of the actor we have to be careful to
ensure we really force a full redraw when the stage is allocated a new
size or the stage viewport changes.
This uses actor paint volumes to perform culling during
clutter_actor_paint.
When performing a clipped redraw (because only a few localized actors
changed) then as we traverse the scenegraph painting the actors we can
now ignore actors that don't intersect the clip region. Early testing
shows this can have a big performance benefit; e.g. 100% fps improvement
for test-state with culling enabled and we hope that there are even much
more compelling examples than that in the real world,
Most Clutter applications are 2Dish interfaces and have quite a lot of
actors that get continuously painted when anything is animated. The
dynamic actors are often localized to an area of user focus though so
with culling we can completely avoid painting any of the static actors
outside the current clip region.
Obviously the cost of culling has to be offset against the cost of
painting to determine if it's a win, but our (limited) testing suggests
it should be a win for most applications.
Note: we hope we will be able to also bring another performance bump
from culling with another iteration - hopefully in the 1.6 cycle - to
avoid doing the culling in screen space and instead do it in the stage's
model space. This will hopefully let us minimize the cost of
transforming the actor volumes for culling.
This adds a private ->relayout_pending boolean similar in spirit to
redraw_pending. This will allow us to queue a relayout without
implicitly queueing a redraw; instead we can depend on the actions
of a relayout to queue any necessary redraw.
There is an internal _clutter_actor_queue_redraw_with_clip API that gets
used for texture-from-pixmap to minimize what we redraw in response to
Damage events. It was previously working in terms of a ClutterActorBox
but it has now been changed so an actor can queue a redraw of volume
instead.
The plan is that clutter_actor_queue_redraw will start to transparently
use _clutter_actor_queue_redraw_with_clip when it can determine a paint
volume for the actor.
This is a fairly extensive second pass at exposing paint volumes for
actors.
The API has changed to allow clutter_actor_get_paint_volume to fail
since there are times - such as when an actor isn't a descendent of the
stage - when the volume can't be determined. Another example is when
something has connected to the "paint" signal of the actor and we simply
have no way of knowing what might be drawn in that handler.
The API has also be changed to return a const ClutterPaintVolume pointer
(transfer none) so we can avoid having to dynamically allocate the
volumes in the most common/performance critical code paths. Profiling was
showing the slice allocation of volumes taking about 1% of an apps time,
for some fairly basic tests. Most volumes can now simply be allocated on
the stack; for clutter_actor_get_paint_volume we return a pointer to
&priv->paint_volume and if we need a more dynamic allocation there is
now a _clutter_stage_paint_volume_stack_allocate() mechanism which lets
us allocate data which expires at the start of the next frame.
The API has been extended to make it easier to implement
get_paint_volume for containers by using
clutter_actor_get_transformed_paint_volume and
clutter_paint_volume_union. The first allows you to query the paint
volume of a child but transformed into parent actor coordinates. The
second lets you combine volumes together so you can union all the
volumes for a container's children and report that as the container's
own volume.
The representation of paint volumes has been updated to consider that
2D actors are the most common.
The effect apis, clutter-texture and clutter-group have been update
accordingly.
This is all internal, so we shouldn't need it; unfortunately, it seems
we're passing invalid data internally, so for the time being catching
inconsistencies should at least emit a warning for us to backtrace.