Initialize External Texture's Internal Params Buffer

Initializes a uniform buffer on ExternalTexture objects that holds data
used by in shaders. Includes modifications to some Mock tests, which
should be using mock external texture objects instead of real ones.

Bug: dawn:1082
Change-Id: I34c02eadaf38aebf22630ac99098e0637ca1279c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/78240
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index fe9722d..582ec87 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -1152,7 +1152,7 @@
     ExternalTextureBase* DeviceBase::APICreateExternalTexture(
         const ExternalTextureDescriptor* descriptor) {
         Ref<ExternalTextureBase> result = nullptr;
-        if (ConsumedError(CreateExternalTexture(descriptor), &result,
+        if (ConsumedError(CreateExternalTextureImpl(descriptor), &result,
                           "calling %s.CreateExternalTexture(%s).", this, descriptor)) {
             return ExternalTextureBase::MakeError(this);
         }
@@ -1418,7 +1418,7 @@
         return GetOrCreatePipelineLayout(descriptor);
     }
 
-    ResultOrError<Ref<ExternalTextureBase>> DeviceBase::CreateExternalTexture(
+    ResultOrError<Ref<ExternalTextureBase>> DeviceBase::CreateExternalTextureImpl(
         const ExternalTextureDescriptor* descriptor) {
         if (IsValidationEnabled()) {
             DAWN_TRY_CONTEXT(ValidateExternalTextureDescriptor(this, descriptor), "validating %s",
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 75e293f..6c6a365 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -206,8 +206,7 @@
             const ComputePipelineDescriptor* descriptor,
             WGPUCreateComputePipelineAsyncCallback callback,
             void* userdata);
-        ResultOrError<Ref<ExternalTextureBase>> CreateExternalTexture(
-            const ExternalTextureDescriptor* descriptor);
+
         ResultOrError<Ref<PipelineLayoutBase>> CreatePipelineLayout(
             const PipelineLayoutDescriptor* descriptor);
         ResultOrError<Ref<QuerySetBase>> CreateQuerySet(const QuerySetDescriptor* descriptor);
@@ -394,6 +393,8 @@
             PipelineCompatibilityToken pipelineCompatibilityToken) = 0;
         virtual ResultOrError<Ref<BufferBase>> CreateBufferImpl(
             const BufferDescriptor* descriptor) = 0;
+        virtual ResultOrError<Ref<ExternalTextureBase>> CreateExternalTextureImpl(
+            const ExternalTextureDescriptor* descriptor);
         virtual ResultOrError<Ref<PipelineLayoutBase>> CreatePipelineLayoutImpl(
             const PipelineLayoutDescriptor* descriptor) = 0;
         virtual ResultOrError<Ref<QuerySetBase>> CreateQuerySetImpl(
diff --git a/src/dawn_native/ExternalTexture.cpp b/src/dawn_native/ExternalTexture.cpp
index 61a9c4d..ed157bc 100644
--- a/src/dawn_native/ExternalTexture.cpp
+++ b/src/dawn_native/ExternalTexture.cpp
@@ -14,8 +14,10 @@
 
 #include "dawn_native/ExternalTexture.h"
 
+#include "dawn_native/Buffer.h"
 #include "dawn_native/Device.h"
 #include "dawn_native/ObjectType_autogen.h"
+#include "dawn_native/Queue.h"
 #include "dawn_native/Texture.h"
 
 #include "dawn_native/dawn_platform.h"
@@ -123,6 +125,43 @@
         mTextureViews[0] = descriptor->plane0;
         mTextureViews[1] = descriptor->plane1;
 
+        // We must create a buffer to store parameters needed by a shader that operates on this
+        // external texture.
+        BufferDescriptor bufferDesc;
+        bufferDesc.size = sizeof(ExternalTextureParams);
+        bufferDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
+        bufferDesc.label = "Dawn_External_Texture_Params_Buffer";
+
+        DAWN_TRY_ASSIGN(mParamsBuffer, device->CreateBuffer(&bufferDesc));
+
+        // Dawn & Tint's YUV to RGB conversion implementation was inspired by the conversions found
+        // in libYUV. If this implementation needs expanded to support more colorspaces, this file
+        // is an excellent reference: chromium/src/third_party/libyuv/source/row_common.cc.
+        //
+        // The conversion from YUV to RGB looks like this:
+        // r = Y * 1.164          + V * vr
+        // g = Y * 1.164 - U * ug - V * vg
+        // b = Y * 1.164 + U * ub
+        //
+        // By changing the values of vr, vg, ub, and ug we can change the destination color space.
+        ExternalTextureParams params;
+        params.numPlanes = descriptor->plane1 == nullptr ? 1 : 2;
+
+        switch (descriptor->colorSpace) {
+            case wgpu::PredefinedColorSpace::Srgb:
+                // Numbers derived from ITU-R recommendation for limited range BT.709
+                params.vr = 1.793;
+                params.vg = 0.392;
+                params.ub = 0.813;
+                params.ug = 2.017;
+                break;
+            case wgpu::PredefinedColorSpace::Undefined:
+                break;
+        }
+
+        DAWN_TRY(device->GetQueue()->WriteBuffer(mParamsBuffer.Get(), 0, &params,
+                                                 sizeof(ExternalTextureParams)));
+
         return {};
     }
 
diff --git a/src/dawn_native/ExternalTexture.h b/src/dawn_native/ExternalTexture.h
index c66ef1e..0b8b28c 100644
--- a/src/dawn_native/ExternalTexture.h
+++ b/src/dawn_native/ExternalTexture.h
@@ -26,6 +26,14 @@
 
     class TextureViewBase;
 
+    struct ExternalTextureParams {
+        uint32_t numPlanes;
+        float vr;
+        float vg;
+        float ub;
+        float ug;
+    };
+
     MaybeError ValidateExternalTextureDescriptor(const DeviceBase* device,
                                                  const ExternalTextureDescriptor* descriptor);
 
@@ -54,7 +62,10 @@
         enum class ExternalTextureState { Alive, Destroyed };
         ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
         ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
+
+        Ref<BufferBase> mParamsBuffer;
         std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> mTextureViews;
+
         ExternalTextureState mState;
     };
 }  // namespace dawn::native
diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp
index a79be15..4510453 100644
--- a/src/dawn_native/d3d12/D3D12Backend.cpp
+++ b/src/dawn_native/d3d12/D3D12Backend.cpp
@@ -106,7 +106,7 @@
             return nullptr;
         }
 
-        Ref<TextureBase> texture = backendDevice->CreateExternalTexture(
+        Ref<TextureBase> texture = backendDevice->CreateD3D12ExternalTexture(
             &textureDescriptor, mD3D12Resource, std::move(d3d11on12Resource),
             descriptor->isSwapChainTexture, descriptor->isInitialized);
 
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index fd68df3..7a72f6e 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -530,7 +530,7 @@
                                                          initialUsage);
     }
 
