converted overdraw effect to new FP system

Bug: skia:
Change-Id: I4cff0ecdf3fc61f584012af519730f08bfd78264
Reviewed-on: https://skia-review.googlesource.com/150484
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/effects/SkOverdrawColorFilter.cpp b/src/effects/SkOverdrawColorFilter.cpp
index 71dbb72..b4a87f5 100644
--- a/src/effects/SkOverdrawColorFilter.cpp
+++ b/src/effects/SkOverdrawColorFilter.cpp
@@ -12,6 +12,36 @@
 #include "SkReadBuffer.h"
 #include "../jumper/SkJumper.h"
 
+#if SK_SUPPORT_GPU
+#include "effects/GrSkSLFP.h"
+
+GR_FP_SRC_STRING SKSL_OVERDRAW_SRC = R"(
+layout(ctype=SkPMColor) in uniform half4 color0;
+layout(ctype=SkPMColor) in uniform half4 color1;
+layout(ctype=SkPMColor) in uniform half4 color2;
+layout(ctype=SkPMColor) in uniform half4 color3;
+layout(ctype=SkPMColor) in uniform half4 color4;
+layout(ctype=SkPMColor) in uniform half4 color5;
+
+void main(int x, int y, inout half4 color) {
+    half alpha = 255.0 * color.a;
+    if (alpha < 0.5) {
+        color = color0;
+    } else if (alpha < 1.5) {
+        color = color1;
+    } else if (alpha < 2.5) {
+        color = color2;
+    } else if (alpha < 3.5) {
+        color = color3;
+    } else if (alpha < 4.5) {
+        color = color4;
+    } else {
+        color = color5;
+    }
+}
+)";
+#endif
+
 void SkOverdrawColorFilter::onAppendStages(SkRasterPipeline* p,
                                            SkColorSpace* dstCS,
                                            SkArenaAlloc* alloc,
@@ -58,12 +88,11 @@
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
 #if SK_SUPPORT_GPU
 
-#include "effects/GrOverdrawFragmentProcessor.h"
-
 std::unique_ptr<GrFragmentProcessor> SkOverdrawColorFilter::asFragmentProcessor(
-        GrContext*, const GrColorSpaceInfo&) const {
-    return GrOverdrawFragmentProcessor::Make(fColors[0], fColors[1], fColors[2], fColors[3],
-                                             fColors[4], fColors[5]);
+        GrContext* context, const GrColorSpaceInfo&) const {
+    static int overdrawIndex = GrSkSLFP::NewIndex();
+    return GrSkSLFP::Make(context, overdrawIndex, "Overdraw", SKSL_OVERDRAW_SRC, fColors,
+                          sizeof(fColors));
 }
 
 #endif
diff --git a/src/effects/imagefilters/SkArithmeticImageFilter.cpp b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
index 2e5b801..86ace3c 100644
--- a/src/effects/imagefilters/SkArithmeticImageFilter.cpp
+++ b/src/effects/imagefilters/SkArithmeticImageFilter.cpp
@@ -29,9 +29,8 @@
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
 #include "glsl/GrGLSLUniformHandler.h"
-#endif
 
-const char* SKSL_ARITHMETIC_SRC = R"(
+GR_FP_SRC_STRING SKSL_ARITHMETIC_SRC = R"(
 in uniform float4 k;
 layout(key) const in bool enforcePMColor;
 in fragmentProcessor child;
@@ -44,6 +43,7 @@
     }
 }
 )";
+#endif
 
 class ArithmeticImageFilterImpl : public SkImageFilter {
 public:
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index c11d985..0cc2f20 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -41,7 +41,8 @@
 #include "effects/GrXfermodeFragmentProcessor.h"
 #include "effects/GrSkSLFP.h"
 
-const char* SKSL_DITHER_SRC = R"(
+#if SK_SUPPORT_GPU
+GR_FP_SRC_STRING SKSL_DITHER_SRC = R"(
 // This controls the range of values added to color channels
 layout(key) in int rangeType;
 
@@ -80,6 +81,7 @@
     color = half4(clamp(color.rgb + value * range, 0.0, color.a), color.a);
 }
 )";
