basic first pass at RGBA F32 support

Draws basically the same as f16.

The existing load_f32, load_f32_dst, and store_f32 stages all had the
same bug that we'd never noticed because dy was always 0 until now.

Change-Id: Ibbd393fa1acc5df414be4cdef0f5a9d11dcccdb3
Reviewed-on: https://skia-review.googlesource.com/137585
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 32eba97..b0d8642 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -926,6 +926,8 @@
         SINK(  "esrgb",  RasterSink,  kRGBA_F16_SkColorType, srgb      );
         SINK( "narrow",  RasterSink, kRGBA_8888_SkColorType, narrow    );
         SINK("enarrow",  RasterSink,  kRGBA_F16_SkColorType, narrow    );
+
+        SINK(    "f32",  RasterSink,  kRGBA_F32_SkColorType, srgbLinear);
     }
 #undef SINK
     return nullptr;
diff --git a/gm/bitmapcopy.cpp b/gm/bitmapcopy.cpp
index 94d6fe6..5f9ae20 100644
--- a/gm/bitmapcopy.cpp
+++ b/gm/bitmapcopy.cpp
@@ -22,6 +22,7 @@
         case kRGB_101010x_SkColorType:  return "101010x";
         case kGray_8_SkColorType:       return "G8";
         case kRGBA_F16_SkColorType:     return "F16";
+        case kRGBA_F32_SkColorType:     return "F32";
     }
     return "";
 }
diff --git a/gm/gamut.cpp b/gm/gamut.cpp
index 55f1b28..1e109a9 100644
--- a/gm/gamut.cpp
+++ b/gm/gamut.cpp
@@ -141,6 +141,7 @@
                                           wideGamutRGB_toXYZD50);
             break;
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
             srgbCS = SkColorSpace::MakeSRGBLinear();
             wideCS = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
                                           wideGamutRGB_toXYZD50);
diff --git a/include/core/SkImageInfo.h b/include/core/SkImageInfo.h
index db3917f..33dd8ca 100644
--- a/include/core/SkImageInfo.h
+++ b/include/core/SkImageInfo.h
@@ -93,7 +93,8 @@
     kRGB_101010x_SkColorType,  //!< pixel with 10 bits each for red, green, blue; in 32-bit word
     kGray_8_SkColorType,       //!< pixel with grayscale level in 8-bit byte
     kRGBA_F16_SkColorType,   //!< pixel with half floats for red, green, blue, alpha; in 64-bit word
-    kLastEnum_SkColorType     = kRGBA_F16_SkColorType,//!< last valid value
+    kRGBA_F32_SkColorType,   //!< pixel with single floats for red, green, blue, alpha
+    kLastEnum_SkColorType     = kRGBA_F32_SkColorType,//!< last valid value
 
 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
     kN32_SkColorType          = kBGRA_8888_SkColorType,//!< native ARGB 32-bit encoding
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index e957f1f..16f3c4a 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -1241,7 +1241,7 @@
         case GrColorType::kAlpha_F16:    return kUnknown_SkColorType;
         case GrColorType::kRGBA_F16:     return kRGBA_F16_SkColorType;
         case GrColorType::kRG_F32:       return kUnknown_SkColorType;
-        case GrColorType::kRGBA_F32:     return kUnknown_SkColorType;
+        case GrColorType::kRGBA_F32:     return kRGBA_F32_SkColorType;
     }
     SK_ABORT("Invalid GrColorType");
     return kUnknown_SkColorType;
@@ -1260,6 +1260,7 @@
         case kRGBA_F16_SkColorType:     return GrColorType::kRGBA_F16;
         case kRGBA_1010102_SkColorType: return GrColorType::kRGBA_1010102;
         case kRGB_101010x_SkColorType:  return GrColorType::kUnknown;
+        case kRGBA_F32_SkColorType:     return GrColorType::kRGBA_F32;
     }
     SK_ABORT("Invalid SkColorType");
     return GrColorType::kUnknown;
