Start adding D3D backend

Bug: skia:
Change-Id: Id24ed653adb80fe9b2ad597a34e459eb91ca53ec
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/271057
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index ab6e22a..0acc43e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -597,6 +597,16 @@
     }
   }
 
+  if (skia_use_direct3d) {
+    public_defines += [ "SK_DIRECT3D" ]
+    sources += skia_direct3d_sources
+    libs += [
+      "d3d12.lib",
+      "dxgi.lib",
+      "d3dcompiler.lib",
+    ]
+  }
+
   cflags_objcc = []
   if (skia_use_metal) {
     public_defines += [ "SK_METAL" ]
@@ -1372,6 +1382,9 @@
     if (skia_use_metal) {
       sources += [ "tools/gpu/mtl/MtlTestContext.mm" ]
     }
+    if (skia_use_direct3d) {
+      sources += [ "tools/gpu/d3d/D3DTestContext.cpp" ]
+    }
     if (skia_use_dawn) {
       public_deps += [ "//third_party/dawn:dawn_headers" ]
       sources += [ "tools/gpu/dawn/DawnTestContext.cpp" ]
diff --git a/gn/gpu.gni b/gn/gpu.gni
index ecc0228..0d2e676 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -726,6 +726,9 @@
   "$_src/gpu/vk/GrVkVertexBuffer.h",
 ]
 
+skia_direct3d_sources = [
+]
+
 skia_dawn_sources = [
   "$_include/gpu/dawn/GrDawnTypes.h",
   "$_src/gpu/dawn/GrDawnBuffer.cpp",
diff --git a/gn/skia.gni b/gn/skia.gni
index 297317e..0fa96e3 100644
--- a/gn/skia.gni
+++ b/gn/skia.gni
@@ -38,6 +38,7 @@
   skia_update_fuchsia_sdk = false
   skia_use_angle = false
   skia_use_dawn = false
+  skia_use_direct3d = false
   skia_use_egl = false
   skia_use_expat = true
   skia_use_experimental_xform = false
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 12d8c5a..62e5c71 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -24,6 +24,7 @@
 class GrClientMappedBufferManager;
 class GrContextPriv;
 class GrContextThreadSafeProxy;
+struct GrD3DBackendContext;
 class GrFragmentProcessor;
 struct GrGLInterface;
 class GrGpu;
@@ -56,7 +57,7 @@
     static sk_sp<GrContext> MakeGL();
 
     /**
-     * The Vulkan context (VkQueue, VkDevice, VkInstance) must be kept alive unitl the returned
+     * The Vulkan context (VkQueue, VkDevice, VkInstance) must be kept alive until the returned
      * GrContext is first destroyed or abandoned.
      */
     static sk_sp<GrContext> MakeVulkan(const GrVkBackendContext&, const GrContextOptions&);
@@ -73,6 +74,16 @@
     static sk_sp<GrContext> MakeMetal(void* device, void* queue);
 #endif
 
+#ifdef SK_DIRECT3D
+    /**
+     * Makes a GrContext which uses Direct3D as the backend. The Direct3D context
+     * must be kept alive until the returned GrContext is first destroyed or abandoned.
+     */
+    static sk_sp<GrContext> MakeDirect3D(const GrD3DBackendContext&,
+                                         const GrContextOptions& options);
+    static sk_sp<GrContext> MakeDirect3D(const GrD3DBackendContext&);
+#endif
+
 #ifdef SK_DAWN
     static sk_sp<GrContext> MakeDawn(const wgpu::Device& device, const GrContextOptions& options);
     static sk_sp<GrContext> MakeDawn(const wgpu::Device& device);
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index c2ccbdb..e7d4f7e 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -133,10 +133,11 @@
  * Possible 3D APIs that may be used by Ganesh.
  */
 enum class GrBackendApi : unsigned {
-    kMetal,
-    kDawn,
     kOpenGL,
     kVulkan,
+    kMetal,
+    kDirect3D,
+    kDawn,
     /**
      * Mock is a backend that does not draw anything. It is used for unit tests
      * and to measure CPU overhead.
diff --git a/include/gpu/d3d/GrD3DBackendContext.h b/include/gpu/d3d/GrD3DBackendContext.h
new file mode 100644
index 0000000..a433257
--- /dev/null
+++ b/include/gpu/d3d/GrD3DBackendContext.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrD3DBackendContext_DEFINED
+#define GrD3DBackendContext_DEFINED
+
+#include "include/core/SkRefCnt.h"
+
+// The BackendContext contains all of the base D3D objects needed by the GrD3DGpu. The assumption
+// is that the client will set these up and pass them to the GrD3DGpu constructor.
+struct SK_API GrD3DBackendContext {
+};
+
+#endif
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 3b11f4f..5a8ab5c 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -1172,11 +1172,12 @@
 #if GR_TEST_UTILS || defined(SK_ENABLE_DUMP_GPU)
 static constexpr const char* GrBackendApiToStr(GrBackendApi api) {
     switch (api) {
-        case GrBackendApi::kMetal:  return "Metal";
-        case GrBackendApi::kDawn:   return "Dawn";
-        case GrBackendApi::kOpenGL: return "OpenGL";
-        case GrBackendApi::kVulkan: return "Vulkan";
-        case GrBackendApi::kMock:   return "Mock";
+        case GrBackendApi::kOpenGL:   return "OpenGL";
+        case GrBackendApi::kVulkan:   return "Vulkan";
+        case GrBackendApi::kMetal:    return "Metal";
+        case GrBackendApi::kDirect3D: return "Direct3D";
+        case GrBackendApi::kDawn:     return "Dawn";
+        case GrBackendApi::kMock:     return "Mock";
     }
     SkUNREACHABLE;
 }
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 61f653c..5e267b4 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -49,6 +49,11 @@
             fMtlFormat = that.fMtlFormat;
             break;
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D:
+            //TODO fD3DFormat = that.fD3DFormat;
+            break;
+#endif
 #ifdef SK_DAWN
         case GrBackendApi::kDawn:
             fDawnFormat = that.fDawnFormat;
@@ -293,6 +298,11 @@
             str.append(GrMtlFormatToStr(fMtlFormat));
 #endif
             break;
+        case GrBackendApi::kDirect3D:
+#ifdef SK_DIRECT3D
+            //TODO str.append(GrD3DFormatToStr(fD3DFormat));
+#endif
+            break;
         case GrBackendApi::kDawn:
 #ifdef SK_DAWN
             str.append(GrDawnFormatToStr(fDawnFormat));
@@ -450,6 +460,11 @@
             fMtlInfo = that.fMtlInfo;
             break;
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D:
+            // TODO fD3DInfo = that.fD3DInfo;
+            break;
+#endif
 #ifdef SK_DAWN
         case GrBackendApi::kDawn:
             fDawnInfo = that.fDawnInfo;
@@ -573,6 +588,10 @@
         case GrBackendApi::kMetal:
             return this->fMtlInfo.fTexture == that.fMtlInfo.fTexture;
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D:
+            return false; //TODO
+#endif
         case GrBackendApi::kMock:
             return fMockInfo.id() == that.fMockInfo.id();
         default:
@@ -599,11 +618,6 @@
             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;
@@ -611,6 +625,16 @@
             return GrBackendFormat::MakeMtl(GrGetMTLPixelFormatFromMtlTextureInfo(mtlInfo));
         }
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D: {
+            return GrBackendFormat(); // TODO
+        }
+#endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn: {
+            return GrBackendFormat::MakeDawn(fDawnInfo.fFormat);
+        }
+#endif
         case GrBackendApi::kMock:
             return fMockInfo.getBackendFormat();
         default:
@@ -646,6 +670,10 @@
         case GrBackendApi::kMetal:
             return t0.fMtlInfo == t1.fMtlInfo;
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D:
+            return false;
+#endif
 #ifdef SK_DAWN
         case GrBackendApi::kDawn:
             return t0.fDawnInfo == t1.fDawnInfo;
@@ -795,16 +823,21 @@
             fVkInfo.assign(that.fVkInfo, this->isValid());
             break;
 #endif
-#ifdef SK_DAWN
-        case GrBackendApi::kDawn:
-            fDawnInfo = that.fDawnInfo;
-            break;
-#endif
 #ifdef SK_METAL
         case GrBackendApi::kMetal:
             fMtlInfo = that.fMtlInfo;
             break;
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D:
+            // TODO fD3DInfo = that.fD3DInfo;
+            break;
+#endif
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn:
+            fDawnInfo = that.fDawnInfo;
+            break;
+#endif
         case GrBackendApi::kMock:
             fMockInfo = that.fMockInfo;
             break;
@@ -898,6 +931,12 @@
             return GrBackendFormat::MakeMtl(GrGetMTLPixelFormatFromMtlTextureInfo(mtlInfo));
         }
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D: {
+            // TODO
+            return GrBackendFormat();
+        }
+#endif
 #ifdef SK_DAWN
         case GrBackendApi::kDawn: {
             GrDawnRenderTargetInfo dawnInfo;
@@ -957,6 +996,10 @@
         case GrBackendApi::kMetal:
             return r0.fMtlInfo == r1.fMtlInfo;
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D:
+            return false; // TODO r0.fD3DInfo == r1.fD3DInfo;
+#endif
 #ifdef SK_DAWN
         case GrBackendApi::kDawn:
             return r0.fDawnInfo == r1.fDawnInfo;
diff --git a/src/gpu/GrLegacyDirectContext.cpp b/src/gpu/GrLegacyDirectContext.cpp
index 04a40bb..31e2678 100644
--- a/src/gpu/GrLegacyDirectContext.cpp
+++ b/src/gpu/GrLegacyDirectContext.cpp
@@ -228,6 +228,29 @@
 }
 #endif
 
+#ifdef SK_DIRECT3D
+sk_sp<GrContext> GrContext::MakeDirect3D(const GrD3DBackendContext& backendContext) {
+    GrContextOptions defaultOptions;
+    return MakeDirect3D(backendContext, defaultOptions);
+}
+
+sk_sp<GrContext> GrContext::MakeDirect3D(const GrD3DBackendContext& backendContext,
+                                         const GrContextOptions& options) {
+    return nullptr;
+    //sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kDirect3D, options));
+
+    //context->fGpu = GrD3DGpu::Make(backendContext, options, context.get());
+    //if (!context->fGpu) {
+    //    return nullptr;
+    //}
+
+    //if (!context->init(context->fGpu->refCaps())) {
+    //    return nullptr;
+    //}
+    //return context;
+}
+#endif
+
 #ifdef SK_DAWN
 sk_sp<GrContext> GrContext::MakeDawn(const wgpu::Device& device) {
     GrContextOptions defaultOptions;
diff --git a/tests/BackendAllocationTest.cpp b/tests/BackendAllocationTest.cpp
index a177089..7b4be8b 100644
--- a/tests/BackendAllocationTest.cpp
+++ b/tests/BackendAllocationTest.cpp
@@ -102,14 +102,6 @@
 
 static bool isBGRA(const GrBackendFormat& format) {
     switch (format.backend()) {
-        case GrBackendApi::kMetal:
-#ifdef SK_METAL
-            return GrMtlFormatIsBGRA(format.asMtlFormat());
-#else
-            return false;
-#endif
-        case GrBackendApi::kDawn:
-            return false;
         case GrBackendApi::kOpenGL:
 #ifdef SK_GL
             return format.asGLFormat() == GrGLFormat::kBGRA8;
@@ -125,6 +117,20 @@
             return false;
 #endif
         }
+        case GrBackendApi::kMetal:
+#ifdef SK_METAL
+            return GrMtlFormatIsBGRA(format.asMtlFormat());
+#else
+            return false;
+#endif
+        case GrBackendApi::kDirect3D:
+#ifdef SK_DIRECT3D
+            return false; // TODO
+#else
+            return false;
+#endif
+        case GrBackendApi::kDawn:
+            return false;
         case GrBackendApi::kMock: {
             SkImage::CompressionType compression = format.asMockCompressionType();
             if (compression != SkImage::CompressionType::kNone) {
@@ -139,10 +145,6 @@
 
 static bool isRGB(const GrBackendFormat& format) {
     switch (format.backend()) {
-        case GrBackendApi::kMetal:
-            return false;  // Metal doesn't even pretend to support this
-        case GrBackendApi::kDawn:
-            return false;
         case GrBackendApi::kOpenGL:
 #ifdef SK_GL
             return format.asGLFormat() == GrGLFormat::kRGB8;
@@ -158,6 +160,12 @@
             return false;
 #endif
         }
+        case GrBackendApi::kMetal:
+            return false;  // Metal doesn't even pretend to support this
+        case GrBackendApi::kDirect3D:
+            return false;  // Not supported in Direct3D 12
+        case GrBackendApi::kDawn:
+            return false;
         case GrBackendApi::kMock:
             return false;  // No GrColorType::kRGB_888
     }
diff --git a/tools/gpu/GrContextFactory.cpp b/tools/gpu/GrContextFactory.cpp
index 4432c87..d89314e 100644
--- a/tools/gpu/GrContextFactory.cpp
+++ b/tools/gpu/GrContextFactory.cpp
@@ -13,7 +13,7 @@
 #endif
 
 #if SK_ANGLE
-    #include "tools/gpu/gl/angle/GLTestContext_angle.h"
+#include "tools/gpu/gl/angle/GLTestContext_angle.h"
 #endif
 #include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
 #ifdef SK_VULKAN
@@ -22,6 +22,9 @@
 #ifdef SK_METAL
 #include "tools/gpu/mtl/MtlTestContext.h"
 #endif
+#ifdef SK_DIRECT3D
+#include "tools/gpu/d3d/D3DTestContext.h"
+#endif
 #ifdef SK_DAWN
 #include "tools/gpu/dawn/DawnTestContext.h"
 #endif
@@ -247,6 +250,18 @@
             break;
         }
 #endif
+#ifdef SK_DIRECT3D
+        case GrBackendApi::kDirect3D: {
+            D3DTestContext* d3dSharedContext = masterContext
+                    ? static_cast<D3DTestContext*>(masterContext->fTestContext) : nullptr;
+            SkASSERT(kDirect3D_ContextType == type);
+            testCtx.reset(CreatePlatformD3DTestContext(d3dSharedContext));
+            if (!testCtx) {
+                return ContextInfo();
+            }
+            break;
+        }
+#endif
 #ifdef SK_DAWN
         case GrBackendApi::kDawn: {
             DawnTestContext* dawnSharedContext = masterContext
diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h
index d1b7fd5..d46e1c1 100644
--- a/tools/gpu/GrContextFactory.h
+++ b/tools/gpu/GrContextFactory.h
@@ -41,6 +41,7 @@
         kCommandBuffer_ContextType,  //! Chromium command buffer OpenGL ES context.
         kVulkan_ContextType,         //! Vulkan
         kMetal_ContextType,          //! Metal
+        kDirect3D_ContextType,       //! Direct3D 12
         kDawn_ContextType,           //! Dawn
         kMock_ContextType,           //! Mock context that does not draw.
         kLastContextType = kMock_ContextType
@@ -72,6 +73,8 @@
                 return GrBackendApi::kVulkan;
             case kMetal_ContextType:
                 return GrBackendApi::kMetal;
+            case kDirect3D_ContextType:
+                return GrBackendApi::kDirect3D;
             case kDawn_ContextType:
                 return GrBackendApi::kDawn;
             case kMock_ContextType:
@@ -103,6 +106,8 @@
                 return "Vulkan";
             case kMetal_ContextType:
                 return "Metal";
+            case kDirect3D_ContextType:
+                return "Direct3D";
             case kDawn_ContextType:
                 return "Dawn";
             case kMock_ContextType:
diff --git a/tools/gpu/d3d/D3DTestContext.cpp b/tools/gpu/d3d/D3DTestContext.cpp
new file mode 100644
index 0000000..c72a6cb
--- /dev/null
+++ b/tools/gpu/d3d/D3DTestContext.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/gpu/d3d/D3DTestContext.h"
+
+#ifdef SK_DIRECT3D
+
+#include "include/gpu/GrContext.h"
+
+namespace {
+
+// TODO: Implement D3DFenceSync
+
+class D3DTestContextImpl : public sk_gpu_test::D3DTestContext {
+public:
+    static D3DTestContext* Create(D3DTestContext* sharedContext) {
+        GrD3DBackendContext backendContext;
+        bool ownsContext;
+        if (sharedContext) {
+            // take from the given context
+            ownsContext = false;
+        } else {
+            // create our own
+            ownsContext = true;
+        }
+        return new D3DTestContextImpl(backendContext, ownsContext);
+    }
+
+    ~D3DTestContextImpl() override { this->teardown(); }
+
+    void testAbandon() override {}
+
+    // There is really nothing to here since we don't own any unqueued command buffers here.
+    void submit() override {}
+
+    void finish() override {}
+
+    sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
+        return GrContext::MakeDirect3D(fD3D, options);
+    }
+
+protected:
+    void teardown() override {
+        INHERITED::teardown();
+        if (fOwnsContext) {
+            // delete all the D3D objects in the backend context
+        }
+    }
+
+private:
+    D3DTestContextImpl(const GrD3DBackendContext& backendContext, bool ownsContext)
+            : D3DTestContext(backendContext, ownsContext) {
+// TODO       fFenceSync.reset(new D3DFenceSync(backendContext));
+    }
+
+    void onPlatformMakeNotCurrent() const override {}
+    void onPlatformMakeCurrent() const override {}
+    std::function<void()> onPlatformGetAutoContextRestore() const override  { return nullptr; }
+    void onPlatformSwapBuffers() const override {}
+
+    typedef sk_gpu_test::D3DTestContext INHERITED;
+};
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+D3DTestContext* CreatePlatformD3DTestContext(D3DTestContext* sharedContext) {
+    return D3DTestContextImpl::Create(sharedContext);
+}
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/tools/gpu/d3d/D3DTestContext.h b/tools/gpu/d3d/D3DTestContext.h
new file mode 100644
index 0000000..c8b9c53
--- /dev/null
+++ b/tools/gpu/d3d/D3DTestContext.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef D3DTestContext_DEFINED
+#define D3DTestContext_DEFINED
+
+#include "tools/gpu/TestContext.h"
+
+#ifdef SK_DIRECT3D
+
+#include "include/gpu/d3d/GrD3DBackendContext.h"
+
+namespace sk_gpu_test {
+class D3DTestContext : public TestContext {
+public:
+    virtual GrBackendApi backend() override { return GrBackendApi::kDirect3D; }
+
+protected:
+    D3DTestContext(const GrD3DBackendContext& d3d, bool ownsContext)
+            : fD3D(d3d)
+            , fOwnsContext(ownsContext) {}
+
+    GrD3DBackendContext fD3D;
+    bool fOwnsContext;
+
+private:
+    typedef TestContext INHERITED;
+};
+
+/**
+ * Creates D3D context object bound to the native D3D library.
+ */
+D3DTestContext* CreatePlatformD3DTestContext(D3DTestContext*);
+
+}  // namespace sk_gpu_test
+
+#endif
+
+#endif