+#endif
 
 GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) {
     GrSurfaceDesc desc;
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index 394b2f2..ec9f30a 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -38,8 +38,6 @@
 class SkPixmap;
 struct SkIRect;
 
-extern const char* SKSL_DITHER_SRC;
-
 ////////////////////////////////////////////////////////////////////////////////
 // Color type conversions
 
diff --git a/src/gpu/effects/GrOverdrawFragmentProcessor.fp b/src/gpu/effects/GrOverdrawFragmentProcessor.fp
deleted file mode 100644
index 9ee6915..0000000
--- a/src/gpu/effects/GrOverdrawFragmentProcessor.fp
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-layout(ctype=SkPMColor) in half4 color0;
-layout(ctype=SkPMColor) in half4 color1;
-layout(ctype=SkPMColor) in half4 color2;
-layout(ctype=SkPMColor) in half4 color3;
-layout(ctype=SkPMColor) in half4 color4;
-layout(ctype=SkPMColor) in half4 color5;
-
-void main() {
-    half alpha = 255.0 * sk_InColor.a;
-    if (alpha < 0.5) {
-        sk_OutColor = color0;
-    } else if (alpha < 1.5) {
-        sk_OutColor = color1;
-    } else if (alpha < 2.5) {
-        sk_OutColor = color2;
-    } else if (alpha < 3.5) {
-        sk_OutColor = color3;
-    } else if (alpha < 4.5) {
-        sk_OutColor = color4;
-    } else {
-        sk_OutColor = color5;
-    }
-}
\ No newline at end of file
diff --git a/src/gpu/effects/GrOverdrawFragmentProcessor.h b/src/gpu/effects/GrOverdrawFragmentProcessor.h
deleted file mode 100644
index 3fd441d..0000000
--- a/src/gpu/effects/GrOverdrawFragmentProcessor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrOverdrawFragmentProcessor.fp; do not modify.
- **************************************************************************************************/
-#ifndef GrOverdrawFragmentProcessor_DEFINED
-#define GrOverdrawFragmentProcessor_DEFINED
-#include "SkTypes.h"
-#include "GrFragmentProcessor.h"
-#include "GrCoordTransform.h"
-class GrOverdrawFragmentProcessor : public GrFragmentProcessor {
-public:
-    SkPMColor color0() const { return fColor0; }
-    SkPMColor color1() const { return fColor1; }
-    SkPMColor color2() const { return fColor2; }
-    SkPMColor color3() const { return fColor3; }
-    SkPMColor color4() const { return fColor4; }
-    SkPMColor color5() const { return fColor5; }
-    static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor color0, SkPMColor color1,
-                                                     SkPMColor color2, SkPMColor color3,
-                                                     SkPMColor color4, SkPMColor color5) {
-        return std::unique_ptr<GrFragmentProcessor>(
-                new GrOverdrawFragmentProcessor(color0, color1, color2, color3, color4, color5));
-    }
-    GrOverdrawFragmentProcessor(const GrOverdrawFragmentProcessor& src);
-    std::unique_ptr<GrFragmentProcessor> clone() const override;
-    const char* name() const override { return "OverdrawFragmentProcessor"; }
-
-private:
-    GrOverdrawFragmentProcessor(SkPMColor color0, SkPMColor color1, SkPMColor color2,
-                                SkPMColor color3, SkPMColor color4, SkPMColor color5)
-            : INHERITED(kGrOverdrawFragmentProcessor_ClassID, kNone_OptimizationFlags)
-            , fColor0(color0)
-            , fColor1(color1)
-            , fColor2(color2)
-            , fColor3(color3)
-            , fColor4(color4)
-            , fColor5(color5) {}
-    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
-    bool onIsEqual(const GrFragmentProcessor&) const override;
-    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
-    SkPMColor fColor0;
-    SkPMColor fColor1;
-    SkPMColor fColor2;
-    SkPMColor fColor3;
-    SkPMColor fColor4;
-    SkPMColor fColor5;
-    typedef GrFragmentProcessor INHERITED;
-};
-#endif
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index 2a52909..9ed8345 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -9,11 +9,9 @@
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProgramBuilder.h"
-#include "GrConstColorProcessor.h"
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrTexture.h"
-#include "SkArithmeticImageFilter.h"
 #include "SkSLUtil.h"
 
 GrSkSLFPFactory::GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl)
@@ -64,8 +62,8 @@
             bool v = *(((bool*) inputs) + offset);
             inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(v)));
             offset += sizeof(bool);
