Experimental: Add R_16 and RG_1616 to Ganesh (take 2)

This is to support the P016 and P010 YUV formats. Initially, only Vulkan and GL support these formats.

Change-Id: I4e896f1d3fb32207227a755517ae5a00a58e6045
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/219403
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index 7543820..9a1222e 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -156,6 +156,9 @@
         case kRGBA_half_GrPixelConfig: return "RGBAHalf";
         case kRGBA_half_Clamped_GrPixelConfig: return "RGBAHalfClamped";
         case kRGB_ETC1_GrPixelConfig: return "RGBETC1";
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig: return "R16";
+        case kRG_1616_GrPixelConfig: return "RG1616";
     }
     SK_ABORT("Invalid pixel config");
     return "<invalid>";
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index b8773ea..8b4de2d 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -260,6 +260,21 @@
             sk_memset64((uint64_t *) dest, rgbaHalf, width * height);
             break;
         }
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig: {
+            uint16_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
+            sk_memset16((uint16_t*) dest, r16, width * height);
+            break;
+        }
+        case kRG_1616_GrPixelConfig: {
+            uint16_t r16 = SkScalarRoundToInt(colorf.fR * 65535.0f);
+            uint16_t g16 = SkScalarRoundToInt(colorf.fG * 65535.0f);
+
+            uint32_t rg1616 = r16 << 16 | g16;
+
+            sk_memset32((uint32_t*) dest, rg1616, width * height);
+            break;
+        }
         default:
             return false;
             break;
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index cf19f10..a5fc8be 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -353,6 +353,9 @@
             return sizeof(int32_t);
         case kUint_GrVertexAttribType:
             return sizeof(uint32_t);
+        // Experimental (for P016 and P010)
+        case kUShort_norm_GrVertexAttribType:
+            return sizeof(uint16_t);
     }
     // GCC fails because SK_ABORT evaluates to non constexpr. clang and cl.exe think this is
     // unreachable and don't complain.
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 2b6987c..d716d39 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -70,6 +70,9 @@
         case GrColorType::kRG_F32:           return false;
         case GrColorType::kRGBA_F32:         return true;
         case GrColorType::kRGB_ETC1:         return false;
+        // Experimental (for P016 and P010)
+        case GrColorType::kR_16:             return false;
+        case GrColorType::kRG_1616:          return false;
     }
     SK_ABORT("Invalid GrColorType");
     return false;
@@ -103,6 +106,9 @@
         case kAlpha_half_as_Red_GrPixelConfig:  return false;
         case kGray_8_as_Lum_GrPixelConfig:      return false;
         case kGray_8_as_Red_GrPixelConfig:      return false;
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig:               return false;
+        case kRG_1616_GrPixelConfig:            return false;
     }
     SK_ABORT("Invalid GrPixelConfig");
     return false;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 5f0e9dc..b144d01 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -319,6 +319,9 @@
         case kRGB_888X_GrPixelConfig:
         case kRG_88_GrPixelConfig:
         case kBGRA_8888_GrPixelConfig:
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig:
+        case kRG_1616_GrPixelConfig:
             return 0;
         case kRGB_565_GrPixelConfig:
             return 1;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index b665b70..48d3f16 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1866,11 +1866,11 @@
     }
 
     ConfigInfo& redInfo = fConfigTable[kAlpha_8_as_Red_GrPixelConfig];
-    redInfo.fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
-    redInfo.fFormatType = kNormalizedFixedPoint_FormatType;
     redInfo.fFormats.fBaseInternalFormat = GR_GL_RED;
     redInfo.fFormats.fSizedInternalFormat = GR_GL_R8;
     redInfo.fFormats.fExternalFormat[kReadPixels_ExternalFormatUsage] = GR_GL_RED;
+    redInfo.fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
+    redInfo.fFormatType = kNormalizedFixedPoint_FormatType;
     shaderCaps->fConfigTextureSwizzle[kAlpha_8_as_Red_GrPixelConfig] = GrSwizzle::RRRR();
 
     // ES2 Command Buffer does not allow TexStorage with R8_EXT (so Alpha_8 and Gray_8)
@@ -1895,11 +1895,11 @@
     }
 
     ConfigInfo& grayLumInfo = fConfigTable[kGray_8_as_Lum_GrPixelConfig];
-    grayLumInfo.fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
-    grayLumInfo.fFormatType = kNormalizedFixedPoint_FormatType;
     grayLumInfo.fFormats.fBaseInternalFormat = GR_GL_LUMINANCE;
     grayLumInfo.fFormats.fSizedInternalFormat = GR_GL_LUMINANCE8;
     grayLumInfo.fFormats.fExternalFormat[kReadPixels_ExternalFormatUsage] = GR_GL_LUMINANCE;
