190 lines
5.9 KiB
C++
190 lines
5.9 KiB
C++
/* -*- 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/webgpu/WebGPUParent.h"
|
|
#include "mozilla/widget/DMABufSurface.h"
|
|
#include "mozilla/widget/DMABufDevice.h"
|
|
#include <gbm.h>
|
|
|
|
namespace mozilla::webgpu {
|
|
|
|
// static
|
|
UniquePtr<ExternalTextureDMABuf> ExternalTextureDMABuf::Create(
|
|
WebGPUParent* aParent, 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;
|
|
}
|
|
|
|
auto* context = aParent->GetContext();
|
|
uint64_t memorySize = 0;
|
|
ffi::WGPUVkImageHandle* vkImage = wgpu_vkimage_create_with_dma_buf(
|
|
context, aDeviceId, aWidth, aHeight, &memorySize);
|
|
if (!vkImage) {
|
|
gfxCriticalNoteOnce << "Failed to create VkImage";
|
|
return nullptr;
|
|
}
|
|
UniquePtr<VkImageHandle> handle =
|
|
MakeUnique<VkImageHandle>(aParent, aDeviceId, vkImage);
|
|
|
|
const auto dmaBufInfo = wgpu_vkimage_get_dma_buf_info(vkImage);
|
|
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(context, aDeviceId, vkImage);
|
|
if (rawFd < 0) {
|
|
gfxCriticalNoteOnce << "Failed to get fd fom VkDeviceMemory";
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<gfx::FileHandleWrapper> fd =
|
|
new gfx::FileHandleWrapper(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>(
|
|
aParent, aDeviceId, std::move(handle), aWidth, aHeight, aFormat, aUsage,
|
|
std::move(surface), desc.get_SurfaceDescriptorDMABuf());
|
|
}
|
|
|
|
ExternalTextureDMABuf::ExternalTextureDMABuf(
|
|
WebGPUParent* aParent, const ffi::WGPUDeviceId aDeviceId,
|
|
UniquePtr<VkImageHandle>&& 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),
|
|
mParent(aParent),
|
|
mDeviceId(aDeviceId),
|
|
mVkImageHandle(std::move(aVkImageHandle)),
|
|
mSurface(std::move(aSurface)),
|
|
mSurfaceDescriptor(aSurfaceDescriptor) {}
|
|
|
|
ExternalTextureDMABuf::~ExternalTextureDMABuf() {}
|
|
|
|
Maybe<layers::SurfaceDescriptor> ExternalTextureDMABuf::ToSurfaceDescriptor() {
|
|
layers::SurfaceDescriptor sd;
|
|
if (!mSurface->Serialize(sd)) {
|
|
return Nothing();
|
|
}
|
|
|
|
if (sd.type() != layers::SurfaceDescriptor::TSurfaceDescriptorDMABuf) {
|
|
return Nothing();
|
|
}
|
|
|
|
auto& sdDMABuf = sd.get_SurfaceDescriptorDMABuf();
|
|
sdDMABuf.semaphoreFd() = mSemaphoreFd;
|
|
|
|
return Some(sd);
|
|
}
|
|
|
|
void ExternalTextureDMABuf::GetSnapshot(const ipc::Shmem& aDestShmem,
|
|
const gfx::IntSize& aSize) {
|
|
const RefPtr<gfx::SourceSurface> surface = mSurface->GetAsSourceSurface();
|
|
if (!surface) {
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
gfxCriticalNoteOnce << "Failed to get SourceSurface from DMABufSurface";
|
|
return;
|
|
}
|
|
|
|
const RefPtr<gfx::DataSourceSurface> dataSurface = surface->GetDataSurface();
|
|
if (!dataSurface) {
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
return;
|
|
}
|
|
|
|
gfx::DataSourceSurface::ScopedMap map(dataSurface,
|
|
gfx::DataSourceSurface::READ);
|
|
if (!map.IsMapped()) {
|
|
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
|
|
return;
|
|
}
|
|
|
|
const uint32_t stride = layers::ImageDataSerializer::ComputeRGBStride(
|
|
gfx::SurfaceFormat::B8G8R8A8, aSize.width);
|
|
uint8_t* src = static_cast<uint8_t*>(map.GetData());
|
|
uint8_t* dst = aDestShmem.get<uint8_t>();
|
|
|
|
MOZ_ASSERT(stride * aSize.height <= aDestShmem.Size<uint8_t>());
|
|
MOZ_ASSERT(static_cast<uint32_t>(map.GetStride()) >= stride);
|
|
|
|
for (int y = 0; y < aSize.height; y++) {
|
|
memcpy(dst, src, stride);
|
|
src += map.GetStride();
|
|
dst += stride;
|
|
}
|
|
}
|
|
|
|
UniqueFileHandle ExternalTextureDMABuf::CloneDmaBufFd() {
|
|
return mSurfaceDescriptor.fds()[0]->ClonePlatformHandle();
|
|
}
|
|
|
|
const ffi::WGPUVkImageHandle* ExternalTextureDMABuf::GetHandle() {
|
|
return mVkImageHandle->Get();
|
|
}
|
|
|
|
void ExternalTextureDMABuf::onBeforeQueueSubmit(RawId aQueueId) {
|
|
if (!mParent) {
|
|
return;
|
|
}
|
|
|
|
auto* context = mParent->GetContext();
|
|
if (!context) {
|
|
return;
|
|
}
|
|
|
|
ffi::WGPUVkSemaphoreHandle* vkSemaphore =
|
|
wgpu_vksemaphore_create_signal_semaphore(context, aQueueId);
|
|
if (!vkSemaphore) {
|
|
gfxCriticalNoteOnce << "Failed to create VkSemaphore";
|
|
return;
|
|
}
|
|
|
|
mVkSemaphoreHandle =
|
|
MakeUnique<VkSemaphoreHandle>(mParent, mDeviceId, vkSemaphore);
|
|
|
|
auto rawFd =
|
|
wgpu_vksemaphore_get_file_descriptor(context, mDeviceId, vkSemaphore);
|
|
if (rawFd < 0) {
|
|
gfxCriticalNoteOnce << "Failed to get fd from VkSemaphore";
|
|
return;
|
|
}
|
|
mSemaphoreFd = new gfx::FileHandleWrapper(UniqueFileHandle(rawFd));
|
|
}
|
|
|
|
} // namespace mozilla::webgpu
|