-        } else if (&v->fType == fCompiler.context().fFloat4_Type.get()) {
-            SkASSERT(v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag);
+        } else if (&v->fType == fCompiler.context().fFloat4_Type.get() ||
+                   &v->fType == fCompiler.context().fHalf4_Type.get()) {
             offset = SkAlign4(offset) + sizeof(float) * 4;
         } else if (&v->fType == fCompiler.context().fFragmentProcessor_Type.get()) {
             // do nothing
@@ -182,23 +180,45 @@
         char* inputs = (char*) outer.fInputs.get();
         const SkSL::Context& context = outer.fFactory->fCompiler.context();
         for (const auto& v : outer.fFactory->fInputVars) {
-            if (&v->fType == context.fFloat4_Type.get()) {
-                offset = SkAlign4(offset);
-                float f1 = *(float*) (inputs + offset);
-                offset += sizeof(float);
-                float f2 = *(float*) (inputs + offset);
-                offset += sizeof(float);
-                float f3 = *(float*) (inputs + offset);
-                offset += sizeof(float);
-                float f4 = *(float*) (inputs + offset);
-                offset += sizeof(float);
+            if (&v->fType == context.fFloat4_Type.get() ||
+                &v->fType == context.fHalf4_Type.get()) {
+                float f1, f2, f3, f4;
+                switch (v->fModifiers.fLayout.fCType) {
+                    case SkSL::Layout::CType::kSkPMColor:
+                        f1 = ((uint8_t*) inputs)[offset++] / 255.0;
+                        f2 = ((uint8_t*) inputs)[offset++] / 255.0;
+                        f3 = ((uint8_t*) inputs)[offset++] / 255.0;
+                        f4 = ((uint8_t*) inputs)[offset++] / 255.0;
+                        break;
+                    case SkSL::Layout::CType::kSkRect: // fall through
+                    case SkSL::Layout::CType::kDefault:
+                        offset = SkAlign4(offset);
+                        f1 = *(float*) (inputs + offset);
+                        offset += sizeof(float);
+                        f2 = *(float*) (inputs + offset);
+                        offset += sizeof(float);
+                        f3 = *(float*) (inputs + offset);
+                        offset += sizeof(float);
+                        f4 = *(float*) (inputs + offset);
+                        offset += sizeof(float);
+                        break;
+                    default:
+                        SK_ABORT("unsupported uniform ctype");
+                }
                 if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
                     pdman.set4f(fUniformHandles[uniformIndex++], f1, f2, f3, f4);
                 }
-            }
-            if (&v->fType == context.fBool_Type.get()) {
+            } else if (&v->fType == context.fInt_Type.get()) {
+                int32_t i = *(int*) (inputs + offset);
+                offset += sizeof(int32_t);
+                if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
+                    pdman.set1i(fUniformHandles[uniformIndex++], i);
+                }
+            } else if (&v->fType == context.fBool_Type.get()) {
                 SkASSERT(!(v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag));
                 ++offset;
+            } else {
+                SkASSERT(&v->fType == context.fFragmentProcessor_Type.get());
             }
         }
     }
@@ -293,7 +313,8 @@
                 b->add32(*(int32_t*) (inputs + offset));
             }
             offset += sizeof(int32_t);