+    grayLumInfo.fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
+    grayLumInfo.fFormatType = kNormalizedFixedPoint_FormatType;
     shaderCaps->fConfigTextureSwizzle[kGray_8_as_Lum_GrPixelConfig] = GrSwizzle::RGBA();
 
     if ((GR_IS_GR_GL(standard) && version <= GR_GL_VER(3, 0)) ||
@@ -1909,13 +1909,13 @@
     }
 
     ConfigInfo& grayRedInfo = fConfigTable[kGray_8_as_Red_GrPixelConfig];
-    grayRedInfo.fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
-    grayRedInfo.fFormatType = kNormalizedFixedPoint_FormatType;
     grayRedInfo.fFormats.fBaseInternalFormat = GR_GL_RED;
     grayRedInfo.fFormats.fSizedInternalFormat = GR_GL_R8;
     grayRedInfo.fFormats.fExternalFormat[kReadPixels_ExternalFormatUsage] = GR_GL_RED;
-    shaderCaps->fConfigTextureSwizzle[kGray_8_as_Red_GrPixelConfig] = GrSwizzle::RRRA();
+    grayRedInfo.fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
+    grayRedInfo.fFormatType = kNormalizedFixedPoint_FormatType;
     grayRedInfo.fFlags = ConfigInfo::kTextureable_Flag;
+    shaderCaps->fConfigTextureSwizzle[kGray_8_as_Red_GrPixelConfig] = GrSwizzle::RRRA();
 
     // Leaving Gray8 as non-renderable, to keep things simple and match raster. However, we do
     // enable the FBOColorAttachment_Flag so that we can bind it to an FBO for copies.
@@ -2132,6 +2132,59 @@
     } // No WebGL support
     shaderCaps->fConfigTextureSwizzle[kRGB_ETC1_GrPixelConfig] = GrSwizzle::RGBA();
 
+    // Experimental (for P016 and P010)
+    {
+        // For desktop:
+        //    GL 3.0 requires support for R16 & RG16
+        //    GL_ARB_texture_rg adds R16 & RG16 support for OpenGL 1.1 and above
+        // For ES:
+        //    GL_EXT_texture_norm16 adds support but it requires ES 3.1
+        //    There is also the GL_NV_image_formats extension - for further investigation
+        bool r16AndRG1616Supported = false;
+        if (GR_IS_GR_GL(standard)) {
+            if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_texture_rg")) {
+                r16AndRG1616Supported = true;
+            }
+        } else if (GR_IS_GR_GL_ES(standard)) {
+            if (version >= GR_GL_VER(3, 1) && ctxInfo.hasExtension("GL_EXT_texture_norm16")) {
+                r16AndRG1616Supported = true;
+            }
+        } // No WebGL support
+
+        {
+            ConfigInfo& r16Info = fConfigTable[kR_16_GrPixelConfig];
+
+            r16Info.fFormats.fBaseInternalFormat = GR_GL_RED;
+            r16Info.fFormats.fSizedInternalFormat = GR_GL_R16;
+            r16Info.fFormats.fExternalFormat[kReadPixels_ExternalFormatUsage] = GR_GL_RED;
+            r16Info.fFormats.fExternalType = GR_GL_UNSIGNED_SHORT;
+            r16Info.fFormatType = kNormalizedFixedPoint_FormatType;
+            if (r16AndRG1616Supported) {
+                r16Info.fFlags = ConfigInfo::kTextureable_Flag;
+            }
+            // We should only ever be sampling the R channel of this format so don't bother
+            // with a fancy swizzle.
+            shaderCaps->fConfigTextureSwizzle[kR_16_GrPixelConfig] = GrSwizzle::RGBA();
+        }
+
+        {
+            ConfigInfo& rg1616Info = fConfigTable[kRG_1616_GrPixelConfig];
+
+            rg1616Info.fFormats.fBaseInternalFormat = GR_GL_RG;
+            rg1616Info.fFormats.fSizedInternalFormat = GR_GL_RG16;
+            rg1616Info.fFormats.fExternalFormat[kReadPixels_ExternalFormatUsage] = GR_GL_RG;
+            rg1616Info.fFormats.fExternalType = GR_GL_UNSIGNED_SHORT;
+            rg1616Info.fFormatType = kNormalizedFixedPoint_FormatType;
+            if (r16AndRG1616Supported) {
+                rg1616Info.fFlags = ConfigInfo::kTextureable_Flag;
+            }
+            // We should only ever be sampling the R and G channels of this format so don't bother
+            // with a fancy swizzle.
+            shaderCaps->fConfigTextureSwizzle[kRG_1616_GrPixelConfig] = GrSwizzle::RGBA();
+        }
+    }
+
+
     // Bulk populate the texture internal/external formats here and then deal with exceptions below.
 
     // ES 2.0 requires that the internal/external formats match.
