First draft of Dawn backend: clears are working.

First draft of (mostly stubbed-out) GrDawnGpu.
Skeletons of GrDawnCaps, GrDawnGpuCommandBuffer, GrDawnRenderTarget.
First draft of DawnTestContext.
First draft of psuedo-fences for Dawn, implemented with MapReadAsync.

Change-Id: Id009436f4441f26ffbc82d485d7af3a499b3281b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/226857
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 8b3e2f1..77a5617 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -10,6 +10,11 @@
 
 #include "src/gpu/gl/GrGLUtil.h"
 
+#ifdef SK_DAWN
+#include "include/gpu/dawn/GrDawnTypes.h"
+#include "src/gpu/dawn/GrDawnUtil.h"
+#endif
+
 #ifdef SK_VULKAN
 #include "include/gpu/vk/GrVkTypes.h"
 #include "src/gpu/vk/GrVkImageLayout.h"
@@ -44,6 +49,11 @@
             fMtlFormat = that.fMtlFormat;
             break;
 #endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn:
+            fDawnFormat = that.fDawnFormat;
+            break;
+#endif
         case GrBackendApi::kMock:
             fMockColorType = that.fMockColorType;
             break;
@@ -138,6 +148,22 @@
     return nullptr;
 }
 
+#ifdef SK_DAWN
+GrBackendFormat::GrBackendFormat(dawn::TextureFormat format)
+        : fBackend(GrBackendApi::kDawn)
+        , fValid(true)
+        , fDawnFormat(format)
+        , fTextureType(GrTextureType::k2D) {
+}
+
+const dawn::TextureFormat* GrBackendFormat::getDawnFormat() const {
+    if (this->isValid() && GrBackendApi::kDawn == fBackend) {
+        return &fDawnFormat;
+    }
+    return nullptr;
+}
+#endif
+
 #ifdef SK_METAL
 GrBackendFormat::GrBackendFormat(GrMTLPixelFormat mtlFormat)
         : fBackend(GrBackendApi::kMetal)
@@ -207,6 +233,11 @@
             return fMtlFormat == that.fMtlFormat;
 #endif
             break;
+        case GrBackendApi::kDawn:
+#ifdef SK_DAWN
+            return fDawnFormat == that.fDawnFormat;
+#endif
+            break;
         case GrBackendApi::kMock:
             return fMockColorType == that.fMockColorType;
         default:
@@ -215,6 +246,19 @@
     return false;
 }
 
+#ifdef SK_DAWN
+GrBackendTexture::GrBackendTexture(int width,
+                                   int height,
+                                   const GrDawnImageInfo& dawnInfo)
+        : fIsValid(true)
+        , fWidth(width)
+        , fHeight(height)
+        , fConfig(GrDawnFormatToPixelConfig(dawnInfo.fFormat))
+        , fMipMapped(GrMipMapped(dawnInfo.fLevelCount > 1))
+        , fBackend(GrBackendApi::kDawn)
+        , fDawnInfo(dawnInfo) {}
+#endif
+
 GrBackendTexture::GrBackendTexture(int width,
                                    int height,
                                    const GrVkImageInfo& vkInfo)
@@ -357,6 +401,11 @@
             fMtlInfo = that.fMtlInfo;
             break;
 #endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn:
+            fDawnInfo = that.fDawnInfo;
+            break;
+#endif
         case GrBackendApi::kMock:
             fMockInfo = that.fMockInfo;
             break;
@@ -367,6 +416,16 @@
     return *this;
 }
 
+#ifdef SK_DAWN
+bool GrBackendTexture::getDawnImageInfo(GrDawnImageInfo* outInfo) const {
+    if (this->isValid() && GrBackendApi::kDawn == fBackend) {
+        *outInfo = fDawnInfo;
+        return true;
+    }
+    return false;
+}
+#endif
+
 bool GrBackendTexture::getVkImageInfo(GrVkImageInfo* outInfo) const {
 #ifdef SK_VULKAN
     if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
@@ -484,6 +543,11 @@
             return GrBackendFormat::MakeVk(info.fFormat);
         }
 #endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn: {
+            return GrBackendFormat::MakeDawn(fDawnInfo.fFormat);
+        }
+#endif
 #ifdef SK_METAL
         case GrBackendApi::kMetal: {
             GrMtlTextureInfo mtlInfo;
@@ -527,6 +591,10 @@
         case GrBackendApi::kMetal:
             return t0.fMtlInfo == t1.fMtlInfo;
 #endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn:
+            return t0.fDawnInfo == t1.fDawnInfo;
+#endif
         default:
             return false;
     }
@@ -535,6 +603,22 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+#ifdef SK_DAWN
+GrBackendRenderTarget::GrBackendRenderTarget(int width,
+                                             int height,
+                                             int sampleCnt,
+                                             int stencilBits,
+                                             const GrDawnImageInfo& dawnInfo)
+        : fIsValid(true)
+        , fWidth(width)
+        , fHeight(height)
+        , fSampleCnt(sampleCnt)
+        , fStencilBits(stencilBits)
+        , fConfig(GrDawnFormatToPixelConfig(dawnInfo.fFormat))
+        , fBackend(GrBackendApi::kDawn)
+        , fDawnInfo(dawnInfo) {}
+#endif
+
 GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                              int height,
                                              int sampleCnt,
@@ -670,6 +754,11 @@
             fVkInfo.assign(that.fVkInfo, this->isValid());
 #endif
             break;
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn:
+            fDawnInfo = that.fDawnInfo;
+            break;
+#endif
 #ifdef SK_METAL
         case GrBackendApi::kMetal:
             fMtlInfo = that.fMtlInfo;
@@ -685,6 +774,16 @@
     return *this;
 }
 