-        } else if (&v->fType == context.fFloat4_Type.get()) {
+        } else if (&v->fType == context.fFloat4_Type.get() ||
+                   &v->fType == context.fHalf4_Type.get()) {
             if (v->fModifiers.fLayout.fKey) {
                 for (size_t i = 0; i < sizeof(float) * 4; ++i) {
                     fKey += inputs[offset + i];
@@ -375,12 +396,17 @@
 
 #if GR_TEST_UTILS
 
-#include "SkGr.h"
+#include "GrConstColorProcessor.h"
+#include "SkArithmeticImageFilter.h"
+
+extern const char* SKSL_ARITHMETIC_SRC;
+extern const char* SKSL_DITHER_SRC;
+extern const char* SKSL_OVERDRAW_SRC;
 
 using Value = SkSL::Program::Settings::Value;
 
 std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
-    int type = d->fRandom->nextULessThan(2);
+    int type = d->fRandom->nextULessThan(3);
     switch (type) {
         case 0: {
             static int ditherIndex = NewIndex();
@@ -406,6 +432,17 @@
                                                         GrConstColorProcessor::InputMode::kIgnore));
             return std::unique_ptr<GrFragmentProcessor>(result.release());
         }
+        case 2: {
+            static int overdrawIndex = NewIndex();
+            SkPMColor inputs[6];
+            for (int i = 0; i < 6; ++i) {
+                inputs[i] = d->fRandom->nextU();
+            }
+            std::unique_ptr<GrSkSLFP> result = GrSkSLFP::Make(d->context(), overdrawIndex,
+                                                              "Overdraw", SKSL_OVERDRAW_SRC,
+                                                              &inputs, sizeof(inputs));
+            return std::unique_ptr<GrFragmentProcessor>(result.release());
+        }
     }
     SK_ABORT("unreachable");
     return nullptr;
diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h
index f89e9bf..c4acfd0 100644
--- a/src/gpu/effects/GrSkSLFP.h
+++ b/src/gpu/effects/GrSkSLFP.h
@@ -17,6 +17,12 @@
 #include "SkRefCnt.h"
 #include "../private/GrSkSLFPFactoryCache.h"
 
+#if GR_TEST_UTILS
+#define GR_FP_SRC_STRING const char*
+#else
+#define GR_FP_SRC_STRING static const char*
+#endif
+
 class GrContext;
 class GrSkSLFPFactory;
 
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index f9c6ee3..5f4665f 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -132,7 +132,7 @@
 }
 
 static String default_value(const Variable& var) {
-    if (var.fModifiers.fLayout.fCType == "GrColor4f") {
+    if (var.fModifiers.fLayout.fCType == SkSL::Layout::CType::kGrColor4f) {
         return "GrColor4f::kIllegalConstructor";
     }
     return default_value(var.fType);
@@ -168,21 +168,28 @@
         fFormatArgs.push_back(cppCode + ".fY");
     } else if (type == *fContext.fFloat4_Type || type == *fContext.fHalf4_Type) {
         this->write(type.name() + "(%f, %f, %f, %f)");
-        if (layout.fCType == "SkPMColor") {
-            fFormatArgs.push_back("SkGetPackedR32(" + cppCode + ") / 255.0");
-            fFormatArgs.push_back("SkGetPackedG32(" + cppCode + ") / 255.0");
-            fFormatArgs.push_back("SkGetPackedB32(" + cppCode + ") / 255.0");
-            fFormatArgs.push_back("SkGetPackedA32(" + cppCode + ") / 255.0");
-        } else if (layout.fCType == "GrColor4f") {
-            fFormatArgs.push_back(cppCode + ".fRGBA[0]");
-            fFormatArgs.push_back(cppCode + ".fRGBA[1]");
-            fFormatArgs.push_back(cppCode + ".fRGBA[2]");
-            fFormatArgs.push_back(cppCode + ".fRGBA[3]");
-        } else {
-            fFormatArgs.push_back(cppCode + ".left()");
-            fFormatArgs.push_back(cppCode + ".top()");
-            fFormatArgs.push_back(cppCode + ".right()");
-            fFormatArgs.push_back(cppCode + ".bottom()");
+        switch (layout.fCType) {
+            case Layout::CType::kSkPMColor:
+                fFormatArgs.push_back("SkGetPackedR32(" + cppCode + ") / 255.0");
+                fFormatArgs.push_back("SkGetPackedG32(" + cppCode + ") / 255.0");
+                fFormatArgs.push_back("SkGetPackedB32(" + cppCode + ") / 255.0");
+                fFormatArgs.push_back("SkGetPackedA32(" + cppCode + ") / 255.0");
+                break;
+            case Layout::CType::kGrColor4f:
+                fFormatArgs.push_back(cppCode + ".fRGBA[0]");
+                fFormatArgs.push_back(cppCode + ".fRGBA[1]");
+                fFormatArgs.push_back(cppCode + ".fRGBA[2]");
+                fFormatArgs.push_back(cppCode + ".fRGBA[3]");
+                break;
+            case Layout::CType::kSkRect: // fall through
+            case Layout::CType::kDefault:
+                fFormatArgs.push_back(cppCode + ".left()");
+                fFormatArgs.push_back(cppCode + ".top()");
+                fFormatArgs.push_back(cppCode + ".right()");
+                fFormatArgs.push_back(cppCode + ".bottom()");
+                break;
+            default:
+                SkASSERT(false);
         }
     } else if (type.kind() == Type::kEnum_Kind) {
         this->write("%d");
@@ -533,11 +540,11 @@
                     // The member statement is different if the mapper reports a default value
                     if (mapper->defaultValue().size() > 0) {
                         this->writef("%s %sPrev = %s;\n",
-                                     mapper->ctype().c_str(), name.c_str(),
+                                     Layout::CTypeToStr(mapper->ctype()), name.c_str(),
                                      mapper->defaultValue().c_str());
                     } else {
                         this->writef("%s %sPrev;\n",
-                                     mapper->ctype().c_str(), name.c_str());
+                                     Layout::CTypeToStr(mapper->ctype()), name.c_str());
                     }
                 }
             }
