Revise GrDataUtils to be more self-contained (take 3)

This makes the GL and Vk backends share more code and sets up for the Metal implementation.

Change-Id: I781d5b6188fb2d46ae4ec48204fda74fe28b18c0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/218964
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index 8b4de2d..965251e 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -117,7 +117,8 @@
     return numBlocks * sizeof(ETC1Block);
 }
 
-void GrFillInETC1WithColor(int width, int height, const SkColor4f& colorf, void* dest) {
+// Fill in 'dest' with ETC1 blocks derived from 'colorf'
+static void fillin_ETC1_with_color(int width, int height, const SkColor4f& colorf, void* dest) {
     SkColor color = colorf.toSkColor();
 
     ETC1Block block;
@@ -130,8 +131,9 @@
     }
 }
 
-bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
-                           const SkColor4f& colorf, void* dest) {
+// Fill in the width x height 'dest' with the munged version of 'colorf' that matches 'config'
+static bool fill_buffer_with_color(GrPixelConfig config, int width, int height,
+                                   const SkColor4f& colorf, void* dest) {
     SkASSERT(kRGB_ETC1_GrPixelConfig != config);
 
     GrColor color = colorf.toBytes_RGBA();
@@ -282,3 +284,78 @@
 
     return true;
 }
+
+size_t GrComputeTightCombinedBufferSize(GrCompression compression, size_t bytesPerPixel,
+                                        int baseWidth, int baseHeight,
+                                        SkTArray<size_t>* individualMipOffsets,
+                                        int mipLevelCount) {
+    SkASSERT(individualMipOffsets && !individualMipOffsets->count());
+    SkASSERT(mipLevelCount >= 1);
+
+    individualMipOffsets->push_back(0);
+
+    size_t combinedBufferSize = baseWidth * bytesPerPixel * baseHeight;
+    if (GrCompression::kETC1 == compression) {
+        SkASSERT(0 == bytesPerPixel);
+        bytesPerPixel = 4; // munge Bpp to make the following code work (and not assert)
+        combinedBufferSize = GrETC1CompressedDataSize(baseWidth, baseHeight);
+    }
+
+    int currentWidth = baseWidth;
+    int currentHeight = baseHeight;
+
+    // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
+    // least 4 bytes and a multiple of the bytes per pixel of the image config.
+    SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
+             bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
+    int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
+
+    for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
+        currentWidth = SkTMax(1, currentWidth / 2);
+        currentHeight = SkTMax(1, currentHeight / 2);
+
+        size_t trimmedSize;
+        if (GrCompression::kETC1 == compression) {
+            trimmedSize = GrETC1CompressedDataSize(currentWidth, currentHeight);
+        } else {
+            trimmedSize = currentWidth * bytesPerPixel * currentHeight;
+        }
+        const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
+        if (alignmentDiff != 0) {
+            combinedBufferSize += desiredAlignment - alignmentDiff;
+        }
+        SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
+
+        individualMipOffsets->push_back(combinedBufferSize);
+        combinedBufferSize += trimmedSize;
+    }
+
+    SkASSERT(individualMipOffsets->count() == mipLevelCount);
+    return combinedBufferSize;
+}
+
+void GrFillInData(GrCompression compression, GrPixelConfig config,
+                  int baseWidth, int baseHeight,
+                  const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
+                  const SkColor4f& colorf) {
+
+    int mipLevels = individualMipOffsets.count();
+
+    int currentWidth = baseWidth;
+    int currentHeight = baseHeight;
+    for (int currentMipLevel = 0; currentMipLevel < mipLevels; ++currentMipLevel) {
+        size_t offset = individualMipOffsets[currentMipLevel];
+
+        if (GrCompression::kETC1 == compression) {
+            // TODO: compute the ETC1 block for 'colorf' just once
+            fillin_ETC1_with_color(currentWidth, currentHeight, colorf, &(dstPixels[offset]));
+        } else {
+            fill_buffer_with_color(config, currentWidth, currentHeight, colorf,
+                                   &(dstPixels[offset]));
+        }
+
+        currentWidth = SkTMax(1, currentWidth / 2);
+        currentHeight = SkTMax(1, currentHeight / 2);
+    }
+}
+