diff options
Diffstat (limited to 'dom/webgpu/ExternalTextureD3D11.cpp')
-rw-r--r-- | dom/webgpu/ExternalTextureD3D11.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/dom/webgpu/ExternalTextureD3D11.cpp b/dom/webgpu/ExternalTextureD3D11.cpp new file mode 100644 index 0000000000..34be281b5b --- /dev/null +++ b/dom/webgpu/ExternalTextureD3D11.cpp @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ExternalTextureD3D11.h" + +#include <d3d11.h> + +#include "mozilla/gfx/DeviceManagerDx.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/layers/ImageDataSerializer.h" + +namespace mozilla::webgpu { + +// static +UniquePtr<ExternalTextureD3D11> ExternalTextureD3D11::Create( + const uint32_t aWidth, const uint32_t aHeight, + const struct ffi::WGPUTextureFormat aFormat, + const ffi::WGPUTextureUsages aUsage) { + const RefPtr<ID3D11Device> d3d11Device = + gfx::DeviceManagerDx::Get()->GetCompositorDevice(); + if (!d3d11Device) { + gfxCriticalNoteOnce << "CompositorDevice does not exist"; + return nullptr; + } + + if (aFormat.tag != ffi::WGPUTextureFormat_Bgra8Unorm) { + gfxCriticalNoteOnce << "Non supported format: " << aFormat.tag; + return nullptr; + } + + CD3D11_TEXTURE2D_DESC desc( + DXGI_FORMAT_B8G8R8A8_UNORM, aWidth, aHeight, 1, 1, + D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + + if (aUsage & WGPUTextureUsages_STORAGE_BINDING) { + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + } + + desc.MiscFlags = + D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; + + RefPtr<ID3D11Texture2D> texture; + HRESULT hr = + d3d11Device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "CreateTexture2D failed: " << gfx::hexa(hr); + return nullptr; + } + + RefPtr<IDXGIResource1> resource; + texture->QueryInterface((IDXGIResource1**)getter_AddRefs(resource)); + if (!resource) { + gfxCriticalNoteOnce << "Failed to get IDXGIResource"; + return 0; + } + + HANDLE sharedHandle; + hr = resource->CreateSharedHandle( + nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, + &sharedHandle); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "GetSharedHandle failed: " << gfx::hexa(hr); + return 0; + } + + RefPtr<gfx::FileHandleWrapper> handle = + new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); + + return MakeUnique<ExternalTextureD3D11>(aWidth, aHeight, aFormat, aUsage, + texture, std::move(handle)); +} + +ExternalTextureD3D11::ExternalTextureD3D11( + const uint32_t aWidth, const uint32_t aHeight, + const struct ffi::WGPUTextureFormat aFormat, + const ffi::WGPUTextureUsages aUsage, const RefPtr<ID3D11Texture2D> aTexture, + RefPtr<gfx::FileHandleWrapper>&& aSharedHandle) + : ExternalTexture(aWidth, aHeight, aFormat, aUsage), + mTexture(aTexture), + mSharedHandle(std::move(aSharedHandle)) { + MOZ_ASSERT(mTexture); +} + +ExternalTextureD3D11::~ExternalTextureD3D11() {} + +void* ExternalTextureD3D11::GetExternalTextureHandle() { + if (!mSharedHandle) { + return nullptr; + } + + return mSharedHandle->GetHandle(); +} + +Maybe<layers::SurfaceDescriptor> ExternalTextureD3D11::ToSurfaceDescriptor( + Maybe<gfx::FenceInfo>& aFenceInfo) { + const auto format = gfx::SurfaceFormat::B8G8R8A8; + return Some(layers::SurfaceDescriptorD3D10( + mSharedHandle, + /* gpuProcessTextureId */ Nothing(), + /* arrayIndex */ 0, format, gfx::IntSize(mWidth, mHeight), + gfx::ColorSpace2::SRGB, gfx::ColorRange::FULL, + /* hasKeyedMutex */ false, aFenceInfo, + /* gpuProcessQueryId */ Nothing())); +} + +void ExternalTextureD3D11::GetSnapshot(const ipc::Shmem& aDestShmem, + const gfx::IntSize& aSize) { + RefPtr<ID3D11Device> device; + mTexture->GetDevice(getter_AddRefs(device)); + if (!device) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to get ID3D11Device"; + return; + } + + RefPtr<ID3D11DeviceContext> deviceContext; + device->GetImmediateContext(getter_AddRefs(deviceContext)); + if (!deviceContext) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNoteOnce << "Failed to get ID3D11DeviceContext"; + return; + } + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + mTexture->GetDesc(&textureDesc); + + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + textureDesc.Usage = D3D11_USAGE_STAGING; + textureDesc.BindFlags = 0; + textureDesc.MiscFlags = 0; + textureDesc.MipLevels = 1; + + RefPtr<ID3D11Texture2D> cpuTexture; + HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr, + getter_AddRefs(cpuTexture)); + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNote << "Failed to create ID3D11Texture2D: " << gfx::hexa(hr); + return; + } + + deviceContext->CopyResource(cpuTexture, mTexture); + + D3D11_MAPPED_SUBRESOURCE map; + hr = deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &map); + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); + gfxCriticalNote << "Failed to map ID3D11Texture2D: " << gfx::hexa(hr); + return; + } + + const uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride( + gfx::SurfaceFormat::B8G8R8A8, aSize.width); + uint8_t* src = static_cast<uint8_t*>(map.pData); + uint8_t* dst = aDestShmem.get<uint8_t>(); + + MOZ_ASSERT(stride * aSize.height <= aDestShmem.Size<uint8_t>()); + + for (int y = 0; y < aSize.height; y++) { + memcpy(dst, src, stride); + src += map.RowPitch; + dst += stride; + } +} + +} // namespace mozilla::webgpu |