Add support for int-typed data payloads.

If we are going to create a new snippet ID every time a runtime effect
is painted, we will overflow a byte very rapidly.

Change-Id: Ic094af2a81e590488bf90b60492b004e9135d4a2
Bug: skia:13405
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/551843
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkPaintParamsKey.cpp b/src/core/SkPaintParamsKey.cpp
index 8f5e3b3..521366d 100644
--- a/src/core/SkPaintParamsKey.cpp
+++ b/src/core/SkPaintParamsKey.cpp
@@ -140,24 +140,19 @@
 }
 #endif // SK_DEBUG
 
-void SkPaintParamsKeyBuilder::addBytes(uint32_t numBytes, const uint8_t* data) {
-    if (!this->isValid()) {
-        return;
+static int field_size(DataPayloadType type) {
+    switch (type) {
+        case DataPayloadType::kByte:
+        case DataPayloadType::kPointerIndex: return 1;
+        case DataPayloadType::kInt:          return 4;
+        case DataPayloadType::kFloat4:       return 16;
     }
-
-    if (fStack.empty()) {
-        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
-        this->makeInvalid();
-        return;
-    }
-
-    SkDEBUGCODE(this->checkExpectations(DataPayloadType::kByte, numBytes);)
-    SkASSERT(!this->isLocked());
-
-    fData.append(numBytes, data);
+    SkUNREACHABLE;
 }
 
-void SkPaintParamsKeyBuilder::add(int numColors, const SkColor4f* color) {
+void SkPaintParamsKeyBuilder::addToKey(uint32_t count,
+                                       const void* data,
+                                       DataPayloadType payloadType) {
     if (!this->isValid()) {
         return;
     }
@@ -168,27 +163,29 @@
         return;
     }
 
-    SkDEBUGCODE(this->checkExpectations(DataPayloadType::kFloat4, numColors);)
+    SkDEBUGCODE(this->checkExpectations(payloadType, count);)
     SkASSERT(!this->isLocked());
 
-    fData.append(16 * numColors, reinterpret_cast<const uint8_t*>(color));
+    fData.append(field_size(payloadType) * count, reinterpret_cast<const uint8_t*>(data));
+}
+
+void SkPaintParamsKeyBuilder::addBytes(uint32_t numBytes, const uint8_t* data) {
+    this->addToKey(numBytes, data, DataPayloadType::kByte);
+}
+
+void SkPaintParamsKeyBuilder::addInts(uint32_t numInts, const int32_t* data) {
+    this->addToKey(numInts, data, DataPayloadType::kInt);
+}
+
+void SkPaintParamsKeyBuilder::add(int numColors, const SkColor4f* colors) {
+    this->addToKey(numColors, colors, DataPayloadType::kFloat4);
 }
 
 void SkPaintParamsKeyBuilder::addPointer(const void* ptr) {
-    if (!this->isValid()) {
-        return;
-    }
-
-    if (fStack.empty()) {
-        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
-        this->makeInvalid();
-        return;
-    }
-
-    SkDEBUGCODE(this->checkExpectations(SkPaintParamsKey::DataPayloadType::kPointerIndex, 1);)
-    SkASSERT(!this->isLocked());
     SkASSERT(fPointerData.size() <= 0xFF);
-    fData.push_back((uint8_t)fPointerData.size());
+    uint8_t pointerIndex = (uint8_t)fPointerData.size();
+
+    this->addToKey(1, &pointerIndex, DataPayloadType::kPointerIndex);
     fPointerData.push_back(ptr);
 }
 
@@ -369,19 +366,10 @@
     return fBlock.subspan(payloadOffset, payloadSize);
 }
 
-static int field_size(const DataPayloadField& field) {
-    switch (field.fType) {
-        case DataPayloadType::kByte:
-        case DataPayloadType::kPointerIndex: return field.fCount;
-        case DataPayloadType::kFloat4:       return field.fCount * 16;
-    }
-    SkUNREACHABLE;
-}
-
 static int field_offset(SkSpan<const DataPayloadField> fields, int fieldIndex) {
     int byteOffset = 0;
     for (int i = 0; i < fieldIndex; ++i) {
-        byteOffset += field_size(fields[i]);
+        byteOffset += field_size(fields[i].fType) * fields[i].fCount;
     }
     return byteOffset;
 }
@@ -401,6 +389,13 @@
                                               fieldIndex);
 }
 
