/* -*- 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/DMABufLibWrapper.h" #include "mozilla/widget/gbm.h" namespace mozilla::webgpu { // static UniquePtr 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; const ffi::WGPUVkImageHandle* vkImage = wgpu_vkimage_create_with_dma_buf( context, aDeviceId, aWidth, aHeight, &memorySize); if (!vkImage) { gfxCriticalNoteOnce << "Failed to create VkImage"; return nullptr; } UniquePtr handle = MakeUnique(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 fd = new gfx::FileHandleWrapper(UniqueFileHandle(rawFd)); RefPtr 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(std::move(handle), aWidth, aHeight, aFormat, aUsage, std::move(surface), desc.get_SurfaceDescriptorDMABuf()); } ExternalTextureDMABuf::ExternalTextureDMABuf( UniquePtr&& aVkImageHandle, const uint32_t aWidth, const uint32_t aHeight, const struct ffi::WGPUTextureFormat aFormat, const ffi::WGPUTextureUsages aUsage, RefPtr&& 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 ExternalTextureDMABuf::ToSurfaceDescriptor( Maybe& 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) { const RefPtr surface = mSurface->GetAsSourceSurface(); if (!surface) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); gfxCriticalNoteOnce << "Failed to get SourceSurface from DMABufSurface"; return; } const RefPtr 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(map.GetData()); uint8_t* dst = aDestShmem.get(); MOZ_ASSERT(stride * aSize.height <= aDestShmem.Size()); MOZ_ASSERT(static_cast(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(); } } // namespace mozilla::webgpu