diff --git a/src/sksl/SkSLCPPUniformCTypes.cpp b/src/sksl/SkSLCPPUniformCTypes.cpp
index 6af8e17..f48b9f9 100644
--- a/src/sksl/SkSLCPPUniformCTypes.cpp
+++ b/src/sksl/SkSLCPPUniformCTypes.cpp
@@ -113,9 +113,9 @@
 }
 
 UniformCTypeMapper::UniformCTypeMapper(
-        const String& ctype, const std::vector<String>& skslTypes,
-        const String& setUniformFormat, bool enableTracking, const String& defaultValue,
-        const String& dirtyExpressionFormat, const String& saveStateFormat)
+        Layout::CType ctype, const std::vector<String>& skslTypes, const String& setUniformFormat,
+        bool enableTracking, const String& defaultValue, const String& dirtyExpressionFormat,
+        const String& saveStateFormat)
     : fCType(ctype)
     , fSKSLTypes(skslTypes)
     , fUniformTemplate(setUniformFormat)
@@ -128,14 +128,14 @@
 // NOTE: These would be macros, but C++ initialization lists for the sksl type names do not play
 // well with macro parsing.
 
-static UniformCTypeMapper REGISTER(const char* ctype, const std::vector<String>& skslTypes,
+static UniformCTypeMapper REGISTER(Layout::CType ctype, const std::vector<String>& skslTypes,
                                    const char* uniformFormat, const char* defaultValue,
                                    const char* dirtyExpression) {
     return UniformCTypeMapper(ctype, skslTypes, uniformFormat, defaultValue, dirtyExpression,
                               "${oldVar} = ${newVar}");
 }
 
-static UniformCTypeMapper REGISTER(const char* ctype, const std::vector<String>& skslTypes,
+static UniformCTypeMapper REGISTER(Layout::CType ctype, const std::vector<String>& skslTypes,
                                    const char* uniformFormat, const char* defaultValue) {
     return REGISTER(ctype, skslTypes, uniformFormat, defaultValue,
                     "${oldVar} != ${newVar}");
@@ -147,43 +147,43 @@
 
 static const std::vector<UniformCTypeMapper>& get_mappers() {
     static const std::vector<UniformCTypeMapper> registeredMappers = {
-    REGISTER("SkRect", { "half4", "float4", "double4" },
+    REGISTER(Layout::CType::kSkRect, { "half4", "float4", "double4" },
         "${pdman}.set4fv(${uniform}, 1, reinterpret_cast<const float*>(&${var}))", // to gpu
         "SkRect::MakeEmpty()",                                                     // default value
         "${oldVar}.isEmpty() || ${oldVar} != ${newVar}"),                          // dirty check
 
-    REGISTER("SkIRect", { "int4", "short4", "byte4" },
+    REGISTER(Layout::CType::kSkIRect, { "int4", "short4", "byte4" },
         "${pdman}.set4iv(${uniform}, 1, reinterpret_cast<const int*>(&${var}))",   // to gpu
         "SkIRect::MakeEmpty()",                                                    // default value
         "${oldVar}.isEmpty() || ${oldVar} != ${newVar}"),                          // dirty check
 
-    REGISTER("GrColor4f", { "half4", "float4", "double4" },
+    REGISTER(Layout::CType::kGrColor4f, { "half4", "float4", "double4" },
         "${pdman}.set4fv(${uniform}, 1, ${var}.fRGBA)",                            // to gpu
         "GrColor4f::kIllegalConstructor"),                                         // default value
 
-    REGISTER("SkPoint", { "half2", "float2", "double2" } ,
+    REGISTER(Layout::CType::kSkPoint, { "half2", "float2", "double2" } ,
         "${pdman}.set2f(${uniform}, ${var}.fX, ${var}.fY)",                        // to gpu
         "SkPoint::Make(SK_FloatNaN, SK_FloatNaN)"),                                // default value
 
-    REGISTER("SkIPoint", { "int2", "short2", "byte2" },
+    REGISTER(Layout::CType::kSkIPoint, { "int2", "short2", "byte2" },
         "${pdman}.set2i(${uniform}, ${var}.fX, ${var}.fY)",                        // to gpu
         "SkIPoint::Make(SK_NaN32, SK_NaN32)"),                                     // default value
 
-    REGISTER("SkMatrix", { "half3x3", "float3x3", "double3x3" },
+    REGISTER(Layout::CType::kSkMatrix, { "half3x3", "float3x3", "double3x3" },
         "${pdman}.setSkMatrix(${uniform}, ${var})",                                // to gpu
         "SkMatrix::MakeScale(SK_FloatNaN)",                                        // default value
         "!${oldVar}.cheapEqualTo(${newVar})"),                                     // dirty check
 
-    REGISTER("SkMatrix44",  { "half4x4", "float4x4", "double4x4" },
+    REGISTER(Layout::CType::kSkMatrix44,  { "half4x4", "float4x4", "double4x4" },
         "${pdman}.setSkMatrix44(${uniform}, ${var})",                              // to gpu
         "SkMatrix::MakeScale(SK_FloatNaN)",                                        // default value
         "!${oldVar}.cheapEqualTo(${newVar})"),                                     // dirty check
 
-    REGISTER("float",  { "half", "float", "double" },
+    REGISTER(Layout::CType::kFloat,  { "half", "float", "double" },
         "${pdman}.set1f(${uniform}, ${var})",                                      // to gpu
         "SK_FloatNaN"),                                                            // default value
 
-    REGISTER("int32_t", { "int", "short", "byte" },
+    REGISTER(Layout::CType::kInt32, { "int", "short", "byte" },
         "${pdman}.set1i(${uniform}, ${var})",                                      // to gpu
         "SK_NaN32"),                                                               // default value
     };
@@ -199,10 +199,10 @@
                                                   const Layout& layout) {
     const std::vector<UniformCTypeMapper>& registeredMappers = get_mappers();
 
-    String ctype = layout.fCType;
+    Layout::CType ctype = layout.fCType;
     // If there's no custom ctype declared in the layout, use the default type mapping
-    if (ctype == "") {
-        ctype = HCodeGenerator::ParameterType(context, type, layout);
+    if (ctype == Layout::CType::kDefault) {
+        ctype = HCodeGenerator::ParameterCType(context, type, layout);
     }
 
     const String& skslType = type.name();
diff --git a/src/sksl/SkSLCPPUniformCTypes.h b/src/sksl/SkSLCPPUniformCTypes.h
index d42fe0a..624b6f3 100644
--- a/src/sksl/SkSLCPPUniformCTypes.h
+++ b/src/sksl/SkSLCPPUniformCTypes.h
@@ -33,13 +33,13 @@
 class UniformCTypeMapper {
 public:
     // Create a templated mapper that does not support state tracking
-    UniformCTypeMapper(const String& ctype, const std::vector<String>& skslTypes,
+    UniformCTypeMapper(Layout::CType ctype, const std::vector<String>& skslTypes,
             const char* setUniformFormat)
         : UniformCTypeMapper(ctype, skslTypes, setUniformFormat, false, "", "", "") { }
 
     // Create a templated mapper that provides extra patterns for the state
     // tracking expressions.
-    UniformCTypeMapper(const String& ctype, const std::vector<String>& skslTypes,
+    UniformCTypeMapper(Layout::CType ctype, const std::vector<String>& skslTypes,
             const String& setUniformFormat, const String& defaultValue,
             const String& dirtyExpressionFormat, const String& saveStateFormat)
         : UniformCTypeMapper(ctype, skslTypes, setUniformFormat,
@@ -58,7 +58,7 @@
     }
 
     // The C++ type name that this mapper applies to
-    const String& ctype() const {
+    Layout::CType ctype() const {
         return fCType;
     }
 
@@ -113,11 +113,11 @@
     }
 
 private:
-    UniformCTypeMapper(const String& ctype, const std::vector<String>& skslTypes,
+    UniformCTypeMapper(Layout::CType ctype, const std::vector<String>& skslTypes,
             const String& setUniformFormat, bool enableTracking, const String& defaultValue,
             const String& dirtyExpressionFormat, const String& saveStateFormat);
 
-    String fCType;
+    Layout::CType fCType;
     std::vector<String> fSKSLTypes;
     String fUniformTemplate;
     bool fInlineValue; // Cached value calculated from fUniformTemplate
diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp
index 17bcfa0..8c6b8f4 100644
--- a/src/sksl/SkSLHCodeGenerator.cpp
+++ b/src/sksl/SkSLHCodeGenerator.cpp
@@ -29,36 +29,46 @@
 
 String HCodeGenerator::ParameterType(const Context& context, const Type& type,
                                      const Layout& layout) {
-    if (layout.fCType != "") {
+    Layout::CType ctype = ParameterCType(context, type, layout);
+    if (ctype != Layout::CType::kDefault) {
+        return Layout::CTypeToStr(ctype);
+    }
+    return type.name();
+}
+
+Layout::CType HCodeGenerator::ParameterCType(const Context& context, const Type& type,
+                                     const Layout& layout) {
+    if (layout.fCType != Layout::CType::kDefault) {
         return layout.fCType;
-    } else if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
-        return "float";
+    }
+    if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
+        return Layout::CType::kFloat;
     } else if (type == *context.fInt_Type ||
                type == *context.fShort_Type ||
                type == *context.fByte_Type) {
-        return "int32_t";
+        return Layout::CType::kInt32;
     } else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
-        return "SkPoint";
+        return Layout::CType::kSkPoint;
     } else if (type == *context.fInt2_Type ||
                type == *context.fShort2_Type ||
                type == *context.fByte2_Type) {
-        return "SkIPoint";
+        return Layout::CType::kSkIPoint;
     } else if (type == *context.fInt4_Type ||
                type == *context.fShort4_Type ||
                type == *context.fByte4_Type) {
-        return "SkIRect";
+        return Layout::CType::kSkIRect;
     } else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
-        return "SkRect";
+        return Layout::CType::kSkRect;
     } else if (type == *context.fFloat3x3_Type || type == *context.fHalf3x3_Type) {
-        return "SkMatrix";
+        return Layout::CType::kSkMatrix;
     } else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
-        return "SkMatrix44";
+        return Layout::CType::kSkMatrix44;
     } else if (type.kind() == Type::kSampler_Kind) {
-        return "sk_sp<GrTextureProxy>";
+        return Layout::CType::kGrTextureProxy;
     } else if (type == *context.fFragmentProcessor_Type) {
-        return "std::unique_ptr<GrFragmentProcessor>";
+        return Layout::CType::kGrFragmentProcessor;
     }
-    return type.name();
+    return Layout::CType::kDefault;
 }
 
 String HCodeGenerator::FieldType(const Context& context, const Type& type,
diff --git a/src/sksl/SkSLHCodeGenerator.h b/src/sksl/SkSLHCodeGenerator.h
index 8c5c232..875bbf9 100644
--- a/src/sksl/SkSLHCodeGenerator.h
+++ b/src/sksl/SkSLHCodeGenerator.h
@@ -33,6 +33,9 @@
 
     static String ParameterType(const Context& context, const Type& type, const Layout& layout);
 
+    static Layout::CType ParameterCType(const Context& context, const Type& type,
+                                        const Layout& layout);
+
     static String FieldType(const Context& context, const Type& type, const Layout& layout);
 
     // Either the field type, or a const reference of the field type if the field type is complex.
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index 6bd0b81..412a09e 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -119,8 +119,12 @@
     TOKEN(INVOCATIONS,                  "invocations");
     TOKEN(WHEN,                         "when");
     TOKEN(KEY,                          "key");
-    TOKEN(CTYPE,                        "ctype");
     TOKEN(TRACKED,                      "tracked");
+    TOKEN(CTYPE,                        "ctype");
+    TOKEN(GRCOLOR4F,                    "GrColor4f");
+    TOKEN(SKRECT,                       "SkRect");
+    TOKEN(SKIRECT,                      "SkIRect");
+    TOKEN(SKPMCOLOR,                    "SkPMColor");
     #undef TOKEN
 }
 
@@ -717,6 +721,30 @@
     return Layout::kKey_Key;
 }
 
+Layout::CType Parser::layoutCType() {
+    if (this->expect(Token::EQ, "'='")) {
+        Token t = this->nextToken();
+        String text = this->text(t);
+        auto found = layoutTokens->find(text);
+        if (found != layoutTokens->end()) {
+            switch (found->second) {
+                case LayoutToken::GRCOLOR4F:
+                    return Layout::CType::kGrColor4f;
+                case LayoutToken::SKRECT:
+                    return Layout::CType::kSkRect;
+                case LayoutToken::SKIRECT:
+                    return Layout::CType::kSkIRect;
+                case LayoutToken::SKPMCOLOR:
+                    return Layout::CType::kSkPMColor;
+                default:
+                    break;
+            }
+        }
+        this->error(t, "unsupported ctype");
+    }
+    return Layout::CType::kDefault;
+}
+
 /* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
 Layout Parser::layout() {
     int flags = 0;
@@ -732,8 +760,8 @@
     int maxVertices = -1;
     int invocations = -1;
     String when;
-    StringFragment ctype;
     Layout::Key key = Layout::kNo_Key;
+    Layout::CType ctype = Layout::CType::kDefault;
     if (this->checkNext(Token::LAYOUT)) {
         if (!this->expect(Token::LPAREN, "'('")) {
             return Layout(flags, location, offset, binding, index, set, builtin,
@@ -861,7 +889,10 @@
                         key = this->layoutKey();
                         break;
                     case LayoutToken::CTYPE:
-                        ctype = this->layoutIdentifier();
+                        ctype = this->layoutCType();
+                        break;
+                    default:
+                        this->error(t, ("'" + text + "' is not a valid layout qualifier").c_str());
                         break;
                 }
             } else if (Layout::ReadFormat(text, &format)) {
diff --git a/src/sksl/SkSLParser.h b/src/sksl/SkSLParser.h
index 8d8702b..febc6bb 100644
--- a/src/sksl/SkSLParser.h
+++ b/src/sksl/SkSLParser.h
@@ -89,8 +89,12 @@
         INVOCATIONS,
         WHEN,
         KEY,
+        TRACKED,
         CTYPE,
-        TRACKED
+        GRCOLOR4F,
+        SKRECT,
+        SKIRECT,
+        SKPMCOLOR,
     };
 
     Parser(const char* text, size_t length, SymbolTable& types, ErrorReporter& errors);
@@ -191,6 +195,8 @@
 
     Layout::Key layoutKey();
 
+    Layout::CType layoutCType();
+
     Layout layout();
 
     Modifiers modifiers();
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index 7986c40..6dfc2e3 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -1729,7 +1729,7 @@
             Type intfStruct(-1, name, fields);
             Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
                           Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
-                          StringFragment());
+                          Layout::CType::kDefault);
             Variable* intfVar = new Variable(-1,
                                              Modifiers(layout, Modifiers::kUniform_Flag),
                                              name,
diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h
index 324c00d..38295ce 100644
--- a/src/sksl/ir/SkSLLayout.h
+++ b/src/sksl/ir/SkSLLayout.h
@@ -76,6 +76,22 @@
         kIdentity_Key,
     };
 
+    enum class CType {
+        kDefault,
+        kFloat,
+        kInt32,
+        kSkRect,
+        kSkIRect,
+        kGrColor4f,
+        kSkPMColor,
+        kSkPoint,
+        kSkIPoint,
+        kSkMatrix,
+        kSkMatrix44,
+        kGrTextureProxy,
+        kGrFragmentProcessor,
+    };
+
     static const char* FormatToStr(Format format) {
         switch (format) {
             case Format::kUnspecified:  return "";
@@ -120,9 +136,43 @@
         return false;
     }
 
+    static const char* CTypeToStr(CType ctype) {
+        switch (ctype) {
+            case CType::kDefault:
+                return nullptr;
+            case CType::kFloat:
+                return "float";
+            case CType::kInt32:
+                return "int32_t";
+            case CType::kSkRect:
+                return "SkRect";
+            case CType::kSkIRect:
+                return "SkIRect";
+            case CType::kGrColor4f:
+                return "GrColor4f";
+            case CType::kSkPMColor:
+                return "SkPMColor";
+            case CType::kSkPoint:
+                return "SkPoint";
+            case CType::kSkIPoint:
+                return "SkIPoint";
+            case CType::kSkMatrix:
+                return "SkMatrix";
+            case CType::kSkMatrix44:
+                return "SkMatrix44";
+            case CType::kGrTextureProxy:
+                return "sk_sp<GrTextureProxy>";
+            case CType::kGrFragmentProcessor:
+                return "std::unique_ptr<GrFragmentProcessor>";
+            default:
+                SkASSERT(false);
+                return nullptr;
+        }
+    }
+
     Layout(int flags, int location, int offset, int binding, int index, int set, int builtin,
            int inputAttachmentIndex, Format format, Primitive primitive, int maxVertices,
-           int invocations, String when, Key key, StringFragment ctype)
+           int invocations, String when, Key key, CType ctype)
     : fFlags(flags)
     , fLocation(location)
     , fOffset(offset)
@@ -152,7 +202,8 @@
     , fPrimitive(kUnspecified_Primitive)
     , fMaxVertices(-1)
     , fInvocations(-1)
-    , fKey(kNo_Key) {}
+    , fKey(kNo_Key)
+    , fCType(CType::kDefault) {}
 
     String description() const {
         String result;
@@ -359,7 +410,7 @@
     int fInvocations;
     String fWhen;
     Key fKey;
-    StringFragment fCType;
+    CType fCType;
 };
 
 } // namespace