diff --git a/include/private/SkImageInfoPriv.h b/include/private/SkImageInfoPriv.h
index 144ad0a..df5e379 100644
--- a/include/private/SkImageInfoPriv.h
+++ b/include/private/SkImageInfoPriv.h
@@ -36,6 +36,7 @@
         case kRGB_101010x_SkColorType:  return kRGB_SkColorTypeComponentFlags;
         case kGray_8_SkColorType:       return kGray_SkColorTypeComponentFlag;
         case kRGBA_F16_SkColorType:     return kRGBA_SkColorTypeComponentFlags;
+        case kRGBA_F32_SkColorType:     return kRGBA_SkColorTypeComponentFlags;
     }
     return 0;
 }
@@ -68,6 +69,7 @@
         case kRGB_101010x_SkColorType:  return 2;
         case kGray_8_SkColorType:       return 0;
         case kRGBA_F16_SkColorType:     return 3;
+        case kRGBA_F32_SkColorType:     return 4;
     }
     return 0;
 }
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index e26f46d..b6485b1 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -365,6 +365,10 @@
             if (load) *load = SkRasterPipeline::load_f16;
             if (store) *store = SkRasterPipeline::store_f16;
             break;
+        case kRGBA_F32_SkColorType:
+            if (load) *load = SkRasterPipeline::load_f32;
+            if (store) *store = SkRasterPipeline::store_f32;
+            break;
     }
 }
 
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index e942a4c..4ef7abf 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -384,6 +384,9 @@
     if (base) {
         base += y * this->rowBytes();
         switch (this->colorType()) {
+            case kRGBA_F32_SkColorType:
+                base += x << 4;
+                break;
             case kRGBA_F16_SkColorType:
                 base += x << 3;
                 break;
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 81ff5ba..2361468 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -210,6 +210,7 @@
         case kBGRA_8888_SkColorType:
         case kRGBA_1010102_SkColorType:
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
             break;
         case kGray_8_SkColorType:
         case kRGB_565_SkColorType:
diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp
index 7385128..057b2a5 100644
--- a/src/core/SkBlitter_Sprite.cpp
+++ b/src/core/SkBlitter_Sprite.cpp
@@ -123,6 +123,7 @@
             case kRGBA_8888_SkColorType:    p.append(SkRasterPipeline::load_8888,    ctx); break;
             case kRGBA_1010102_SkColorType: p.append(SkRasterPipeline::load_1010102, ctx); break;
             case kRGBA_F16_SkColorType:     p.append(SkRasterPipeline::load_f16,     ctx); break;
+            case kRGBA_F32_SkColorType:     p.append(SkRasterPipeline::load_f32,     ctx); break;
 
             case kRGB_888x_SkColorType:     p.append(SkRasterPipeline::load_8888,    ctx);
                                             p.append(SkRasterPipeline::force_opaque     ); break;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index be3ebb1..b297f98 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2871,6 +2871,7 @@
         case kRGB_565_SkColorType:
         case kN32_SkColorType:
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
         case kRGBA_1010102_SkColorType:
             break;
         default:
diff --git a/src/core/SkConvertPixels.cpp b/src/core/SkConvertPixels.cpp
index b0d37cd..25645d4 100644
--- a/src/core/SkConvertPixels.cpp
+++ b/src/core/SkConvertPixels.cpp
@@ -231,6 +231,16 @@
             }
             break;
         }
+        case kRGBA_F32_SkColorType: {
+            auto rgba = (const float*)src;
+            for (int y = 0; y < srcInfo.height(); y++) {
+                for (int x = 0; x < srcInfo.width(); x++) {
+                    dst[x] = (uint8_t)(255.0f * rgba[4*x+3]);
+                }
+                dst  = SkTAddOffset<uint8_t>(dst, dstRB);
+                rgba = SkTAddOffset<const float>(rgba, srcRB);
+            }
+        } break;
         default:
             SkASSERT(false);
             break;
@@ -270,6 +280,9 @@
         case kRGBA_F16_SkColorType:
             pipeline.append(SkRasterPipeline::load_f16, &src);
             break;
+        case kRGBA_F32_SkColorType:
+            pipeline.append(SkRasterPipeline::load_f32, &src);
+            break;
         case kGray_8_SkColorType:
             pipeline.append(SkRasterPipeline::load_g8, &src);
             break;
