Direct3D: add aliasing texture support

In D3D we can alias a resource's allocation and re-use it for
another resource. For example, this is used in the mipmap generator
when we have an sRGB texture. The sRGB formats can't be used in a
UAV, but we can use an aliased texture with the corresponding linear
format, and do the sRGB conversion in the compute shader.

Change-Id: I6995cdecf5be36aafbed5c48e639c09f41ec4f8b
Bug: skia:10446
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/397996
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/include/gpu/d3d/GrD3DTypes.h b/include/gpu/d3d/GrD3DTypes.h
index 53f499c..33c079d 100644
--- a/include/gpu/d3d/GrD3DTypes.h
+++ b/include/gpu/d3d/GrD3DTypes.h
@@ -166,6 +166,11 @@
                                                  D3D12_RESOURCE_STATES initialResourceState,
                                                  sk_sp<GrD3DAlloc>* allocation,
                                                  const D3D12_CLEAR_VALUE*) = 0;
+    virtual gr_cp<ID3D12Resource> createAliasingResource(sk_sp<GrD3DAlloc>& allocation,
+                                                         uint64_t localOffset,
+                                                         const D3D12_RESOURCE_DESC*,
+                                                         D3D12_RESOURCE_STATES initialResourceState,
+                                                         const D3D12_CLEAR_VALUE*) = 0;
 };
 
 // Note: there is no notion of Borrowed or Adopted resources in the D3D backend,
diff --git a/src/gpu/d3d/GrD3DAMDMemoryAllocator.cpp b/src/gpu/d3d/GrD3DAMDMemoryAllocator.cpp
index 32ece37..74bd279 100644
--- a/src/gpu/d3d/GrD3DAMDMemoryAllocator.cpp
+++ b/src/gpu/d3d/GrD3DAMDMemoryAllocator.cpp
@@ -9,7 +9,7 @@
 #include "src/gpu/d3d/GrD3DUtil.h"
 
 sk_sp<GrD3DMemoryAllocator> GrD3DAMDMemoryAllocator::Make(IDXGIAdapter* adapter,
-                                                             ID3D12Device* device) {
+                                                          ID3D12Device* device) {
     D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
     allocatorDesc.pAdapter = adapter;
     allocatorDesc.pDevice = device;
@@ -46,3 +46,19 @@
     allocation->reset(new Alloc(d3d12maAllocation));
     return resource;
 }
+
+gr_cp<ID3D12Resource> GrD3DAMDMemoryAllocator::createAliasingResource(
+        sk_sp<GrD3DAlloc>& allocation, uint64_t localOffset,
+        const D3D12_RESOURCE_DESC* resourceDesc, D3D12_RESOURCE_STATES initialResourceState,
+        const D3D12_CLEAR_VALUE* clearValue) {
+    Alloc* alloc = (Alloc*)allocation.get();
+    gr_cp<ID3D12Resource> resource;
+    HRESULT hr = fAllocator->CreateAliasingResource(alloc->fAllocation, localOffset, resourceDesc,
+                                                    initialResourceState, clearValue,
+                                                    IID_PPV_ARGS(&resource));
+    if (!SUCCEEDED(hr)) {
+        return nullptr;
+    }
+
+    return resource;
+}
diff --git a/src/gpu/d3d/GrD3DAMDMemoryAllocator.h b/src/gpu/d3d/GrD3DAMDMemoryAllocator.h
index a6fff7d..fba7674 100644
--- a/src/gpu/d3d/GrD3DAMDMemoryAllocator.h
+++ b/src/gpu/d3d/GrD3DAMDMemoryAllocator.h
@@ -31,6 +31,12 @@
                                          sk_sp<GrD3DAlloc>* allocation,
                                          const D3D12_CLEAR_VALUE*) override;
 
+    gr_cp<ID3D12Resource> createAliasingResource(sk_sp<GrD3DAlloc>& allocation,
+                                                 uint64_t localOffset,
+                                                 const D3D12_RESOURCE_DESC*,
+                                                 D3D12_RESOURCE_STATES initialResourceState,
+                                                 const D3D12_CLEAR_VALUE*) override;
+
     class Alloc : public GrD3DAlloc {
     public:
         Alloc(D3D12MA::Allocation* allocation) : fAllocation(allocation) {}
@@ -38,6 +44,7 @@
             fAllocation->Release();
         }
     private:
+        friend class GrD3DAMDMemoryAllocator;
         D3D12MA::Allocation* fAllocation;
     };
 
diff --git a/src/gpu/d3d/GrD3DTexture.cpp b/src/gpu/d3d/GrD3DTexture.cpp
index 83e3694..9960b7b 100644
--- a/src/gpu/d3d/GrD3DTexture.cpp
+++ b/src/gpu/d3d/GrD3DTexture.cpp
@@ -108,6 +108,31 @@
                                                 ioType));
 }
 
+sk_sp<GrD3DTexture> GrD3DTexture::MakeAliasingTexture(GrD3DGpu* gpu,
+                                                      sk_sp<GrD3DTexture> originalTexture,
+                                                      DXGI_FORMAT format) {
+    GrD3DTextureResourceInfo info = originalTexture->fInfo;
+    D3D12_RESOURCE_DESC desc = originalTexture->d3dResource()->GetDesc();
+    desc.Format = format;
+
+    info.fResource = gpu->memoryAllocator()->createAliasingResource(info.fAlloc, 0, &desc,
+                                                                    info.fResourceState, nullptr);
+    if (!info.fResource) {
+        return false;
+    }
+
+    sk_sp<GrD3DResourceState> state(
+        new GrD3DResourceState(static_cast<D3D12_RESOURCE_STATES>(info.fResourceState)));
+
+    GrD3DDescriptorHeap::CPUHandle shaderResourceView =
+        gpu->resourceProvider().createShaderResourceView(info.fResource.get());
+
+    GrD3DTexture* tex = new GrD3DTexture(gpu, SkBudgeted::kNo, originalTexture->dimensions(),
+                                         info, std::move(state), shaderResourceView,
+                                         originalTexture->mipmapStatus());
+    return sk_sp<GrD3DTexture>(tex);
+}
+
 void GrD3DTexture::onRelease() {
     GrD3DGpu* gpu = this->getD3DGpu();
     gpu->resourceProvider().recycleShaderView(fShaderResourceView);
diff --git a/src/gpu/d3d/GrD3DTexture.h b/src/gpu/d3d/GrD3DTexture.h
index e57dd29..ddfecd4 100644
--- a/src/gpu/d3d/GrD3DTexture.h
+++ b/src/gpu/d3d/GrD3DTexture.h
@@ -30,6 +30,10 @@
                                                   const GrD3DTextureResourceInfo&,
                                                   sk_sp<GrD3DResourceState>);
 
+    static sk_sp<GrD3DTexture> MakeAliasingTexture(GrD3DGpu*,
+                                                   sk_sp<GrD3DTexture>,
+                                                   DXGI_FORMAT);
+
     ~GrD3DTexture() override {}
 
     GrBackendTexture getBackendTexture() const override;