-
Notifications
You must be signed in to change notification settings - Fork 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
[impellerc] Adds an SkSL backend #34441
Conversation
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!). If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again. |
4618e3e
to
754ea63
Compare
I've done the best I can to exclude features that can't be translated to SkSL, but it's likely that I've missed some cases. The failure mode there is that the SkSL will fail to compile at runtime rather than at app build time. Most of the heavy lifting is in |
@@ -3906,27 +3906,65 @@ class FragmentProgram extends NativeFieldWrapperClass1 { | |||
/// [A current specification of valid SPIR-V is here.](https://github.com/flutter/engine/blob/master/lib/spirv/README.md) | |||
/// SPIR-V not meeting this specification will throw an exception. | |||
static Future<FragmentProgram> compile({ |
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.
I don't think we should combine this new functionality into the old API. Instead we should start from scratch with a new one and deprecate this.
maybe we'd always want to retain an API for loading bytes from the dart heap - just to support certain dynamic cases, but for bundled assets ideally we would only pass a reference to the asset (probably the string key) and let the engine do the loading.
That would also allow me to support hot reload with no framework side changes.
Also, can impellerc include uniform counts into the blob it creates so users don't need to manage that?
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.
Yeah all of that makes sense to me. Not sure what new API here would make life easiest. Do you have any suggestions?
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.
Something like:
FragmentProgram.fromAsset(String key)
or if needs to be async, then
static Future<FragmentProgram> fromAsset(String key)
Depending on the ownership needs of the engine, we could also use immutable buffer but that implies at least one copy.
Where the key would be an asset containing platform specific (metal, sksl, et cetera) blob that had enough information.
That said, we also don't need to come up with this API in this PR, and could instead leave the old API for now and land the compiler changes to allow for experimentation?
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.
I reviewed the impellerc and testing bits and this is great start. I agree with @jonahwilliams that we don't need to modify the current API or come up with a new one in this PR. Separately, I think we can also update the impellerc unittests harness to compile the SKSL shaders generated to verify correctness. Some nits but otherwise LGTM.
impeller/compiler/compiler.cc
Outdated
@@ -151,6 +160,7 @@ Compiler::Compiler(const fml::Mapping& source_mapping, | |||
shaderc_spirv_version::shaderc_spirv_version_1_0); | |||
break; | |||
case TargetPlatform::kFlutterSPIRV: | |||
case TargetPlatform::kSkSL: // TODO(zra): Allow optimizations. |
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.
Let's file an issue for this and cross reference it here? Curious, did you try to see what happens? We can figure it out later though.
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.
The SkSL loop analysis code doesn't correctly handle everything that's allowed by the grammar. Added a comment, and filed an issue.
|
||
namespace impeller { | ||
namespace compiler { | ||
|
||
struct CompilerBackend { | ||
using MSLCompiler = std::shared_ptr<spirv_cross::CompilerMSL>; | ||
using GLSLCompiler = std::shared_ptr<spirv_cross::CompilerGLSL>; | ||
using Compiler = std::variant<MSLCompiler, GLSLCompiler>; | ||
using SkSLCompiler = std::shared_ptr<CompilerSkSL>; | ||
using Compiler = std::variant<MSLCompiler, GLSLCompiler, SkSLCompiler>; |
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.
Ooh, sorry about this. This is a cleanup that is tracked in flutter/flutter#106376.
b08f01b
to
0827891
Compare
I think what I should do is:
|
impeller/compiler/spirv_sksl.cc
Outdated
statement("// This SkSL shader is autogenerated by spirv-cross."); | ||
statement(""); | ||
|
||
// This builtin is copied from |
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.
This is unlikely to keep working (it's an accident that it works today). I'm curious about the semantics you expect to get here -- are the shaders you're using being written to use gl_FragCoord? We've deliberately hidden that from people in SkSL for several reasons:
- gl_FragCoord is origin-relative (ie, often bottom-left). sk_FragCoord is always top-left relative.
- These coordinates are always in device space, so they aren't impact by canvas transformations (this is generally not what people want).
2b) More importantly, because they're in device space, they expose people to the implementation details of things like saveLayer.
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.
The near-term goal is to mimic the SPIR-V -> SkSL transpiler in the Engine so that we can remove it. The main constraint is that we can't break the ink_sparkle shader. The ink_sparkle shader references gl_FragCoord
, and the existing transpiler translates that to float4(iFragCoord, 0, 0)
, where iFragCoord
is the input of SkSL's main()
. I've modified this PR to do the same thing instead of hacking in sk_FragCoord
.
It sounds like going forward we'll have to think a bit harder about this setup if we're going to aim for parity between the different backends.
This PR adds a Compiler implementation to impellerc that translates SPIRV to SkSL. It is implemented by inheriting from the SPIRV to GLSL compiler, rejecting some features that aren't supported, and massaging the output slightly to look like an SkSL SkRuntimeEffect shader.
This PR also modifies the
FragmentProgram.compile()
API to accept araw
optional named argument, to which the SkSL can be passed. This is the same API that will be needed when we want to pass the backend-specific output when impeller is enabled.Fixes flutter/flutter#106823