@@ -381,6 +394,9 @@
         case kRGBA_F16_SkColorType:
             pipeline.append(SkRasterPipeline::store_f16, &dst);
             break;
+        case kRGBA_F32_SkColorType:
+            pipeline.append(SkRasterPipeline::store_f32, &dst);
+            break;
         case kARGB_4444_SkColorType:
             pipeline.append(SkRasterPipeline::store_4444, &dst);
             break;
diff --git a/src/core/SkImageInfo.cpp b/src/core/SkImageInfo.cpp
index c094301..0a98c28 100644
--- a/src/core/SkImageInfo.cpp
+++ b/src/core/SkImageInfo.cpp
@@ -23,6 +23,7 @@
         case kRGB_101010x_SkColorType:  return 4;
         case kGray_8_SkColorType:       return 1;
         case kRGBA_F16_SkColorType:     return 8;
+        case kRGBA_F32_SkColorType:     return 16;
     }
     return 0;
 }
@@ -74,6 +75,7 @@
         case kBGRA_8888_SkColorType:
         case kRGBA_1010102_SkColorType:
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
             if (kUnknown_SkAlphaType == alphaType) {
                 return false;
             }
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 6eaf679..77b174b 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -230,6 +230,7 @@
         }
 
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
             // The colorspace is unspecified, so assume linear just like getColor().
             this->erase(SkColor4f{(1 / 255.0f) * r,
                                   (1 / 255.0f) * g,
@@ -254,15 +255,29 @@
 
     const SkColor4f color = origColor.pin();
 
-    if (kRGBA_F16_SkColorType != pm.colorType()) {
-        return pm.erase(color.toSkColor());
+    if (pm.colorType() == kRGBA_F16_SkColorType) {
+        const uint64_t half4 = color.premul().toF16();
+        for (int y = 0; y < pm.height(); ++y) {
+            sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
+        }
+        return true;
     }
 
-    const uint64_t half4 = color.premul().toF16();
-    for (int y = 0; y < pm.height(); ++y) {
-        sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
+    if (pm.colorType() == kRGBA_F32_SkColorType) {
+        const SkPM4f rgba = color.premul();
+        for (int y = 0; y < pm.height(); ++y) {
+            auto row = (float*)pm.writable_addr();
+            for (int x = 0; x < pm.width(); ++x) {
+                row[4*x+0] = rgba.r();
+                row[4*x+1] = rgba.g();
+                row[4*x+2] = rgba.b();
+                row[4*x+3] = rgba.a();
+            }
+        }
+        return true;
     }
-    return true;
+
+    return pm.erase(color.toSkColor());
 }
 
 bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) const {
@@ -396,17 +411,31 @@
                  | (uint32_t)( a * 255.0f ) << 24;
         }
         case kRGBA_F16_SkColorType: {
-             const uint64_t* addr =
-                 (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
-             Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
-             if (p4[3] && needsUnpremul) {
-                 float inva = 1 / p4[3];
-                 p4 = p4 * Sk4f(inva, inva, inva, 1);
-             }
-             SkColor c;
-             SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
-             // p4 is RGBA, but we want BGRA, so we need to swap next
-             return SkSwizzle_RB(c);
+            const uint64_t* addr =
+                (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x;
+            Sk4f p4 = SkHalfToFloat_finite_ftz(*addr);
+            if (p4[3] && needsUnpremul) {
+                float inva = 1 / p4[3];
+                p4 = p4 * Sk4f(inva, inva, inva, 1);
+            }
+            SkColor c;
+            SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
+            // p4 is RGBA, but we want BGRA, so we need to swap next
+            return SkSwizzle_RB(c);
+        }
+        case kRGBA_F32_SkColorType: {
+            const float* rgba =
+                (const float*)fPixels + 4*y*(fRowBytes >> 4) + 4*x;
+            Sk4f p4 = Sk4f::Load(rgba);
+            // From here on, just like F16:
+            if (p4[3] && needsUnpremul) {
+                float inva = 1 / p4[3];
+                p4 = p4 * Sk4f(inva, inva, inva, 1);
+            }
+            SkColor c;
+            SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c);
+            // p4 is RGBA, but we want BGRA, so we need to swap next
+            return SkSwizzle_RB(c);
         }
         default:
             SkDEBUGFAIL("");
diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h
index 1dd346f..36f7ce3 100644
--- a/src/core/SkRasterPipeline.h
+++ b/src/core/SkRasterPipeline.h
@@ -49,7 +49,7 @@
     M(load_565)  M(load_565_dst)  M(store_565)  M(gather_565)      \
     M(load_4444) M(load_4444_dst) M(store_4444) M(gather_4444)     \
     M(load_f16)  M(load_f16_dst)  M(store_f16)  M(gather_f16)      \
-    M(load_f32)  M(load_f32_dst)  M(store_f32)                     \
+    M(load_f32)  M(load_f32_dst)  M(store_f32)  M(gather_f32)      \
     M(load_8888) M(load_8888_dst) M(store_8888) M(gather_8888)     \
     M(load_bgra) M(load_bgra_dst) M(store_bgra) M(gather_bgra)     \
     M(load_1010102) M(load_1010102_dst) M(store_1010102) M(gather_1010102) \
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index 8b37bef..66a4a62 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -210,7 +210,8 @@
 
     // When we're drawing a constant color in Src mode, we can sometimes just memset.
     // (The previous two optimizations help find more opportunities for this one.)
-    if (is_constant && blitter->fBlend == SkBlendMode::kSrc) {
+    if (is_constant && blitter->fBlend == SkBlendMode::kSrc
+                    && blitter->fDst.shiftPerPixel() <= 3 /*TODO: F32*/) {
         // Run our color pipeline all the way through to produce what we'd memset when we can.
         // Not all blits can memset, so we need to keep colorPipeline too.
         SkRasterPipeline_<256> p;
@@ -243,6 +244,7 @@
         case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::load_8888_dst,    ctx); break;
         case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::load_1010102_dst, ctx); break;
         case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::load_f16_dst,     ctx); break;
+        case kRGBA_F32_SkColorType:     p->append(SkRasterPipeline::load_f32_dst,     ctx); break;
 
         case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::load_8888_dst,    ctx);
                                         p->append(SkRasterPipeline::force_opaque_dst     ); break;
@@ -275,6 +277,7 @@
         case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::store_8888,    ctx); break;
         case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::store_1010102, ctx); break;
         case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::store_f16,     ctx); break;