+#ifdef SK_DAWN
+bool GrBackendRenderTarget::getDawnImageInfo(GrDawnImageInfo* outInfo) const {
+    if (this->isValid() && GrBackendApi::kDawn == fBackend) {
+        *outInfo = fDawnInfo;
+        return true;
+    }
+    return false;
+}
+#endif
+
 bool GrBackendRenderTarget::getVkImageInfo(GrVkImageInfo* outInfo) const {
 #ifdef SK_VULKAN
     if (this->isValid() && GrBackendApi::kVulkan == fBackend) {
@@ -802,6 +901,10 @@
         case GrBackendApi::kMetal:
             return r0.fMtlInfo == r1.fMtlInfo;
 #endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn:
+            return r0.fDawnInfo == r1.fDawnInfo;
+#endif
         default:
             return false;
     }
diff --git a/src/gpu/GrContextPriv.cpp b/src/gpu/GrContextPriv.cpp
index ad6d8ab..14795d2 100644
--- a/src/gpu/GrContextPriv.cpp
+++ b/src/gpu/GrContextPriv.cpp
@@ -231,14 +231,16 @@
 
     static const char* kBackendStr[] = {
         "Metal",
+        "Dawn",
         "OpenGL",
         "Vulkan",
         "Mock",
     };
     GR_STATIC_ASSERT(0 == (unsigned)GrBackendApi::kMetal);
-    GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kOpenGL);
-    GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kVulkan);
-    GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kMock);
+    GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kDawn);
+    GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kOpenGL);
+    GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kVulkan);
+    GR_STATIC_ASSERT(4 == (unsigned)GrBackendApi::kMock);
     writer.appendString("backend", kBackendStr[(unsigned)fContext->backend()]);
 
     writer.appendName("caps");
diff --git a/src/gpu/GrLegacyDirectContext.cpp b/src/gpu/GrLegacyDirectContext.cpp
index 4c3f756..b6bfd12 100644
--- a/src/gpu/GrLegacyDirectContext.cpp
+++ b/src/gpu/GrLegacyDirectContext.cpp
@@ -23,6 +23,9 @@
 #ifdef SK_VULKAN
 #include "src/gpu/vk/GrVkGpu.h"
 #endif
+#ifdef SK_DAWN
+#include "dawn/GrDawnGpu.h"
+#endif
 
 #ifdef SK_DISABLE_REDUCE_OPLIST_SPLITTING
 static const bool kDefaultReduceOpListSplitting = false;
@@ -218,3 +221,23 @@
 }
 #endif
 
