GPU clear values: just 4 floats

We previously represented these as SkPMColor4f. However, upcoming
changes will add limited support for clearing/drawing to unpremul
dst. Just store the clear values as four floats without assigned
interpretation.

Also, noticed a bug by code inspection: we weren't accounting for
write view swizzle in GrRTC. Fixed and added gm to test.

Bug: skia:11019
Change-Id: I1bce1f6c97a156c0377ebad1b166eb641362b67a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/340098
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrOpsRenderPass.cpp b/src/gpu/GrOpsRenderPass.cpp
index 4dde2cc..c22ae3f 100644
--- a/src/gpu/GrOpsRenderPass.cpp
+++ b/src/gpu/GrOpsRenderPass.cpp
@@ -35,7 +35,7 @@
     this->resetActiveBuffers();
 }
 
-void GrOpsRenderPass::clear(const GrScissorState& scissor, const SkPMColor4f& color) {
+void GrOpsRenderPass::clear(const GrScissorState& scissor, std::array<float, 4> color) {
     SkASSERT(fRenderTarget);
     // A clear at this level will always be a true clear, so make sure clears were not supposed to
     // be redirected to draws instead
diff --git a/src/gpu/GrOpsRenderPass.h b/src/gpu/GrOpsRenderPass.h
index 8349117..25da976 100644
--- a/src/gpu/GrOpsRenderPass.h
+++ b/src/gpu/GrOpsRenderPass.h
@@ -33,9 +33,9 @@
     virtual ~GrOpsRenderPass() {}
 
     struct LoadAndStoreInfo {
-        GrLoadOp    fLoadOp;
-        GrStoreOp   fStoreOp;
-        SkPMColor4f fClearColor;
+        GrLoadOp             fLoadOp;
+        GrStoreOp            fStoreOp;
+        std::array<float, 4> fClearColor;
     };
 
     // Load-time clears of the stencil buffer are always to 0 so we don't store
@@ -124,7 +124,7 @@
      * is restricted to 'scissor'. Must check caps.performPartialClearsAsDraws() before using an
      * enabled scissor test; must check caps.performColorClearsAsDraws() before using this at all.
      */
-    void clear(const GrScissorState& scissor, const SkPMColor4f&);
+    void clear(const GrScissorState& scissor, std::array<float, 4> color);
 
     /**
      * Same as clear() but modifies the stencil; check caps.performStencilClearsAsDraws() and
@@ -195,7 +195,7 @@
     virtual void onDrawIndexedIndirect(const GrBuffer*, size_t offset, int drawCount) {
         SK_ABORT("Not implemented.");  // Only called if caps.nativeDrawIndirectSupport().
     }
-    virtual void onClear(const GrScissorState&, const SkPMColor4f&) = 0;
+    virtual void onClear(const GrScissorState&, std::array<float, 4> color) = 0;
     virtual void onClearStencilClip(const GrScissorState&, bool insideStencilMask) = 0;
     virtual void onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) {}
 
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index 9f95b37..6316a14 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -509,7 +509,7 @@
                                            GrSurfaceOrigin origin,
                                            const SkIRect& bounds,
                                            GrLoadOp colorLoadOp,
-                                           const SkPMColor4f& loadClearColor,
+                                           const std::array<float, 4>& loadClearColor,
                                            GrLoadOp stencilLoadOp,
                                            GrStoreOp stencilStoreOp,
                                            const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
@@ -653,7 +653,7 @@
     return true;
 }
 
-void GrOpsTask::setColorLoadOp(GrLoadOp op, const SkPMColor4f& color) {
+void GrOpsTask::setColorLoadOp(GrLoadOp op, std::array<float, 4> color) {
     fColorLoadOp = op;
     fLoadClearColor = color;
     if (GrLoadOp::kClear == fColorLoadOp) {
@@ -701,7 +701,11 @@
             SkDebugf("kLoad\n");
             break;
         case GrLoadOp::kClear:
-            SkDebugf("kClear (0x%x)\n", fLoadClearColor.toBytes_RGBA());
+            SkDebugf("kClear {%g, %g, %g, %g}\n",
+                     fLoadClearColor[0],
+                     fLoadClearColor[1],
+                     fLoadClearColor[2],
+                     fLoadClearColor[3]);
             break;
         case GrLoadOp::kDiscard:
             SkDebugf("kDiscard\n");
diff --git a/src/gpu/GrOpsTask.h b/src/gpu/GrOpsTask.h
index c77e69f..39cfaa4 100644
--- a/src/gpu/GrOpsTask.h
+++ b/src/gpu/GrOpsTask.h
@@ -13,7 +13,6 @@
 #include "include/core/SkStrokeRec.h"
 #include "include/core/SkTypes.h"
 #include "include/gpu/GrRecordingContext.h"
-#include "include/private/SkColorData.h"
 #include "include/private/SkTArray.h"
 #include "include/private/SkTDArray.h"
 #include "src/core/SkArenaAlloc.h"
@@ -126,12 +125,7 @@
     void setMustPreserveStencil() { fMustPreserveStencil = true; }
 
     // Must only be called if native color buffer clearing is enabled.
-    void setColorLoadOp(GrLoadOp op, const SkPMColor4f& color);
-    // Sets the clear color to transparent black
-    void setColorLoadOp(GrLoadOp op) {
-        static const SkPMColor4f kDefaultClearColor = {0.f, 0.f, 0.f, 0.f};
-        this->setColorLoadOp(op, kDefaultClearColor);
-    }
+    void setColorLoadOp(GrLoadOp op, std::array<float, 4> color = {0, 0, 0, 0});
 
     enum class CanDiscardPreviousOps : bool {
         kYes = true,
@@ -255,7 +249,7 @@
     GrAuditTrail*              fAuditTrail;
 
     GrLoadOp fColorLoadOp = GrLoadOp::kLoad;
-    SkPMColor4f fLoadClearColor = SK_PMColor4fTRANSPARENT;
+    std::array<float, 4> fLoadClearColor = {0, 0, 0, 0};
     StencilContent fInitialStencilContent = StencilContent::kDontCare;
     bool fMustPreserveStencil = false;
 
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 4f4c46f..a310047b 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -107,18 +107,20 @@
         writeSwizzle = context->priv().caps()->getWriteSwizzle(format, colorType);
     }
 
-    GrSurfaceProxyView readView(proxy, origin, readSwizzle);
+    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
     GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
 
-    return std::make_unique<GrRenderTargetContext>(context, std::move(readView),
-                                                   std::move(writeView), colorType,
-                                                   std::move(colorSpace), surfaceProps,
+    return std::make_unique<GrRenderTargetContext>(context,
+                                                   std::move(readView),
+                                                   std::move(writeView),
+                                                   colorType,
+                                                   std::move(colorSpace),
+                                                   surfaceProps,
                                                    flushTimeOpsTask);
 }
 
 std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::Make(
         GrRecordingContext* context,
-        GrColorType colorType,
         sk_sp<SkColorSpace> colorSpace,
         SkBackingFit fit,
         SkISize dimensions,
@@ -126,6 +128,8 @@
         int sampleCnt,
         GrMipmapped mipMapped,
         GrProtected isProtected,
+        GrSwizzle readSwizzle,
+        GrSwizzle writeSwizzle,
         GrSurfaceOrigin origin,
         SkBudgeted budgeted,
         const SkSurfaceProps* surfaceProps) {
@@ -138,17 +142,27 @@
     }
 
     sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(
-            format, dimensions, GrRenderable::kYes, sampleCnt, mipMapped, fit, budgeted,
+            format,
+            dimensions,
+            GrRenderable::kYes,
+            sampleCnt,
+            mipMapped,
+            fit,
+            budgeted,
             isProtected);
     if (!proxy) {
         return nullptr;
     }
 
-    auto rtc = GrRenderTargetContext::Make(context, colorType, std::move(colorSpace),
-                                           std::move(proxy), origin, surfaceProps);
-    if (!rtc) {
-        return nullptr;
-    }
+    GrSurfaceProxyView readView (           proxy, origin,  readSwizzle);
+    GrSurfaceProxyView writeView(std::move(proxy), origin, writeSwizzle);
+
+    auto rtc = std::make_unique<GrRenderTargetContext>(context,
+                                                       std::move(readView),
+                                                       std::move(writeView),
+                                                       GrColorType::kUnknown,
+                                                       std::move(colorSpace),
+                                                       surfaceProps);
     rtc->discard();
     return rtc;
 }
@@ -169,9 +183,24 @@
     if (!format.isValid()) {
         return nullptr;
     }
+    sk_sp<GrTextureProxy> proxy = context->priv().proxyProvider()->createProxy(
+            format,
+            dimensions,
+            GrRenderable::kYes,
+            sampleCnt,
+            mipMapped,
+            fit,
+            budgeted,
+            isProtected);
+    if (!proxy) {
+        return nullptr;
+    }
 
-    return GrRenderTargetContext::Make(context, colorType, std::move(colorSpace), fit, dimensions,
-                                       format, sampleCnt, mipMapped, isProtected, origin, budgeted,
+    return GrRenderTargetContext::Make(context,
+                                       colorType,
+                                       std::move(colorSpace),
+                                       std::move(proxy),
+                                       origin,
                                        surfaceProps);
 }
 
@@ -554,8 +583,9 @@
         GrOpsTask* opsTask = this->getOpsTask();
         if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
             !this->caps()->performColorClearsAsDraws()) {
+            SkPMColor4f clearColor = this->writeSurfaceView().swizzle().applyTo(color);
             // The op list was emptied and native clears are allowed, so just use the load op
-            opsTask->setColorLoadOp(GrLoadOp::kClear, color);
+            opsTask->setColorLoadOp(GrLoadOp::kClear, clearColor.array());
             return;
         } else {
             // Will use an op for the clear, reset the load op to discard since the op will
@@ -575,7 +605,8 @@
                         GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
                                                     SkRect::Make(scissorState.rect())));
     } else {
-        this->addOp(GrClearOp::MakeColor(fContext, scissorState, color));
+        SkPMColor4f clearColor = this->writeSurfaceView().swizzle().applyTo(color);
+        this->addOp(GrClearOp::MakeColor(fContext, scissorState, clearColor.array()));
     }
 }
 
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index b40dbb7..fd9d647 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -60,24 +60,15 @@
  */
 class GrRenderTargetContext : public GrSurfaceContext {
 public:
-    static std::unique_ptr<GrRenderTargetContext> Make(
-            GrRecordingContext*, GrColorType, sk_sp<SkColorSpace>, sk_sp<GrSurfaceProxy>,
-            GrSurfaceOrigin, const SkSurfaceProps*, bool flushTimeOpsTask = false);
-
     static std::unique_ptr<GrRenderTargetContext> Make(GrRecordingContext*,
                                                        GrColorType,
                                                        sk_sp<SkColorSpace>,
-                                                       SkBackingFit,
-                                                       SkISize dimensions,
-                                                       const GrBackendFormat&,
-                                                       int sampleCnt,
-                                                       GrMipmapped,
-                                                       GrProtected,
+                                                       sk_sp<GrSurfaceProxy>,
                                                        GrSurfaceOrigin,
-                                                       SkBudgeted,
-                                                       const SkSurfaceProps*);
+                                                       const SkSurfaceProps*,
+                                                       bool flushTimeOpsTask = false);
 
-    // Same as above but will use the default GrBackendFormat for the given GrColorType
+    /* Uses the default texture format for the color type */
     static std::unique_ptr<GrRenderTargetContext> Make(
             GrRecordingContext*,
             GrColorType,
@@ -91,6 +82,24 @@
             SkBudgeted = SkBudgeted::kYes,
             const SkSurfaceProps* = nullptr);
 
+    /**
+     * Takes custom swizzles rather than determining swizzles from color type and format.
+     * It will have color type kUnknown.
+     */
+    static std::unique_ptr<GrRenderTargetContext> Make(GrRecordingContext*,
+                                                       sk_sp<SkColorSpace>,
+                                                       SkBackingFit,
+                                                       SkISize dimensions,
+                                                       const GrBackendFormat&,
+                                                       int sampleCnt,
+                                                       GrMipmapped,
+                                                       GrProtected,
+                                                       GrSwizzle readSwizzle,
+                                                       GrSwizzle writeSwizzle,
+                                                       GrSurfaceOrigin,
+                                                       SkBudgeted,
+                                                       const SkSurfaceProps*);
+
     static std::tuple<GrColorType, GrBackendFormat> GetFallbackColorTypeAndFormat(GrImageContext*,
                                                                                   GrColorType,
                                                                                   int sampleCnt);
diff --git a/src/gpu/GrRenderTask.h b/src/gpu/GrRenderTask.h
index 0224d72..08c6253 100644
--- a/src/gpu/GrRenderTask.h
+++ b/src/gpu/GrRenderTask.h
@@ -9,8 +9,7 @@
 #define GrRenderTask_DEFINED
 
 #include "include/core/SkRefCnt.h"
-#include "include/private/SkColorData.h"
-#include "include/private/SkTDArray.h"
+#include "include/private/SkTArray.h"
 #include "src/gpu/GrSurfaceProxyView.h"
 #include "src/gpu/GrTextureProxy.h"
 #include "src/gpu/GrTextureResolveManager.h"
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index ba5c161..0d5c7a6 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -284,10 +284,20 @@
         }
     }
     if (src->asTextureProxy()) {
-        auto dstContext = GrRenderTargetContext::Make(
-                context, GrColorType::kUnknown, nullptr, fit, {width, height}, format, 1, mipMapped,
-                src->isProtected(), origin, budgeted, nullptr);
-        GrSurfaceProxyView view(sk_ref_sp(src), origin, GrSwizzle("rgba"));
+        auto dstContext = GrRenderTargetContext::Make(context,
+                                                      nullptr,
+                                                      fit,
+                                                      {width, height},
+                                                      format,
+                                                      /* sample count*/ 1,
+                                                      mipMapped,
+                                                      src->isProtected(),
+                                                      GrSwizzle::RGBA(),
+                                                      GrSwizzle::RGBA(),
+                                                      origin,
+                                                      budgeted,
+                                                      /*surface props*/ nullptr);
+        GrSurfaceProxyView view(sk_ref_sp(src), origin, GrSwizzle::RGBA());
         if (dstContext && dstContext->blitTexture(std::move(view), srcRect, dstPoint)) {
             return dstContext->asSurfaceProxyRef();
         }
diff --git a/src/gpu/d3d/GrD3DCommandList.cpp b/src/gpu/d3d/GrD3DCommandList.cpp
index 670d1a6..246eed8 100644
--- a/src/gpu/d3d/GrD3DCommandList.cpp
+++ b/src/gpu/d3d/GrD3DCommandList.cpp
@@ -391,7 +391,7 @@
 }
 
 void GrD3DDirectCommandList::clearRenderTargetView(const GrD3DRenderTarget* renderTarget,
-                                                   const SkPMColor4f& color,
+                                                   std::array<float, 4> color,
                                                    const D3D12_RECT* rect) {
     this->addingWork();
     this->addResource(renderTarget->resource());
@@ -400,8 +400,8 @@
         this->addResource(msaaTextureResource->resource());
     }
     unsigned int numRects = rect ? 1 : 0;
-    fCommandList->ClearRenderTargetView(renderTarget->colorRenderTargetView(),
-                                        color.vec(), numRects, rect);
+    fCommandList->ClearRenderTargetView(renderTarget->colorRenderTargetView(), color.data(),
+                                        numRects, rect);
 }
 
 void GrD3DDirectCommandList::clearDepthStencilView(const GrD3DAttachment* stencil,
diff --git a/src/gpu/d3d/GrD3DCommandList.h b/src/gpu/d3d/GrD3DCommandList.h
index 9f473e9..e749c63 100644
--- a/src/gpu/d3d/GrD3DCommandList.h
+++ b/src/gpu/d3d/GrD3DCommandList.h
@@ -10,7 +10,6 @@
 
 #include "include/gpu/GrTypes.h"
 #include "include/gpu/d3d/GrD3DTypes.h"
-#include "include/private/SkColorData.h"
 #include "src/gpu/GrManagedResource.h"
 #include "src/gpu/GrRingBuffer.h"
 #include "src/gpu/d3d/GrD3DRootSignature.h"
@@ -172,7 +171,8 @@
     void executeIndirect(const sk_sp<GrD3DCommandSignature> commandSig, unsigned int maxCommandCnt,
                          const GrD3DBuffer* argumentBuffer, size_t argumentBufferOffset);
 
-    void clearRenderTargetView(const GrD3DRenderTarget* renderTarget, const SkPMColor4f& color,
+    void clearRenderTargetView(const GrD3DRenderTarget* renderTarget,
+                               std::array<float, 4> color,
                                const D3D12_RECT* rect);
     void clearDepthStencilView(const GrD3DAttachment*,
                                uint8_t stencilClearValue,
diff --git a/src/gpu/d3d/GrD3DOpsRenderPass.cpp b/src/gpu/d3d/GrD3DOpsRenderPass.cpp
index e4f2645..8b0611e 100644
--- a/src/gpu/d3d/GrD3DOpsRenderPass.cpp
+++ b/src/gpu/d3d/GrD3DOpsRenderPass.cpp
@@ -314,7 +314,7 @@
     return clearRect;
 }
 
-void GrD3DOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
+void GrD3DOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
     D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin);
     auto d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
     SkASSERT(d3dRT->grD3DResourceState()->getResourceState() == D3D12_RESOURCE_STATE_RENDER_TARGET);
diff --git a/src/gpu/d3d/GrD3DOpsRenderPass.h b/src/gpu/d3d/GrD3DOpsRenderPass.h
index 8953bbf..d6dfed5 100644
--- a/src/gpu/d3d/GrD3DOpsRenderPass.h
+++ b/src/gpu/d3d/GrD3DOpsRenderPass.h
@@ -56,7 +56,7 @@
     void onDrawIndirect(const GrBuffer*, size_t offset, int drawCount) override;
     void onDrawIndexedIndirect(const GrBuffer*, size_t offset, int drawCount) override;
 
-    void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override;
+    void onClear(const GrScissorState& scissor, std::array<float, 4> color) override;
 
     void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override;
 
@@ -68,7 +68,7 @@
     SkIRect fCurrentPipelineBounds;
 
     GrLoadOp fColorLoadOp;
-    SkPMColor4f fClearColor;
+    std::array<float, 4> fClearColor;
     GrLoadOp fStencilLoadOp;
 
     using INHERITED = GrOpsRenderPass;
diff --git a/src/gpu/dawn/GrDawnOpsRenderPass.cpp b/src/gpu/dawn/GrDawnOpsRenderPass.cpp
index ec9df40..956be08 100644
--- a/src/gpu/dawn/GrDawnOpsRenderPass.cpp
+++ b/src/gpu/dawn/GrDawnOpsRenderPass.cpp
@@ -59,7 +59,7 @@
     }
     auto stencilAttachment = static_cast<GrDawnAttachment*>(fRenderTarget->getStencilAttachment());
 
