Skip to content

Optimize ShaderDefs updates #1046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed

Conversation

yrns
Copy link
Contributor

@yrns yrns commented Dec 11, 2020

  • change ShaderDefIterator to iterate every ShaderDef defined or not
  • remove clear system, and only update on change

Related to #63.

yrns added 2 commits December 11, 2020 14:33
- change ShaderDefIterator to iterate every ShaderDef defined or not
- remove clear system, and only update on change
query
.iter_mut()
// (Handle<T>, _) -> (&T, _)
.filter_map(|(h, p)| assets.get(h).map(|a| (a, p)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect this to behave incorrectly when an asset isn't loaded yet. Ex:

  1. begin loading a "shader def" asset and assign its handle to a component
  2. this system runs. the entity with the handle shows up in the query iteration because the handle was changed
  3. it gets filtered out because the asset isn't loaded yet
  4. later, when the asset finishes loading, this system doesn't run on the entity we skipped, because the Changed flag is no longer set.

@cart
Copy link
Member

cart commented Dec 12, 2020

Good call! This is definitely something we should do incrementally. Just one hangup (see comment above)

@yrns
Copy link
Contributor Author

yrns commented Dec 12, 2020

Hmm, this doesn't happen in practice with StandardMaterial or ColorMaterial. You'd have to be deserializing ShaderDefs off disk or something? So I should track empty handles and wait for asset creation events later?

@cart
Copy link
Member

cart commented Dec 12, 2020

Yeah currently its not a huge problem because StandardMaterial and ColorMaterial are generally created "immediately". But as soon as we start loading materials from disk, we'll hit this problem (ex: its probably already a problem when using StandardMaterial handles from a still-loading gltf file)

Your suggested fix is how we should do it. We also need to account for "asset change events". Because the value of the asset could change after loading it.

I think using the general approach we use for meshes is probably the right call:

pub fn mesh_resource_provider_system(

Another Problem

remove clear system, and only update on change

I'm now realizing that this breaks down when the asset "changes". Doing this "incrementally" is actually pretty hard. We would need to:

  1. remove the old defs associated with the asset (which we no longer have the asset value for).
  2. If another asset provided the same def (unlikely but possible), we would need to ensure we don't remove that def because its still valid
  3. insert the new defs

This is do-able, but not with the current design. Rather than merge them all into a single ShaderDefs, maybe it should be a key->value mapping that gets merged when we actually compile the shader. That way we could "replace" the shader defs for a specific context without knowing about the global context (or needing to know the past values for a given context).

@yrns
Copy link
Contributor Author

yrns commented Dec 12, 2020

I tried getting it to happen with the gltf example. The stock impls of ShaderDefs don't care if the sub-assets are loaded, only that the Option/bool is set. I can make a test case where it happens.

So the key is the asset handle? And log warnings if there are collisions when merged?

@cart
Copy link
Member

cart commented Dec 12, 2020

Yeah the key should probably be HandleUntyped so that we can support multiple handle types.

@cart
Copy link
Member

cart commented Dec 12, 2020

I think collisions shouldn't be a problem. Can you see that producing undesirable behavior?

@Moxinilian Moxinilian added C-Performance A change motivated by improving speed, memory usage or compile times A-Rendering Drawing game state to the screen labels Dec 15, 2020
@yrns yrns marked this pull request as draft December 18, 2020 20:19
@yrns
Copy link
Contributor Author

yrns commented Dec 18, 2020

@cart, this works as-is, minus some cleanup (mainly reverting the macro changes). I'm wondering what you think of not tracking entities <-> handles like mesh_resource_provider_system does. I started into it then realized entities were never removed from the hashmap, so I went with this simpler version to start. It's slower but I imagine asset updates are infrequent? Also, does this tracking of shader defs per-component via Uuid look right? Nothing currently uses shader_defs_system.

It seems like there's a case here for a nicer abstraction for systems that deal with changing assets/handles. I see this pattern appears in a few places, but I haven't looked at all of them.

@cart
Copy link
Member

cart commented Dec 30, 2020

Sorry for the delay. Diving back in now!

{
query
.iter_mut()
.map(|(s, p)| (s, (T::TYPE_UUID).into(), p))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the TypeId here instead of TypeUuid? So far we aren't requiring TypeUuid on components and we use TypeId as the unique identifier everywhere else.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Assets do require TypeUuid though)

@cart
Copy link
Member

cart commented Dec 31, 2020

I'm wondering what you think of not tracking entities <-> handles like mesh_resource_provider_system does. I started into it then realized entities were never removed from the hashmap, so I went with this simpler version to start. It's slower but I imagine asset updates are infrequent?

Yeah I think this approach works great. Good call!

Also, does this tracking of shader defs per-component via Uuid look right? Nothing currently uses shader_defs_system.

We should use TypeId here for now (see comment above)

It seems like there's a case here for a nicer abstraction for systems that deal with changing assets/handles. I see this pattern appears in a few places, but I haven't looked at all of them.

Agreed. If we can find a better pattern I'm definitely sold!

@cart
Copy link
Member

cart commented Dec 31, 2020

In general this approach looks good to me. Lets solve the FIX items, rebase / resolve conflicts, and transition out of draft mode!

Base automatically changed from master to main February 19, 2021 20:44
@cart cart added the S-Pre-Relicense This PR was made before Bevy added the Apache license. Cannot be merged or used for other work label Jul 23, 2021
@DJMcNab DJMcNab removed the S-Pre-Relicense This PR was made before Bevy added the Apache license. Cannot be merged or used for other work label Aug 6, 2021
@DJMcNab
Copy link
Member

DJMcNab commented Aug 6, 2021

This still seems like a useful change - it seems that we still clear all the shader defs each frame (!) on main

However, I that this will get integrated into the upcoming render rework; if you don't want to continue pushing this forward, feel free to close it @yrns.

I suspect rebasing this PR will not be useful at the moment, as the render rework is in flight - we can check back in once that lands to check the relevance of these changes then.

@yrns yrns closed this Aug 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Performance A change motivated by improving speed, memory usage or compile times
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants