Scenic v0.10.2 Scenic.Cache.Dynamic.Texture View Source
In memory cache for static dynamic Image assets.
In graphics-speak, an image that is being drawn to the screen is a "Texture".
Unlike Scenic.Cache.Static.Texture
, this module assumes that the pixels to be rendered
in the image are being generated on the at runtime and change, perhaps rapidly.
The primary example is capturing an image off of a camera. This data is generated on the fly and needs to be presented to the video card with as little encoding being done as possible.
So instead of using a hash of the data as a key (which doesn't make sense given that the data is changing...), you pick a unique string to represent the stream of data. It is up to you to make sure the names you choose are unique in your app.
The only data the Scenic.Cache.Dynamic.Texture
accepts is a raw pixel map. Please use the Scenic.Utilities.Texture
module to help build and manage these data sets.
Goals
Given this situation, the dynamic Cache module has multiple goals.
- Reuse - assets used by multiple scenes should only be stored in memory once
- Copy time - assets are stored in ETS, so they don't need to be copied as they are used
- Pub/Sub - Consumers of static assets (drivers...) should be notified when an asset is loaded or changed. They should not poll the system.
Scope
When a texture term is loaded into the cache, it is assigned a scope.
The scope is used to
determine how long to hold the asset in memory before it is unloaded. Scope is either
the atom :global
, or a pid
.
The typical flow is that a scene will load a font into the cache. A scope is automatically defined that tracks the asset against the pid of the scene that loaded it. When the scene is closed, the scope becomes empty and the asset is unloaded.
If, while that scene is loaded, another scene (or any process...) attempts to load the same asset into the cache, a second scope is added and the duplicate load is skipped. When the first scene closes, the asset stays in memory as long as the second scope remains valid.
When a scene closes, it's scope stays valid for a short time in order to give the next scene a chance to load its assets (or claim a scope) and possibly re-use the already loaded assets.
This is also useful in the event of a scene crashing and being restarted. The delay in unloading the scope means that the replacement scene will use already loaded assets instead of loading the same files again for no real benefit.
When you load assets you can alternately provide your own scope instead of taking the
default, which is your processes pid. If you provide :global
, then the asset will
stay in memory until you explicitly release it.
Pub/Sub
Drivers (or any process...) listen to the font Cache via a simple pub/sub api.
Because the graph, may be computed during compile time and pushed at some other time than the assets are loaded, the drivers need to know when the assets become available.
Whenever any asset is loaded into the cache, messages are sent to any subscribing processes along with the affected keys. This allows them to react in a loosely-coupled way to how the assets are managed in your scene.
Link to this section Summary
Functions
Add a scope to an existing texture in the cache
Tests if a key is claimed by the given scope
Retrieve a texture from the cache and wrap it in an {:ok, _}
tuple
Retrieve a texture from the Cache
Retrieve a texture from the Cache and raise an error if it doesn't exist
Returns a list of keys claimed by the given scope
Tests if a key is claimed by any scope
Insert texture into the Cache
Insert a new texture into the Cache
Release a scope claim on an texture
Get the current status of a texture in the cache
Subscribe the calling process to cache messages
Unsubscribe the calling process from cache messages
Link to this section Functions
claim(hash, scope \\ nil)
View Source
claim(
hash :: Scenic.Cache.Base.hash(),
scope :: :global | nil | GenServer.server()
) :: term()
claim( hash :: Scenic.Cache.Base.hash(), scope :: :global | nil | GenServer.server() ) :: term()
Add a scope to an existing texture in the cache.
Claiming an asset in the cache adds a lifetime scope to it. This is essentially a refcount that is bound to a pid.
Returns true
if the item is loaded and the scope is added.
Returns false
if the asset is not loaded into the cache.
claimed?(hash, scope \\ nil)
View Source
claimed?(
hash :: Scenic.Cache.Base.hash(),
scope :: :global | nil | GenServer.server()
) :: true | false
claimed?( hash :: Scenic.Cache.Base.hash(), scope :: :global | nil | GenServer.server() ) :: true | false
Tests if a key is claimed by the given scope.
fetch(hash)
View Source
fetch(hash :: Scenic.Cache.Base.hash()) :: term() | {:error, :not_found}
fetch(hash :: Scenic.Cache.Base.hash()) :: term() | {:error, :not_found}
Retrieve a texture from the cache and wrap it in an {:ok, _}
tuple.
This function ideal if you need to pattern match on the result.
Examples
iex> Elixir.Scenic.Cache.Dynamic.Texture.fetch("missing_hash")
...> {:error, :not_found}
iex> Elixir.Scenic.Cache.Dynamic.Texture.fetch("valid_hash")
...> {:ok, :test_data}
get(hash, default \\ nil)
View Source
get(hash :: Scenic.Cache.Base.hash(), default :: term()) :: term() | nil
get(hash :: Scenic.Cache.Base.hash(), default :: term()) :: term() | nil
Retrieve a texture from the Cache.
If there is no item in the Cache that corresponds to the hash the function will return either nil or the supplied default value
Examples
iex> Elixir.Scenic.Cache.Dynamic.Texture.get("missing_hash")
nil
...> Elixir.Scenic.Cache.Dynamic.Texture.fetch("valid_hash")
{:ok, :test_data}
get!(hash)
View Source
get!(hash :: Scenic.Cache.Base.hash()) :: term()
get!(hash :: Scenic.Cache.Base.hash()) :: term()
Retrieve a texture from the Cache and raise an error if it doesn't exist.
If there is no item in the Cache that corresponds to the hash the function will raise an error.
keys(scope \\ nil)
View Source
keys(scope :: :global | nil | GenServer.server()) :: list()
keys(scope :: :global | nil | GenServer.server()) :: list()
Returns a list of keys claimed by the given scope.
member?(hash)
View Source
member?(hash :: Scenic.Cache.Base.hash()) :: true | false
member?(hash :: Scenic.Cache.Base.hash()) :: true | false
Tests if a key is claimed by any scope.
put(hash, data, scope \\ nil)
View Source
put(
hash :: Scenic.Cache.Base.hash(),
data :: term(),
scope :: :global | nil | GenServer.server()
) :: term()
put( hash :: Scenic.Cache.Base.hash(), data :: term(), scope :: :global | nil | GenServer.server() ) :: term()
Insert texture into the Cache.
If the texture is already in the cache, its data is overwritten.
Parameters:
hash
- term to use as the retrieval key. Typically a hash of the data itself. It will be required to be a hash of the data in the future.data
- term to use as the stored datascope
- Optional scope to track the lifetime of this asset against. Can be:global
but is usually nil, which defaults to the pid of the calling process.
Returns: {:ok, hash}
put_new(hash, data, scope \\ nil)
View Source
put_new(
hash :: Scenic.Cache.Base.hash(),
data :: term(),
scope :: :global | nil | GenServer.server()
) :: term()
put_new( hash :: Scenic.Cache.Base.hash(), data :: term(), scope :: :global | nil | GenServer.server() ) :: term()
Insert a new texture into the Cache.
If the texture is already in the cache, put_new does nothing and just returns {:ok, hash}
Parameters:
hash
- term to use as the retrieval key. Typically a hash of the data itself. It will be required to be a hash of the data in the future.data
- term to use as the stored datascope
- Optional scope to track the lifetime of this asset against. Can be:global
but is usually nil, which defaults to the pid of the calling process.
Returns: {:ok, hash}
release(hash, opts \\ [])
View Source
release(hash :: Scenic.Cache.Base.hash(), opts :: list()) :: :ok
release(hash :: Scenic.Cache.Base.hash(), opts :: list()) :: :ok
Release a scope claim on an texture.
Usually the scope is released automatically when a process shuts down. However if you want to manually clean up, or unload an asset with the :global scope, then you should use release.
Parameters:
key
- the key to release.options
- options list
Options:
scope
- set to:global
to release the global scope.delay
- add a delay of n milliseconds before releasing. This allows starting processes a chance to claim a scope before it is unloaded.
status(hash, scope \\ nil)
View Source
status(
hash :: Scenic.Cache.Base.hash(),
scope :: :global | nil | GenServer.server()
) :: :ok
status( hash :: Scenic.Cache.Base.hash(), scope :: :global | nil | GenServer.server() ) :: :ok
Get the current status of a texture in the cache.
This is used to test if the current process has claimed a scope on an asset.
subscribe(hash, sub_type \\ :all)
View Source
subscribe(
hash :: Scenic.Cache.Base.hash() | :all,
sub_type :: Scenic.Cache.Base.sub_types()
) :: :ok
subscribe( hash :: Scenic.Cache.Base.hash() | :all, sub_type :: Scenic.Cache.Base.sub_types() ) :: :ok
Subscribe the calling process to cache messages.
Parameters
hash
- The hash key of the asset you want to listen to messages about. Pass in :all for messages about all keyssub_type
- Pass in the type of messages you want to unsubscribe from.:put
- sent when assets are put into the cache:delete
- sent when assets are fully unloaded from the cache:claim
- sent when a scope is claimed:release
- sent when a scope is released:all
- all of the above message types
unsubscribe(hash, sub_type \\ :all)
View Source
unsubscribe(
hash :: Scenic.Cache.Base.hash() | :all,
sub_type :: Scenic.Cache.Base.sub_types()
) :: :ok
unsubscribe( hash :: Scenic.Cache.Base.hash() | :all, sub_type :: Scenic.Cache.Base.sub_types() ) :: :ok
Unsubscribe the calling process from cache messages.
Parameters
hash
- The hash key of the asset you want to listen to messages about. Pass in :all for messages about all keyssub_type
- Pass in the type of messages you want to unsubscribe from.:put
- sent when assets are put into the cache:delete
- sent when assets are fully unloaded from the cache:claim
- sent when a scope is claimed:release
- sent when a scope is released:all
- all of the above message types