+        case kRGBA_F32_SkColorType:     p->append(SkRasterPipeline::store_f32,     ctx); break;
 
         case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::force_opaque         );
                                         p->append(SkRasterPipeline::store_8888,       ctx); break;
@@ -305,7 +308,7 @@
                 case 1: sk_memset16(fDst.writable_addr16(x,y), fMemsetColor, w); break;
                 case 2: sk_memset32(fDst.writable_addr32(x,y), fMemsetColor, w); break;
                 case 3: sk_memset64(fDst.writable_addr64(x,y), fMemsetColor, w); break;
-                default: break;
+                default: SkASSERT(false); break;
             }
         }
         return;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index f872756..a0a9340 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -252,6 +252,8 @@
             return kGray_8_GrPixelConfig;
         case kRGBA_F16_SkColorType:
             return kRGBA_half_GrPixelConfig;
+        case kRGBA_F32_SkColorType:
+            return kRGBA_float_GrPixelConfig;
     }
     SkASSERT(0);    // shouldn't get here
     return kUnknown_GrPixelConfig;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index d180ac2..43979fa 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -2894,6 +2894,11 @@
                 *config = kRGBA_half_GrPixelConfig;
             }
             break;
+        case kRGBA_F32_SkColorType:
+            if (GR_GL_RGBA32F == format) {
+                *config = kRGBA_float_GrPixelConfig;
+            }
+            break;
     }
 
     return kUnknown_GrPixelConfig != *config;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index cc9d0ca..1a14648 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -625,6 +625,11 @@
                 *config = kRGBA_half_GrPixelConfig;
             }
             break;
