Add new method for storing DrawOpAtlas texture index.

Storing the texture index in the lower bit of each texture coordinate
seems to have issues on certain iOS devices. Rather than do that, we
use the sign of the texture coordinate to act as our storage bit.
To manage encoding 0 we map [0, N] to [-1, -N-1] to represent a bit.

Change-Id: Ic588ee92cf858915a1833cf482d4b23bd11c1000
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/263561
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index 1a217f8..466e98f 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -21,6 +21,10 @@
 #include "src/gpu/GrSurfaceProxyPriv.h"
 #include "src/gpu/GrTracing.h"
 
+#ifdef DUMP_ATLAS_DATA
+static bool gDumpAtlasData = false;
+#endif
+
 // When proxy allocation is deferred until flush time the proxies acting as atlases require
 // special handling. This is because the usage that can be determined from the ops themselves
 // isn't sufficient. Independent of the ops there will be ASAP and inline uploads to the
@@ -57,9 +61,32 @@
     return atlas;
 }
 
-#ifdef DUMP_ATLAS_DATA
-static bool gDumpAtlasData = false;
-#endif
+// The two bits that make up the texture index are packed into the u and v coordinate
+// respectively. To represent a '1', we negate the coordinate and subtract 1 (to handle 0).
+std::pair<int16_t, int16_t> GrDrawOpAtlas::PackIndexInTexCoords(int16_t u, int16_t v,
+                                                                int texIndex) {
+    SkASSERT(texIndex >= 0 && texIndex < 4);
+    if (texIndex & 0x2) {
+        u = -u-1;
+    }
+    if (texIndex & 0x1) {
+        v = -v-1;
+    }
+    return std::make_pair(u, v);
+}
+
+std::tuple<int16_t, int16_t, int> GrDrawOpAtlas::UnpackIndexFromTexCoords(int16_t u, int16_t v) {
+    int texIndex = 0;
+    if (u < 0) {
+        u = -u-1;
+        texIndex |= 0x2;
+    }
+    if (v < 0) {
+        v = -v-1;
+        texIndex |= 0x1;
+    }
+    return std::make_tuple(u, v, texIndex);
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 GrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY,
diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h
index 4d81ca9..4829b47 100644
--- a/src/gpu/GrDrawOpAtlas.h
+++ b/src/gpu/GrDrawOpAtlas.h
@@ -100,6 +100,28 @@
                                                GrDrawOpAtlas::EvictionFunc func, void* data);
 
     /**
+     * Packs a texture atlas index into the signed int16 texture coordinates.
+     *  @param u      U texture coordinate
+     *  @param v      V texture coordinate
+     *  @param texIndex           index of the texture these coordinates apply to. Must be in the range [0, 3].
+     *  @return                 The new u and v coordinates with the packed value
+     */
+    static std::pair<int16_t, int16_t> PackIndexInTexCoords(int16_t u, int16_t v, int texIndex);
+
+    /**
+     * Unpacks a texture atlas index from signed int16 texture coordinates.
+     *  @param u      Packed U texture coordinate
+     *  @param v      Packed V texture coordinate
+     *  @return    The unpacked u and v coordinates with the texture index.
+     */
+    static std::tuple<int16_t, int16_t, int> UnpackIndexFromTexCoords(int16_t u, int16_t v);
+
+    // Maximum texture size that can be used for atlases.
+    // On lower-end GPUs texture coordinates end up being half floats, which means we only
+    // have enough precision to represent 2048 texels.
+    static constexpr int kMaxTextureSize = 2048;
+
+    /**
      * Adds a width x height subimage to the atlas. Upon success it returns 'kSucceeded' and returns
      * the ID and the subimage's coordinates in the backing texture. 'kTryAgain' is returned if
      * the subimage cannot fit in the atlas without overwriting texels that will be read in the
diff --git a/src/gpu/effects/GrAtlasedShaderHelpers.h b/src/gpu/effects/GrAtlasedShaderHelpers.h
index edf8d9d..5196b37 100644
--- a/src/gpu/effects/GrAtlasedShaderHelpers.h
+++ b/src/gpu/effects/GrAtlasedShaderHelpers.h
@@ -15,27 +15,30 @@
 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
 
 static void append_index_uv_varyings(GrGLSLPrimitiveProcessor::EmitArgs& args,
+                                     int numTextureSamplers,
                                      const char* inTexCoordsName,
                                      const char* atlasDimensionsInvName,
                                      GrGLSLVarying* uv,
                                      GrGLSLVarying* texIdx,
                                      GrGLSLVarying* st) {
-    using Interpolation = GrGLSLVaryingHandler::Interpolation;
-
     // This extracts the texture index and texel coordinates from the same variable
-    // Packing structure: texel coordinates are multiplied by 2 (or shifted left 1)
-    //                    texture index is stored as lower bits of both x and y
-    if (args.fShaderCaps->integerSupport()) {
-        args.fVertBuilder->codeAppendf("int2 signedCoords = int2(%s.x, %s.y);",
-                                       inTexCoordsName, inTexCoordsName);
-        args.fVertBuilder->codeAppend("int texIdx = 2*(signedCoords.x & 0x1) + (signedCoords.y & 0x1);");
-        args.fVertBuilder->codeAppend("float2 unormTexCoords = float2(signedCoords.x/2, signedCoords.y/2);");
+    // Packing structure: to store an index bit, texel coordinate [0,N] is mapped to [-1,-N-1]
+    args.fVertBuilder->codeAppendf("float2 unormTexCoords = float2(%s.x, %s.y);",
+                                   inTexCoordsName, inTexCoordsName);
+    if (numTextureSamplers < 2) {
+        args.fVertBuilder->codeAppend("float texIdx = 0;");
     } else {
-        args.fVertBuilder->codeAppendf("float2 indexTexCoords = float2(%s.x, %s.y);",
-                                       inTexCoordsName, inTexCoordsName);
-        args.fVertBuilder->codeAppend("float2 unormTexCoords = floor(0.5*indexTexCoords);");
-        args.fVertBuilder->codeAppend("float2 diff = indexTexCoords - 2.0*unormTexCoords;");
-        args.fVertBuilder->codeAppend("float texIdx = 2.0*diff.x + diff.y;");
+        args.fVertBuilder->codeAppend("float indexX = 0; float indexY = 0;");
+        // Could possibly do this with mix() but not clear it's worth it.
+        args.fVertBuilder->codeAppend("if (unormTexCoords.x < 0) {");
+        args.fVertBuilder->codeAppend("  unormTexCoords.x = -unormTexCoords.x-1;");
+        args.fVertBuilder->codeAppend("  indexX = 2;");
+        args.fVertBuilder->codeAppend("}");
+        args.fVertBuilder->codeAppend("if (unormTexCoords.y < 0) {");
+        args.fVertBuilder->codeAppend("  unormTexCoords.y = -unormTexCoords.y-1;");
+        args.fVertBuilder->codeAppend("  indexY = 1;");
+        args.fVertBuilder->codeAppend("}");
+        args.fVertBuilder->codeAppend("float texIdx = indexX + indexY;");
     }
 
     // Multiply by 1/atlasDimensions to get normalized texture coordinates
@@ -43,9 +46,7 @@
     args.fVertBuilder->codeAppendf("%s = unormTexCoords * %s;", uv->vsOut(),
                                    atlasDimensionsInvName);
 
-    args.fVaryingHandler->addVarying("TexIndex", texIdx, args.fShaderCaps->integerSupport()
-                                                                 ? Interpolation::kMustBeFlat
-                                                                 : Interpolation::kCanBeFlat);
+    args.fVaryingHandler->addVarying("TexIndex", texIdx);
     args.fVertBuilder->codeAppendf("%s = texIdx;", texIdx->vsOut());
 
     if (st) {
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 48b2397..e6734f0 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -37,10 +37,9 @@
                 kVertex_GrShaderFlag, kFloat2_GrSLType, "AtlasSizeInv", &atlasDimensionsInvName);
 
         GrGLSLVarying uv(kFloat2_GrSLType);
-        GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
-        GrGLSLVarying texIdx(texIdxType);
-        append_index_uv_varyings(args, btgp.inTextureCoords().name(), atlasDimensionsInvName, &uv,
-                                 &texIdx, nullptr);
+        GrGLSLVarying texIdx(kFloat_GrSLType);
+        append_index_uv_varyings(args, btgp.numTextureSamplers(), btgp.inTextureCoords().name(),
+                                 atlasDimensionsInvName, &uv, &texIdx, nullptr);
 
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         // Setup pass through color
@@ -146,8 +145,8 @@
         fInColor = MakeColorAttribute("inColor", wideColor);
     }
 
-    fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
-                        caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
+    fInTextureCoords = {"inTextureCoords", kShort2_GrVertexAttribType,
+                        caps.integerSupport() ? kShort2_GrSLType : kFloat2_GrSLType};
     this->setVertexAttributes(&fInPosition, 3);
 
     if (numActiveViews) {
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 0fe675a..2ffc319 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -67,10 +67,10 @@
 
         // add varyings
         GrGLSLVarying uv(kFloat2_GrSLType);
-        GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
-        GrGLSLVarying texIdx(texIdxType);
+        GrGLSLVarying texIdx(kFloat_GrSLType);
         GrGLSLVarying st(kFloat2_GrSLType);
-        append_index_uv_varyings(args, dfTexEffect.inTextureCoords().name(), atlasDimensionsInvName,
+        append_index_uv_varyings(args, dfTexEffect.numTextureSamplers(),
+                                 dfTexEffect.inTextureCoords().name(), atlasDimensionsInvName,
                                  &uv, &texIdx, &st);
 
         bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
@@ -233,8 +233,8 @@
         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
     }
     fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType };
-    fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
-                        caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
+    fInTextureCoords = {"inTextureCoords", kShort2_GrVertexAttribType,
+                        caps.integerSupport() ? kShort2_GrSLType : kFloat2_GrSLType};
     this->setVertexAttributes(&fInPosition, 3);
 
     if (numViews) {
@@ -344,11 +344,11 @@
                                                                 &atlasDimensionsInvName);
 
         GrGLSLVarying uv(kFloat2_GrSLType);
-        GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
-        GrGLSLVarying texIdx(texIdxType);
+        GrGLSLVarying texIdx(kFloat_GrSLType);
         GrGLSLVarying st(kFloat2_GrSLType);
-        append_index_uv_varyings(args, dfPathEffect.inTextureCoords().name(),
-                                 atlasDimensionsInvName, &uv, &texIdx, &st);
+        append_index_uv_varyings(args, dfPathEffect.numTextureSamplers(),
+                                 dfPathEffect.inTextureCoords().name(), atlasDimensionsInvName,
+                                 &uv, &texIdx, &st);
 
         // setup pass through color
         varyingHandler->addPassThroughAttribute(dfPathEffect.inColor(), args.fOutputColor);
@@ -525,8 +525,8 @@
 
     fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
     fInColor = MakeColorAttribute("inColor", wideColor);
-    fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
-                        caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
+    fInTextureCoords = {"inTextureCoords", kShort2_GrVertexAttribType,
+                        caps.integerSupport() ? kShort2_GrSLType : kFloat2_GrSLType};
     this->setVertexAttributes(&fInPosition, 3);
 
     if (numViews) {
@@ -649,10 +649,10 @@
 
         // set up varyings
         GrGLSLVarying uv(kFloat2_GrSLType);
-        GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
-        GrGLSLVarying texIdx(texIdxType);
+        GrGLSLVarying texIdx(kFloat_GrSLType);
         GrGLSLVarying st(kFloat2_GrSLType);
-        append_index_uv_varyings(args, dfTexEffect.inTextureCoords().name(), atlasDimensionsInvName,
+        append_index_uv_varyings(args, dfTexEffect.numTextureSamplers(),
+                                 dfTexEffect.inTextureCoords().name(), atlasDimensionsInvName,
                                  &uv, &texIdx, &st);
 
         GrGLSLVarying delta(kFloat_GrSLType);
@@ -848,8 +848,8 @@
         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
     }
     fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
-    fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
-                        caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
+    fInTextureCoords = {"inTextureCoords", kShort2_GrVertexAttribType,
+                        caps.integerSupport() ? kShort2_GrSLType : kFloat2_GrSLType};
     this->setVertexAttributes(&fInPosition, 3);
 
     if (numViews) {
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 90f3f3b..7a41cac 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -192,17 +192,22 @@
             // In the LCD case the color will be garbage, but we'll overwrite it with the texcoords
             // and it avoids a lot of conditionals.
             auto color = *reinterpret_cast<const SkColor*>(blobVertices + sizeof(SkPoint));
-            size_t coordOffset = vertexStride - 2*sizeof(uint16_t);
-            auto* blobCoordsLT = reinterpret_cast<const uint16_t*>(blobVertices + coordOffset);
-            auto* blobCoordsRB = reinterpret_cast<const uint16_t*>(blobVertices + 3 * vertexStride +
+            size_t coordOffset = vertexStride - 2*sizeof(int16_t);
+            auto* blobCoordsLT = reinterpret_cast<const int16_t*>(blobVertices + coordOffset);
+            auto* blobCoordsRB = reinterpret_cast<const int16_t*>(blobVertices + 3 * vertexStride +
                                                                    coordOffset);
             // Pull out the texel coordinates and texture index bits
-            uint16_t coordsRectL = blobCoordsLT[0] >> 1;
-            uint16_t coordsRectT = blobCoordsLT[1] >> 1;
-            uint16_t coordsRectR = blobCoordsRB[0] >> 1;
-            uint16_t coordsRectB = blobCoordsRB[1] >> 1;
-            uint16_t pageIndexX = blobCoordsLT[0] & 0x1;
-            uint16_t pageIndexY = blobCoordsLT[1] & 0x1;
+            int16_t coordsRectL = blobCoordsLT[0];
+            int16_t coordsRectT = blobCoordsLT[1];
+            int16_t coordsRectR = blobCoordsRB[0];
+            int16_t coordsRectB = blobCoordsRB[1];
+            int index0, index1;
+
+            std::tie(coordsRectL, coordsRectT, index0) =
+                    GrDrawOpAtlas::UnpackIndexFromTexCoords(coordsRectL, coordsRectT);
+            std::tie(coordsRectR, coordsRectB, index1) =
+                    GrDrawOpAtlas::UnpackIndexFromTexCoords(coordsRectR, coordsRectB);
+            SkASSERT(index0 == index1);
 
             int positionRectWidth = positionRect.width();
             int positionRectHeight = positionRect.height();
@@ -228,10 +233,10 @@
             positionRect.fBottom -= delta;
 
             // Repack texel coordinates and index
-            coordsRectL = coordsRectL << 1 | pageIndexX;
-            coordsRectT = coordsRectT << 1 | pageIndexY;
-            coordsRectR = coordsRectR << 1 | pageIndexX;
-            coordsRectB = coordsRectB << 1 | pageIndexY;
+            std::tie(coordsRectL, coordsRectT) =
+                    GrDrawOpAtlas::PackIndexInTexCoords(coordsRectL, coordsRectT, index0);
+            std::tie(coordsRectR, coordsRectB) =
+                    GrDrawOpAtlas::PackIndexInTexCoords(coordsRectR, coordsRectB, index1);
 
             // Set new positions and coords
             SkPoint* currPosition = reinterpret_cast<SkPoint*>(currVertex);
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index e8a410a..06b6571 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -625,17 +625,20 @@
         shapeData->fBounds.fRight /= scale;
         shapeData->fBounds.fBottom /= scale;
 
-        // We pack the 2bit page index in the low bit of the u and v texture coords
+        // Pack the page index into the u and v texture coords
         uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(id);
         SkASSERT(pageIndex < 4);
-        uint16_t uBit = (pageIndex >> 1) & 0x1;
-        uint16_t vBit = pageIndex & 0x1;
-        shapeData->fTextureCoords.set((atlasLocation.fX+SK_DistanceFieldPad) << 1 | uBit,
-                                      (atlasLocation.fY+SK_DistanceFieldPad) << 1 | vBit,
-                                      (atlasLocation.fX+SK_DistanceFieldPad+
-                                       devPathBounds.width()) << 1 | uBit,
-                                      (atlasLocation.fY+SK_DistanceFieldPad+
-                                       devPathBounds.height()) << 1 | vBit);
+        int16_t left, top, right, bottom;
+        std::tie(left, top, right, bottom) =
+                std::make_tuple(atlasLocation.fX + SK_DistanceFieldPad,
+                                atlasLocation.fY + SK_DistanceFieldPad,
+                                atlasLocation.fX + SK_DistanceFieldPad + devPathBounds.width(),
+                                atlasLocation.fY + SK_DistanceFieldPad + devPathBounds.height());
+        std::tie(left, top) =
+                GrDrawOpAtlas::PackIndexInTexCoords(left, top, pageIndex);
+        std::tie(right, bottom) =
+                GrDrawOpAtlas::PackIndexInTexCoords(right, bottom, pageIndex);
+        shapeData->fTextureCoords.set(left, top, right, bottom);
 
         fShapeCache->add(shapeData);
         fShapeList->addToTail(shapeData);
@@ -723,14 +726,18 @@
         shapeData->fBounds = SkRect::Make(devPathBounds);
         shapeData->fBounds.offset(-translateX, -translateY);
 
-        // We pack the 2bit page index in the low bit of the u and v texture coords
+        // Pack the page index into the u and v texture coords
         uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(id);
         SkASSERT(pageIndex < 4);
-        uint16_t uBit = (pageIndex >> 1) & 0x1;
-        uint16_t vBit = pageIndex & 0x1;
-        shapeData->fTextureCoords.set(atlasLocation.fX << 1 | uBit, atlasLocation.fY << 1 | vBit,
-                                      (atlasLocation.fX+width) << 1 | uBit,
-                                      (atlasLocation.fY+height) << 1 | vBit);
+        int16_t left, top, right, bottom;
+        std::tie(left, top, right, bottom) = std::make_tuple(atlasLocation.fX, atlasLocation.fY,
+                                                             atlasLocation.fX+width,
+                                                             atlasLocation.fY+height);
+        std::tie(left, top) =
+                GrDrawOpAtlas::PackIndexInTexCoords(left, top, pageIndex);
+        std::tie(right, bottom) =
+                GrDrawOpAtlas::PackIndexInTexCoords(right, bottom, pageIndex);
+        shapeData->fTextureCoords.set(left, top, right, bottom);
 
         fShapeCache->add(shapeData);
         fShapeList->addToTail(shapeData);
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index 894a227..45ba8df 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -228,14 +228,14 @@
     const size_t vertexStride = this->vertexStride();
     const size_t texCoordOffset = this->texCoordOffset();
     char* vertex = this->quadStart(begin);
-    uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
+    int16_t* textureCoords = reinterpret_cast<int16_t*>(vertex + texCoordOffset);
     for (int i = begin; i < end; i++) {
         GrGlyph* glyph = this->fGlyphs[i];
         SkASSERT(glyph != nullptr);
 
         int width = glyph->fBounds.width();
         int height = glyph->fBounds.height();
-        uint16_t u0, v0, u1, v1;
+        int16_t u0, v0, u1, v1;
         if (this->drawAsDistanceFields()) {
             u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
             v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
@@ -248,32 +248,23 @@
             v1 = v0 + height;
         }
 
-        // We pack the 2bit page index in the low bit of the u and v texture coords
+        // We pack the 2bit page index as the sign bit of the u and v texture coords
         uint32_t pageIndex = glyph->pageIndex();
-        SkASSERT(pageIndex < 4);
-        uint16_t uBit = (pageIndex >> 1u) & 0x1u;
-        uint16_t vBit = pageIndex & 0x1u;
-        u0 <<= 1u;
-        u0 |= uBit;
-        v0 <<= 1u;
-        v0 |= vBit;
-        u1 <<= 1u;
-        u1 |= uBit;
-        v1 <<= 1u;
-        v1 |= vBit;
+        std::tie(u0, v0) = GrDrawOpAtlas::PackIndexInTexCoords(u0, v0, pageIndex);
+        std::tie(u1, v1) = GrDrawOpAtlas::PackIndexInTexCoords(u1, v1, pageIndex);
 
         textureCoords[0] = u0;
         textureCoords[1] = v0;
-        textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
+        textureCoords = SkTAddOffset<int16_t>(textureCoords, vertexStride);
         textureCoords[0] = u0;
         textureCoords[1] = v1;
-        textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
+        textureCoords = SkTAddOffset<int16_t>(textureCoords, vertexStride);
         textureCoords[0] = u1;
         textureCoords[1] = v0;
-        textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
+        textureCoords = SkTAddOffset<int16_t>(textureCoords, vertexStride);
         textureCoords[0] = u1;
         textureCoords[1] = v1;
-        textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
+        textureCoords = SkTAddOffset<int16_t>(textureCoords, vertexStride);
     }
 }