Added DSL modifiers declarations

Change-Id: I97a7c5cfb3ce3f430074092616a3256422c8ad5e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/444979
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/include/sksl/DSLCore.h b/include/sksl/DSLCore.h
index 003ee53..b60a39d 100644
--- a/include/sksl/DSLCore.h
+++ b/include/sksl/DSLCore.h
@@ -91,6 +91,11 @@
 DSLStatement Continue(PositionInfo pos = PositionInfo::Capture());
 
 /**
+ * Adds a modifiers declaration to the current program.
+ */
+void Declare(const DSLModifiers& modifiers, PositionInfo pos = PositionInfo::Capture());
+
+/**
  * Creates a local variable declaration statement.
  */
 DSLStatement Declare(DSLVar& var, PositionInfo pos = PositionInfo::Capture());
diff --git a/src/sksl/SkSLDSLParser.cpp b/src/sksl/SkSLDSLParser.cpp
index 2b8227a..cc331ff 100644
--- a/src/sksl/SkSLDSLParser.cpp
+++ b/src/sksl/SkSLDSLParser.cpp
@@ -292,7 +292,9 @@
         return this->interfaceBlock(modifiers);
     }
     if (lookahead.fKind == Token::Kind::TK_SEMICOLON) {
-        this->error(lookahead, "modifiers declarations are not yet supported");
+        this->nextToken();
+        Declare(modifiers, position(lookahead));
+        return true;
     }
     if (lookahead.fKind == Token::Kind::TK_STRUCT) {
         SkTArray<DSLGlobalVar> result = this->structVarDeclaration(modifiers);
diff --git a/src/sksl/dsl/DSLCore.cpp b/src/sksl/dsl/DSLCore.cpp
index df62f85..1139fea 100644
--- a/src/sksl/dsl/DSLCore.cpp
+++ b/src/sksl/dsl/DSLCore.cpp
@@ -130,6 +130,11 @@
         return SkSL::ContinueStatement::Make(pos.offset());
     }
 
+    static void Declare(const DSLModifiers& modifiers) {
+        DSLWriter::ProgramElements().push_back(std::make_unique<SkSL::ModifiersDeclaration>(
+                DSLWriter::Modifiers(modifiers.fModifiers)));
+    }
+
     static DSLStatement Declare(DSLVar& var, PositionInfo pos) {
         if (var.fDeclared) {
             DSLWriter::ReportError("variable has already been declared", pos);
@@ -344,6 +349,16 @@
     return DSLCore::Continue(pos);
 }
 
+void Declare(const DSLModifiers& modifiers, PositionInfo pos) {
+    SkSL::ProgramKind kind = DSLWriter::GetProgramConfig()->fKind;
+    if (kind != ProgramKind::kFragment &&
+        kind != ProgramKind::kVertex) {
+        DSLWriter::ReportError("layout qualifiers are not allowed in this kind of program", pos);
+        return;
+    }
+    DSLCore::Declare(modifiers);
+}
+
 // Logically, we'd want the variable's initial value to appear on here in Declare, since that
 // matches how we actually write code (and in fact that was what our first attempt looked like).
 // Unfortunately, C++ doesn't guarantee execution order between arguments, and Declare() can appear
diff --git a/tests/SkSLDSLTest.cpp b/tests/SkSLDSLTest.cpp
index 4a96f6e..8ba27a6 100644
--- a/tests/SkSLDSLTest.cpp
+++ b/tests/SkSLDSLTest.cpp
@@ -2130,3 +2130,10 @@
     REPORTER_ASSERT(r, DSLWriter::ProgramElements().size() == 1);
     EXPECT_EQUAL(*DSLWriter::ProgramElements()[0], "#extension test_extension : enable");
 }
+
+DEF_GPUTEST_FOR_MOCK_CONTEXT(DSLModifiersDeclaration, r, ctxInfo) {
+    AutoDSLContext context(ctxInfo.directContext()->priv().getGpu());
+    Declare(Modifiers(Layout().blendSupportAllEquations(), kOut_Modifier));
+    REPORTER_ASSERT(r, DSLWriter::ProgramElements().size() == 1);
+    EXPECT_EQUAL(*DSLWriter::ProgramElements()[0], "layout(blend_support_all_equations) out;");
+}