-    Ref<TextureBase> Device::CreateExternalTexture(
+    Ref<TextureBase> Device::CreateD3D12ExternalTexture(
         const TextureDescriptor* descriptor,
         ComPtr<ID3D12Resource> d3d12Texture,
         Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index 09b2246..609de05 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -128,11 +128,12 @@
 
         StagingDescriptorAllocator* GetDepthStencilViewAllocator() const;
 
-        Ref<TextureBase> CreateExternalTexture(const TextureDescriptor* descriptor,
-                                               ComPtr<ID3D12Resource> d3d12Texture,
-                                               Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
-                                               bool isSwapChainTexture,
-                                               bool isInitialized);
+        Ref<TextureBase> CreateD3D12ExternalTexture(
+            const TextureDescriptor* descriptor,
+            ComPtr<ID3D12Resource> d3d12Texture,
+            Ref<D3D11on12ResourceCacheEntry> d3d11on12Resource,
+            bool isSwapChainTexture,
+            bool isInitialized);
 
         ComPtr<ID3D11On12Device> GetOrCreateD3D11on12Device();
 
diff --git a/src/tests/unittests/native/DestroyObjectTests.cpp b/src/tests/unittests/native/DestroyObjectTests.cpp
index 548dbb4..4b6b031 100644
--- a/src/tests/unittests/native/DestroyObjectTests.cpp
+++ b/src/tests/unittests/native/DestroyObjectTests.cpp
@@ -285,13 +285,18 @@
         EXPECT_FALSE(externalTextureMock.IsAlive());
     }
 
-    // We can use an actual ExternalTexture object to test the implicit case.
     TEST_F(DestroyObjectTests, ExternalTextureImplicit) {
-        ExternalTextureDescriptor desc = {};
-        Ref<ExternalTextureBase> externalTexture;
-        DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTexture(&desc));
+        ExternalTextureMock* externalTextureMock = new ExternalTextureMock(&mDevice);
+        EXPECT_CALL(*externalTextureMock, DestroyImpl).Times(1);
+        {
+            ExternalTextureDescriptor desc = {};
+            Ref<ExternalTextureBase> externalTexture;
+            EXPECT_CALL(mDevice, CreateExternalTextureImpl)
+                .WillOnce(Return(ByMove(AcquireRef(externalTextureMock))));
+            DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTextureImpl(&desc));
 
-        EXPECT_TRUE(externalTexture->IsAlive());
+            EXPECT_TRUE(externalTexture->IsAlive());
+        }
     }
 
     TEST_F(DestroyObjectTests, PipelineLayoutExplicit) {
@@ -552,6 +557,7 @@
         BufferMock* bufferMock = new BufferMock(&mDevice, BufferBase::BufferState::Unmapped);
         CommandBufferMock* commandBufferMock = new CommandBufferMock(&mDevice);
         ComputePipelineMock* computePipelineMock = new ComputePipelineMock(&mDevice);
+        ExternalTextureMock* externalTextureMock = new ExternalTextureMock(&mDevice);
         PipelineLayoutMock* pipelineLayoutMock = new PipelineLayoutMock(&mDevice);
         QuerySetMock* querySetMock = new QuerySetMock(&mDevice);
         RenderPipelineMock* renderPipelineMock = new RenderPipelineMock(&mDevice);
@@ -571,6 +577,7 @@
             EXPECT_CALL(*bindGroupMock, DestroyImpl).Times(1);
             EXPECT_CALL(*bindGroupLayoutMock, DestroyImpl).Times(1);
             EXPECT_CALL(*shaderModuleMock, DestroyImpl).Times(1);
+            EXPECT_CALL(*externalTextureMock, DestroyImpl).Times(1);
             EXPECT_CALL(*textureViewMock, DestroyImpl).Times(1);
             EXPECT_CALL(*textureMock, DestroyImpl).Times(1);
             EXPECT_CALL(*querySetMock, DestroyImpl).Times(1);
@@ -638,7 +645,9 @@
         Ref<ExternalTextureBase> externalTexture;
         {
             ExternalTextureDescriptor desc = {};
-            DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTexture(&desc));
+            EXPECT_CALL(mDevice, CreateExternalTextureImpl)
+                .WillOnce(Return(ByMove(AcquireRef(externalTextureMock))));
+            DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTextureImpl(&desc));
             EXPECT_TRUE(externalTexture->IsAlive());
         }
 
diff --git a/src/tests/unittests/native/mocks/DeviceMock.h b/src/tests/unittests/native/mocks/DeviceMock.h
index 4e673f3..6ba104f 100644
--- a/src/tests/unittests/native/mocks/DeviceMock.h
+++ b/src/tests/unittests/native/mocks/DeviceMock.h
@@ -68,6 +68,10 @@
                     CreateUninitializedComputePipelineImpl,
                     (const ComputePipelineDescriptor*),
                     (override));
+        MOCK_METHOD(ResultOrError<Ref<ExternalTextureBase>>,
+                    CreateExternalTextureImpl,
+                    (const ExternalTextureDescriptor*),
+                    (override));
         MOCK_METHOD(ResultOrError<Ref<PipelineLayoutBase>>,
                     CreatePipelineLayoutImpl,
                     (const PipelineLayoutDescriptor*),