SecondHalfGames / yakui

yakui is a declarative Rust UI library for games
Apache License 2.0
237 stars 21 forks source link

texture rewrite #46

Closed sanbox-irl closed 1 year ago

sanbox-irl commented 2 years ago

This refactors TextureId creation in Yakui, so that Yakui entirely relies upon the host renderer for texture id creation.

Here is the current workflow:

First, when users create yakui::State, they must provide a texture reservation function. This isn't terribly elegant, and i have some thoughts to allow users to skip this stage, but that's how we start things right now. This doesn't mean users need to uplaod textures (though they can, and return a variant of an enum to signify that they have), but it does mean that users need to reserve a texture id. You can see in yakui_wgpu how this may be trivially implemented in that scheme. In my own game engine, I just use slabs id reservation system with an Arc'd texture manager.

Inside yakui, when a widget needs a new texture (for example, very quickly the text renderer needs to allocate its atlas), it asks for an ID. yakui_wgpu doesn't upload textures when its asked to reserve the ID, so it only reserves the ID and then later will get a TextureDelta::Add event, which is when it actually uploads the texture.

Finally, calls outputs textures which the renderer at this point knows it always is aware of.

--

The big shortcoming rn is that this loaded function can be difficult for ~some~ users to write, but at least for me, this is not hard. I experimented with yakui keeping an internal id space (which it can allocate to freely), and an external id space, but (unlike egui which does this) we only use one pass to paint and generate our IDs, so we actually have already generated our PaintCall before we have an ID in user space. The only solution if we maintain that design is to later take our PaintCall (which has "InternalId" in it) and transmogrify it into ExternalPaintCall (with "external id" in it). Either we do that, or the user does that, but either way, there's a big lookup stage involved for every paint call.

This also encouraged me to rewrite the GlyphCache. I renamed it LateBindingGlyphCache and made it the default -- moreover, I made it into a trait object, which allows me to write a glyph cache as a user which already has all the glyphs etched onto it, and where every location is known. That's convenient to me, since I do my font atlas creation offline, and don't want to waste the effort of making it several times! I didn't make that yet, since more font work is needed before then. However, doing this work also helped the default cause tremendously -- we're not quite there yet, but LateBindingGlyphCache is very well set up to have more than one texture in its cache.

--

How do we get rid of requiring a loader function?

I suspect the simplest option is for us to provide a default function, and allow users to override that function as they wish (and they will wish! which is why I haven't done it here), probably being one where we assign to numbers from u64 backwards. This also leads us to wonder about Internal vs. External ids, but see the sections above where I ran into pain points there.

--

Okay, that's mostly what I did! Let me know if you have any questions or concerns

sanbox-irl commented 2 years ago

ahh there's some docs here which will need to be updated, but it's making its way there

sanbox-irl commented 1 year ago

gonna go ahead and close this guy!