+        case kRGBA_F32_SkColorType:
+            if (VK_FORMAT_R32G32B32A32_SFLOAT == format) {
+                *config = kRGBA_float_GrPixelConfig;
+            }
+            break;
     }
 
     return kUnknown_GrPixelConfig != *config;
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 8f79584..2e55ffd 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -269,6 +269,7 @@
 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
     switch (info.colorType()) {
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
         case kRGBA_8888_SkColorType:
         case kBGRA_8888_SkColorType:
             return true;
@@ -283,6 +284,7 @@
         case kSBGRA_8888_GrPixelConfig:
             return caps->srgbSupport();
         case kRGBA_half_GrPixelConfig:
+        case kRGBA_float_GrPixelConfig:
         case kRGBA_8888_GrPixelConfig:
         case kBGRA_8888_GrPixelConfig:
             return true;
diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp
index 73ff4ba..4076dff 100644
--- a/src/image/SkSurface_Raster.cpp
+++ b/src/image/SkSurface_Raster.cpp
@@ -62,6 +62,7 @@
         case kBGRA_8888_SkColorType:
             break;
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
             break;
         default:
             return false;
diff --git a/src/images/SkImageEncoderFns.h b/src/images/SkImageEncoderFns.h
index d8d1c64..6bf0081 100644
--- a/src/images/SkImageEncoderFns.h
+++ b/src/images/SkImageEncoderFns.h
@@ -410,6 +410,39 @@
     p.run(0,0, width,1);
 }
 
+/**
+ * Transform from kRGBA_F32 to 8-bytes-per-pixel RGBA.
+ */
+static inline void transform_scanline_F32(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                          int width, int, const SkPMColor*) {
+    SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
+                       dst_ctx = { (void*)dst, 0 };
+    SkRasterPipeline_<256> p;
+    p.append(SkRasterPipeline::load_f32, &src_ctx);
+    p.append(SkRasterPipeline::clamp_0);  // F32 values may be out of [0,1] range, so clamp.
+    p.append(SkRasterPipeline::clamp_1);
+    p.append(SkRasterPipeline::to_srgb);
+    p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
+    p.run(0,0, width,1);
+}
+
+/**
+ * Transform from kPremul, kRGBA_F32 to 8-bytes-per-pixel RGBA.
+ */
+static inline void transform_scanline_F32_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                                 int width, int, const SkPMColor*) {
+    SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
+                       dst_ctx = { (void*)dst, 0 };
+    SkRasterPipeline_<256> p;
+    p.append(SkRasterPipeline::load_f32, &src_ctx);
+    p.append(SkRasterPipeline::unpremul);
+    p.append(SkRasterPipeline::clamp_0);  // F32 values may be out of [0,1] range, so clamp.
+    p.append(SkRasterPipeline::clamp_1);
+    p.append(SkRasterPipeline::to_srgb);
+    p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
+    p.run(0,0, width,1);
+}
+
 static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
     SkColorSpace* cs = info.colorSpace();
     if (!cs) {
@@ -417,7 +450,8 @@
     }
 
     sk_sp<SkColorSpace> owned;
