diff --git a/dom/webgpu/Buffer.cpp b/dom/webgpu/Buffer.cpp index 786916a36bb2..bfc25fbbbf66 100644 --- a/dom/webgpu/Buffer.cpp +++ b/dom/webgpu/Buffer.cpp @@ -43,9 +43,11 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Buffer) NS_IMPL_CYCLE_COLLECTION_TRACE_END Buffer::Buffer(Device* const aParent, RawId aId, BufferAddress aSize, - uint32_t aUsage, ipc::Shmem&& aShmem) - : ChildOf(aParent), mId(aId), mSize(aSize), mUsage(aUsage), mShmem(aShmem) { + uint32_t aUsage, ipc::WritableSharedMemoryMapping&& aShmem) + : ChildOf(aParent), mId(aId), mSize(aSize), mUsage(aUsage) { mozilla::HoldJSObjects(this); + mShmem = + std::make_shared(std::move(aShmem)); MOZ_ASSERT(mParent); } @@ -58,14 +60,16 @@ already_AddRefed Buffer::Create(Device* aDevice, RawId aDeviceId, const dom::GPUBufferDescriptor& aDesc, ErrorResult& aRv) { if (aDevice->IsLost()) { - RefPtr buffer = - new Buffer(aDevice, 0, aDesc.mSize, 0, ipc::Shmem()); + RefPtr buffer = new Buffer(aDevice, 0, aDesc.mSize, 0, + ipc::WritableSharedMemoryMapping()); return buffer.forget(); } RefPtr actor = aDevice->GetBridge(); - ipc::Shmem shmem; + auto handle = ipc::UnsafeSharedMemoryHandle(); + auto mapping = ipc::WritableSharedMemoryMapping(); + bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE | dom::GPUBufferUsage_Binding::MAP_READ); if (hasMapFlags || aDesc.mMappedAtCreation) { @@ -75,29 +79,28 @@ already_AddRefed Buffer::Create(Device* aDevice, RawId aDeviceId, return nullptr; } size_t size = checked.value(); - if (size == 0) { - // Can't send zero-sized shmems. - size = 1; - } - if (!actor->AllocUnsafeShmem(size, &shmem)) { + auto maybeShmem = ipc::UnsafeSharedMemoryHandle::CreateAndMap(size); + + if (maybeShmem.isNothing()) { aRv.ThrowAbortError( nsPrintfCString("Unable to allocate shmem of size %" PRIuPTR, size)); return nullptr; } + handle = std::move(maybeShmem.ref().first); + mapping = std::move(maybeShmem.ref().second); + + MOZ_RELEASE_ASSERT(mapping.Size() >= size); + // zero out memory - memset(shmem.get(), 0, size); + memset(mapping.Bytes().data(), 0, size); } - MaybeShmem maybeShmem = mozilla::null_t(); - if (shmem.IsReadable()) { - maybeShmem = shmem; - } - RawId id = actor->DeviceCreateBuffer(aDeviceId, aDesc, std::move(maybeShmem)); + RawId id = actor->DeviceCreateBuffer(aDeviceId, aDesc, std::move(handle)); RefPtr buffer = - new Buffer(aDevice, id, aDesc.mSize, aDesc.mUsage, std::move(shmem)); + new Buffer(aDevice, id, aDesc.mSize, aDesc.mUsage, std::move(mapping)); if (aDesc.mMappedAtCreation) { // Mapped at creation's raison d'ĂȘtre is write access, since the buffer is // being created and there isn't anything interesting to read in it yet. @@ -212,10 +215,17 @@ already_AddRefed Buffer::MapAsync( return promise.forget(); } +static void ExternalBufferFreeCallback(void* aContents, void* aUserData) { + Unused << aContents; + auto shm = static_cast*>( + aUserData); + delete shm; +} + void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset, const dom::Optional& aSize, JS::Rooted* aObject, ErrorResult& aRv) { - if (!mMapped || !mShmem.IsReadable()) { + if (!mMapped) { aRv.ThrowInvalidStateError("Buffer is not mapped"); return; } @@ -233,8 +243,15 @@ void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset, return; } - auto* const arrayBuffer = GetDevice().CreateExternalArrayBuffer( - aCx, checkedOffset.value(), checkedSize.value(), mShmem); + auto offset = checkedOffset.value(); + auto size = checkedSize.value(); + auto span = mShmem->Bytes().Subspan(offset, size); + + std::shared_ptr* userData = + new std::shared_ptr(mShmem); + auto* const arrayBuffer = JS::NewExternalArrayBuffer( + aCx, size, span.data(), &ExternalBufferFreeCallback, userData); + if (!arrayBuffer) { aRv.NoteJSContextException(aCx); return; @@ -293,8 +310,8 @@ void Buffer::Unmap(JSContext* aCx, ErrorResult& aRv) { if (!hasMapFlags) { // We get here if the buffer was mapped at creation without map flags. // It won't be possible to map the buffer again so we can get rid of - // our shmem handle on this side. The parent side will deallocate it. - mShmem = ipc::Shmem(); + // our shmem on this side. + mShmem = std::make_shared(); } if (!GetDevice().IsLost()) { diff --git a/dom/webgpu/Buffer.h b/dom/webgpu/Buffer.h index dac7c9d976ec..3f77ab8381cf 100644 --- a/dom/webgpu/Buffer.h +++ b/dom/webgpu/Buffer.h @@ -8,10 +8,11 @@ #include "js/RootingAPI.h" #include "mozilla/dom/Nullable.h" -#include "mozilla/ipc/Shmem.h" #include "mozilla/webgpu/WebGPUTypes.h" #include "nsTArray.h" #include "ObjectModel.h" +#include "mozilla/ipc/RawShmem.h" +#include namespace mozilla { class ErrorResult; @@ -22,9 +23,6 @@ template class Optional; } // namespace dom -namespace ipc { -class Shmem; -} // namespace ipc namespace webgpu { class Device; @@ -63,7 +61,7 @@ class Buffer final : public ObjectBase, public ChildOf { private: Buffer(Device* const aParent, RawId aId, BufferAddress aSize, uint32_t aUsage, - ipc::Shmem&& aShmem); + ipc::WritableSharedMemoryMapping&& aShmem); virtual ~Buffer(); Device& GetDevice() { return *mParent; } void Drop(); @@ -83,7 +81,7 @@ class Buffer final : public ObjectBase, public ChildOf { RefPtr mMapRequest; // mShmem does not point to a shared memory segment if the buffer is not // mappable. - ipc::Shmem mShmem; + std::shared_ptr mShmem; }; } // namespace webgpu diff --git a/dom/webgpu/ipc/PWebGPU.ipdl b/dom/webgpu/ipc/PWebGPU.ipdl index 67651ffc3b7b..d0fecab0940c 100644 --- a/dom/webgpu/ipc/PWebGPU.ipdl +++ b/dom/webgpu/ipc/PWebGPU.ipdl @@ -13,6 +13,7 @@ using dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h"; using dom::GPUBufferDescriptor from "mozilla/dom/WebGPUBinding.h"; using MaybeScopedError from "mozilla/webgpu/WebGPUTypes.h"; using WebGPUCompilationMessage from "mozilla/webgpu/WebGPUTypes.h"; +[MoveOnly] using class mozilla::ipc::UnsafeSharedMemoryHandle from "mozilla/ipc/RawShmem.h"; include "mozilla/ipc/ByteBufUtils.h"; include "mozilla/layers/LayersMessageUtils.h"; @@ -40,7 +41,7 @@ parent: async CommandEncoderAction(RawId selfId, RawId aDeviceId, ByteBuf buf); async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId); - async CreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, MaybeShmem shmem); + async CreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc, UnsafeSharedMemoryHandle shm); async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId[] ids) returns (ByteBuf byteBuf); async AdapterRequestDevice(RawId selfId, ByteBuf buf, RawId newId) returns (bool success); diff --git a/dom/webgpu/ipc/WebGPUChild.cpp b/dom/webgpu/ipc/WebGPUChild.cpp index 586ca9bd7749..7397965e2e53 100644 --- a/dom/webgpu/ipc/WebGPUChild.cpp +++ b/dom/webgpu/ipc/WebGPUChild.cpp @@ -16,6 +16,7 @@ #include "DeviceLostInfo.h" #include "Sampler.h" #include "CompilationInfo.h" +#include "mozilla/ipc/RawShmem.h" namespace mozilla::webgpu { @@ -356,9 +357,9 @@ Maybe WebGPUChild::AdapterRequestDevice( RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId, const dom::GPUBufferDescriptor& aDesc, - MaybeShmem&& aShmem) { + ipc::UnsafeSharedMemoryHandle&& aShmem) { RawId bufferId = ffi::wgpu_client_make_buffer_id(mClient.get(), aSelfId); - if (!SendCreateBuffer(aSelfId, bufferId, aDesc, aShmem)) { + if (!SendCreateBuffer(aSelfId, bufferId, aDesc, std::move(aShmem))) { MOZ_CRASH("IPC failure"); } return bufferId; diff --git a/dom/webgpu/ipc/WebGPUChild.h b/dom/webgpu/ipc/WebGPUChild.h index e3bc2a77527a..3d17c135df9f 100644 --- a/dom/webgpu/ipc/WebGPUChild.h +++ b/dom/webgpu/ipc/WebGPUChild.h @@ -12,6 +12,9 @@ #include "mozilla/webgpu/ffi/wgpu.h" namespace mozilla { +namespace ipc { +class UnsafeSharedMemoryHandle; +} // namespace ipc namespace dom { struct GPURequestAdapterOptions; } // namespace dom @@ -64,7 +67,7 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr { RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc, ffi::WGPULimits* aLimits); RawId DeviceCreateBuffer(RawId aSelfId, const dom::GPUBufferDescriptor& aDesc, - MaybeShmem&& aShmem); + ipc::UnsafeSharedMemoryHandle&& aShmem); RawId DeviceCreateTexture(RawId aSelfId, const dom::GPUTextureDescriptor& aDesc); RawId TextureCreateView(RawId aSelfId, RawId aDeviceId, diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp index 1e7cf3986b10..bfb06cb13484 100644 --- a/dom/webgpu/ipc/WebGPUParent.cpp +++ b/dom/webgpu/ipc/WebGPUParent.cpp @@ -346,22 +346,26 @@ WebGPUParent::BufferMapData* WebGPUParent::GetBufferMapData(RawId aBufferId) { return &iter->second; } -ipc::IPCResult WebGPUParent::RecvCreateBuffer(RawId aDeviceId, RawId aBufferId, - dom::GPUBufferDescriptor&& aDesc, - MaybeShmem&& aShmem) { +ipc::IPCResult WebGPUParent::RecvCreateBuffer( + RawId aDeviceId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc, + ipc::UnsafeSharedMemoryHandle&& aShmem) { webgpu::StringHelper label(aDesc.mLabel); - if (aShmem.type() == MaybeShmem::TShmem) { - bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE | - dom::GPUBufferUsage_Binding::MAP_READ); + auto shmem = + ipc::WritableSharedMemoryMapping::Open(std::move(aShmem)).value(); + + bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE | + dom::GPUBufferUsage_Binding::MAP_READ); + if (hasMapFlags || aDesc.mMappedAtCreation) { uint64_t offset = 0; uint64_t size = 0; if (aDesc.mMappedAtCreation) { size = aDesc.mSize; - MOZ_RELEASE_ASSERT(aShmem.get_Shmem().Size() >= size); + MOZ_RELEASE_ASSERT(shmem.Size() >= aDesc.mSize); } - mSharedMemoryMap[aBufferId] = {aShmem.get_Shmem(), hasMapFlags, offset, - size}; + + BufferMapData data = {std::move(shmem), hasMapFlags, offset, size}; + mSharedMemoryMap.insert({aBufferId, std::move(data)}); } ErrorBuffer error; @@ -436,10 +440,10 @@ static void MapCallback(ffi::WGPUBufferMapAsyncStatus status, const auto src = ffi::wgpu_server_buffer_get_mapped_range( req->mContext, req->mBufferId, offset, size); - MOZ_RELEASE_ASSERT(mapData->mShmem.Size() >= offset + size); + MOZ_RELEASE_ASSERT(mapData->mShmem.Size() >= offset + size); if (src.ptr != nullptr && src.length >= size) { - auto dstPtr = mapData->mShmem.get() + offset; - memcpy(dstPtr, src.ptr, size); + auto dst = mapData->mShmem.Bytes().Subspan(offset, size); + memcpy(dst.data(), src.ptr, size); } } @@ -509,16 +513,16 @@ ipc::IPCResult WebGPUParent::RecvBufferUnmap(RawId aDeviceId, RawId aBufferId, uint64_t offset = mapData->mMappedOffset; uint64_t size = mapData->mMappedSize; - uint8_t* srcPtr = mapData->mShmem.get() + offset; - const auto mapped = ffi::wgpu_server_buffer_get_mapped_range( mContext.get(), aBufferId, offset, size); if (mapped.ptr != nullptr && mapped.length >= size) { - auto shmSize = mapData->mShmem.Size(); + auto shmSize = mapData->mShmem.Size(); MOZ_RELEASE_ASSERT(offset <= shmSize); MOZ_RELEASE_ASSERT(size <= shmSize - offset); - memcpy(mapped.ptr, srcPtr, size); + + auto src = mapData->mShmem.Bytes().Subspan(offset, size); + memcpy(mapped.ptr, src.data(), size); } mapData->mMappedOffset = 0; @@ -541,7 +545,6 @@ ipc::IPCResult WebGPUParent::RecvBufferUnmap(RawId aDeviceId, RawId aBufferId, void WebGPUParent::DeallocBufferShmem(RawId aBufferId) { const auto iter = mSharedMemoryMap.find(aBufferId); if (iter != mSharedMemoryMap.end()) { - DeallocShmem(iter->second.mShmem); mSharedMemoryMap.erase(iter); } } diff --git a/dom/webgpu/ipc/WebGPUParent.h b/dom/webgpu/ipc/WebGPUParent.h index d1caaeecd693..0210ca413c74 100644 --- a/dom/webgpu/ipc/WebGPUParent.h +++ b/dom/webgpu/ipc/WebGPUParent.h @@ -9,6 +9,7 @@ #include "mozilla/webgpu/ffi/wgpu.h" #include "mozilla/webgpu/PWebGPUParent.h" #include "mozilla/webrender/WebRenderAPI.h" +#include "mozilla/ipc/RawShmem.h" #include "WebGPUTypes.h" #include "base/timer.h" @@ -37,7 +38,7 @@ class WebGPUParent final : public PWebGPUParent { ipc::IPCResult RecvDeviceDestroy(RawId aDeviceId); ipc::IPCResult RecvCreateBuffer(RawId aDeviceId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc, - MaybeShmem&& aShmem); + ipc::UnsafeSharedMemoryHandle&& aShmem); ipc::IPCResult RecvBufferReturnShmem(RawId aBufferId, Shmem&& aShmem); ipc::IPCResult RecvBufferMap(RawId aBufferId, uint32_t aMode, uint64_t aOffset, uint64_t size, @@ -107,7 +108,7 @@ class WebGPUParent final : public PWebGPUParent { void ActorDestroy(ActorDestroyReason aWhy) override; struct BufferMapData { - Shmem mShmem; + ipc::WritableSharedMemoryMapping mShmem; // True if buffer's usage has MAP_READ or MAP_WRITE set. bool mHasMapFlags; uint64_t mMappedOffset;