-    const float *c = fColorInfo.fClearColor.vec();
+    const float* c = fColorInfo.fClearColor.data();
 
     wgpu::RenderPassColorAttachmentDescriptor colorAttachment;
     colorAttachment.attachment = static_cast<GrDawnRenderTarget*>(fRenderTarget)->textureView();
@@ -103,7 +103,7 @@
     fPassEncoder = beginRenderPass(wgpu::LoadOp::Load, wgpu::LoadOp::Clear);
 }
 
-void GrDawnOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
+void GrDawnOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
     SkASSERT(!scissor.enabled());
     fPassEncoder.EndPass();
     fPassEncoder = beginRenderPass(wgpu::LoadOp::Clear, wgpu::LoadOp::Load);
diff --git a/src/gpu/dawn/GrDawnOpsRenderPass.h b/src/gpu/dawn/GrDawnOpsRenderPass.h
index f547b98..e01ddfe 100644
--- a/src/gpu/dawn/GrDawnOpsRenderPass.h
+++ b/src/gpu/dawn/GrDawnOpsRenderPass.h
@@ -51,7 +51,7 @@
     void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance,
                                 int baseVertex) override;
 
-    void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override;
+    void onClear(const GrScissorState& scissor, std::array<float, 4> color) override;
 
     void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override;
 
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 1057fb8..9a6b33f 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1339,7 +1339,7 @@
             this->flushScissorTest(GrScissorTest::kDisabled);
             this->disableWindowRectangles();
             this->flushColorWrite(true);