@@ -3249,6 +3302,13 @@
         case GR_GL_R16F:
             config = kAlpha_half_as_Red_GrPixelConfig;
             break;
+        // Experimental (for P016 and P010)
+        case GR_GL_R16:
+            config = kR_16_GrPixelConfig;
+            break;
+        case GR_GL_RG16:
+            config = kRG_1616_GrPixelConfig;
+            break;
     }
 
     return config;
@@ -3306,6 +3366,11 @@
             return GR_GL_RGBA32F == format;
         case GrColorType::kRGB_ETC1:
             return GR_GL_COMPRESSED_RGB8_ETC2 == format || GR_GL_COMPRESSED_ETC1_RGB8 == format;
+        // Experimental (for P016 and P010)
+        case GrColorType::kR_16:
+            return GR_GL_R16 == format;
+        case GrColorType::kRG_1616:
+            return GR_GL_RG16 == format;
     }
     SK_ABORT("Unknown color type");
     return false;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index a0296d5..98a3743 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -887,6 +887,12 @@
         case kRGB_ETC1_GrPixelConfig:
         case kUnknown_GrPixelConfig:
             return 0;
+
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig:
+            return 2;
+        case kRG_1616_GrPixelConfig:
+            return 4;
     }
     SK_ABORT("Invalid pixel config");
     return 0;
@@ -1615,6 +1621,12 @@
         case GR_GL_COMPRESSED_RGB8_ETC2: // fall through
         case GR_GL_COMPRESSED_ETC1_RGB8:
             return 0;
+
+        // Experimental (for P016 and P010)
+        case GR_GL_R16:
+            return 2;
+        case GR_GL_RG16:
+            return 4;
     }
 
     SK_ABORT("Invalid GL format");
@@ -4056,6 +4068,14 @@
         case GR_GL_R16F:
             *config = kAlpha_half_GrPixelConfig;
             return true;
+
+        // Experimental (for P016 and P010)
+        case GR_GL_R16:
+            *config = kR_16_GrPixelConfig;
+            return true;
+        case GR_GL_RG16:
+            *config = kRG_1616_GrPixelConfig;
+            return true;
     }
 
     SK_ABORT("Unexpected config");
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 2c67f70..8f67be7 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -589,3 +589,46 @@
     return 4 * width * height;
 }
 
+size_t GrGLBytesPerFormat(GrGLenum glFormat) {
+    switch (glFormat) {
+        case GR_GL_LUMINANCE8:
+        case GR_GL_ALPHA8:
+        case GR_GL_R8:
+            return 1;
+
+        case GR_GL_RGB565:
+        case GR_GL_RGBA4:
+        case GR_GL_RG8:
+        case GR_GL_R16F:
+            return 2;
+
+        case GR_GL_RGB8:
+            return 3;
+
+        case GR_GL_RGBA8:
+        case GR_GL_SRGB8_ALPHA8:
+        case GR_GL_BGRA8:
+        case GR_GL_RGB10_A2:
+            return 4;
+
+        case GR_GL_RGBA16F:
+        case GR_GL_RG32F:
+            return 8;
+
+        case GR_GL_RGBA32F:
+            return 16;
+
+        case GR_GL_COMPRESSED_RGB8_ETC2: // fall through
+        case GR_GL_COMPRESSED_ETC1_RGB8:
+            return 0;
+
+        // Experimental (for P016 and P010)
+        case GR_GL_R16:
+            return 2;
+        case GR_GL_RG16:
+            return 4;
+    }
+
+    SK_ABORT("Invalid GL format");
+    return 0;
+}
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index d820b9d..c9bd3c2 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -269,4 +269,6 @@
  */
 size_t GrGLFormatCompressedDataSize(GrGLenum glFormat, int width, int height);
 
+size_t GrGLBytesPerFormat(GrGLenum glFormat);
+
 #endif
diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp
index 00d7d8d..4e6346d 100644
--- a/src/gpu/gl/GrGLVertexArray.cpp
+++ b/src/gpu/gl/GrGLVertexArray.cpp
@@ -74,6 +74,9 @@
             return {false, 1, GR_GL_INT};
         case kUint_GrVertexAttribType:
             return {false, 1, GR_GL_UNSIGNED_INT};
