Add support for the pixel_local modifier to WGSL.
This keyword isn't fully supported by WGSL yet, so it generates
an error when compiled.
https://docs.google.com/document/d/1djJwQLJcVGnDXOA7nhsweppim-hhbqglB4JNyfZcRqQ
Bug: b/299504320
Bug: dawn:1704
Change-Id: Ifb1fcc0192d6aa0087e93de12c269eb38251ff7b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/753566
Reviewed-by: Arman Uguray <armansito@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni
index 2c9bc69..e35e810 100644
--- a/gn/sksl_tests.gni
+++ b/gn/sksl_tests.gni
@@ -417,6 +417,7 @@
"wgsl/MainHasVoidReturn.sksl",
"wgsl/MatrixConstructorDiagonal.sksl",
"wgsl/OutParams.sksl",
+ "wgsl/PixelLocalStorage.sksl",
"wgsl/Sample.sksl",
"wgsl/TextureIntrinsics.compute",
"wgsl/UniformArrays.sksl",
diff --git a/resources/sksl/BUILD.bazel b/resources/sksl/BUILD.bazel
index a00954a..af8643e 100644
--- a/resources/sksl/BUILD.bazel
+++ b/resources/sksl/BUILD.bazel
@@ -1097,6 +1097,7 @@
"wgsl/MainHasVoidReturn.sksl",
"wgsl/MatrixConstructorDiagonal.sksl",
"wgsl/OutParams.sksl",
+ "wgsl/PixelLocalStorage.sksl",
"wgsl/Sample.sksl",
"wgsl/TextureIntrinsics.compute",
"wgsl/UniformArrays.sksl",
diff --git a/resources/sksl/wgsl/PixelLocalStorage.sksl b/resources/sksl/wgsl/PixelLocalStorage.sksl
new file mode 100644
index 0000000..4770cdb
--- /dev/null
+++ b/resources/sksl/wgsl/PixelLocalStorage.sksl
@@ -0,0 +1,11 @@
+struct PixelLocalData {
+ int i;
+ float f;
+};
+
+pixel_local PixelLocalData pls;
+
+void main() {
+ pls.i++;
+ pls.f *= 2.0;
+}
diff --git a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
index 91ff42f..403d71f 100644
--- a/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp
@@ -79,6 +79,7 @@
#include <memory>
#include <optional>
#include <string>
+#include <utility>
using namespace skia_private;
@@ -717,20 +718,30 @@
};
WGSLCodeGenerator::ProgramRequirements resolve_program_requirements(const Program* program) {
- WGSLCodeGenerator::ProgramRequirements::DepsMap dependencies;
+ WGSLCodeGenerator::ProgramRequirements requirements;
for (const ProgramElement* e : program->elements()) {
- if (!e->is<FunctionDefinition>()) {
- continue;
+ switch (e->kind()) {
+ case ProgramElement::Kind::kFunction: {
+ const FunctionDeclaration& decl = e->as<FunctionDefinition>().declaration();
+
+ FunctionDependencyResolver resolver(program, &decl, &requirements.fDependencies);
+ requirements.fDependencies.set(&decl, resolver.resolve());
+ break;
+ }
+ case ProgramElement::Kind::kGlobalVar: {
+ const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
+ if (decl.varDeclaration().var()->modifierFlags().isPixelLocal()) {
+ requirements.fPixelLocalExtension = true;
+ }
+ break;
+ }
+ default:
+ break;
}
-
- const FunctionDeclaration& decl = e->as<FunctionDefinition>().declaration();
-
- FunctionDependencyResolver resolver(program, &decl, &dependencies);
- dependencies.set(&decl, resolver.resolve());
}
- return WGSLCodeGenerator::ProgramRequirements(std::move(dependencies));
+ return requirements;
}
void collect_pipeline_io_vars(const Program* program,
@@ -912,7 +923,7 @@
{
AutoOutputStream outputToHeader(this, &fHeader, &fIndentation);
- this->writeLine("diagnostic(off, derivative_uniformity);");
+ this->writeEnables();
this->writeStageInputStruct();
this->writeStageOutputStruct();
this->writeUniformsAndBuffers();
@@ -1480,7 +1491,7 @@
// Generate a function call to the user-defined main.
this->write("_skslMain(");
auto separator = SkSL::String::Separator();
- WGSLFunctionDependencies* deps = fRequirements.dependencies.find(&main.declaration());
+ WGSLFunctionDependencies* deps = fRequirements.fDependencies.find(&main.declaration());
if (deps) {
if (*deps & WGSLFunctionDependency::kPipelineInputs) {
this->write(separator());
@@ -3574,10 +3585,9 @@
switch (e.kind()) {
case ProgramElement::Kind::kExtension:
// TODO(skia:13092): WGSL supports extensions via the "enable" directive
- // (https://www.w3.org/TR/WGSL/#language-extensions). While we could easily emit this
+ // (https://www.w3.org/TR/WGSL/#enable-extensions-sec ). While we could easily emit this
// directive, we should first ensure that all possible SkSL extension names are
- // converted to their appropriate WGSL extension. Currently there are no known supported
- // WGSL extensions aside from the hypotheticals listed in the spec.
+ // converted to their appropriate WGSL extension.
break;
case ProgramElement::Kind::kGlobalVar:
this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
@@ -3678,6 +3688,8 @@
this->write("const ");
} else if (var.modifierFlags().isWorkgroup()) {
this->write("var<workgroup> ");
+ } else if (var.modifierFlags().isPixelLocal()) {
+ this->write("var<pixel_local> ");
} else {
this->write("var<private> ");
}
@@ -3770,6 +3782,13 @@
fIndentation--;
}
+void WGSLCodeGenerator::writeEnables() {
+ this->writeLine("diagnostic(off, derivative_uniformity);");
+ if (fRequirements.fPixelLocalExtension) {
+ this->writeLine("enable chromium_experimental_pixel_local;");
+ }
+}
+
bool WGSLCodeGenerator::needsStageInputStruct() const {
// It is illegal to declare a struct with no members; we can't emit a placeholder empty stage
// input struct.
@@ -4008,7 +4027,7 @@
}
std::string WGSLCodeGenerator::functionDependencyArgs(const FunctionDeclaration& f) {
- WGSLFunctionDependencies* deps = fRequirements.dependencies.find(&f);
+ WGSLFunctionDependencies* deps = fRequirements.fDependencies.find(&f);
std::string args;
if (deps && *deps) {
const char* separator = "";
@@ -4025,7 +4044,7 @@
}
bool WGSLCodeGenerator::writeFunctionDependencyParams(const FunctionDeclaration& f) {
- WGSLFunctionDependencies* deps = fRequirements.dependencies.find(&f);
+ WGSLFunctionDependencies* deps = fRequirements.fDependencies.find(&f);
if (!deps || !*deps) {
return false;
}
diff --git a/src/sksl/codegen/SkSLWGSLCodeGenerator.h b/src/sksl/codegen/SkSLWGSLCodeGenerator.h
index c779974..cb11848 100644
--- a/src/sksl/codegen/SkSLWGSLCodeGenerator.h
+++ b/src/sksl/codegen/SkSLWGSLCodeGenerator.h
@@ -22,7 +22,6 @@
#include <memory>
#include <string>
#include <string_view>
-#include <utility>
namespace SkSL {
@@ -127,12 +126,12 @@
using DepsMap = skia_private::THashMap<const FunctionDeclaration*,
WGSLFunctionDependencies>;
- ProgramRequirements() = default;
- ProgramRequirements(DepsMap dependencies) : dependencies(std::move(dependencies)) {}
-
// Mappings used to synthesize function parameters according to dependencies on pipeline
// input/output variables.
- DepsMap dependencies;
+ DepsMap fDependencies;
+
+ // These flags track extensions that will need to be enabled.
+ bool fPixelLocalExtension = false;
};
WGSLCodeGenerator(const Context* context, const Program* program, OutputStream* out)
@@ -306,6 +305,7 @@
void prepareUniformPolyfillsForInterfaceBlock(const InterfaceBlock* interfaceBlock,
std::string_view instanceName,
MemoryLayout::Standard nativeLayout);
+ void writeEnables();
void writeUniformPolyfills();
void writeTextureOrSampler(const Variable& var,
@@ -339,7 +339,7 @@
// We assign unique names to anonymous interface blocks based on the type.
skia_private::THashMap<const Type*, std::string> fInterfaceBlockNameMap;
- // Stores the disallowed identifier names.
+ // Stores the functions which use stage inputs/outputs as well as required WGSL extensions.
ProgramRequirements fRequirements;
skia_private::TArray<const Variable*> fPipelineInputs;
skia_private::TArray<const Variable*> fPipelineOutputs;
diff --git a/src/sksl/ir/SkSLVarDeclarations.cpp b/src/sksl/ir/SkSLVarDeclarations.cpp
index 5f2f0cc..af35d67 100644
--- a/src/sksl/ir/SkSLVarDeclarations.cpp
+++ b/src/sksl/ir/SkSLVarDeclarations.cpp
@@ -261,6 +261,11 @@
// Only non-opaque types allow `in` and `out`.
permitted |= ModifierFlag::kIn | ModifierFlag::kOut;
}
+ if (ProgramConfig::IsFragment(context.fConfig->fKind) && baseType->isStruct() &&
+ !baseType->isInterfaceBlock()) {
+ // Only structs in fragment shaders allow `pixel_local`.
+ permitted |= ModifierFlag::kPixelLocal;
+ }
if (ProgramConfig::IsCompute(context.fConfig->fKind)) {
// Only compute shaders allow `workgroup`.
if (!baseType->isOpaque() || baseType->isAtomic()) {
diff --git a/tests/sksl/wgsl/PixelLocalStorage.wgsl b/tests/sksl/wgsl/PixelLocalStorage.wgsl
new file mode 100644
index 0000000..1e944a3
--- /dev/null
+++ b/tests/sksl/wgsl/PixelLocalStorage.wgsl
@@ -0,0 +1,25 @@
+### Compilation failed:
+
+error: :2:1 error: chromium_experimental_pixel_local requires TINT_ENABLE_LOCAL_STORAGE_EXTENSION
+enable chromium_experimental_pixel_local;
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+diagnostic(off, derivative_uniformity);
+enable chromium_experimental_pixel_local;
+struct PixelLocalData {
+ i: i32,
+ f: f32,
+};
+var<pixel_local> pls: PixelLocalData;
+fn _skslMain() {
+ {
+ pls.i = pls.i + i32(1);
+ pls.f = pls.f * 2.0;
+ }
+}
+@fragment fn main() {
+ _skslMain();
+}
+
+1 error