add array to the Uniforms

Note: I have changed from using a byte offset for index to
an ordinary array index at the builder interface, but the
builder converts this to a byte offset for the instruction.
This makes the API easier to use.

I've added pushArray, and pushArrayF to the Uniforms, and
convenience methods on the builder to take Uniforms.

I've expanded the tests to use the new API.

Change-Id: Id538e826a96d4d242ae6482acc711d84c9041239
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/432036
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/core/SkVM.cpp b/src/core/SkVM.cpp
index cf9514b..ceee3ad 100644
--- a/src/core/SkVM.cpp
+++ b/src/core/SkVM.cpp
@@ -624,8 +624,9 @@
         return {this, push(Op::uniform32, NA,NA,NA,NA, ptr.ix, offset)};
     }
 
+    // Note: this converts the array index into a byte offset for the op.
     I32 Builder::array32  (Ptr ptr, int offset, int index) {
-        return {this, push(Op::array32, NA,NA,NA,NA, ptr.ix, offset, index)};
+        return {this, push(Op::array32, NA,NA,NA,NA, ptr.ix, offset, index * sizeof(int))};
     }
 
     I32 Builder::splat(int n) { return {this, push(Op::splat, NA,NA,NA,NA, n) }; }
diff --git a/src/core/SkVM.h b/src/core/SkVM.h
index ebe3546..8214628 100644
--- a/src/core/SkVM.h
+++ b/src/core/SkVM.h
@@ -544,6 +544,14 @@
             }
             return {base, (int)( sizeof(int)*(buf.size() - SK_ARRAY_COUNT(ints)) )};
         }
+
+        Uniform pushArray(int32_t a[]) {
+            return this->pushPtr(a);
+        }
+
+        Uniform pushArrayF(float a[]) {
+            return this->pushPtr(a);
+        }
     };
 
     struct PixelFormat {
@@ -633,8 +641,12 @@
         I32 uniform32(Ptr ptr, int offset);
         F32 uniformF (Ptr ptr, int offset) { return pun_to_F32(uniform32(ptr,offset)); }
 
-        // Load i32/f32 uniform with byte-count offset and index.
+        // Load i32/f32 uniform with byte-count offset and an c-style array index. The address of
+        // the element is (*(ptr + byte-count offset))[index].
         I32 array32  (Ptr ptr, int offset, int index);
+        F32 arrayF   (Ptr ptr, int offset, int index) {
+            return pun_to_F32(array32(ptr, offset, index));
+        }
 
         // Push and load this color as a uniform.
         Color uniformColor(SkColor4f, Uniforms*);
@@ -655,6 +667,11 @@
         I32 gather32 (Uniform u, I32 index) { return this->gather32 (u.ptr, u.offset, index); }
         F32 gatherF  (Uniform u, I32 index) { return this->gatherF  (u.ptr, u.offset, index); }
 
+        // Convenience methods for working with array pointers in skvm::Uniforms. Index is an
+        // array index and not a byte offset. The array pointer is stored at u.
+        I32 array32  (Uniform a, int index) { return this->array32  (a.ptr, a.offset, index); }
+        F32 arrayF   (Uniform a, int index) { return this->arrayF   (a.ptr, a.offset, index); }
+
         // Load an immediate constant.
         I32 splat(int      n);
         I32 splat(unsigned u) { return splat((int)u); }
diff --git a/tests/SkVMTest.cpp b/tests/SkVMTest.cpp
index 0432fc4..efd5d80 100644
--- a/tests/SkVMTest.cpp
+++ b/tests/SkVMTest.cpp
@@ -770,42 +770,63 @@
 }
 
 DEF_TEST(SKVM_array32, r) {
+
+
+
     skvm::Builder b;
+    skvm::Uniforms uniforms(b.uniform(), 0);
+    // Take up the first slot, so other uniforms are not at 0 offset.
+    uniforms.push(0);
+    int i[] = {3, 7};
+    skvm::Uniform array = uniforms.pushArray(i);
+    float f[] = {5, 9};
+    skvm::Uniform arrayF = uniforms.pushArrayF(f);
     {
         skvm::Ptr buf0     = b.varying<int32_t>(),
                   buf1     = b.varying<int32_t>(),
-                  uniforms = b.uniform();
+                  buf2     = b.varying<int32_t>();
 
-        skvm::I32 x = b.array32(uniforms, 0, 0);
-        b.store32(buf0, x);
-        skvm::I32 y = b.array32(uniforms, 0, 4);
-        b.store32(buf1, y);
+        skvm::I32 j = b.array32(array, 0);
+        b.store32(buf0, j);
+        skvm::I32 k = b.array32(array, 1);
+        b.store32(buf1, k);
+
+        skvm::F32 x = b.arrayF(arrayF, 0);
+        skvm::F32 y = b.arrayF(arrayF, 1);
+        b.store32(buf2, b.trunc(b.add(x, y)));
     }
 
     test_jit_and_interpreter(b, [&](const skvm::Program& program) {
-        const int K = 20;
-        int i[2] = {3, 7};
-        struct {
-            int* g;
-        } uniforms{i};
-        int32_t buf0[K];
-        int32_t buf1[K];
+        const int K = 10;
+        int32_t buf0[K],
+                buf1[K],
+                buf2[K];
 
-        program.eval(K, buf0, buf1, &uniforms);
+        // reset the i[0] for the two tests.
+        i[0] = 3;
+        f[1] = 9;
+        program.eval(K, uniforms.buf.data(), buf0, buf1, buf2);
         for (auto v : buf0) {
             REPORTER_ASSERT(r, v == 3);
         }
         for (auto v : buf1) {
             REPORTER_ASSERT(r, v == 7);
         }
+        for (auto v : buf2) {
+            REPORTER_ASSERT(r, v == 14);
+        }
         i[0] = 4;
-        program.eval(K, buf0, buf1, &uniforms);
+        f[1] = 10;
+        program.eval(K, uniforms.buf.data(), buf0, buf1, buf2);
         for (auto v : buf0) {
             REPORTER_ASSERT(r, v == 4);
         }
         for (auto v : buf1) {
             REPORTER_ASSERT(r, v == 7);
         }
+        for (auto v : buf2) {
+            REPORTER_ASSERT(r, v == 15);
+        }
     });
 }