-    if (kRGBA_F16_SkColorType == info.colorType()) {
+    if (kRGBA_F16_SkColorType == info.colorType() ||
+        kRGBA_F32_SkColorType == info.colorType()) {
         owned = cs->makeSRGBGamma();
         cs = owned.get();
     }
diff --git a/src/images/SkPngEncoder.cpp b/src/images/SkPngEncoder.cpp
index fffda73..7520b90 100644
--- a/src/images/SkPngEncoder.cpp
+++ b/src/images/SkPngEncoder.cpp
@@ -106,6 +106,7 @@
     int bitDepth = 8;
     switch (srcInfo.colorType()) {
         case kRGBA_F16_SkColorType:
+        case kRGBA_F32_SkColorType:
             SkASSERT(srcInfo.colorSpace());
             sigBit.red = 16;
             sigBit.green = 16;
@@ -288,6 +289,17 @@
                     SkASSERT(false);
                     return nullptr;
             }
+        case kRGBA_F32_SkColorType:
+            switch (info.alphaType()) {
+                case kOpaque_SkAlphaType:
+                case kUnpremul_SkAlphaType:
+                    return transform_scanline_F32;
+                case kPremul_SkAlphaType:
+                    return transform_scanline_F32_premul;
+                default:
+                    SkASSERT(false);
+                    return nullptr;
+            }
         case kRGBA_1010102_SkColorType:
             switch (info.alphaType()) {
                 case kOpaque_SkAlphaType:
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index fac5d1b..2431ad7 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -1712,15 +1712,23 @@
 }
 
 STAGE(load_f32, const SkJumper_MemoryCtx* ctx) {
-    auto ptr = ptr_at_xy<const float>(ctx, 4*dx,dy);
+    auto ptr = ptr_at_xy<const float>(ctx, 4*dx,4*dy);
     load4(ptr,tail, &r,&g,&b,&a);
 }
 STAGE(load_f32_dst, const SkJumper_MemoryCtx* ctx) {
-    auto ptr = ptr_at_xy<const float>(ctx, 4*dx,dy);
+    auto ptr = ptr_at_xy<const float>(ctx, 4*dx,4*dy);
     load4(ptr,tail, &dr,&dg,&db,&da);
 }
+STAGE(gather_f32, const SkJumper_GatherCtx* ctx) {
+    const float* ptr;
+    U32 ix = ix_and_ptr(&ptr, ctx, r,g);
+    r = gather(ptr, 4*ix + 0);
+    g = gather(ptr, 4*ix + 1);
+    b = gather(ptr, 4*ix + 2);
+    a = gather(ptr, 4*ix + 3);
+}
 STAGE(store_f32, const SkJumper_MemoryCtx* ctx) {
-    auto ptr = ptr_at_xy<float>(ctx, 4*dx,dy);
+    auto ptr = ptr_at_xy<float>(ctx, 4*dx,4*dy);
     store4(ptr,tail, r,g,b,a);
 }
 
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index 97bd6cb..aa5ecba 100644
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -369,6 +369,7 @@
             case kRGBA_8888_SkColorType:    p->append(SkRasterPipeline::gather_8888,    ctx); break;
             case kRGBA_1010102_SkColorType: p->append(SkRasterPipeline::gather_1010102, ctx); break;
             case kRGBA_F16_SkColorType:     p->append(SkRasterPipeline::gather_f16,     ctx); break;
+            case kRGBA_F32_SkColorType:     p->append(SkRasterPipeline::gather_f32,     ctx); break;
 
             case kRGB_888x_SkColorType:     p->append(SkRasterPipeline::gather_8888,    ctx);
                                             p->append(SkRasterPipeline::force_opaque       ); break;
diff --git a/tests/DeferredDisplayListTest.cpp b/tests/DeferredDisplayListTest.cpp
index 697f003..afe93ad 100644
--- a/tests/DeferredDisplayListTest.cpp
+++ b/tests/DeferredDisplayListTest.cpp
@@ -132,6 +132,8 @@
                     return GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_2D);
                 }
                 break;
+            case kRGBA_F32_SkColorType:
+                return GrBackendFormat();
         }
     }
     break;
@@ -199,6 +201,8 @@
                     return  GrBackendFormat::MakeVk(VK_FORMAT_R16G16B16A16_SFLOAT);
                 }
                 break;
+            case kRGBA_F32_SkColorType:
+                return GrBackendFormat();
         }
         break;
 #endif
@@ -267,6 +271,8 @@
                     return  GrBackendFormat::MakeMock(config);
                 }
                 break;
+            case kRGBA_F32_SkColorType:
+                return GrBackendFormat();
         }
         break;
     default:
diff --git a/tests/ImageGeneratorTest.cpp b/tests/ImageGeneratorTest.cpp
index 0bddcd9..735e13e 100644
--- a/tests/ImageGeneratorTest.cpp
+++ b/tests/ImageGeneratorTest.cpp
@@ -104,11 +104,13 @@
         { kRGBA_8888_SkColorType, kPremul_SkAlphaType, kRGBA_8888_SkColorType == kN32_SkColorType },
         { kBGRA_8888_SkColorType, kPremul_SkAlphaType, kBGRA_8888_SkColorType == kN32_SkColorType },
         { kRGBA_F16_SkColorType,  kPremul_SkAlphaType, true },
