Age | Commit message (Collapse) | Author |
|
This adds an api for maintaining a list of pre-render module
contexts on-stream which will be rendered via til_stream_render()
before rendering hte main module context on the stream that's
been set via til_stream_set_module_context().
til_stream_add_pre_module_context()
til_stream_del_pre_module_context()
are the new functions, no references are taken for now (but
comments note the possibility of adding that)
This is just a preparatory commit, no real functional difference.
|
|
til_stream_render() bumps the frame counter, so there's no more
need for a discrete frame start mechanism.
|
|
This introduces a concept of a stream's module context, which is
used to render the stream via til_stream_render().
The context is set using til_stream_set_module_context(), but at
this time no reference is taken - it just puts the context into
the stream for use by the render calls. The caller is
responsible for ensuring it persist as long as the stream uses
it.
This is a preparatory commit for implementing pre/post render
module contexts that get hooked into a stream. The impetus for
this is supporting background music via modules like playit,
without requiring stuff like rkt scenes to always include the bgm
context in the scene's module context heirarchy.
Nothing is functionally different here, the commit only adds the
new interfaces for setting the context and rendering via stream
instead of til_module_render() of the context you'd now set on
the stream.
|
|
Until now everything interested in audio just used a plain getter
on the stream to get at the context.
But with how things work currently, audio is always left in a
paused state until explicitly unpaused. This works fine with
modules/rkt, which manages pause/unpause explicitly. When
there's nothing like modules/rkt in charge though, the audio just
sits stuck paused. Meaning if you do some simple thing like
--module=playit, it won't ever get unpaused.
With this commit, something like modules/rkt takes control of the
stream's audio context, in a way that prevents anything else from
taking control of the same context on the same stream. That
enables having main try take control of the audio context after
creating the module contexts, then in the rendering thread ensure
the audio is unpaused if main is in control of the audio context
and something's queueing audio frames.
For now there's no mechanism for releasing control of the audio
context. It doesn't seem appropriate to make this more elaborate
than necessary. There's basically just two use cases WRT audio:
1. Something like rkt, which takes control once for the process
and stays in control until process exit.
2. Something far simpler where nothing's taking control like
rkt, and main just needs to get things unpaused when
needed because something's generating audio frames.
|
|
Preliminary means of making the audio context available to
modules.
|
|
There are no users of this, it can come back if needed.
|
|
In the case of clones there's multiple identical contexts at the
same path, putting their taps on the same pipe.
Since these clones likely exist for the purpose of parallel
rendering, chaotically scheduled, it's arbitrary which of the
clones will render first in a given frame. So it would just be a
matter of luck if the first to render was also the driving tap
established at context create time. Until the driving context
rendered, the non-driving contexts would render potentially stale
values from their taps, carried from the last frame. Then the
driving tap's context would render, advancing all taps it drove,
and it plus any subsequent renders sharing the pipe in the frame
would have the new tapped values, producing randomly inconsistent
results.
You can easily cause this today with checkers::fill_module=plato,
since plato has some taps for the orbit/spin rates, and checkers
uses context clones for parallel fill_module= rendering.
Note this is orthogonal to cases like modules/rkt, where hooks
are used to steal ownership of the pipes when they're created.
rkt also becomes the driver of the taps from its ctor hook, since
it bridges Rocket data to the taps, and this commit does
potentially interfere with that by introducing a per-frame
competition to determine driver. But since rkt is the top-level
rendering module when its in use, calling into the per-scene
module contexts when appropriate, it's guaranteed to always win
the race as long as it maintains its taps using Rocket-provided
values before rendering the scene - which is the way it works
today.
|
|
This needs the stream pulled in so the signature changed to
accomodate that.
Also modules/rkt was calling this conditionally which won't be
compatible with the per-frame driver race model, so always call
it to maintain the driving position every frame.
|
|
This is needed for determining which tap's first on a given pipe
per-frame.
|
|
This adds til_stream_start_frame() which advances a per-stream
counter.
Subsequent commits will make use of this for implementing a
pre-frame competition for pipe ownership.
|
|
It's expected that all mondule contexts will have been cleaned up
by the final gc in til_stream_free(). If the gc returns a
non-zero skipped count, it suggests there's a program bug leaking
registered contexts.
|
|
Preparatory commit for making til_stream_free() assert on leaked
module contexts.
|
|
Leaving the larger n_module_contexts on reuse creates the
potential for a NULL ptr dereference in places like gc which
check the refcount of each countext in the set, without testing
for NULL.
Rather than making everything check for NULL, just shrink the
count when it gets reused in a smaller case. This whole reuse
thing is kind of a silly little optimization anyways, and will be
revisited when cloning either happens or the sets become
deprecated.
For now just prevent creating situations that can crash.
|
|
Plug a small leak
|
|
Technically this was leaking contexts but it's only done on the
road to process exit currently anyways.
|
|
The tap->ptr indirection must always be updated even when we're
the driver on a fresh pipe created by us.
This bug only triggers when the caller's tap was already
on-stream, without being the driver, and the driving tap/context
has since exited the stream, untapping itself which removed the
associated pipes - even the ones it didn't own but was driving.
In that scenario when pipe is created by the previously
non-driving tap on its first update since the driver exited, its
tap->ptr still points at the stale driver. This manifested as a
UAF bug in that case.
The fix is a simple matter of always updating tap->ptr to reflect
the driving tap.
This also fixes the real bug causing 468c78e3 to crash, such that
the syncronous gc performed there shouldn't really be necessary
to prevent crashing. It was the awkward overlapping existence of
contexts at the same path which produced the triggering lifecycle
pattern WRT driving taps at that path.
|
|
Due to how meta-modules reference other modules from within their
context, they pin the related refcounts until their gc is
performed.
So repeat the gc passess until nothing gets freed, to gc those
recursive references immediately.
Fortunately this isn't intended to be done at perf-sensitive
times...
|
|
til_stream_register_module_contexts() reuses the container when
c->n_contexts is sufficiently large, and deliberately leaves
c->n_contexts as-is to potentially accomodate a larger set in the
future. The excess was NULLified in prepping for reuse so it
should be fine, just add a blurb about it so it doesn't look like
an oversight.
|
|
This stows the duration (in ticks (which are ms for now)) of a
given module context's most recent, as well as tracking the max,
in til_module_context_t.
For now it's also added to --print-module-contexts output, but
this is still rather primitive and nearly inscrutible in
practice... that output is a flickery and unsorted mess during
playback. But this is just a start.
Ticks may need to move up to microseconds if it'll also be the
units for measuring timings. Right now things are slow enough
that the low-hanging fruit stand out as multiple if not dozens of
milliseconds so it's still useful for now.
|
|
rkt needs a way to signal the end of a sequence, this will
probably get more work in the future but something simple is fine
for now
|
|
I thought the build was already using -Wall but that seems to not
be the case, maybe got lost somewhere along the line or messed up
in configure.ac
After forcing a build with -Wall -Werror, these showed up.
Fixed up in the obvious way, nothing too scary.
|
|
In order for modules like rkt to be able to do integrated
transitions, there must be a way for discovering existing module
contexts by path and using them for rendering in new
compositions.
This is a first stab at something along those lines. The whole
multiple contexts at the same path pattern has been partially
handled in this implementation, but I think it will just be going
away and checkers::fill_module refactored to not do that.
|
|
When all the stream encapsulated were pipes/taps, naming was less
precise. With module contexts in the process of being registered
in the stream, there's a need to distinguish things more.
This is a largely mechanical naming change...
|
|
This is already in the header
|
|
Mechanical rename in preparation for context buckets for hashing
all contexts existing on a stream.
|
|
There needs to be a way for a meta module like rocket to take
ownership of pipes immediately upon instantiation. Since the
pipes are created on demand as they become tapped by the modules
using htem, the simplest way to do this is to register some
callbacks with the ability to intercept the pipe creation in
terms of ownership and driving tap control etc.
This commit forms a minimal implementation of that, with the
ability to have a single intercepter hooked into a given stream.
It's a first-come-first-served situation, but that should suffice
for now since the rocket meta module would be the entrypoint for
such constructions. It then calls into another module to produce
on the stream, after it'll already have its hooks registered.
There might be a need for stacking hooks to let multiple modules
control pipes. GNU Rocket for instance only deals with
floats/doubles, and doesn't make it particularly easy to work on
higher order concepts like say orbiting a vector around a point
spatially. It might make sense to allow compositing of editors
where there's rocket controlling the simple floats, and another
doing dimensional/spatial stuff, with separate stacked meta
modules accomodating those editors. But that's putting the cart
before the horse, let's do the stupid simple thing for now and
see what this is like.
|
|
The driving tap's owner and pipe's owner are decoupled. When
tearing down an owner from a stream, any pipes its taps are
driving should also just go away. Otherwise its taps could
linger on pipes it doesn't own, which would be a UAF bug.
If the pipe is still needed, it'll just get recreated by another
tap. So there's a small perf hit, but this shouldn't be a
continuos kind of occurrence.
|
|
Some clarifications
|
|
|
|
When a driving tap becomes inactive, til_stream_tap() should be
able to notice and replace the driver.
An example driving tap becoming inactive would be a GNU Rocket
track that once had keys in it, but then had them all deleted.
This should set the inactive flag so the tap's automation can
take over. This gives the user at the Rocket editor the ability
to both take over from the tap automation and surrender control
back, by populating vs. emptying the respective track.
|
|
In order to implement something like a rocket module there needs
to be a way to iterate the pipes in the stream, and take
owernship of them when not already owned by rocket.
The way rocket's API works is you lookup tracks by name at
runtime. The rocket module will be a meta module that calls into
another module for rendering, arbitrarily configured via a rocket
setting a la checkers::fill_module.
So it won't be until the underlying modules do some rendering
that their taps get their respective pipes established in the
stream. Then the rocket module can look at all the pipes and for
any it doesn't own yet, it can get the tracks for those names and
take ownership while stowing the track handle in owner_foo for
the pipe.
While iterating all the pipes, the pipes already owned will have
the tracks readily available which can produce the values to
stick in the tap.
Something like that anyways, the til_stream_t api changes in this
commit are all preparatory for a rocket module.
|
|
Just clarify some verbiage, and actually assert type+n_elems
match. Note mismatch also fallsthrough to an -EINVAL just in
case asserts() have been compiled out (-DNDEBUG).
|
|
It seems likely that pipe owners will need not only a way to
differentiate themselves via the owner pointer, but also
somewhere to register a pipe-specific reference.
There probably needs to be a result pointer added for storing the
owner_foo when the owner taps, so the owner can make use of it.
|
|
Just some banal paperwork...
|
|
Until now there's just been a forward declared type for
til_fb_fragment_t.stream's type, and it's been completely unused.
The purpose of the stream is to provide a continous inter-frame
object where information can be stored pertaining to the stream
of frames.
Right now, that information is limited to emergent "pipes" formed
by using taps against a given stream. Taps at new paths in the
stream become added as pipes for those paths, with the
responsible tap hooked in as the driving tap. Taps at existing
paths become diverted to the driving taps, enabling potential for
external drivers for tapped variables.
This commit only adds the implementation, nothing is actually
using it yet.
|