Bug 1795311 - Use the new shmem classes in the WebGPU buffer impl. r=jgilbert

Depends on D159398

Differential Revision: https://phabricator.services.mozilla.com/D159399
This commit is contained in:
Nicolas Silva 2022-11-10 15:52:32 +00:00
Родитель a1971c2e74
Коммит 84411fce11
7 изменённых файлов: 75 добавлений и 51 удалений

Просмотреть файл

@ -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<ipc::WritableSharedMemoryMapping>(std::move(aShmem));
MOZ_ASSERT(mParent);
}
@ -58,14 +60,16 @@ already_AddRefed<Buffer> Buffer::Create(Device* aDevice, RawId aDeviceId,
const dom::GPUBufferDescriptor& aDesc,
ErrorResult& aRv) {
if (aDevice->IsLost()) {
RefPtr<Buffer> buffer =
new Buffer(aDevice, 0, aDesc.mSize, 0, ipc::Shmem());
RefPtr<Buffer> buffer = new Buffer(aDevice, 0, aDesc.mSize, 0,
ipc::WritableSharedMemoryMapping());
return buffer.forget();
}
RefPtr<WebGPUChild> 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> 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<uint8_t>(), 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> 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<dom::Promise> Buffer::MapAsync(
return promise.forget();
}
static void ExternalBufferFreeCallback(void* aContents, void* aUserData) {
Unused << aContents;
auto shm = static_cast<std::shared_ptr<ipc::WritableSharedMemoryMapping>*>(
aUserData);
delete shm;
}
void Buffer::GetMappedRange(JSContext* aCx, uint64_t aOffset,
const dom::Optional<uint64_t>& aSize,
JS::Rooted<JSObject*>* 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<ipc::WritableSharedMemoryMapping>* userData =
new std::shared_ptr<ipc::WritableSharedMemoryMapping>(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<ipc::WritableSharedMemoryMapping>();
}
if (!GetDevice().IsLost()) {

Просмотреть файл

@ -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 <memory>
namespace mozilla {
class ErrorResult;
@ -22,9 +23,6 @@ template <typename T>
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<Device> {
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<Device> {
RefPtr<dom::Promise> mMapRequest;
// mShmem does not point to a shared memory segment if the buffer is not
// mappable.
ipc::Shmem mShmem;
std::shared_ptr<ipc::WritableSharedMemoryMapping> mShmem;
};
} // namespace webgpu

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<DeviceRequest> 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;

Просмотреть файл

@ -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,

Просмотреть файл

@ -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<uint8_t>() >= 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<uint8_t>() >= offset + size);
MOZ_RELEASE_ASSERT(mapData->mShmem.Size() >= offset + size);
if (src.ptr != nullptr && src.length >= size) {
auto dstPtr = mapData->mShmem.get<uint8_t>() + 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<uint8_t>() + 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<uint8_t>();
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);
}
}

Просмотреть файл

@ -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;