-            this->flushClearColor(SK_PMColor4fTRANSPARENT);
+            this->flushClearColor({0, 0, 0, 0});
             for (int i = 0; i < mipLevelCount; ++i) {
                 if (levelClearMask & (1U << i)) {
                     this->bindSurfaceFBOForPixelOps(tex.get(), i, GR_GL_FRAMEBUFFER,
@@ -1889,8 +1889,10 @@
     return bufferState->fGLTarget;
 }
 
-void GrGLGpu::clear(const GrScissorState& scissor, const SkPMColor4f& color,
-                    GrRenderTarget* target, GrSurfaceOrigin origin) {
+void GrGLGpu::clear(const GrScissorState& scissor,
+                    std::array<float, 4> color,
+                    GrRenderTarget* target,
+                    GrSurfaceOrigin origin) {
     // parent class should never let us get here with no RT
     SkASSERT(target);
     SkASSERT(!this->caps()->performColorClearsAsDraws());
@@ -2719,8 +2721,8 @@
     }
 }
 
-void GrGLGpu::flushClearColor(const SkPMColor4f& color) {
-    GrGLfloat r = color.fR, g = color.fG, b = color.fB, a = color.fA;
+void GrGLGpu::flushClearColor(std::array<float, 4> color) {
+    GrGLfloat r = color[0], g = color[1], b = color[2], a = color[3];
     if (this->glCaps().clearToBoundaryValuesIsBroken() &&
         (1 == r || 0 == r) && (1 == g || 0 == g) && (1 == b || 0 == b) && (1 == a || 0 == a)) {
         static const GrGLfloat safeAlpha1 = nextafter(1.f, 2.f);
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 872e1e3..99651b1 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -108,7 +108,7 @@
     // The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu.
     // Thus this is the implementation of the clear call for the corresponding passthrough function
     // on GrGLOpsRenderPass.
-    void clear(const GrScissorState&, const SkPMColor4f&, GrRenderTarget*, GrSurfaceOrigin);
+    void clear(const GrScissorState&, std::array<float, 4> color, GrRenderTarget*, GrSurfaceOrigin);
 
     // The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu.
     // Thus this is the implementation of the clearStencil call for the corresponding passthrough
@@ -397,7 +397,7 @@
     void flushPatchVertexCount(uint8_t count);
 
     void flushColorWrite(bool writeColor);
-    void flushClearColor(const SkPMColor4f&);
+    void flushClearColor(std::array<float, 4>);
 
     // flushes the scissor. see the note on flushBoundTextureAndParams about
     // flushing the scissor after that function is called.
diff --git a/src/gpu/gl/GrGLOpsRenderPass.cpp b/src/gpu/gl/GrGLOpsRenderPass.cpp
index 5df891a..ef1ea9e 100644
--- a/src/gpu/gl/GrGLOpsRenderPass.cpp
+++ b/src/gpu/gl/GrGLOpsRenderPass.cpp
@@ -383,7 +383,7 @@
     }
 }
 
-void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
+void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
     fGpu->clear(scissor, color, fRenderTarget, fOrigin);
 }
 
diff --git a/src/gpu/gl/GrGLOpsRenderPass.h b/src/gpu/gl/GrGLOpsRenderPass.h
index 5a19083..8458d68 100644
--- a/src/gpu/gl/GrGLOpsRenderPass.h
+++ b/src/gpu/gl/GrGLOpsRenderPass.h
@@ -73,7 +73,7 @@
                                int drawCount) override;
     void multiDrawElementsANGLEOrWebGL(const GrBuffer* drawIndirectBuffer, size_t offset,
                                        int drawCount);
-    void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override;
+    void onClear(const GrScissorState& scissor, std::array<float, 4> color) override;
     void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override;
 
     GrGLGpu* fGpu;
diff --git a/src/gpu/mock/GrMockOpsRenderPass.h b/src/gpu/mock/GrMockOpsRenderPass.h
index c9c6ffa..7712fa6 100644
--- a/src/gpu/mock/GrMockOpsRenderPass.h
+++ b/src/gpu/mock/GrMockOpsRenderPass.h
@@ -45,7 +45,7 @@
     void onDrawIndexedInstanced(int, int, int, int, int) override { this->dummyDraw(); }
     void onDrawIndirect(const GrBuffer*, size_t, int) override { this->dummyDraw(); }
     void onDrawIndexedIndirect(const GrBuffer*, size_t, int) override { this->dummyDraw(); }
-    void onClear(const GrScissorState& scissor, const SkPMColor4f&) override {
+    void onClear(const GrScissorState& scissor, std::array<float, 4>) override {
         this->markRenderTargetDirty();
     }
     void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override {}
diff --git a/src/gpu/mtl/GrMtlOpsRenderPass.h b/src/gpu/mtl/GrMtlOpsRenderPass.h
index 2fa52f0..a967b00 100644
--- a/src/gpu/mtl/GrMtlOpsRenderPass.h
+++ b/src/gpu/mtl/GrMtlOpsRenderPass.h
@@ -49,7 +49,7 @@
     void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance,
                                 int baseVertex) override;
 
-    void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override;
+    void onClear(const GrScissorState& scissor, std::array<float, 4> color) override;
 
     void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override;
 
diff --git a/src/gpu/mtl/GrMtlOpsRenderPass.mm b/src/gpu/mtl/GrMtlOpsRenderPass.mm
index 548c077..62071b0 100644
--- a/src/gpu/mtl/GrMtlOpsRenderPass.mm
+++ b/src/gpu/mtl/GrMtlOpsRenderPass.mm
@@ -123,7 +123,7 @@
     return true;
 }
 
