-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Move ShaderCache shader defs into PipelineCache #7903
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One problem I see with this approach is that it could be easy to forget to initialise one’s shader def Vec with these shader defs. It feels perhaps a little easy to do the wrong thing at the moment.
In that sense it might be easier to do the right thing if the shader defs were passed into the specialisation function. What do you think @Shfty @robtfm ?
12b882d
to
d8b6272
Compare
@superdump Yeah, I agree - passing shader defs in from outside would remove the footgun of soft-requiring the user to magic them up from inside their own impl. If API change is acceptable, I'm happy to go through and rework this appropriately. Also, now #7771 has been merged, should we consider restoring the |
e68d928
to
e516011
Compare
@superdump @robtfm I've reworked this PR to make Overall, I'm much happier with this approach; it slots comfortably into the existing data structure, centralizes the defs in question, avoids adding unnecessary fields to As such, this is now an explicitly breaking change, which will better signal the need for migration to existing implementors. Testing-wise, I've gone through the rendering examples and noticed nothing obviously amiss, and I've updated the top post with the appropriate outline, changelog and migration guide. |
i haven't been through in detail but i wonder if you have a feeling for how this interacts with what i proposed in #5703 - i suspect this would solve your problem as well since those platform defs then woudn't be present in any spirv shaders since there's no mechanism to use imports with spirv anyway. |
@robtfm I believe it's orthogonal to the intent of this PR: The motivation behind #7772 was to remove the blocker caused by With this PR, SPIR-V users can receive the previously-unavailable defs in the (For a more complex practical example, If the primary source of truth for those shader defs were to move into a WGSL module exclusively accessible via |
(Also, I'm realising that much of this context is absent from the top post, having mainly been discussed in Discord. Will edit to amend.) |
thanks, that context makes it clearer for me. since i'm late i'm going to summarize to make sure we are on the same page
if i understood correctly, what you're suggesting is
so in the non-spirv case, we would still have a variant being "selected"/built by the shader cache + preprocessor based on what defs are passed in from pipeline cache plus specialize, and in the spirv case we have the variant being selected by the pipeline itself, based on the (platform-subset-of) defs generated by the pipeline cache, and the defs that are output from specialize are ignored. it feels pretty convoluted to me to have the usage location of the defs vary like this depending on the shader type. in particular i think it would make on-the-fly compiling / caching of shaders (from naga to spirv) harder in the future, since pipelines would need to know ahead of time what "style" of shader they are using, where currently they just do their specializing job regardless of the shader format. it would also maybe mean you can't share spirv shaders so easily between pipelines by just varying the defs that the pipeline outputs. i think the better answer is to use the defs in the shader cache itself to select the variant somehow for spirv, similarly to what we do for non-spirv. i don't know exactly how to do that - perhaps the Shader::Spirv variant could have a lookup based on entry point plus shader defs that the shader cache uses to select a final entry point, or something like that? or maybe there's a better mechanism to operate on spirv itself like there is with naga, to actually modify the shader code somehow. i'm not sure exactly how it should look but i would need some strong reason why Pipeline::specialize is the right place to do this for spirv, rather than putting that functionality alongside the equivalent non-spirv functionality in the shader cache itself. |
Indeed - though I consider definitions made in shader code via My "all shader defs" bulletpoint is probably a little broad in that sense!
Somewhat. The defs are accessed in I'm not proposing to codify bevy SPIR-V handling as part of this PR. That's beyond scope; the intent here is to open the door for user code to codify its own SPIR-V handling in the absence of official support for something like
As-is, SPIR-V has no intrinsic (or bevy-provided) way to specialize. What you describe is effectively the case for SPIR-V in the existing codebase outside of
In terms of internal code, it makes sense that a lower-level solution would be preferable. That implies either exposing a lower level trait that can be implemented to custom-specialize at the
I put together a shader def -> entrypoint permutation mapping in the course of building the trait machinery to specify entrypoints in However, it's arbitrary, as would be any solution that operates on an equally-arbitrary SPIR-V input. My plugin has the luxury of being a third-party codegen-backend-specific integration that can introduce such a restriction with the understanding that it will be handled automatically by the backend, provided that the user follows instructions. I don't feel the same is true for bevy, since SPIR-V is intrinsically a black box, and the expectation for an engine is to accept that black box without imposing any additional restrictions. If On the topic of a (I'll post some context on how I arrived at the current approach in a separate message re. justifying the |
Some additional context on how I arrived at the This PR originally avoided API changes by introducing a free-floating function to retrieve the defs in question, which would be called at construction time by any During the initial rework, I tried using a Unfortunately, this didn't work, as one of the sprite pipeline systems started throwing a "does not implement " error at its Looking for alternatives, I noted that |
i'm basically going to repeat what i said before: I don't think if you can select (either the whole spirv module or the entry point) based on defs in the shader cache in a way that works for you, then maybe it'll work for everyone. if not, we can iterate on it in future.
sure, but bevy's
if so you can work around this using a tuple argument like |
That's clear, but separable from both the issue of the The former remains a demonstrable bevy-specific problem that should be fixed, or documented on the And the latter can be removed from the equation entirely. Specialization best practices would not have entered the discussion if my touchstone example had been anything other than a skunkworks Ergo, given that I am not asking bevy to compromise its own approach to specialization, it's irrelevant unless upcoming changes to the associated machinery are liable to reduce or remove access to shader definitions in |
this is exactly the case with the |
I haven’t had time to catch up on this discussion nor do I right this moment. I just want to say that I haven’t either had the time to look at @robtfm ’s proposed changes and so I hadn’t considered that my proposal might impact them. I’ve chatted with Rob on Discord a bit to align our thinking and it sounds like this platform definitions approach is going to be generally useful. That said, I haven’t quite understood yet what breaks what, though I trust Rob’s judgement to find a solution that fits the use cases and I hope it won’t be too much bother to adjust things to address them all. I’m not the only authority around rendering parts anymore. :) I’ll catch up when I can. My line of thought was founded in that shader defs impact shader code which impact the pipeline that is constructed. I was thinking then that generally, specialisation should control how pipelines are configured, so it made sense that all shader defs one way or another go through the specialisation function on Material. However, if there are good reasons that globally-constant shader defs should not go through pipeline specialisation, but should be available to shaders to use, then I’m open to understanding what the tradeoffs are and why we want to make an exception. |
In which case, it would be productive to detail those changes in the appropriate issue / PR / RFC so potentially-controversial regressions - and their accompanying resolutions - can be discussed, before using them as justification against affected PRs. #5703 only references shader defs in a limited capacity that doesn't suggest a level of impact comparable to what you've implied here. It's very well to be told that my existing entrypoints may be taken away because the approach they support doesn't align with bevy's development trajectory - that's an implicit occupational hazard - but I can only contribute effectively and follow said trajectory if the rules of engagement exist on paper.
Is there an RFC or issue open for discussing potential stratification of bevy's SPIR-V handling? This seems like a controversial change from the perspective of using the format for the sake of total control, so it would be good to contribute to discussion on that front.
Of course, I understand that there's much to do in many spheres outside my localized And it's no bother - I just want to make sure the correct solution has been found, or at least progressed toward, when the time comes to give it full consideration. |
e516011
to
4cfed74
Compare
Another use case I've seen asked for: Having a custom material that all it does is use the standard material shaders, but removes the ENVIRONMENT_MAP_LIGHT shader def to disable environment map lighting for a specific mesh. |
Objective
NO_STORAGE_BUFFERS_SUPPORT
,NO_ARRAY_TEXTURES_SUPPORT
andSIXTEEN_BYTE_ALIGNMENT
are injected byShaderCache::get
, which occurs after pipeline specialization, and therefore afterMaterial
gets the chance to inspect or mutate them inMaterial::specialize
.Fixes
Material::specialize
is provided an incomplete set of engine-sourced shader definitions #8190Related: Allow SPIR-V shaders to process when shader defs are present #7772 lifted an incidental restriction preventing the use of SPIR-V in
Material
, but full access to engine-sourced shader definitions inMaterial::specialize
is still an outstanding issue.Solution
Material
implementors to access the aforementioned defs by moving them intoPipelineCache
, and extended the existing pipeline specialization machinery to pass them down the call chain fromSpecialized*Pipelines::specialize
.Changelog
PipelineCache::base_shader_defs
added (populated from the render device inPipelineCache::new
), and exposed via a newPipelineCache::base_shader_defs()
by-clone accessorshader_defs: Vec<ShaderDefVal>
param added toSpecializedRenderPipeline::specialize
,SpecializedComputePipeline::specialize
, andSpecializedMeshPipeline::specialize
PipelineCache
inSpecialized*Pipelines::specialize
and passed into the respective trait methodsVec<ShaderDefVal>
Migration Guide
This is a breaking change.
Specialized*Pipeline
implementors should use the newly-providedshader_defs
vector instead of constructing their own, extending it with new definitions as necessary, and ensuring that it gets passed into the appropriate pipeline descriptors for access in downstream code.