Support input color argument to process() function in sksl .fp files

--

This expands sksl's capabilities with .fp files. Previously, it was possible to declare "in fragmentProcessor foo" and emit it automatically when "process(foo);" was called. This adds a variant of process that takes a second argument, which must be a half4 expression. This argument specifies the value, or dynamic expression calculated earlier in the parent shader, to use as sk_InColor by the child.

The CL is longer than anticipated because of properly handling dependencies between previous sksl statements and the input to the child. The original writeEmitCode() collected all extra emission code (the calls to build->emitChild) and put them before any call to codeAppendf. This makes it impossible to use a parent's variable, or the output of another child, as the input for process.

To solve this, there is now a flushEmittedCode() function that takes over the logic of outputting the extra emission code and the necessary codeAppendf calls. When invoked, it (by default) only appends completed sksl statements, and places any current expression back at the beginning of the output stream. It now updates fFormatArgs and fExtraEmitCodeCode as it consumes their contents. This allows writeFunctionCall() for a call to "process" to flush all previous statements before it adds its emit child code.

Bug: skia:
Change-Id: I63c41af6f3e0620aa890d10d14436ee6244f0051
Reviewed-on: https://skia-review.googlesource.com/148395
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index 39255d6..6c67bad 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -23,6 +23,21 @@
     bool generateCode() override;
 
 private:
+    // When inside writeEmitCode(), certain SkSL elements need to control
+    // when fragBuilder->codeAppendf is added to the function block. This
+    // takes all completed statements in the SkSL buffer, and their corresponding
+    // format args, and writes them into the emitCode()'s statement block
+    // using writeCodeAppend().
+    //
+    // This control is necessary for handling special functions in SkSL, like
+    // process(), which need to intermix the current FP's SkSL with that of
+    // an emitted child.
+    //
+    //  :forceAll - If false, only the completed statements (terminated by ;),
+    //     will be flushed and the sksl buffer will be set to any partial
+    //     statements that remain. If true, everything is flushed, regardless.
+    void flushEmittedCode(bool forceAll = false);
+
     void writef(const char* s, va_list va) SKSL_PRINTF_LIKE(2, 0);
 
     void writef(const char* s, ...) SKSL_PRINTF_LIKE(2, 3);
@@ -88,6 +103,15 @@
 
     void writeTest();
 
+    // If the returned C++ is included in the generated code, then the variable
+    // name stored in cppVar will refer to a valid SkString that matches the
+    // Expression. Successful returns leave the output buffer (and related state)
+    // unmodified.
+    //
+    // In the simplest cases, this will return "SkString {cppVar}(\"{e}\");",
+    // while more advanced cases will properly insert format arguments.
+    String convertSKSLExpressionToCPP(const Expression& e, const String& cppVar);
+
     String fName;
     String fFullName;
     SectionAndParameterHelper fSectionAndParameterHelper;
@@ -98,6 +122,11 @@
     bool fCPPMode = false;
     bool fInMain = false;
 
+    // if not null, we are accumulating SkSL for emitCode into fOut, which
+    // replaced the original buffer with a StringStream. The original buffer is
+    // stored here for restoration.
+    OutputStream* fCPPBuffer = nullptr;
+
     typedef GLSLCodeGenerator INHERITED;
 };