-void GrMtlOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
+void GrMtlOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
     // Partial clears are not supported
     SkASSERT(!scissor.enabled());
 
@@ -212,7 +212,7 @@
             static_cast<GrMtlRenderTarget*>(fRenderTarget)->mtlColorTexture();
     renderPassDesc.colorAttachments[0].slice = 0;
     renderPassDesc.colorAttachments[0].level = 0;
-    const SkPMColor4f& clearColor = colorInfo.fClearColor;
+    const std::array<float, 4>& clearColor = colorInfo.fClearColor;
     renderPassDesc.colorAttachments[0].clearColor =
             MTLClearColorMake(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
     renderPassDesc.colorAttachments[0].loadAction =
diff --git a/src/gpu/ops/GrClearOp.cpp b/src/gpu/ops/GrClearOp.cpp
index 8637b8f..946ae31 100644
--- a/src/gpu/ops/GrClearOp.cpp
+++ b/src/gpu/ops/GrClearOp.cpp
@@ -20,18 +20,24 @@
 
 GrOp::Owner GrClearOp::MakeColor(GrRecordingContext* context,
                                  const GrScissorState& scissor,
-                                 const SkPMColor4f& color) {
+                                 std::array<float, 4> color) {
     return GrOp::Make<GrClearOp>(context, Buffer::kColor, scissor, color, false);
 }
 
 GrOp::Owner GrClearOp::MakeStencilClip(GrRecordingContext* context,
                                        const GrScissorState& scissor,
                                        bool insideMask) {
-    return GrOp::Make<GrClearOp>(context, Buffer::kStencilClip, scissor, SkPMColor4f(), insideMask);
+    return GrOp::Make<GrClearOp>(context,
+                                 Buffer::kStencilClip,
+                                 scissor,
+                                 std::array<float, 4>(),
+                                 insideMask);
 }
 
-GrClearOp::GrClearOp(Buffer buffer, const GrScissorState& scissor,
-                     const SkPMColor4f& color, bool insideMask)
+GrClearOp::GrClearOp(Buffer buffer,
+                     const GrScissorState& scissor,
+                     std::array<float, 4> color,
+                     bool insideMask)
         : INHERITED(ClassID())
         , fScissor(scissor)
         , fColor(color)
diff --git a/src/gpu/ops/GrClearOp.h b/src/gpu/ops/GrClearOp.h
index 61ae9fe..5856e8a 100644
--- a/src/gpu/ops/GrClearOp.h
+++ b/src/gpu/ops/GrClearOp.h
@@ -22,7 +22,7 @@
     // A fullscreen or scissored clear, depending on the clip and proxy dimensions
     static GrOp::Owner MakeColor(GrRecordingContext* context,
                                  const GrScissorState& scissor,
-                                 const SkPMColor4f& color);
+                                 std::array<float, 4> color);
 
     static GrOp::Owner MakeStencilClip(GrRecordingContext* context,
                                        const GrScissorState& scissor,
@@ -41,7 +41,10 @@
     };
     GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Buffer);
 