+SkSpan<const int32_t> SkPaintParamsKey::BlockReader::ints(int fieldIndex) const {
+    SkASSERT(fEntry->fDataPayloadExpectations[fieldIndex].fType == DataPayloadType::kInt);
+    return payload_subspan_for_field<int32_t>(this->dataPayload(),
+                                              fEntry->fDataPayloadExpectations,
+                                              fieldIndex);
+}
+
 SkSpan<const SkColor4f> SkPaintParamsKey::BlockReader::colors(int fieldIndex) const {
     SkASSERT(fEntry->fDataPayloadExpectations[fieldIndex].fType == DataPayloadType::kFloat4);
     return payload_subspan_for_field<SkColor4f>(this->dataPayload(),
diff --git a/src/core/SkPaintParamsKey.h b/src/core/SkPaintParamsKey.h
index 3dfee18..6a09fed 100644
--- a/src/core/SkPaintParamsKey.h
+++ b/src/core/SkPaintParamsKey.h
@@ -54,6 +54,7 @@
 
     enum class DataPayloadType {
         kByte,
+        kInt,
         kFloat4,
         // Represents a position inside the fPointerData span.
         kPointerIndex,
@@ -86,6 +87,7 @@
         // Retrieve the fieldIndex-th field in the data payload as a span. The type being read
         // is checked against the data payload's structure.
         SkSpan<const uint8_t> bytes(int fieldIndex) const;
+        SkSpan<const int32_t> ints(int fieldIndex) const;
         SkSpan<const SkColor4f> colors(int fieldIndex) const;
         const void* pointer(int fieldIndex) const;
 
@@ -209,7 +211,11 @@
     void addByte(uint8_t data) {
         this->addBytes(1, &data);
     }
-    void add(int numColors, const SkColor4f* color);
+    void addInts(uint32_t numInts, const int32_t* data);
+    void addInt(int32_t data) {
+        this->addInts(1, &data);
+    }
+    void add(int numColors, const SkColor4f* colors);
     void add(const SkColor4f& color) {
         this->add(/*numColors=*/1, &color);
     }
@@ -252,6 +258,7 @@
     SkDEBUGCODE(bool isLocked() const { return fLocked; })
 
 private:
+    void addToKey(uint32_t count, const void* data, SkPaintParamsKey::DataPayloadType payloadType);
     void makeInvalid();
 
 #ifdef SK_DEBUG
diff --git a/tests/graphite/KeyTest.cpp b/tests/graphite/KeyTest.cpp
index 65a4d4b..88c1b25 100644
--- a/tests/graphite/KeyTest.cpp
+++ b/tests/graphite/KeyTest.cpp
@@ -190,20 +190,20 @@
     static constexpr SkPaintParamsKey::DataPayloadField kDataFields[] = {
             {"ByteX",   SkPaintParamsKey::DataPayloadType::kByte,   kCountX},
             {"Float4Y", SkPaintParamsKey::DataPayloadType::kFloat4, kCountY},
-            {"ByteZ",   SkPaintParamsKey::DataPayloadType::kByte,   kCountZ},
+            {"IntZ",    SkPaintParamsKey::DataPayloadType::kInt,    kCountZ},
     };
 
     int userSnippetID = dict->addUserDefinedSnippet("key", kDataFields);
 
     static constexpr uint8_t   kDataX[kCountX] = {1, 2, 3};
     static constexpr SkColor4f kDataY[kCountY] = {{4, 5, 6, 7}, {8, 9, 10, 11}};
-    static constexpr uint8_t   kDataZ[kCountZ] = {12, 13, 14, 15, 16, 17, 18};
+    static constexpr int32_t   kDataZ[kCountZ] = {-1234567, 13, 14, 15, 16, 17, 7654321};
 
     SkPaintParamsKeyBuilder builder(dict, SkBackend::kGraphite);
     builder.beginBlock(userSnippetID);
     builder.addBytes(kCountX, kDataX);
     builder.add     (kCountY, kDataY);
-    builder.addBytes(kCountZ, kDataZ);
+    builder.addInts (kCountZ, kDataZ);
     builder.endBlock();
 
     SkPaintParamsKey key = builder.lockAsKey();
@@ -222,7 +222,7 @@
     REPORTER_ASSERT(reporter, readerDataY.size() == kCountY);
     REPORTER_ASSERT(reporter, 0 == memcmp(readerDataY.data(), kDataY, sizeof(kDataY)));
 
-    SkSpan<const uint8_t> readerBytesZ = reader.bytes(2);
+    SkSpan<const int32_t> readerBytesZ = reader.ints(2);
     REPORTER_ASSERT(reporter, readerBytesZ.size() == kCountZ);
     REPORTER_ASSERT(reporter, 0 == memcmp(readerBytesZ.data(), kDataZ, sizeof(kDataZ)));
 }