+        // Experimental (for P016 and P010)
+        case kUShort_norm_GrVertexAttribType:
+            return {true, 1, GR_GL_UNSIGNED_SHORT};
     }
     SK_ABORT("Unknown vertex attrib type");
     return {false, 0, 0};
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index e1b0b81..25cd522 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -442,6 +442,13 @@
 
     info = &fConfigTable[kRGBA_half_Clamped_GrPixelConfig];
     info->fFlags = ConfigInfo::kAllFlags;
+
+    // Experimental (for P016 and P010)
+    info = &fConfigTable[kR_16_GrPixelConfig];
+    info->fFlags = 0;
+
+    info = &fConfigTable[kRG_1616_GrPixelConfig];
+    info->fFlags = 0;
 }
 
 void GrMtlCaps::initStencilFormat(id<MTLDevice> physDev) {
@@ -574,6 +581,13 @@
         case MTLPixelFormatBGRA8Unorm:
             return kBGRA_8888_GrPixelConfig;
             break;
+        // Experimental (for P016 and P010)
+        case MTLPixelFormatR16Unorm:
+            return kR_16_GrPixelConfig;
+            break;
+        case MTLPixelFormatRG16Unorm:
+            return kRG_1616_GrPixelConfig;
+            break;
         default:
             return kUnknown_GrPixelConfig;
             break;
@@ -648,6 +662,11 @@
 #else
             return MTLPixelFormatETC2_RGB8 == format;
 #endif
+        // Experimental (for P016 and P010)
+        case GrColorType::kR_16:
+            return MTLPixelFormatR16Unorm == format;
+        case GrColorType::kRG_1616:
+            return MTLPixelFormatRG16Unorm == format;
     }
     SK_ABORT("Unknown color type");
     return false;
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 8e3408a..957a5b2 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -756,6 +756,13 @@
             *config = kRGB_ETC1_GrPixelConfig;
             return true;
 #endif
+        // Experimental (for P016 and P010)
+        case MTLPixelFormatR16Unorm:
+            *config = kR_16_GrPixelConfig;
+            return true;
+        case MTLPixelFormatRG16Unorm:
+            *config = kRG_1616_GrPixelConfig;
+            return true;
         default:
             return false;
     }
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index c816dd6..90b91ef 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -141,6 +141,9 @@
             return MTLVertexFormatInt;
         case kUint_GrVertexAttribType:
             return MTLVertexFormatUInt;
+        // Experimental (for P016 and P010)
+        case kUShort_norm_GrVertexAttribType:
+            return MTLVertexFormatUShortNormalized;
     }
     SK_ABORT("Unknown vertex attribute type");
     return MTLVertexFormatInvalid;
diff --git a/src/gpu/mtl/GrMtlUtil.mm b/src/gpu/mtl/GrMtlUtil.mm
index a0319d5..5bd6222 100644
--- a/src/gpu/mtl/GrMtlUtil.mm
+++ b/src/gpu/mtl/GrMtlUtil.mm
@@ -104,6 +104,12 @@
 #else
             return false;
 #endif
+        case kR_16_GrPixelConfig:
+            *format = MTLPixelFormatR16Unorm;
+            return true;
+        case kRG_1616_GrPixelConfig:
+            *format = MTLPixelFormatRG16Unorm;
+            return true;
     }
     SK_ABORT("Unexpected config");
     return false;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index b1bd5de..230ad8e 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -110,6 +110,11 @@
         case kGray_8_as_Lum_GrPixelConfig:
             SK_ABORT("Unsupported Vulkan pixel config");
             return 0;
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig:
+            return 2;
+        case kRG_1616_GrPixelConfig:
+            return 4;
     }
     SK_ABORT("Invalid pixel config");
     return 0;
@@ -710,6 +715,9 @@
         case VK_FORMAT_R32G32_SFLOAT:
         case VK_FORMAT_R16G16B16A16_SFLOAT:
         case VK_FORMAT_R16_SFLOAT:
+        // Experimental (for P016 and P010)
+        case VK_FORMAT_R16_UNORM:
+        case VK_FORMAT_R16G16_UNORM:
             return false;
         default:
             SK_ABORT("Unsupported VkFormat");
@@ -736,7 +744,11 @@
     VK_FORMAT_R32G32_SFLOAT,
     VK_FORMAT_R8G8B8A8_SRGB,
     VK_FORMAT_B8G8R8A8_SRGB,