+#ifdef SK_DAWN
+sk_sp<GrContext> GrContext::MakeDawn(const dawn::Device& device) {
+    GrContextOptions defaultOptions;
+    return MakeDawn(device, defaultOptions);
+}
+
+sk_sp<GrContext> GrContext::MakeDawn(const dawn::Device& device, const GrContextOptions& options) {
+    sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kDawn, options));
+
+    context->fGpu = GrDawnGpu::Make(device, options, context.get());
+    if (!context->fGpu) {
+        return nullptr;
+    }
+
+    if (!context->init(context->fGpu->refCaps(), nullptr)) {
+        return nullptr;
+    }
+    return context;
+}
+#endif
diff --git a/src/gpu/dawn/GrDawnCaps.cpp b/src/gpu/dawn/GrDawnCaps.cpp
new file mode 100644
index 0000000..3fb9a55
--- /dev/null
+++ b/src/gpu/dawn/GrDawnCaps.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDawnCaps.h"
+
+GrDawnCaps::GrDawnCaps(const GrContextOptions& contextOptions) : INHERITED(contextOptions) {
+    fBufferMapThreshold = SK_MaxS32;  // FIXME: get this from Dawn?
+    fShaderCaps.reset(new GrShaderCaps(contextOptions));
+    fMaxTextureSize = 2048;
+    fPerformPartialClearsAsDraws = true;
+}
+
+bool GrDawnCaps::isFormatSRGB(const GrBackendFormat& format) const {
+    return false;
+}
+
+bool GrDawnCaps::isConfigTexturable(GrPixelConfig config) const {
+    switch (config) {
+        case kRGBA_8888_GrPixelConfig:
+        case kBGRA_8888_GrPixelConfig:
+        case kAlpha_8_GrPixelConfig:
+            return true;
+        default:
+            return false;
+    }
+}
+
+GrPixelConfig GrDawnCaps::onGetConfigFromBackendFormat(const GrBackendFormat& format,
+                                                     GrColorType colorType) const {
+    dawn::TextureFormat textureFormat = *format.getDawnFormat();
+    switch (colorType) {
+        case GrColorType::kUnknown:
+            return kUnknown_GrPixelConfig;
+        case GrColorType::kAlpha_8:
+            if (dawn::TextureFormat::R8Unorm == textureFormat) {
+                return kAlpha_8_as_Red_GrPixelConfig;
+            }
+            break;
+        case GrColorType::kRGBA_8888:
+            if (dawn::TextureFormat::R8G8B8A8Unorm == textureFormat) {
+                return kRGBA_8888_GrPixelConfig;
+            }
+            break;
+        case GrColorType::kRGB_888x:
+            break;
+        case GrColorType::kBGRA_8888:
+            if (dawn::TextureFormat::B8G8R8A8Unorm == textureFormat) {
+                return kBGRA_8888_GrPixelConfig;
+            }
+            break;
+        default:
+            break;
+    }
+    return kUnknown_GrPixelConfig;
+}
+
+GrPixelConfig GrDawnCaps::getYUVAConfigFromBackendFormat(const GrBackendFormat& backendFormat)
+        const {
+    const dawn::TextureFormat* format = backendFormat.getDawnFormat();
+    if (!format) {
+        return kUnknown_GrPixelConfig;
+    }
+    switch (*format) {
+        case dawn::TextureFormat::R8Unorm:
+            return kAlpha_8_as_Red_GrPixelConfig;
+            break;
+        case dawn::TextureFormat::R8G8B8A8Unorm:
+            return kRGBA_8888_GrPixelConfig;
+            break;
+        case dawn::TextureFormat::B8G8R8A8Unorm:
+            return kBGRA_8888_GrPixelConfig;
+            break;
+        default:
+            return kUnknown_GrPixelConfig;
+            break;
+    }
+}
+
+size_t GrDawnCaps::onTransferFromOffsetAlignment(GrColorType bufferColorType) const {
+    if (bufferColorType == GrColorType::kRGB_888x) {
+        return false;
+    }
+    size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
+    switch (bpp & 0b11) {
+        case 0:     return bpp;
+        case 2:     return 2 * bpp;
+        default:    return 4 * bpp;
+    }
+}
+
+static GrSwizzle get_swizzle(const GrBackendFormat& format, GrColorType colorType,
+                             bool forOutput) {
+    SkASSERT(format.getDawnFormat());
+
+    switch (colorType) {
+        case GrColorType::kAlpha_8: // fall through
+        case GrColorType::kAlpha_F16:
+            if (forOutput) {
+                return GrSwizzle::AAAA();
+            } else {
+                return GrSwizzle::RRRR();
+            }
+        case GrColorType::kGray_8:
+            if (!forOutput) {
+                return GrSwizzle::RRRA();
+            }
+            break;
+        case GrColorType::kRGB_888x:
+            if (!forOutput) {
+                return GrSwizzle::RGB1();
+            }
+        default:
+            return GrSwizzle::RGBA();
+    }
+    return GrSwizzle::RGBA();
+}
+
+bool GrDawnCaps::isFormatTexturable(GrColorType ct, const GrBackendFormat& format) const {
+    GrPixelConfig config = this->getConfigFromBackendFormat(format, ct);
+    if (kUnknown_GrPixelConfig == config) {
+        return false;
+    }
+
+    return this->isConfigTexturable(config);
+}
+
+bool GrDawnCaps::isFormatCopyable(GrColorType ct, const GrBackendFormat& format) const {
+    return true;
+}
+
+int GrDawnCaps::getRenderTargetSampleCount(int requestedCount, GrColorType ct,
+                                           const GrBackendFormat& format) const {
+    GrPixelConfig config = this->getConfigFromBackendFormat(format, ct);
+    if (kUnknown_GrPixelConfig == config) {
+        return 0;
+    }
+
+    return this->getRenderTargetSampleCount(requestedCount, config);
+}
+
+GrBackendFormat GrDawnCaps::getBackendFormatFromColorType(GrColorType ct) const {
+    GrPixelConfig config = GrColorTypeToPixelConfig(ct);
+    if (config == kUnknown_GrPixelConfig) {
+        return GrBackendFormat();
+    }
+    dawn::TextureFormat format;
+    if (!GrPixelConfigToDawnFormat(config, &format)) {
+        return GrBackendFormat();
+    }
+    return GrBackendFormat::MakeDawn(format);
+}
+
+GrBackendFormat GrDawnCaps::getBackendFormatFromCompressionType(SkImage::CompressionType type) const
+{
+    return GrBackendFormat();
+}
+
+GrSwizzle GrDawnCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const
+{
+    return get_swizzle(format, colorType, false);
+}
+
+bool GrDawnCaps::canClearTextureOnCreation() const {
+    return true;
+}
+
+GrSwizzle GrDawnCaps::getOutputSwizzle(const GrBackendFormat& format, GrColorType colorType) const
+{
+    return get_swizzle(format, colorType, true);
+}
+
+bool GrDawnCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
+                                                   const GrBackendFormat& format) const {
+    return true;
+}
diff --git a/src/gpu/dawn/GrDawnCaps.h b/src/gpu/dawn/GrDawnCaps.h
new file mode 100644
index 0000000..a28eae0
--- /dev/null
+++ b/src/gpu/dawn/GrDawnCaps.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDawnCaps_DEFINED
+#define GrDawnCaps_DEFINED
+
+#include "src/gpu/GrCaps.h"
+#include "include/gpu/GrContextOptions.h"
+#include "src/gpu/dawn/GrDawnUtil.h"
+#include "include/gpu/GrBackendSurface.h"
+
+class GrDawnCaps : public GrCaps {
+public:
+    GrDawnCaps(const GrContextOptions& contextOptions);
+
+    bool isFormatSRGB(const GrBackendFormat& format) const override;
+    bool isFormatTexturable(GrColorType, const GrBackendFormat& format) const override;
+    bool isFormatCopyable(GrColorType, const GrBackendFormat& format) const override;
+
+    bool isConfigTexturable(GrPixelConfig config) const override;
+
+    bool isConfigCopyable(GrPixelConfig config) const override {
+        return true;
+    }
+
+    bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
+                          const SkIRect& srcRect, const SkIPoint& dstPoint) const override {
+        return true;
+    }
+
+    bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
+                            bool* rectsMustMatch, bool* disallowSubrect) const override {
+        return false;
+    }
+
+    GrPixelConfig validateBackendRenderTarget(const GrBackendRenderTarget&, GrColorType) const
+                                                                                         override {
+        return GrPixelConfig::kUnknown_GrPixelConfig;
+    }
+
+    GrPixelConfig onGetConfigFromBackendFormat(const GrBackendFormat&, GrColorType) const override;
+
+    GrPixelConfig getYUVAConfigFromBackendFormat(const GrBackendFormat&) const override;
+
+    SurfaceReadPixelsSupport surfaceSupportsReadPixels(const GrSurface*) const override {
+        return SurfaceReadPixelsSupport::kSupported;
+    }
+
+    bool onSurfaceSupportsWritePixels(const GrSurface* surface) const override {
+        return true;
+    }
+
+    int getRenderTargetSampleCount(int requestedCount, GrColorType,
+                                   const GrBackendFormat&) const override;
+
+    int getRenderTargetSampleCount(int requestedCount, GrPixelConfig config) const override {
+        return this->isConfigTexturable(config) ? 1 : 0;
+    }
+
+    int maxRenderTargetSampleCount(GrColorType ct,
+                                   const GrBackendFormat& format) const override {
+        return this->maxRenderTargetSampleCount(this->getConfigFromBackendFormat(format, ct));
+    }
+
+    int maxRenderTargetSampleCount(GrPixelConfig config) const override {
+        return this->isConfigTexturable(config) ? 1 : 0;
+    }
+
+    GrBackendFormat getBackendFormatFromColorType(GrColorType ct) const override;
+
+    GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
+
+    bool canClearTextureOnCreation() const override;
+
+    GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
+
+    GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
+
+    size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const override;
+
+    bool onAreColorTypeAndFormatCompatible(GrColorType, const GrBackendFormat&) const override;
+
+    typedef GrCaps INHERITED;
+};
+
+#endif
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
new file mode 100644
index 0000000..b3d4a97
--- /dev/null
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDawnGpu.h"
+
+#include "include/gpu/GrBackendSemaphore.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContextOptions.h"
+#include "src/gpu/GrGeometryProcessor.h"
+#include "src/gpu/GrGpuResourceCacheAccess.h"
+#include "src/gpu/GrMesh.h"
+#include "src/gpu/dawn/GrDawnCaps.h"
+#include "src/gpu/dawn/GrDawnRenderTarget.h"
+#include "src/gpu/dawn/GrDawnGpuCommandBuffer.h"
+#include "src/gpu/GrPipeline.h"
+#include "src/gpu/GrRenderTargetPriv.h"
+#include "src/gpu/GrSemaphore.h"
+#include "src/gpu/GrTexturePriv.h"
+
+#include "src/sksl/SkSLCompiler.h"
+
+#if !defined(SK_BUILD_FOR_WIN)
+#include <unistd.h>
+#endif // !defined(SK_BUILD_FOR_WIN)
+
+sk_sp<GrGpu> GrDawnGpu::Make(const dawn::Device& device,
+                             const GrContextOptions& options, GrContext* context) {
+    if (!device) {
+        return nullptr;
+    }
+
+    return sk_sp<GrGpu>(new GrDawnGpu(context, options, device));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrDawnGpu::GrDawnGpu(GrContext* context, const GrContextOptions& options,
+                   const dawn::Device& device)
+        : INHERITED(context)
+        , fDevice(device)
+        , fQueue(device.CreateQueue())
+        , fCompiler(new SkSL::Compiler()) {
+    fCaps.reset(new GrDawnCaps(options));
+}
+
+GrDawnGpu::~GrDawnGpu() {
+}
+
+
+void GrDawnGpu::disconnect(DisconnectType type) {
+    INHERITED::disconnect(type);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGpuRTCommandBuffer* GrDawnGpu::getCommandBuffer(
+            GrRenderTarget* rt, GrSurfaceOrigin origin, const SkRect& bounds,
+            const GrGpuRTCommandBuffer::LoadAndStoreInfo& colorInfo,
+            const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo& stencilInfo) {
+    fCachedRTCommandBuffer.reset(
+        new GrDawnGpuRTCommandBuffer(this, rt, origin, colorInfo, stencilInfo));
+    return fCachedRTCommandBuffer.get();
+}
+
+GrGpuTextureCommandBuffer* GrDawnGpu::getCommandBuffer(GrTexture* texture,
+                                                       GrSurfaceOrigin origin) {
+    return nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+sk_sp<GrGpuBuffer> GrDawnGpu::onCreateBuffer(size_t size, GrGpuBufferType type,
+                                             GrAccessPattern accessPattern, const void* data) {
+    return nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool GrDawnGpu::onWritePixels(GrSurface* surface,
+                              int left, int top, int width, int height,
+                              GrColorType colorType,
+                              const GrMipLevel texels[], int mipLevelCount) {
+    return false;
+}
+
+bool GrDawnGpu::onTransferPixelsTo(GrTexture* texture,
+                                  int left, int top, int width, int height,
+                                  GrColorType colorType, GrGpuBuffer* transferBuffer,
+                                  size_t bufferOffset, size_t rowBytes) {
+    return false;
+}
+
+bool GrDawnGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
+                                     GrColorType, GrGpuBuffer* transferBuffer, size_t offset) {
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+sk_sp<GrTexture> GrDawnGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
+                                            const GrMipLevel texels[], int mipLevelCount) {
+    return nullptr;
+}
+
+sk_sp<GrTexture> GrDawnGpu::onCreateCompressedTexture(int width, int height,
+                                                      SkImage::CompressionType, SkBudgeted,
+                                                      const void* data) {
+    return nullptr;
+}
+
+sk_sp<GrTexture> GrDawnGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
+                                                 GrWrapOwnership ownership,
+                                                 GrWrapCacheable cacheable,
+                                                 GrIOType) {
+    return nullptr;
+}
+
+sk_sp<GrTexture> GrDawnGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
+                                                           int sampleCnt, GrColorType,
+                                                           GrWrapOwnership,
+                                                           GrWrapCacheable cacheable) {
+    return nullptr;
+}
+
+sk_sp<GrRenderTarget> GrDawnGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget&) {
+    return nullptr;
+}
+
+sk_sp<GrRenderTarget> GrDawnGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
+                                                                    int sampleCnt) {
+    GrDawnImageInfo info;
+    if (!tex.getDawnImageInfo(&info)) {
+        return nullptr;
+    }
+    if (!info.fTexture) {
+        return nullptr;
+    }
+
+    GrSurfaceDesc desc;
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+    desc.fWidth = tex.width();
+    desc.fHeight = tex.height();
+    desc.fConfig = tex.config();
+    desc.fSampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, tex.config());
+    if (desc.fSampleCnt < 1) {
+        return nullptr;
+    }
+
+    sk_sp<GrDawnRenderTarget> tgt = GrDawnRenderTarget::MakeWrapped(this, desc, info);
+    return tgt;
+}
+
+GrStencilAttachment* GrDawnGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
+                                                                       int width,
+                                                                       int height,
+                                                                       int numStencilSamples) {
+    return nullptr;
+}
+
+GrBackendTexture GrDawnGpu::createBackendTexture(int width, int height,
+                                                 const GrBackendFormat& format,
+                                                 GrMipMapped mipMapped,
+                                                 GrRenderable renderable,
+                                                 const void* pixels,
+                                                 size_t rowBytes,
+                                                 const SkColor4f* color,
+                                                 GrProtected isProtected) {
+    return GrBackendTexture();
+}
+
+void GrDawnGpu::deleteBackendTexture(const GrBackendTexture& tex) {
+}
+
+#if GR_TEST_UTILS
+bool GrDawnGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
+    return false;
+}
+
+GrBackendRenderTarget GrDawnGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) {
+    return GrBackendRenderTarget();
+}
+
+void GrDawnGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {
+}
+
+void GrDawnGpu::testingOnly_flushGpuAndSync() {
+}
+
+#endif
+
+void GrDawnGpu::onFinishFlush(GrSurfaceProxy*[], int n, SkSurface::BackendSurfaceAccess access,
+                              const GrFlushInfo& info, const GrPrepareForExternalIORequests&) {
+}
+
+bool GrDawnGpu::onCopySurface(GrSurface* dst,
+                              GrSurface* src,
+                              const SkIRect& srcRect,
+                              const SkIPoint& dstPoint,
+                              bool canDiscardOutsideDstRect) {
+    return false;
+}
+
+bool GrDawnGpu::onReadPixels(GrSurface* surface,
+                             int left, int top, int width, int height,
+                             GrColorType colorType,
+                             void* buffer,
+                             size_t rowBytes) {
+    return false;
+}
+
+bool GrDawnGpu::onRegenerateMipMapLevels(GrTexture*) {
+    return false;
+}
+
+void GrDawnGpu::submit(GrGpuCommandBuffer* buffer) {
+    if (auto buf = static_cast<GrDawnGpuRTCommandBuffer*>(buffer->asRTCommandBuffer())) {
+        buf->submit();
+    }
+}
+
+GrFence SK_WARN_UNUSED_RESULT GrDawnGpu::insertFence() {
+    return GrFence();
+}
+
+bool GrDawnGpu::waitFence(GrFence fence, uint64_t timeout) {
+    return false;
+}
+
+void GrDawnGpu::deleteFence(GrFence fence) const {
+}
+
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrDawnGpu::makeSemaphore(bool isOwned) {
+    return nullptr;
+}
+
+sk_sp<GrSemaphore> GrDawnGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                                   GrResourceProvider::SemaphoreWrapType wrapType,
+                                                   GrWrapOwnership ownership) {
+    SkASSERT(!"unimplemented");
+    return nullptr;
+}
+
+void GrDawnGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore) {
+    SkASSERT(!"unimplemented");
+}
+
+void GrDawnGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
+    SkASSERT(!"unimplemented");
+}
+
+void GrDawnGpu::checkFinishProcs() {
+    SkASSERT(!"unimplemented");
+}
+
+sk_sp<GrSemaphore> GrDawnGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
+    return nullptr;
+}
diff --git a/src/gpu/dawn/GrDawnGpu.h b/src/gpu/dawn/GrDawnGpu.h
new file mode 100644
index 0000000..e3c428f
--- /dev/null
+++ b/src/gpu/dawn/GrDawnGpu.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDawnGpu_DEFINED
+#define GrDawnGpu_DEFINED
+
+#include "src/gpu/GrGpu.h"
+#include "dawn/dawncpp.h"
+
+class GrPipeline;
+class GrDawnGpuRTCommandBuffer;
+
+namespace SkSL {
+    class Compiler;
+}
+
+class GrDawnGpu : public GrGpu {
+public:
+    static sk_sp<GrGpu> Make(const dawn::Device& device, const GrContextOptions&, GrContext*);
+    GrDawnGpu(GrContext* context, const GrContextOptions& options, const dawn::Device& device);
+
+    ~GrDawnGpu() override;
+
+    void disconnect(DisconnectType) override;
+
+    const dawn::Device& device() const { return fDevice; }
+    const dawn::Queue&  queue() const { return fQueue; }
+
+    void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
+
+    GrBackendTexture createBackendTexture(int w, int h,
+                                          const GrBackendFormat &,
+                                          GrMipMapped,
+                                          GrRenderable,
+                                          const void* pixels,
+                                          size_t rowBytes,
+                                          const SkColor4f* color,
+                                          GrProtected isProtected) override;
+    void deleteBackendTexture(const GrBackendTexture&) override;
+#if GR_TEST_UTILS
+    bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
+
+    GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
+    void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
+
+    void testingOnly_flushGpuAndSync() override;
+#endif
+
+    GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
+                                                                int width,
+                                                                int height,
+                                                                int numStencilSamples) override;
+
+    GrGpuRTCommandBuffer* getCommandBuffer(
+            GrRenderTarget*, GrSurfaceOrigin, const SkRect& bounds,
+            const GrGpuRTCommandBuffer::LoadAndStoreInfo&,
+            const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo&) override;
+
+    GrGpuTextureCommandBuffer* getCommandBuffer(GrTexture*, GrSurfaceOrigin) override;
+
+    SkSL::Compiler* shaderCompiler() const {
+        return fCompiler.get();
+    }
+
+    void submit(GrGpuCommandBuffer* cb) override;
+    GrFence SK_WARN_UNUSED_RESULT insertFence() override;
+    bool waitFence(GrFence, uint64_t timeout) override;
+    void deleteFence(GrFence) const override;
+
+    sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true) override;
+    sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+                                            GrResourceProvider::SemaphoreWrapType wrapType,
+                                            GrWrapOwnership ownership) override;
+    void insertSemaphore(sk_sp<GrSemaphore> semaphore) override;
+    void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
+    void checkFinishProcs() override;
+
+    sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
+
+private:
+    void onResetContext(uint32_t resetBits) override {}
+
+    virtual void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override {}
+
+    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
+                                     const GrMipLevel texels[], int mipLevelCount) override;
+
+    sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, SkImage::CompressionType,
+                                               SkBudgeted, const void* data) override;
+
+    sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership,
+                                          GrWrapCacheable, GrIOType) override;
+    sk_sp<GrTexture> onWrapRenderableBackendTexture(const GrBackendTexture&, int sampleCnt,
+                                                    GrColorType, GrWrapOwnership,
+                                                    GrWrapCacheable) override;
+    sk_sp<GrRenderTarget> onWrapBackendRenderTarget(const GrBackendRenderTarget&) override;
+
+    sk_sp<GrRenderTarget> onWrapBackendTextureAsRenderTarget(const GrBackendTexture&,
+                                                             int sampleCnt) override;
+
+    sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType type, GrAccessPattern,
+                                      const void* data) override;
+
+    bool onReadPixels(GrSurface* surface,
+                      int left, int top, int width, int height,
+                      GrColorType, void* buffer, size_t rowBytes) override;
+
+    bool onWritePixels(GrSurface* surface,
+                       int left, int top, int width, int height,
+                       GrColorType, const GrMipLevel texels[], int mipLevelCount) override;
+
+    bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height,
+                            GrColorType colorType, GrGpuBuffer* transferBuffer,
+                            size_t offset, size_t rowBytes) override;
+
+    bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
+                              GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override;
+
+    void onResolveRenderTarget(GrRenderTarget* target) override {
+    }
+
+    bool onRegenerateMipMapLevels(GrTexture*) override;
+
+    bool onCopySurface(GrSurface* dst, GrSurface* src,
+                       const SkIRect& srcRect, const SkIPoint& dstPoint,
+                       bool canDiscardOutsideDstRect) override;
+
+    void onFinishFlush(GrSurfaceProxy*[], int n, SkSurface::BackendSurfaceAccess access,
+                       const GrFlushInfo& info, const GrPrepareForExternalIORequests&) override;
+
+    dawn::Device                                 fDevice;
+    dawn::Queue                                  fQueue;    // Must be Graphics queue
+
+    // Compiler used for compiling sksl into spirv. We only want to create the compiler once since
+    // there is significant overhead to the first compile of any compiler.
+    std::unique_ptr<SkSL::Compiler> fCompiler;
+
+    std::unique_ptr<GrDawnGpuRTCommandBuffer> fCachedRTCommandBuffer;
+
+    typedef GrGpu INHERITED;
+};
+
+#endif
diff --git a/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp b/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
new file mode 100644
index 0000000..39e3169
--- /dev/null
+++ b/src/gpu/dawn/GrDawnGpuCommandBuffer.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDawnGpuCommandBuffer.h"
+
+#include "src/gpu/GrFixedClip.h"
+#include "src/gpu/GrMesh.h"
+#include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrPipeline.h"
+#include "src/gpu/GrRenderTargetPriv.h"
+#include "src/gpu/GrTexturePriv.h"
+#include "src/gpu/dawn/GrDawnGpu.h"
+#include "src/gpu/dawn/GrDawnRenderTarget.h"
+#include "include/core/SkRect.h"
+
+void GrDawnGpuTextureCommandBuffer::copy(GrSurface* src, const SkIRect& srcRect,
+                                         const SkIPoint& dstPoint) {
+}
+
+void GrDawnGpuTextureCommandBuffer::insertEventMarker(const char* msg) {
+}
+
+void GrDawnGpuTextureCommandBuffer::submit() {
+    for (int i = 0; i < fCopies.count(); ++i) {
+        CopyInfo& copyInfo = fCopies[i];
+        fGpu->copySurface(fTexture, copyInfo.fSrc, copyInfo.fSrcRect, copyInfo.fDstPoint);
+    }
+}
+
+GrDawnGpuTextureCommandBuffer::~GrDawnGpuTextureCommandBuffer() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+dawn::LoadOp to_dawn_load_op(GrLoadOp loadOp) {
+    switch (loadOp) {
+        case GrLoadOp::kLoad:
+            return dawn::LoadOp::Load;
+        case GrLoadOp::kClear:
+            return dawn::LoadOp::Clear;
+        case GrLoadOp::kDiscard:
+        default:
+            SK_ABORT("Invalid LoadOp");
+            return dawn::LoadOp::Load;
+    }
+}
+
+GrDawnGpuRTCommandBuffer::GrDawnGpuRTCommandBuffer(GrDawnGpu* gpu,
+                                                   GrRenderTarget* rt, GrSurfaceOrigin origin,
+                                                   const LoadAndStoreInfo& colorInfo,
+                                                   const StencilLoadAndStoreInfo& stencilInfo)
+        : INHERITED(rt, origin)
+        , fGpu(gpu) {
+    this->init();
+}
+
+void GrDawnGpuRTCommandBuffer::init() {
+}
+
+
+GrDawnGpuRTCommandBuffer::~GrDawnGpuRTCommandBuffer() {
+}
+
+GrGpu* GrDawnGpuRTCommandBuffer::gpu() { return fGpu; }
+
+void GrDawnGpuRTCommandBuffer::end() {
+}
+
+void GrDawnGpuRTCommandBuffer::submit() {
+    if (fCommandBuffer) {
+        fGpu->queue().Submit(1, &fCommandBuffer);
+    }
+}
+
+void GrDawnGpuRTCommandBuffer::insertEventMarker(const char* msg) {
+}
+
+void GrDawnGpuRTCommandBuffer::transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
+                                            GrGpuBuffer* transferBuffer, size_t offset) {
+    fGpu->transferPixelsFrom(fRenderTarget, srcRect.fLeft, srcRect.fTop, srcRect.width(),
+                             srcRect.height(), bufferColorType, transferBuffer, offset);
+}
+
+void GrDawnGpuRTCommandBuffer::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
+}
+
+void GrDawnGpuRTCommandBuffer::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDawnGpuRTCommandBuffer::inlineUpload(GrOpFlushState* state,
+                                            GrDeferredTextureUploadFn& upload) {
+}
+
+void GrDawnGpuRTCommandBuffer::copy(GrSurface* src, const SkIRect& srcRect,
+                                    const SkIPoint& dstPoint) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDawnGpuRTCommandBuffer::bindGeometry(const GrBuffer* indexBuffer,
+                                            const GrBuffer* vertexBuffer,
+                                            const GrBuffer* instanceBuffer) {
+}
+
+void GrDawnGpuRTCommandBuffer::onDraw(const GrPrimitiveProcessor& primProc,
+                                      const GrPipeline& pipeline,
+                                      const GrPipeline::FixedDynamicState* fixedDynamicState,
+                                      const GrPipeline::DynamicStateArrays* dynamicStateArrays,
+                                      const GrMesh meshes[],
+                                      int meshCount,
+                                      const SkRect& bounds) {
+    if (!meshCount) {
+        return;
+    }
+    GrFragmentProcessor::Iter iter(pipeline);
+
+    for (int i = 0; i < meshCount; ++i) {
+        const GrMesh& mesh = meshes[i];
+        mesh.sendToGpu(this);
+    }
+}
+
+void GrDawnGpuRTCommandBuffer::sendInstancedMeshToGpu(GrPrimitiveType,
+                                                      const GrBuffer* vertexBuffer,
+                                                      int vertexCount,
+                                                      int baseVertex,
+                                                      const GrBuffer* instanceBuffer,
+                                                      int instanceCount,
+                                                      int baseInstance) {
+    this->bindGeometry(nullptr, vertexBuffer, instanceBuffer);
+    fGpu->stats()->incNumDraws();
+}
+
+void GrDawnGpuRTCommandBuffer::sendIndexedInstancedMeshToGpu(GrPrimitiveType,
+                                                             const GrBuffer* indexBuffer,
+                                                             int indexCount,
+                                                             int baseIndex,
+                                                             const GrBuffer* vertexBuffer,
+                                                             int baseVertex,
+                                                             const GrBuffer* instanceBuffer,
+                                                             int instanceCount,
+                                                             int baseInstance,
+                                                             GrPrimitiveRestart restart) {
+    this->bindGeometry(indexBuffer, vertexBuffer, instanceBuffer);
+    fGpu->stats()->incNumDraws();
+}
+
diff --git a/src/gpu/dawn/GrDawnGpuCommandBuffer.h b/src/gpu/dawn/GrDawnGpuCommandBuffer.h
new file mode 100644
index 0000000..4a6fd46
--- /dev/null
+++ b/src/gpu/dawn/GrDawnGpuCommandBuffer.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDawnGpuCommandBuffer_DEFINED
+#define GrDawnGpuCommandBuffer_DEFINED
+
+#include "src/gpu/GrGpuCommandBuffer.h"
+
+#include "src/gpu/GrColor.h"
+#include "src/gpu/GrMesh.h"
+#include "include/gpu/GrTypes.h"
+#include "dawn/dawncpp.h"
+
+class GrDawnGpu;
+class GrDawnRenderTarget;
+
+class GrDawnGpuTextureCommandBuffer : public GrGpuTextureCommandBuffer {
+public:
+    GrDawnGpuTextureCommandBuffer(GrDawnGpu* gpu, GrTexture* texture, GrSurfaceOrigin origin)
+        : INHERITED(texture, origin)
+        , fGpu(gpu) {
+    }
+
+    ~GrDawnGpuTextureCommandBuffer() override;
+
+    void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
+
+    void insertEventMarker(const char*) override;
+
+private:
+    void submit();
+
+    struct CopyInfo {
+        CopyInfo(GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect,
+                 const SkIPoint& dstPoint)
+            : fSrc(src), fSrcOrigin(srcOrigin), fSrcRect(srcRect), fDstPoint(dstPoint) {}
+
+        GrSurface*      fSrc;
+        GrSurfaceOrigin fSrcOrigin;
+        SkIRect         fSrcRect;
+        SkIPoint        fDstPoint;
+    };
+
+    GrDawnGpu*                   fGpu;
+    SkTArray<CopyInfo>          fCopies;
+
+    typedef GrGpuTextureCommandBuffer INHERITED;
+};
+
+class GrDawnGpuRTCommandBuffer : public GrGpuRTCommandBuffer, private GrMesh::SendToGpuImpl {
+public:
+    GrDawnGpuRTCommandBuffer(GrDawnGpu*, GrRenderTarget*, GrSurfaceOrigin,
+                             const LoadAndStoreInfo&,
+                             const StencilLoadAndStoreInfo&);
+
+    ~GrDawnGpuRTCommandBuffer() override;
+
+    void begin() override { }
+    void end() override;
+
+    void transferFrom(const SkIRect& srcRect, GrColorType bufferColorType,
+                      GrGpuBuffer* transferBuffer, size_t offset) override;
+    void insertEventMarker(const char*) override;
+
+    void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override;
+
+    void copy(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
+
+    void submit();
+
+private:
+    void init();
+
+    GrGpu* gpu() override;
+
+    // Bind vertex and index buffers
+    void bindGeometry(const GrBuffer* indexBuffer,
+                      const GrBuffer* vertexBuffer,
+                      const GrBuffer* instanceBuffer);
+
+    void onDraw(const GrPrimitiveProcessor& primProc,
+                const GrPipeline& pipeline,
+                const GrPipeline::FixedDynamicState* fixedDynamicState,
+                const GrPipeline::DynamicStateArrays* dynamicStateArrays,
+                const GrMesh mesh[],
+                int meshCount,
+                const SkRect& bounds) override;
+
+    void sendMeshToGpu(GrPrimitiveType primType, const GrBuffer* vertexBuffer, int vertexCount,
+                       int baseVertex) final {
+        this->sendInstancedMeshToGpu(primType, vertexBuffer, vertexCount, baseVertex,
+                                     nullptr, 1, 0);
+    }
+
+    void sendIndexedMeshToGpu(GrPrimitiveType primType,
+                              const GrBuffer* indexBuffer, int indexCount, int baseIndex,
+                              uint16_t /*minIndexValue*/, uint16_t /*maxIndexValue*/,
+                              const GrBuffer* vertexBuffer, int baseVertex,
+                              GrPrimitiveRestart restart) final {
+        this->sendIndexedInstancedMeshToGpu(primType, indexBuffer, indexCount, baseIndex,
+                                            vertexBuffer, baseVertex, nullptr, 1, 0, restart);
+    }
+
+    void sendInstancedMeshToGpu(GrPrimitiveType,
+                                const GrBuffer* vertexBuffer, int vertexCount, int baseVertex,
+                                const GrBuffer* instanceBuffer, int instanceCount,
+                                int baseInstance) final;
+
+    void sendIndexedInstancedMeshToGpu(GrPrimitiveType,
+                                       const GrBuffer* indexBuffer, int indexCount, int baseIndex,
+                                       const GrBuffer* vertexBuffer, int baseVertex,
+                                       const GrBuffer* instanceBuffer, int instanceCount,
+                                       int baseInstance, GrPrimitiveRestart) final;
+
+    void onClear(const GrFixedClip&, const SkPMColor4f& color) override;
+
+    void onClearStencilClip(const GrFixedClip&, bool insideStencilMask) override;
+
+    struct InlineUploadInfo {
+        InlineUploadInfo(GrOpFlushState* state, const GrDeferredTextureUploadFn& upload)
+                : fFlushState(state), fUpload(upload) {}
+
+        GrOpFlushState* fFlushState;
+        GrDeferredTextureUploadFn fUpload;
+    };
+
+    struct CopyInfo {
+        CopyInfo(GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect,
+                 const SkIPoint& dstPoint)
+            : fSrc(src), fSrcOrigin(srcOrigin), fSrcRect(srcRect), fDstPoint(dstPoint) {}
+
+        GrSurface*      fSrc;
+        GrSurfaceOrigin fSrcOrigin;
+        SkIRect         fSrcRect;
+        SkIPoint        fDstPoint;
+    };
+
+    dawn::CommandBuffer         fCommandBuffer;
+    GrDawnGpu*                  fGpu;
+
+    typedef GrGpuRTCommandBuffer INHERITED;
+};
+
+#endif
diff --git a/src/gpu/dawn/GrDawnRenderTarget.cpp b/src/gpu/dawn/GrDawnRenderTarget.cpp
new file mode 100644
index 0000000..02b8a5b
--- /dev/null
+++ b/src/gpu/dawn/GrDawnRenderTarget.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDawnRenderTarget.h"
+
+#include "include/gpu/GrBackendSurface.h"
+#include "src/gpu/dawn/GrDawnGpu.h"
+#include "src/gpu/dawn/GrDawnUtil.h"
+
+GrDawnRenderTarget::GrDawnRenderTarget(GrDawnGpu* gpu,
+                                       const GrSurfaceDesc& desc,
+                                       const GrDawnImageInfo& info,
+                                       GrBackendObjectOwnership ownership)
+    : GrSurface(gpu, desc)
+    , GrRenderTarget(gpu, desc)
+    , fInfo(info) {
+    this->registerWithCacheWrapped(GrWrapCacheable::kNo);
+}
+
+GrDawnRenderTarget*
+GrDawnRenderTarget::Create(GrDawnGpu* gpu,
+                           const GrSurfaceDesc& desc,
+                           const GrDawnImageInfo& info,
+                           GrBackendObjectOwnership ownership) {
+    SkASSERT(1 == info.fLevelCount);
+    return new GrDawnRenderTarget(gpu, desc, info, ownership);
+}
+
+sk_sp<GrDawnRenderTarget>
+GrDawnRenderTarget::MakeWrapped(GrDawnGpu* gpu,
+                                const GrSurfaceDesc& desc,
+                                const GrDawnImageInfo& info) {
+    return sk_sp<GrDawnRenderTarget>(
+        GrDawnRenderTarget::Create(gpu, desc, info,
+                                  GrBackendObjectOwnership::kBorrowed));
+}
+
+bool GrDawnRenderTarget::completeStencilAttachment() {
+    return true;
+}
+
+GrDawnRenderTarget::~GrDawnRenderTarget() {
+}
+
+void GrDawnRenderTarget::onRelease() {
+    INHERITED::onRelease();
+}
+
+void GrDawnRenderTarget::onAbandon() {
+    INHERITED::onAbandon();
+}
+
+GrBackendRenderTarget GrDawnRenderTarget::getBackendRenderTarget() const {
+    return GrBackendRenderTarget(this->width(), this->height(), this->numSamples(),
+                                 this->numSamples(), fInfo);
+}
+
+GrBackendFormat GrDawnRenderTarget::backendFormat() const {
+    return GrBackendFormat::MakeDawn(fInfo.fFormat);
+}
diff --git a/src/gpu/dawn/GrDawnRenderTarget.h b/src/gpu/dawn/GrDawnRenderTarget.h
new file mode 100644
index 0000000..271eff0
--- /dev/null
+++ b/src/gpu/dawn/GrDawnRenderTarget.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrDawnRenderTarget_DEFINED
+#define GrDawnRenderTarget_DEFINED
+
+#include "include/gpu/dawn/GrDawnTypes.h"
+#include "include/gpu/GrRenderTarget.h"
+
+class GrDawnGpu;
+
+class GrDawnRenderTarget: public GrRenderTarget {
+public:
+    static sk_sp<GrDawnRenderTarget> MakeWrapped(GrDawnGpu*, const GrSurfaceDesc&,
+                                                 const GrDawnImageInfo&);
+
+    ~GrDawnRenderTarget() override;
+
+    // override of GrRenderTarget
+    ResolveType getResolveType() const override {
+        if (this->numSamples() > 1) {
+            return kCanResolve_ResolveType;
+        }
+        return kAutoResolves_ResolveType;
+    }
+
+    bool canAttemptStencilAttachment() const override {
+        return true;
+    }
+
+    GrBackendRenderTarget getBackendRenderTarget() const override;
+    GrBackendFormat backendFormat() const override;
+
+protected:
+    GrDawnRenderTarget(GrDawnGpu* gpu,
+                       const GrSurfaceDesc& desc,
+                       const GrDawnImageInfo& info,
+                       GrBackendObjectOwnership);
+
+    GrDawnGpu* getDawnGpu() const;
+
+    void onAbandon() override;
+    void onRelease() override;
+    void onSetRelease(sk_sp<GrRefCntedCallback> releaseHelper) override {}
+
+    // This accounts for the texture's memory and any MSAA renderbuffer's memory.
+    size_t onGpuMemorySize() const override {
+        // The plus 1 is to account for the resolve texture or if not using msaa the RT itself
+        int numSamples = this->numSamples() + 1;
+        return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
+                                      numSamples, GrMipMapped::kNo);
+    }
+
+    static GrDawnRenderTarget* Create(GrDawnGpu*, const GrSurfaceDesc&,
+                                      const GrDawnImageInfo&, GrBackendObjectOwnership);
+
+    bool completeStencilAttachment() override;
+    GrDawnImageInfo fInfo;
+    typedef GrRenderTarget INHERITED;
+};
+
+#endif
diff --git a/src/gpu/dawn/GrDawnUtil.cpp b/src/gpu/dawn/GrDawnUtil.cpp
new file mode 100644
index 0000000..fbb7b43
--- /dev/null
+++ b/src/gpu/dawn/GrDawnUtil.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDawnUtil.h"
+
+GrPixelConfig GrDawnFormatToPixelConfig(dawn::TextureFormat format) {
+    switch (format) {
+        case dawn::TextureFormat::R8G8B8A8Unorm:
+            return kRGBA_8888_GrPixelConfig;
+        case dawn::TextureFormat::B8G8R8A8Unorm:
+            return kBGRA_8888_GrPixelConfig;
+        case dawn::TextureFormat::R8Unorm:
+            return kAlpha_8_GrPixelConfig;
+        case dawn::TextureFormat::D32FloatS8Uint:
+        default:
+            SkASSERT(false);
+            return kRGBA_8888_GrPixelConfig;
+    }
+}
+
+bool GrPixelConfigToDawnFormat(GrPixelConfig config, dawn::TextureFormat* format) {
+    switch (config) {
+        case kRGBA_8888_GrPixelConfig:
+        case kRGBA_4444_GrPixelConfig:
+        case kRGB_565_GrPixelConfig:
+        case kGray_8_GrPixelConfig:
+            *format = dawn::TextureFormat::R8G8B8A8Unorm;
+            return true;
+        case kBGRA_8888_GrPixelConfig:
+            *format = dawn::TextureFormat::B8G8R8A8Unorm;
+            return true;
+        case kAlpha_8_GrPixelConfig:
+            *format = dawn::TextureFormat::R8Unorm;
+            return true;
+        default:
+            return false;
+    }
+}
diff --git a/src/gpu/dawn/GrDawnUtil.h b/src/gpu/dawn/GrDawnUtil.h
new file mode 100644
index 0000000..6cf973d
--- /dev/null
+++ b/src/gpu/dawn/GrDawnUtil.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDawnUtil_DEFINED
+#define GrDawnUtil_DEFINED
+
+#include "include/private/GrTypesPriv.h"
+#include "dawn/dawncpp.h"
+
+GrPixelConfig GrDawnFormatToPixelConfig(dawn::TextureFormat format);
+bool GrPixelConfigToDawnFormat(GrPixelConfig config, dawn::TextureFormat* format);
+
+#endif // GrDawnUtil_DEFINED