-    GrClearOp(Buffer buffer, const GrScissorState& scissor, const SkPMColor4f& color, bool stencil);
+    GrClearOp(Buffer buffer,
+              const GrScissorState& scissor,
+              std::array<float, 4> color,
+              bool stencil);
 
     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override;
 
@@ -61,15 +64,15 @@
         } else {
             string.append("disabled");
         }
-        string.appendf("], Color: 0x%08x\n", fColor.toBytes_RGBA());
+        string.appendf("], Color: {%g, %g, %g, %g}\n", fColor[0], fColor[1], fColor[2], fColor[3]);
         return string;
     }
 #endif
 
-    GrScissorState fScissor;
-    SkPMColor4f    fColor;
-    bool           fStencilInsideMask;
-    Buffer         fBuffer;
+    GrScissorState       fScissor;
+    std::array<float, 4> fColor;
+    bool                 fStencilInsideMask;
+    Buffer               fBuffer;
 
     using INHERITED = GrOp;
 };
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index 8d7cf7e..86320d2 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -63,9 +63,8 @@
 
 bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
                              const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
-                             const SkPMColor4f& clearColor,
+                             std::array<float, 4> clearColor,
                              bool withStencil) {
-
     VkAttachmentLoadOp loadOp;
     VkAttachmentStoreOp storeOp;
     get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp,
@@ -352,13 +351,13 @@
     fCurrentCBIsEmpty = false;
 }
 