-    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK
+    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
+
+    // Experimental (for P016 and P010)
+    VK_FORMAT_R16_UNORM,
+    VK_FORMAT_R16G16_UNORM,
 };
 
 const GrVkCaps::FormatInfo& GrVkCaps::getFormatInfo(VkFormat format) const {
@@ -1075,6 +1087,11 @@
             return kBGRA_8888_GrPixelConfig;
         case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
             return kRGBA_1010102_GrPixelConfig;
+        // Experimental (for P016 and P010)
+        case VK_FORMAT_R16_UNORM:
+            return kR_16_GrPixelConfig;
+        case VK_FORMAT_R16G16_UNORM:
+            return kRG_1616_GrPixelConfig;
         default:
             return kUnknown_GrPixelConfig;
     }
@@ -1137,6 +1154,11 @@
             return VK_FORMAT_R32G32B32A32_SFLOAT == vkFormat;
         case GrColorType::kRGB_ETC1:
             return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK == vkFormat;
+        // Experimental (for P016 and P010)
+        case GrColorType::kR_16:
+            return VK_FORMAT_R16_UNORM == vkFormat;
+        case GrColorType::kRG_1616:
+            return VK_FORMAT_R16G16_UNORM == vkFormat;
     }
     SK_ABORT("Unknown color type");
     return false;
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 9fa324c..6dd6b0b 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -223,7 +223,7 @@
 
         SkTDArray<int> fColorSampleCounts;
     };
-    static const size_t kNumVkFormats = 17;
+    static const size_t kNumVkFormats = 19;
     FormatInfo fFormatTable[kNumVkFormats];
 
     const FormatInfo& getFormatInfo(VkFormat) const;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index dc772c9..83ce19e 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1856,6 +1856,13 @@
         case VK_FORMAT_R16_SFLOAT:
             *config = kAlpha_half_GrPixelConfig;
             return true;
+        // Experimental (for P016 and P010)
+        case VK_FORMAT_R16_UNORM:
+            *config = kR_16_GrPixelConfig;
+            return true;
+        case VK_FORMAT_R16G16_UNORM:
+            *config = kRG_1616_GrPixelConfig;
+            return true;
         default:
             return false;
     }
diff --git a/src/gpu/vk/GrVkPipeline.cpp b/src/gpu/vk/GrVkPipeline.cpp
index f7bdf6d..2501f06 100644
--- a/src/gpu/vk/GrVkPipeline.cpp
+++ b/src/gpu/vk/GrVkPipeline.cpp
@@ -74,6 +74,9 @@
             return VK_FORMAT_R32_SINT;
         case kUint_GrVertexAttribType:
             return VK_FORMAT_R32_UINT;
+        // Experimental (for P016 and P010)
+        case kUShort_norm_GrVertexAttribType:
+            return VK_FORMAT_R16_UNORM;
     }
     SK_ABORT("Unknown vertex attrib type");
     return VK_FORMAT_UNDEFINED;
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index 7d3ee65..8787e50 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -83,6 +83,13 @@
         case kAlpha_half_as_Red_GrPixelConfig:
             *format = VK_FORMAT_R16_SFLOAT;
             return true;
+        // Experimental (for P016 and P010)
+        case kR_16_GrPixelConfig:
+            *format = VK_FORMAT_R16_UNORM;
+            return true;
+        case kRG_1616_GrPixelConfig:
+            *format = VK_FORMAT_R16G16_UNORM;
+            return true;
     }
     SK_ABORT("Unexpected config");
     return false;
@@ -129,6 +136,11 @@
         case VK_FORMAT_R16_SFLOAT:
             return kAlpha_half_GrPixelConfig == config ||
                    kAlpha_half_as_Red_GrPixelConfig == config;
+        // Experimental (for P016 and P010)
+        case VK_FORMAT_R16_UNORM:
+            return kR_16_GrPixelConfig == config;
+        case VK_FORMAT_R16G16_UNORM:
+            return kRG_1616_GrPixelConfig == config;
         default:
             return false;
     }
@@ -153,6 +165,10 @@
         case VK_FORMAT_R32G32_SFLOAT:
         case VK_FORMAT_R16G16B16A16_SFLOAT:
         case VK_FORMAT_R16_SFLOAT:
+
+        // Experimental (for P016 and P010)
+        case VK_FORMAT_R16_UNORM:
+        case VK_FORMAT_R16G16_UNORM:
             return true;
         default:
             return false;
@@ -290,6 +306,12 @@
         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
             return 8;
 
+        // Experimental (for P016 and P010)
+        case VK_FORMAT_R16_UNORM:
+            return 2;
+        case VK_FORMAT_R16G16_UNORM:
+            return 4;
+
         default:
             SK_ABORT("Invalid Vk format");
             return 0;