+        { kRGBA_F32_SkColorType,  kPremul_SkAlphaType, true },
         { kRGBA_1010102_SkColorType, kPremul_SkAlphaType, true },
 
         { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, false },
         { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, false },
         { kRGBA_F16_SkColorType,  kUnpremul_SkAlphaType, false },
+        { kRGBA_F32_SkColorType,  kUnpremul_SkAlphaType, false },
         { kRGBA_1010102_SkColorType, kUnpremul_SkAlphaType, false },
     };
 
@@ -118,7 +120,7 @@
                                                  SkImage::BitDepth::kU8, colorspace);
 
     // worst case for all requests
-    SkAutoMalloc storage(100 * 100 * SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType));
+    SkAutoMalloc storage(100 * 100 * SkColorTypeBytesPerPixel(kRGBA_F32_SkColorType));
 
     for (const auto& rec : recs) {
         SkImageInfo info = SkImageInfo::Make(100, 100, rec.fColorType, rec.fAlphaType, colorspace);
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 9a3a3aa..3370e76 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -894,7 +894,8 @@
 static void test_surface_creation_and_snapshot_with_color_space(
     skiatest::Reporter* reporter,
     const char* prefix,
-    bool f16Support,
+    bool supportsF16,
+    bool supportsF32,
     bool supports1010102,
     std::function<sk_sp<SkSurface>(const SkImageInfo&)> surfaceMaker) {
 
@@ -914,17 +915,21 @@
         bool                fShouldWork;
         const char*         fDescription;
     } testConfigs[] = {
-        { kN32_SkColorType,       nullptr,          true,  "N32-nullptr" },
-        { kN32_SkColorType,       linearColorSpace, true,  "N32-linear"  },
-        { kN32_SkColorType,       srgbColorSpace,   true,  "N32-srgb"    },
-        { kN32_SkColorType,       oddColorSpace,    true,  "N32-odd"     },
-        { kRGBA_F16_SkColorType,  nullptr,          true,  "F16-nullptr" },
-        { kRGBA_F16_SkColorType,  linearColorSpace, true,  "F16-linear"  },
-        { kRGBA_F16_SkColorType,  srgbColorSpace,   true,  "F16-srgb"    },
-        { kRGBA_F16_SkColorType,  oddColorSpace,    true,  "F16-odd"     },
-        { kRGB_565_SkColorType,   srgbColorSpace,   false, "565-srgb"    },
-        { kAlpha_8_SkColorType,   srgbColorSpace,   false, "A8-srgb"     },
-        { kRGBA_1010102_SkColorType, nullptr,       true,  "1010102-nullptr" },
+        { kN32_SkColorType,       nullptr,                     true,  "N32-nullptr" },
+        { kN32_SkColorType,       linearColorSpace,            true,  "N32-linear"  },
+        { kN32_SkColorType,       srgbColorSpace,              true,  "N32-srgb"    },
+        { kN32_SkColorType,       oddColorSpace,               true,  "N32-odd"     },
+        { kRGBA_F16_SkColorType,  nullptr,              supportsF16,  "F16-nullptr" },
+        { kRGBA_F16_SkColorType,  linearColorSpace,     supportsF16,  "F16-linear"  },
+        { kRGBA_F16_SkColorType,  srgbColorSpace,       supportsF16,  "F16-srgb"    },
+        { kRGBA_F16_SkColorType,  oddColorSpace,        supportsF16,  "F16-odd"     },
+        { kRGBA_F32_SkColorType,  nullptr,              supportsF32,  "F32-nullptr" },
+        { kRGBA_F32_SkColorType,  linearColorSpace,     supportsF32,  "F32-linear"  },
+        { kRGBA_F32_SkColorType,  srgbColorSpace,       supportsF32,  "F32-srgb"    },
+        { kRGBA_F32_SkColorType,  oddColorSpace,        supportsF32,  "F32-odd"     },
+        { kRGB_565_SkColorType,   srgbColorSpace,             false,  "565-srgb"    },
+        { kAlpha_8_SkColorType,   srgbColorSpace,             false,  "A8-srgb"     },
+        { kRGBA_1010102_SkColorType, nullptr,       supports1010102,  "1010102-nullptr" },
     };
 
     for (auto& testConfig : testConfigs) {
@@ -932,16 +937,11 @@
         SkImageInfo info = SkImageInfo::Make(10, 10, testConfig.fColorType, kPremul_SkAlphaType,
                                              testConfig.fColorSpace);
 
-        // For some GPU contexts (eg ANGLE), we don't have f16 support, so we should fail to create
-        // any surface of that type:
-        bool shouldWork = testConfig.fShouldWork &&
-                          (f16Support || kRGBA_F16_SkColorType != testConfig.fColorType) &&
-                          (supports1010102 || kRGBA_1010102_SkColorType != testConfig.fColorType);
-
         auto surface(surfaceMaker(info));
-        REPORTER_ASSERT(reporter, SkToBool(surface) == shouldWork, fullTestName.c_str());
+        REPORTER_ASSERT(reporter,
+                SkToBool(surface) == testConfig.fShouldWork, fullTestName.c_str());
 
-        if (shouldWork && surface) {
+        if (testConfig.fShouldWork && surface) {
             sk_sp<SkImage> image(surface->makeImageSnapshot());
             REPORTER_ASSERT(reporter, image, testConfig.fDescription);
             SkColorSpace* imageColorSpace = as_IB(image)->onImageInfo().colorSpace();
@@ -956,22 +956,25 @@
         return SkSurface::MakeRaster(info);
     };
 
-    test_surface_creation_and_snapshot_with_color_space(reporter, "raster", true, true,
+    test_surface_creation_and_snapshot_with_color_space(reporter, "raster",
+                                                        true, true, true,
                                                         surfaceMaker);
 }
 
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCreationWithColorSpace_Gpu, reporter, ctxInfo) {
     auto context = ctxInfo.grContext();
 
-    bool f16Support = context->contextPriv().caps()->isConfigRenderable(kRGBA_half_GrPixelConfig);
-    bool supports1010102 =
-            context->contextPriv().caps()->isConfigRenderable(kRGBA_1010102_GrPixelConfig);
+    bool supportsF16 = context->contextPriv().caps()->isConfigRenderable(kRGBA_half_GrPixelConfig),
+         supportsF32 = context->contextPriv().caps()->isConfigRenderable(kRGBA_float_GrPixelConfig),
+         supports1010102 = context->contextPriv().caps()->isConfigRenderable(kRGBA_1010102_GrPixelConfig);
+
     auto surfaceMaker = [context](const SkImageInfo& info) {
         return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
     };
 
-    test_surface_creation_and_snapshot_with_color_space(reporter, "gpu", f16Support,
-                                                        supports1010102, surfaceMaker);
+    test_surface_creation_and_snapshot_with_color_space(reporter, "gpu",
+                                                        supportsF16, supportsF32, supports1010102,
+                                                        surfaceMaker);
 
     std::vector<GrBackendTexture> backendTextures;
     auto wrappedSurfaceMaker = [ context, &backendTextures ](const SkImageInfo& info) {
@@ -996,8 +999,9 @@
                                                  sk_ref_sp(info.colorSpace()), nullptr);
     };
 
-    test_surface_creation_and_snapshot_with_color_space(reporter, "wrapped", f16Support,
-                                                        supports1010102, wrappedSurfaceMaker);
+    test_surface_creation_and_snapshot_with_color_space(reporter, "wrapped",
+                                                        supportsF16, supportsF32, supports1010102,
+                                                        wrappedSurfaceMaker);
 
     context->flush();
 
diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp
index 99b03a4..df4d75f 100644
--- a/tools/sk_tool_utils.cpp
+++ b/tools/sk_tool_utils.cpp
@@ -55,6 +55,7 @@
         case kRGB_101010x_SkColorType:  return "RGB_101010x";
         case kGray_8_SkColorType:       return "Gray_8";
         case kRGBA_F16_SkColorType:     return "RGBA_F16";
+        case kRGBA_F32_SkColorType:     return "RGBA_F32";
     }
     SkASSERT(false);
     return "unexpected colortype";