-void GrVkOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) {
+void GrVkOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
     if (!fCurrentRenderPass) {
         SkASSERT(fGpu->isDeviceLost());
         return;
     }
 
-    VkClearColorValue vkColor = {{color.fR, color.fG, color.fB, color.fA}};
+    VkClearColorValue vkColor = {{color[0], color[1], color[2], color[3]}};
 
     // If we end up in a situation where we are calling clear without a scissior then in general it
     // means we missed an opportunity higher up the stack to set the load op to be a clear. However,
diff --git a/src/gpu/vk/GrVkOpsRenderPass.h b/src/gpu/vk/GrVkOpsRenderPass.h
index 05bf86c..2fdc44e 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.h
+++ b/src/gpu/vk/GrVkOpsRenderPass.h
@@ -52,7 +52,7 @@
 private:
     bool init(const GrOpsRenderPass::LoadAndStoreInfo&,
               const GrOpsRenderPass::StencilLoadAndStoreInfo&,
-              const SkPMColor4f& clearColor,
+              std::array<float, 4> clearColor,
               bool withStencil);
 
     // Called instead of init when we are drawing to a render target that already wraps a secondary
@@ -88,7 +88,7 @@
     void onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset,
                                int drawCount) override;
 
-    void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override;
+    void onClear(const GrScissorState& scissor, std::array<float, 4> color) override;
 
     void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override;