Bug 1920361 - Add ExternalTextureDMABuf for handling DMA buf for WebGPU r=webgpu-reviewers,stransky,nical

Add ExternalTextureDMABuf for handling DMA buf for WebGPU. Actual DMA buf allocation is going to be done in Vulkan by another bug.

Differential Revision: https://phabricator.services.mozilla.com/D223062
This commit is contained in:
sotaro 2024-09-24 16:19:35 +00:00
parent f540d8b924
commit 09eab18be0
10 changed files with 423 additions and 7 deletions

View File

@ -9,16 +9,24 @@
# include "mozilla/webgpu/ExternalTextureD3D11.h"
#endif
#ifdef MOZ_WIDGET_GTK
# include "mozilla/webgpu/ExternalTextureDMABuf.h"
#endif
namespace mozilla::webgpu {
// static
UniquePtr<ExternalTexture> ExternalTexture::Create(
const ffi::WGPUGlobal* aContext, const ffi::WGPUDeviceId aDeviceId,
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat,
const ffi::WGPUTextureUsages aUsage) {
UniquePtr<ExternalTexture> texture;
#ifdef XP_WIN
texture = ExternalTextureD3D11::Create(aWidth, aHeight, aFormat, aUsage);
#elif defined(MOZ_WIDGET_GTK)
texture = ExternalTextureDMABuf::Create(aContext, aDeviceId, aWidth, aHeight,
aFormat, aUsage);
#endif
return texture;
}

View File

@ -18,11 +18,14 @@ class Shmem;
namespace webgpu {
class ExternalTextureDMABuf;
// A texture that can be used by the WebGPU implementation but is created and
// owned by Gecko
class ExternalTexture {
public:
static UniquePtr<ExternalTexture> Create(
const ffi::WGPUGlobal* aContext, const ffi::WGPUDeviceId aDeviceId,
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat,
const ffi::WGPUTextureUsages aUsage);
@ -40,6 +43,8 @@ class ExternalTexture {
virtual void GetSnapshot(const ipc::Shmem& aDestShmem,
const gfx::IntSize& aSize) {}
virtual ExternalTextureDMABuf* AsExternalTextureDMABuf() { return nullptr; }
gfx::IntSize GetSize() { return gfx::IntSize(mWidth, mHeight); }
void SetSubmissionIndex(uint64_t aSubmissionIndex);

View File

@ -0,0 +1,116 @@
/* -*- 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 "ExternalTextureDMABuf.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/widget/DMABufSurface.h"
#include "mozilla/widget/DMABufLibWrapper.h"
#include "mozilla/widget/gbm.h"
namespace mozilla::webgpu {
// static
UniquePtr<ExternalTextureDMABuf> ExternalTextureDMABuf::Create(
const ffi::WGPUGlobal* aContext, const ffi::WGPUDeviceId aDeviceId,
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat,
const ffi::WGPUTextureUsages aUsage) {
if (aFormat.tag != ffi::WGPUTextureFormat_Bgra8Unorm) {
gfxCriticalNoteOnce << "Non supported format: " << aFormat.tag;
return nullptr;
}
uint64_t memorySize = 0;
UniquePtr<ffi::WGPUVkImageHandle> vkImage(wgpu_vkimage_create_with_dma_buf(
aContext, aDeviceId, aWidth, aHeight, &memorySize));
if (!vkImage) {
gfxCriticalNoteOnce << "Failed to create VkImage";
return nullptr;
}
const auto dmaBufInfo = wgpu_vkimage_get_dma_buf_info(vkImage.get());
if (!dmaBufInfo.is_valid) {
gfxCriticalNoteOnce << "Invalid DMABufInfo";
return nullptr;
}
MOZ_ASSERT(dmaBufInfo.plane_count <= 3);
if (dmaBufInfo.plane_count > 3) {
gfxCriticalNoteOnce << "Invalid plane count";
return nullptr;
}
auto rawFd =
wgpu_vkimage_get_file_descriptor(aContext, aDeviceId, vkImage.get());
if (rawFd < 0) {
gfxCriticalNoteOnce << "Failed to get fd fom VkDeviceMemory";
return nullptr;
}
auto fd = mozilla::UniqueFileHandle(rawFd);
RefPtr<DMABufSurface> surface = DMABufSurfaceRGBA::CreateDMABufSurface(
std::move(fd), dmaBufInfo, aWidth, aHeight);
if (!surface) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
layers::SurfaceDescriptor desc;
if (!surface->Serialize(desc)) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
const auto sdType = desc.type();
if (sdType != layers::SurfaceDescriptor::TSurfaceDescriptorDMABuf) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
return MakeUnique<ExternalTextureDMABuf>(std::move(vkImage), aWidth, aHeight,
aFormat, aUsage, std::move(surface),
desc.get_SurfaceDescriptorDMABuf());
}
ExternalTextureDMABuf::ExternalTextureDMABuf(
UniquePtr<ffi::WGPUVkImageHandle> aVkImageHandle, const uint32_t aWidth,
const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat,
const ffi::WGPUTextureUsages aUsage, RefPtr<DMABufSurface>&& aSurface,
const layers::SurfaceDescriptorDMABuf& aSurfaceDescriptor)
: ExternalTexture(aWidth, aHeight, aFormat, aUsage),
mVkImageHandle(std::move(aVkImageHandle)),
mSurface(std::move(aSurface)),
mSurfaceDescriptor(aSurfaceDescriptor) {}
ExternalTextureDMABuf::~ExternalTextureDMABuf() {}
void* ExternalTextureDMABuf::GetExternalTextureHandle() { return nullptr; }
Maybe<layers::SurfaceDescriptor> ExternalTextureDMABuf::ToSurfaceDescriptor(
Maybe<gfx::FenceInfo>& aFenceInfo) {
layers::SurfaceDescriptor sd;
if (!mSurface->Serialize(sd)) {
return Nothing();
}
if (sd.type() != layers::SurfaceDescriptor::TSurfaceDescriptorDMABuf) {
return Nothing();
}
return Some(sd);
}
void ExternalTextureDMABuf::GetSnapshot(const ipc::Shmem& aDestShmem,
const gfx::IntSize& aSize) {}
UniqueFileHandle ExternalTextureDMABuf::CloneDmaBufFd() {
return mSurfaceDescriptor.fds()[0].ClonePlatformHandle();
}
} // namespace mozilla::webgpu

View File

@ -0,0 +1,56 @@
/* -*- 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/. */
#ifndef GPU_ExternalTextureDMABuf_H_
#define GPU_ExternalTextureDMABuf_H_
#include "mozilla/gfx/FileHandleWrapper.h"
#include "mozilla/webgpu/ExternalTexture.h"
class DMABufSurface;
namespace mozilla {
namespace webgpu {
class ExternalTextureDMABuf final : public ExternalTexture {
public:
static UniquePtr<ExternalTextureDMABuf> Create(
const ffi::WGPUGlobal* aContext, const ffi::WGPUDeviceId aDeviceId,
const uint32_t aWidth, const uint32_t aHeight,
const struct ffi::WGPUTextureFormat aFormat,
const ffi::WGPUTextureUsages aUsage);
ExternalTextureDMABuf(
UniquePtr<ffi::WGPUVkImageHandle> aVkImageHandle, const uint32_t aWidth,
const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat,
const ffi::WGPUTextureUsages aUsage, RefPtr<DMABufSurface>&& aSurface,
const layers::SurfaceDescriptorDMABuf& aSurfaceDescriptor);
virtual ~ExternalTextureDMABuf();
void* GetExternalTextureHandle() override;
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor(
Maybe<gfx::FenceInfo>& aFenceInfo) override;
void GetSnapshot(const ipc::Shmem& aDestShmem,
const gfx::IntSize& aSize) override;
ExternalTextureDMABuf* AsExternalTextureDMABuf() override { return this; }
UniqueFileHandle CloneDmaBufFd();
ffi::WGPUVkImageHandle* GetHandle() { return mVkImageHandle.get(); }
protected:
UniquePtr<ffi::WGPUVkImageHandle> mVkImageHandle;
RefPtr<DMABufSurface> mSurface;
const layers::SurfaceDescriptorDMABuf mSurfaceDescriptor;
};
} // namespace webgpu
} // namespace mozilla
#endif // GPU_Texture_H_

View File

@ -24,6 +24,10 @@
# include "mozilla/gfx/DeviceManagerDx.h"
#endif
#if MOZ_WIDGET_GTK
# include "mozilla/webgpu/ExternalTextureDMABuf.h"
#endif
namespace mozilla::webgpu {
const uint64_t POLL_TIME_MS = 100;
@ -73,6 +77,51 @@ extern void* wgpu_server_get_external_texture_handle(void* aParam,
return sharedHandle;
}
extern int32_t wgpu_server_get_dma_buf_fd(void* aParam, WGPUTextureId aId) {
auto* parent = static_cast<WebGPUParent*>(aParam);
auto texture = parent->GetExternalTexture(aId);
if (!texture) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return -1;
}
#ifdef MOZ_WIDGET_GTK
auto* textureDMABuf = texture->AsExternalTextureDMABuf();
if (!textureDMABuf) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return -1;
}
auto fd = textureDMABuf->CloneDmaBufFd();
// fd should be closed by the caller.
return fd.release();
#else
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return -1;
#endif
}
extern WGPUVkImageHandle* wgpu_server_get_vk_image_handle(void* aParam,
WGPUTextureId aId) {
auto* parent = static_cast<WebGPUParent*>(aParam);
auto texture = parent->GetExternalTexture(aId);
if (!texture) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
#if defined(MOZ_WIDGET_GTK)
auto* textureDMABuf = texture->AsExternalTextureDMABuf();
if (!textureDMABuf) {
return nullptr;
}
return textureDMABuf->GetHandle();
#else
return nullptr;
#endif
}
} // namespace ffi
// A fixed-capacity buffer for receiving textual error messages from
@ -1526,8 +1575,8 @@ std::shared_ptr<ExternalTexture> WebGPUParent::CreateExternalTexture(
MOZ_RELEASE_ASSERT(mExternalTextures.find(aTextureId) ==
mExternalTextures.end());
UniquePtr<ExternalTexture> texture =
ExternalTexture::Create(aWidth, aHeight, aFormat, aUsage);
UniquePtr<ExternalTexture> texture = ExternalTexture::Create(
mContext.get(), aDeviceId, aWidth, aHeight, aFormat, aUsage);
if (!texture) {
return nullptr;
}

View File

@ -78,6 +78,14 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
"ExternalTextureD3D11.cpp",
]
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
EXPORTS.mozilla.webgpu += [
"ExternalTextureDMABuf.h",
]
UNIFIED_SOURCES += [
"ExternalTextureDMABuf.cpp",
]
if CONFIG["CC_TYPE"] in ("clang", "clang-cl"):
CXXFLAGS += ["-Werror=implicit-int-conversion", "-Wno-shorten-64-to-32"]
CXXFLAGS += ["-Werror=switch"]

View File

@ -215,6 +215,22 @@ pub unsafe extern "C" fn wgpu_server_instance_request_adapter(
}
}
#[allow(unreachable_code)]
#[allow(unused_variables)]
fn support_use_external_texture_in_swap_chain(
global: &Global,
self_id: id::AdapterId,
backend: wgt::Backend,
is_hardware: bool,
) -> bool {
#[cfg(target_os = "windows")]
{
return backend == wgt::Backend::Dx12 && is_hardware;
}
false
}
#[no_mangle]
pub unsafe extern "C" fn wgpu_server_adapter_pack_info(
global: &Global,
@ -247,11 +263,8 @@ pub unsafe extern "C" fn wgpu_server_adapter_pack_info(
);
}
let support_use_external_texture_in_swap_chain = if cfg!(target_os = "windows") {
backend == wgt::Backend::Dx12 && is_hardware
} else {
false
};
let support_use_external_texture_in_swap_chain =
support_use_external_texture_in_swap_chain(global, id, backend, is_hardware);
let info = AdapterInformation {
id,
@ -629,6 +642,90 @@ pub extern "C" fn wgpu_server_get_device_fence_handle(
ptr::null_mut()
}
#[derive(Debug)]
#[repr(C)]
pub struct DMABufInfo {
pub is_valid: bool,
pub modifier: u64,
pub plane_count: u32,
pub offsets: [u64; 3],
pub strides: [u64; 3],
}
#[derive(Debug)]
pub struct VkImageHandle {
//pub image: vk::Image,
//pub memory: vk::DeviceMemory,
pub memory_size: u64,
pub memory_type_index: u32,
pub modifier: u64,
//pub layouts: Vec<vk::SubresourceLayout>,
}
impl VkImageHandle {
pub fn new(
//image: vk::Image,
//memory: vk::DeviceMemory,
memory_size: u64,
memory_type_index: u32,
modifier: u64,
//layouts: Vec<vk::SubresourceLayout>,
) -> VkImageHandle {
VkImageHandle {
//image,
//memory,
memory_size,
memory_type_index,
modifier,
//layouts,
}
}
}
#[no_mangle]
#[allow(unused_variables)]
#[cfg(target_os = "linux")]
pub extern "C" fn wgpu_vkimage_create_with_dma_buf(
global: &Global,
device_id: id::DeviceId,
width: u32,
height: u32,
out_memory_size: *mut u64,
) -> *mut VkImageHandle {
return ptr::null_mut();
}
#[no_mangle]
pub unsafe extern "C" fn wgpu_vkimage_delete(handle: *mut VkImageHandle) {
let _ = Box::from_raw(handle);
}
#[no_mangle]
#[allow(unused_variables)]
#[cfg(target_os = "linux")]
pub extern "C" fn wgpu_vkimage_get_file_descriptor(
global: &Global,
device_id: id::DeviceId,
handle: &VkImageHandle,
) -> i32 {
-1
}
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn wgpu_vkimage_get_dma_buf_info(handle: &VkImageHandle) -> DMABufInfo {
let offsets: [u64; 3] = [0; 3];
let strides: [u64; 3] = [0; 3];
DMABufInfo {
is_valid: false,
modifier: 0,
plane_count: 0,
offsets,
strides,
}
}
extern "C" {
#[allow(dead_code)]
fn wgpu_server_use_external_texture_for_swap_chain(
@ -651,6 +748,14 @@ extern "C" {
param: *mut c_void,
id: id::TextureId,
) -> *mut c_void;
#[allow(improper_ctypes)]
#[allow(dead_code)]
fn wgpu_server_get_vk_image_handle(
param: *mut c_void,
texture_id: id::TextureId,
) -> *mut VkImageHandle;
#[allow(dead_code)]
fn wgpu_server_get_dma_buf_fd(param: *mut c_void, id: id::TextureId) -> i32;
}
impl Global {

View File

@ -58,6 +58,14 @@ class DefaultDelete<webgpu::ffi::WGPUGlobal> {
}
};
template <>
class DefaultDelete<webgpu::ffi::WGPUVkImageHandle> {
public:
void operator()(webgpu::ffi::WGPUVkImageHandle* aPtr) const {
webgpu::ffi::wgpu_vkimage_delete(aPtr);
}
};
} // namespace mozilla
#endif // WGPU_h

View File

@ -536,6 +536,42 @@ bool DMABufSurfaceRGBA::Create(mozilla::gl::GLContext* aGLContext,
return true;
}
bool DMABufSurfaceRGBA::Create(
mozilla::UniqueFileHandle&& aFd,
const mozilla::webgpu::ffi::WGPUDMABufInfo& aDMABufInfo, int aWidth,
int aHeight) {
LOGDMABUF(("DMABufSurfaceRGBA::Create() UID %d size %d x %d\n", mUID, mWidth,
mHeight));
mWidth = aWidth;
mHeight = aHeight;
mBufferModifiers[0] = aDMABufInfo.modifier;
mGmbFormat = GetDMABufDevice()->GetGbmFormat(true);
mDrmFormats[0] = mGmbFormat->mFormat;
mBufferPlaneCount = aDMABufInfo.plane_count;
ipc::FileDescriptor fd = ipc::FileDescriptor(std::move(aFd));
for (uint32_t i = 0; i < aDMABufInfo.plane_count; i++) {
auto clonedFd = fd.ClonePlatformHandle();
mDmabufFds[i] = clonedFd.release();
mStrides[i] = aDMABufInfo.strides[i];
mOffsets[i] = aDMABufInfo.offsets[i];
}
if (mDmabufFds[0] < 0) {
LOGDMABUF(
(" ExportDMABUFImageMESA failed, mDmabufFds[0] is invalid, quit"));
return false;
}
LOGDMABUF((" imported size %d x %d format %x planes %d modifiers %" PRIx64,
mWidth, mHeight, mDrmFormats[0], mBufferPlaneCount,
mBufferModifiers[0]));
return true;
}
bool DMABufSurfaceRGBA::ImportSurfaceDescriptor(
const SurfaceDescriptor& aDesc) {
const SurfaceDescriptorDMABuf& desc = aDesc.get_SurfaceDescriptorDMABuf();
@ -982,6 +1018,17 @@ already_AddRefed<DMABufSurface> DMABufSurfaceRGBA::CreateDMABufSurface(
return surf.forget();
}
already_AddRefed<DMABufSurface> DMABufSurfaceRGBA::CreateDMABufSurface(
mozilla::UniqueFileHandle&& aFd,
const mozilla::webgpu::ffi::WGPUDMABufInfo& aDMABufInfo, int aWidth,
int aHeight) {
RefPtr<DMABufSurfaceRGBA> surf = new DMABufSurfaceRGBA();
if (!surf->Create(std::move(aFd), aDMABufInfo, aWidth, aHeight)) {
return nullptr;
}
return surf.forget();
}
already_AddRefed<DMABufSurfaceYUV> DMABufSurfaceYUV::CreateYUVSurface(
const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, int aHeight) {
RefPtr<DMABufSurfaceYUV> surf = new DMABufSurfaceYUV();

View File

@ -15,6 +15,7 @@
#include "nsISupportsImpl.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/Mutex.h"
#include "mozilla/webgpu/ffi/wgpu.h"
typedef void* EGLImageKHR;
typedef void* EGLSyncKHR;
@ -44,6 +45,11 @@ class SurfaceDescriptorDMABuf;
namespace gl {
class GLContext;
}
namespace webgpu {
namespace ffi {
struct WGPUDMABufInfo;
}
} // namespace webgpu
} // namespace mozilla
typedef enum {
@ -228,6 +234,11 @@ class DMABufSurfaceRGBA final : public DMABufSurface {
mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage,
int aWidth, int aHeight);
static already_AddRefed<DMABufSurface> CreateDMABufSurface(
mozilla::UniqueFileHandle&& aFd,
const mozilla::webgpu::ffi::WGPUDMABufInfo& aDMABufInfo, int aWidth,
int aHeight);
bool Serialize(mozilla::layers::SurfaceDescriptor& aOutDescriptor) override;
DMABufSurfaceRGBA* GetAsDMABufSurfaceRGBA() override { return this; }
@ -284,6 +295,9 @@ class DMABufSurfaceRGBA final : public DMABufSurface {
bool Create(const mozilla::layers::SurfaceDescriptor& aDesc) override;
bool Create(mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage,
int aWidth, int aHeight);
bool Create(mozilla::UniqueFileHandle&& aFd,
const mozilla::webgpu::ffi::WGPUDMABufInfo& aDMABufInfo,
int aWidth, int aHeight);
bool ImportSurfaceDescriptor(const mozilla::layers::SurfaceDescriptor& aDesc);