Closed einarf closed 6 years ago
Slightly OT: I wonder if this is a use for async / await ?
Not bad input.
I thought about that as well to speed up loading making each loading routine async through for example aiofiles
. For the challenge describe above I don't think asyncio has any solution that wouldn't massively complicating things. I might to wrong, so feel free to correct me.
I've mainly been using asynchio with simpler problems reducing blocking time in a program or request by making IO async (files, http requests and whatnot), or in situations where I needed better control over long running operations yielding back control to the event loop on intervals + timeout support.
New branch for poking at things https://github.com/Contraz/demosys-py/tree/resource-loading
Looks like the reasonable way to go is to load the resources directly instead of scheduling loading to a separate referred loading stage. The downside is that we lose track of what resources should be loaded not being able to track loading progress feedback.
This can be solved by providing functionality to generate a resources.py
file that would contain all the loaded resources during the run time of the project.
We remove the get()
method for the more explicit load()
method.
shaders.load("shader.glsl")
texture.load("texture.png")
We still keep track of all loaded resources in each respective pool in order to avoid loading a resource multiple times. This way we can do a pre-load stage with resources.py
before initializing effects.
Another great advantage is that we no longer really need to make wrappers over moderngl types. Making people using moderngl objects directly is better for everyone and encourage us to contribute to moderngl features and docs even more.
1.0.5 can contain the loading change 2.0.0 should remove moderngl wrappers
Merged #37
Currently the system is designed to schedule resources for loading returning an empty objects. This scheduling typically happens in
Effect.__init__
and actions after loading happens inpost_load()
.For effects this is working perfectly fine, but built in features such as the text writer and mesh shaders for scenes makes this a bit more awkward. We don't know when the user instantiate these objects, before or after resource loading.
TextRenderer2D
is a good example where a user might need to dynamically create new instances during the programs execution. This issue was flagged by a user who dynamically generate labels for network nodes.The solution so far has been to register resources at the module level so they are injected on import.
The next next problem is that
TextWriter2D
also need to do initialization after resources are loaded, so it registers a callback topost_load
. If the class was instantiated after resource loading, thepost_load
callback would not happen.This was solved by immediately triggering the callback if resources were done loading because we know they were loaded since they where injected at import. Effects can also subscribe to this event, so we created a race condition: What
post_load
function would be called first? A priority system for callbacks where created to solve this. System files would use 100 while effect callbacks would use 0.This gets even more confusing when extending classes registering callbacks in
__init__
. Both initializers should register a callback causing it to trigger twice and often before the child class is ready. Something should be figured out here.An additional problem is that most opengl objects fetch the moderngl context in
__init__
. If for example an empty texture object is created before context creation we'll trigger an error, something that is completely unnecessary. We should not store the modernglctx
variable on the instances itself. They should be properties fetching the context from the window itself.This way we can create empty resource objects at any time and we don't have to care about import order.
Conclusion
I'm left with the feeling that resource loading issues can cause a lot of people to find the demosys hard to use. Most people will be fine when sticking to effects, but anything outside the ordinary can cause a lot of confusion because its designed to pre load all data before the draw loop starts. This is also not necessarily what everyone wants. It makes sense for what this package was originally made for, but doesn't lend itself well to more general purposes.
My thoughts so far is to allow resource loading even after the loading stage, but it will trigger a warning message. Each resource pool class will have a flag set when loading is done. When a resource is requested with
get(..)
after the loading stage, we immediately load and return the object followed by a warning message. This can also possibly be configurable insettings
having the most liberal policy by default.Also, finders currently returns the first matching resource found. This should be changed to the last resource found. Otherwise it will be impossible to override system resources and it matches how other other finder systems deal with resource overriding.
In addition we should use probably python
Path
objects internally.The resource system also needs proper tests and documentation.