diff options
Diffstat (limited to 'dom/webgpu/ipc/WebGPUParent.cpp')
-rw-r--r-- | dom/webgpu/ipc/WebGPUParent.cpp | 713 |
1 files changed, 713 insertions, 0 deletions
diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp new file mode 100644 index 0000000000..5728d7c242 --- /dev/null +++ b/dom/webgpu/ipc/WebGPUParent.cpp @@ -0,0 +1,713 @@ +/* -*- Mode: C++; tab-width: 20; 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 "WebGPUParent.h" +#include "mozilla/webgpu/ffi/wgpu.h" +#include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/layers/TextureHost.h" + +namespace mozilla { +namespace webgpu { + +const uint64_t POLL_TIME_MS = 100; + +// A helper class to force error checks coming across FFI. +// It will assert in destructor if unchecked. +// TODO: refactor this to avoid stack-allocating the buffer all the time. +class ErrorBuffer { + // if the message doesn't fit, it will be truncated + static constexpr unsigned BUFFER_SIZE = 256; + char mUtf8[BUFFER_SIZE] = {}; + bool mGuard = false; + + public: + ErrorBuffer() { mUtf8[0] = 0; } + ErrorBuffer(const ErrorBuffer&) = delete; + ~ErrorBuffer() { MOZ_ASSERT(!mGuard); } + + ffi::WGPUErrorBuffer ToFFI() { + mGuard = true; + ffi::WGPUErrorBuffer errorBuf = {mUtf8, BUFFER_SIZE}; + return errorBuf; + } + + bool CheckAndForward(PWebGPUParent* aParent, RawId aDeviceId) { + mGuard = false; + if (!mUtf8[0]) { + return false; + } + nsAutoCString cString(mUtf8); + if (!aParent->SendError(aDeviceId, cString)) { + NS_ERROR("Unable to SendError"); + } + return true; + } +}; + +class PresentationData { + NS_INLINE_DECL_REFCOUNTING(PresentationData); + + public: + RawId mDeviceId = 0; + RawId mQueueId = 0; + RefPtr<layers::MemoryTextureHost> mTextureHost; + uint32_t mSourcePitch = 0; + uint32_t mTargetPitch = 0; + uint32_t mRowCount = 0; + std::vector<RawId> mUnassignedBufferIds; + std::vector<RawId> mAvailableBufferIds; + std::vector<RawId> mQueuedBufferIds; + Mutex mBuffersLock; + + PresentationData() : mBuffersLock("WebGPU presentation buffers") { + MOZ_COUNT_CTOR(PresentationData); + } + + private: + ~PresentationData() { MOZ_COUNT_DTOR(PresentationData); } +}; + +static void FreeAdapter(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeAdapter(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeDevice(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeDevice(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeSwapChain(RawId id, void* param) { + Unused << id; + Unused << param; +} +static void FreePipelineLayout(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreePipelineLayout(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeShaderModule(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeShaderModule(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeBindGroupLayout(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeBindGroupLayout(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeBindGroup(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeBindGroup(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeCommandBuffer(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeCommandBuffer(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeRenderPipeline(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeRenderPipeline(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeComputePipeline(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeComputePipeline(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeBuffer(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeBuffer(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeTexture(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeTexture(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeTextureView(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeTextureView(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeSampler(RawId id, void* param) { + if (!static_cast<WebGPUParent*>(param)->SendFreeSampler(id)) { + MOZ_CRASH("IPC failure"); + } +} +static void FreeSurface(RawId id, void* param) { + Unused << id; + Unused << param; +} + +static ffi::WGPUIdentityRecyclerFactory MakeFactory(void* param) { + ffi::WGPUIdentityRecyclerFactory factory = {param}; + factory.free_adapter = FreeAdapter; + factory.free_device = FreeDevice; + factory.free_swap_chain = FreeSwapChain; + factory.free_pipeline_layout = FreePipelineLayout; + factory.free_shader_module = FreeShaderModule; + factory.free_bind_group_layout = FreeBindGroupLayout; + factory.free_bind_group = FreeBindGroup; + factory.free_command_buffer = FreeCommandBuffer; + factory.free_render_pipeline = FreeRenderPipeline; + factory.free_compute_pipeline = FreeComputePipeline; + factory.free_buffer = FreeBuffer; + factory.free_texture = FreeTexture; + factory.free_texture_view = FreeTextureView; + factory.free_sampler = FreeSampler; + factory.free_surface = FreeSurface; + return factory; +} + +WebGPUParent::WebGPUParent() + : mContext(ffi::wgpu_server_new(MakeFactory(this))) { + mTimer.Start(base::TimeDelta::FromMilliseconds(POLL_TIME_MS), this, + &WebGPUParent::MaintainDevices); +} + +WebGPUParent::~WebGPUParent() = default; + +void WebGPUParent::MaintainDevices() { + ffi::wgpu_server_poll_all_devices(mContext, false); +} + +ipc::IPCResult WebGPUParent::RecvInstanceRequestAdapter( + const dom::GPURequestAdapterOptions& aOptions, + const nsTArray<RawId>& aTargetIds, + InstanceRequestAdapterResolver&& resolver) { + ffi::WGPURequestAdapterOptions options = {}; + if (aOptions.mPowerPreference.WasPassed()) { + options.power_preference = static_cast<ffi::WGPUPowerPreference>( + aOptions.mPowerPreference.Value()); + } + // TODO: make available backends configurable by prefs + + ErrorBuffer error; + int8_t index = ffi::wgpu_server_instance_request_adapter( + mContext, &options, aTargetIds.Elements(), aTargetIds.Length(), + error.ToFFI()); + if (index >= 0) { + resolver(aTargetIds[index]); + } else { + resolver(0); + } + error.CheckAndForward(this, 0); + + // free the unused IDs + for (size_t i = 0; i < aTargetIds.Length(); ++i) { + if (static_cast<int8_t>(i) != index && !SendFreeAdapter(aTargetIds[i])) { + NS_ERROR("Unable to SendFreeAdapter"); + } + } + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice( + RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc, RawId aNewId) { + ffi::WGPUDeviceDescriptor desc = {}; + desc.shader_validation = true; // required for implicit pipeline layouts + + if (aDesc.mLimits.WasPassed()) { + const auto& lim = aDesc.mLimits.Value(); + desc.limits.max_bind_groups = lim.mMaxBindGroups; + desc.limits.max_dynamic_uniform_buffers_per_pipeline_layout = + lim.mMaxDynamicUniformBuffersPerPipelineLayout; + desc.limits.max_dynamic_storage_buffers_per_pipeline_layout = + lim.mMaxDynamicStorageBuffersPerPipelineLayout; + desc.limits.max_sampled_textures_per_shader_stage = + lim.mMaxSampledTexturesPerShaderStage; + desc.limits.max_samplers_per_shader_stage = lim.mMaxSamplersPerShaderStage; + desc.limits.max_storage_buffers_per_shader_stage = + lim.mMaxStorageBuffersPerShaderStage; + desc.limits.max_storage_textures_per_shader_stage = + lim.mMaxStorageTexturesPerShaderStage; + desc.limits.max_uniform_buffers_per_shader_stage = + lim.mMaxUniformBuffersPerShaderStage; + desc.limits.max_uniform_buffer_binding_size = + lim.mMaxUniformBufferBindingSize; + } else { + ffi::wgpu_server_fill_default_limits(&desc.limits); + } + + ErrorBuffer error; + ffi::wgpu_server_adapter_request_device(mContext, aSelfId, &desc, aNewId, + error.ToFFI()); + error.CheckAndForward(this, 0); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvAdapterDestroy(RawId aSelfId) { + ffi::wgpu_server_adapter_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvDeviceDestroy(RawId aSelfId) { + ffi::wgpu_server_device_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvBufferReturnShmem(RawId aSelfId, + Shmem&& aShmem) { + mSharedMemoryMap[aSelfId] = aShmem; + return IPC_OK(); +} + +struct MapRequest { + const ffi::WGPUGlobal* const mContext; + ffi::WGPUBufferId mBufferId; + ffi::WGPUHostMap mHostMap; + uint64_t mOffset; + ipc::Shmem mShmem; + WebGPUParent::BufferMapResolver mResolver; + MapRequest(const ffi::WGPUGlobal* context, ffi::WGPUBufferId bufferId, + ffi::WGPUHostMap hostMap, uint64_t offset, ipc::Shmem&& shmem, + WebGPUParent::BufferMapResolver&& resolver) + : mContext(context), + mBufferId(bufferId), + mHostMap(hostMap), + mOffset(offset), + mShmem(shmem), + mResolver(resolver) {} +}; + +static void MapCallback(ffi::WGPUBufferMapAsyncStatus status, + uint8_t* userdata) { + auto* req = reinterpret_cast<MapRequest*>(userdata); + // TODO: better handle errors + MOZ_ASSERT(status == ffi::WGPUBufferMapAsyncStatus_Success); + if (req->mHostMap == ffi::WGPUHostMap_Read) { + const uint8_t* ptr = ffi::wgpu_server_buffer_get_mapped_range( + req->mContext, req->mBufferId, req->mOffset, + req->mShmem.Size<uint8_t>()); + memcpy(req->mShmem.get<uint8_t>(), ptr, req->mShmem.Size<uint8_t>()); + } + req->mResolver(std::move(req->mShmem)); + delete req; +} + +ipc::IPCResult WebGPUParent::RecvBufferMap(RawId aSelfId, + ffi::WGPUHostMap aHostMap, + uint64_t aOffset, uint64_t aSize, + BufferMapResolver&& aResolver) { + auto* request = new MapRequest(mContext, aSelfId, aHostMap, aOffset, + std::move(mSharedMemoryMap[aSelfId]), + std::move(aResolver)); + ffi::WGPUBufferMapOperation mapOperation = { + aHostMap, &MapCallback, reinterpret_cast<uint8_t*>(request)}; + ffi::wgpu_server_buffer_map(mContext, aSelfId, aOffset, aSize, mapOperation); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvBufferUnmap(RawId aSelfId, Shmem&& aShmem, + bool aFlush) { + if (aFlush) { + // TODO: flush exact modified sub-range + uint8_t* ptr = ffi::wgpu_server_buffer_get_mapped_range( + mContext, aSelfId, 0, aShmem.Size<uint8_t>()); + MOZ_ASSERT(ptr != nullptr); + memcpy(ptr, aShmem.get<uint8_t>(), aShmem.Size<uint8_t>()); + } + + ffi::wgpu_server_buffer_unmap(mContext, aSelfId); + + const auto iter = mSharedMemoryMap.find(aSelfId); + if (iter == mSharedMemoryMap.end()) { + DeallocShmem(aShmem); + } else { + iter->second = aShmem; + } + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvBufferDestroy(RawId aSelfId) { + ffi::wgpu_server_buffer_drop(mContext, aSelfId); + + const auto iter = mSharedMemoryMap.find(aSelfId); + if (iter != mSharedMemoryMap.end()) { + DeallocShmem(iter->second); + mSharedMemoryMap.erase(iter); + } + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvTextureDestroy(RawId aSelfId) { + ffi::wgpu_server_texture_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvTextureViewDestroy(RawId aSelfId) { + ffi::wgpu_server_texture_view_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvSamplerDestroy(RawId aSelfId) { + ffi::wgpu_server_sampler_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvCommandEncoderFinish( + RawId aSelfId, RawId aDeviceId, + const dom::GPUCommandBufferDescriptor& aDesc) { + Unused << aDesc; + ffi::WGPUCommandBufferDescriptor desc = {}; + ErrorBuffer error; + ffi::wgpu_server_encoder_finish(mContext, aSelfId, &desc, error.ToFFI()); + + error.CheckAndForward(this, aDeviceId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvCommandEncoderDestroy(RawId aSelfId) { + ffi::wgpu_server_encoder_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvCommandBufferDestroy(RawId aSelfId) { + ffi::wgpu_server_command_buffer_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvQueueSubmit( + RawId aSelfId, const nsTArray<RawId>& aCommandBuffers) { + ffi::wgpu_server_queue_submit(mContext, aSelfId, aCommandBuffers.Elements(), + aCommandBuffers.Length()); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvQueueWriteBuffer(RawId aSelfId, + RawId aBufferId, + uint64_t aBufferOffset, + Shmem&& aShmem) { + ffi::wgpu_server_queue_write_buffer(mContext, aSelfId, aBufferId, + aBufferOffset, aShmem.get<uint8_t>(), + aShmem.Size<uint8_t>()); + DeallocShmem(aShmem); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvQueueWriteTexture( + RawId aSelfId, const ffi::WGPUTextureCopyView& aDestination, Shmem&& aShmem, + const ffi::WGPUTextureDataLayout& aDataLayout, + const ffi::WGPUExtent3d& aExtent) { + ffi::wgpu_server_queue_write_texture( + mContext, aSelfId, &aDestination, aShmem.get<uint8_t>(), + aShmem.Size<uint8_t>(), &aDataLayout, &aExtent); + DeallocShmem(aShmem); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvBindGroupLayoutDestroy(RawId aSelfId) { + ffi::wgpu_server_bind_group_layout_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvPipelineLayoutDestroy(RawId aSelfId) { + ffi::wgpu_server_pipeline_layout_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvBindGroupDestroy(RawId aSelfId) { + ffi::wgpu_server_bind_group_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvShaderModuleDestroy(RawId aSelfId) { + ffi::wgpu_server_shader_module_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvComputePipelineDestroy(RawId aSelfId) { + ffi::wgpu_server_compute_pipeline_drop(mContext, aSelfId); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvRenderPipelineDestroy(RawId aSelfId) { + ffi::wgpu_server_render_pipeline_drop(mContext, aSelfId); + return IPC_OK(); +} + +// TODO: proper destruction +static const uint64_t kBufferAlignment = 0x100; + +static uint64_t Align(uint64_t value) { + return (value | (kBufferAlignment - 1)) + 1; +} + +ipc::IPCResult WebGPUParent::RecvDeviceCreateSwapChain( + RawId aSelfId, RawId aQueueId, const RGBDescriptor& aDesc, + const nsTArray<RawId>& aBufferIds, ExternalImageId aExternalId) { + const auto rows = aDesc.size().height; + const auto bufferStride = + Align(static_cast<uint64_t>(aDesc.size().width) * 4); + const auto textureStride = layers::ImageDataSerializer::GetRGBStride(aDesc); + const auto wholeBufferSize = CheckedInt<size_t>(textureStride) * rows; + if (!wholeBufferSize.isValid()) { + NS_ERROR("Invalid total buffer size!"); + return IPC_OK(); + } + auto* textureHostData = new (fallible) uint8_t[wholeBufferSize.value()]; + if (!textureHostData) { + NS_ERROR("Unable to allocate host data!"); + return IPC_OK(); + } + RefPtr<layers::MemoryTextureHost> textureHost = new layers::MemoryTextureHost( + textureHostData, aDesc, layers::TextureFlags::NO_FLAGS); + textureHost->DisableExternalTextures(); + textureHost->CreateRenderTexture(aExternalId); + nsTArray<RawId> bufferIds(aBufferIds.Clone()); + RefPtr<PresentationData> data = new PresentationData(); + data->mDeviceId = aSelfId; + data->mQueueId = aQueueId; + data->mTextureHost = textureHost; + data->mSourcePitch = bufferStride; + data->mTargetPitch = textureStride; + data->mRowCount = rows; + for (const RawId id : bufferIds) { + data->mUnassignedBufferIds.push_back(id); + } + if (!mCanvasMap.insert({AsUint64(aExternalId), data}).second) { + NS_ERROR("External image is already registered as WebGPU canvas!"); + } + return IPC_OK(); +} + +struct PresentRequest { + const ffi::WGPUGlobal* mContext; + RefPtr<PresentationData> mData; +}; + +static void PresentCallback(ffi::WGPUBufferMapAsyncStatus status, + uint8_t* userdata) { + auto* req = reinterpret_cast<PresentRequest*>(userdata); + PresentationData* data = req->mData.get(); + // get the buffer ID + data->mBuffersLock.Lock(); + RawId bufferId = data->mQueuedBufferIds.back(); + data->mQueuedBufferIds.pop_back(); + data->mAvailableBufferIds.push_back(bufferId); + data->mBuffersLock.Unlock(); + // copy the data + if (status == ffi::WGPUBufferMapAsyncStatus_Success) { + const auto bufferSize = data->mRowCount * data->mSourcePitch; + const uint8_t* ptr = ffi::wgpu_server_buffer_get_mapped_range( + req->mContext, bufferId, 0, bufferSize); + uint8_t* dst = data->mTextureHost->GetBuffer(); + for (uint32_t row = 0; row < data->mRowCount; ++row) { + memcpy(dst, ptr, data->mTargetPitch); + dst += data->mTargetPitch; + ptr += data->mSourcePitch; + } + wgpu_server_buffer_unmap(req->mContext, bufferId); + } else { + // TODO: better handle errors + NS_WARNING("WebGPU frame mapping failed!"); + } + // free yourself + delete req; +} + +ipc::IPCResult WebGPUParent::RecvSwapChainPresent( + wr::ExternalImageId aExternalId, RawId aTextureId, + RawId aCommandEncoderId) { + // step 0: get the data associated with the swapchain + const auto& lookup = mCanvasMap.find(AsUint64(aExternalId)); + if (lookup == mCanvasMap.end()) { + NS_WARNING("WebGPU presenting on a destroyed swap chain!"); + return IPC_OK(); + } + RefPtr<PresentationData> data = lookup->second.get(); + RawId bufferId = 0; + const auto& size = data->mTextureHost->GetSize(); + const auto bufferSize = data->mRowCount * data->mSourcePitch; + + // step 1: find an available staging buffer, or create one + data->mBuffersLock.Lock(); + if (!data->mAvailableBufferIds.empty()) { + bufferId = data->mAvailableBufferIds.back(); + data->mAvailableBufferIds.pop_back(); + } else if (!data->mUnassignedBufferIds.empty()) { + bufferId = data->mUnassignedBufferIds.back(); + data->mUnassignedBufferIds.pop_back(); + + ffi::WGPUBufferUsage usage = + WGPUBufferUsage_COPY_DST | WGPUBufferUsage_MAP_READ; + ffi::WGPUBufferDescriptor desc = {}; + desc.size = bufferSize; + desc.usage = usage; + + ErrorBuffer error; + ffi::wgpu_server_device_create_buffer(mContext, data->mDeviceId, &desc, + bufferId, error.ToFFI()); + if (error.CheckAndForward(this, data->mDeviceId)) { + return IPC_OK(); + } + } else { + bufferId = 0; + } + if (bufferId) { + data->mQueuedBufferIds.insert(data->mQueuedBufferIds.begin(), bufferId); + } + data->mBuffersLock.Unlock(); + if (!bufferId) { + // TODO: add a warning - no buffer are available! + return IPC_OK(); + } + + // step 3: submit a copy command for the frame + ffi::WGPUCommandEncoderDescriptor encoderDesc = {}; + { + ErrorBuffer error; + ffi::wgpu_server_device_create_encoder(mContext, data->mDeviceId, + &encoderDesc, aCommandEncoderId, + error.ToFFI()); + if (error.CheckAndForward(this, data->mDeviceId)) { + return IPC_OK(); + } + } + + const ffi::WGPUTextureCopyView texView = { + aTextureId, + }; + const ffi::WGPUTextureDataLayout bufLayout = { + 0, + data->mSourcePitch, + 0, + }; + const ffi::WGPUBufferCopyView bufView = { + bufferId, + bufLayout, + }; + const ffi::WGPUExtent3d extent = { + static_cast<uint32_t>(size.width), + static_cast<uint32_t>(size.height), + 1, + }; + ffi::wgpu_server_encoder_copy_texture_to_buffer(mContext, aCommandEncoderId, + &texView, &bufView, &extent); + ffi::WGPUCommandBufferDescriptor commandDesc = {}; + { + ErrorBuffer error; + ffi::wgpu_server_encoder_finish(mContext, aCommandEncoderId, &commandDesc, + error.ToFFI()); + if (error.CheckAndForward(this, data->mDeviceId)) { + return IPC_OK(); + } + } + + ffi::wgpu_server_queue_submit(mContext, data->mQueueId, &aCommandEncoderId, + 1); + + // step 4: request the pixels to be copied into the external texture + // TODO: this isn't strictly necessary. When WR wants to Lock() the external + // texture, + // we can just give it the contents of the last mapped buffer instead of the + // copy. + auto* const presentRequest = new PresentRequest{ + mContext, + data, + }; + + ffi::WGPUBufferMapOperation mapOperation = { + ffi::WGPUHostMap_Read, &PresentCallback, + reinterpret_cast<uint8_t*>(presentRequest)}; + ffi::wgpu_server_buffer_map(mContext, bufferId, 0, bufferSize, mapOperation); + + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvSwapChainDestroy( + wr::ExternalImageId aExternalId) { + const auto& lookup = mCanvasMap.find(AsUint64(aExternalId)); + MOZ_ASSERT(lookup != mCanvasMap.end()); + RefPtr<PresentationData> data = lookup->second.get(); + mCanvasMap.erase(AsUint64(aExternalId)); + data->mTextureHost = nullptr; + layers::TextureHost::DestroyRenderTexture(aExternalId); + + data->mBuffersLock.Lock(); + for (const auto bid : data->mUnassignedBufferIds) { + if (!SendFreeBuffer(bid)) { + NS_WARNING("Unable to free an ID for non-assigned buffer"); + } + } + for (const auto bid : data->mAvailableBufferIds) { + ffi::wgpu_server_buffer_drop(mContext, bid); + } + for (const auto bid : data->mQueuedBufferIds) { + ffi::wgpu_server_buffer_drop(mContext, bid); + } + data->mBuffersLock.Unlock(); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvShutdown() { + mTimer.Stop(); + for (const auto& p : mCanvasMap) { + const wr::ExternalImageId extId = {p.first}; + layers::TextureHost::DestroyRenderTexture(extId); + } + mCanvasMap.clear(); + ffi::wgpu_server_poll_all_devices(mContext, true); + ffi::wgpu_server_delete(const_cast<ffi::WGPUGlobal*>(mContext)); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvDeviceAction(RawId aSelf, + const ipc::ByteBuf& aByteBuf) { + ipc::ByteBuf byteBuf; + ErrorBuffer error; + ffi::wgpu_server_device_action(mContext, aSelf, ToFFI(&aByteBuf), + ToFFI(&byteBuf), error.ToFFI()); + + if (byteBuf.mData) { + if (!SendDropAction(std::move(byteBuf))) { + NS_WARNING("Unable to set a drop action!"); + } + } + + error.CheckAndForward(this, aSelf); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvTextureAction(RawId aSelf, RawId aDevice, + const ipc::ByteBuf& aByteBuf) { + ErrorBuffer error; + ffi::wgpu_server_texture_action(mContext, aSelf, ToFFI(&aByteBuf), + error.ToFFI()); + + error.CheckAndForward(this, aDevice); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvCommandEncoderAction( + RawId aSelf, RawId aDevice, const ipc::ByteBuf& aByteBuf) { + ErrorBuffer error; + ffi::wgpu_server_command_encoder_action(mContext, aSelf, ToFFI(&aByteBuf), + error.ToFFI()); + error.CheckAndForward(this, aDevice); + return IPC_OK(); +} + +ipc::IPCResult WebGPUParent::RecvBumpImplicitBindGroupLayout(RawId aPipelineId, + bool aIsCompute, + uint32_t aIndex, + RawId aAssignId) { + ErrorBuffer error; + if (aIsCompute) { + ffi::wgpu_server_compute_pipeline_get_bind_group_layout( + mContext, aPipelineId, aIndex, aAssignId, error.ToFFI()); + } else { + ffi::wgpu_server_render_pipeline_get_bind_group_layout( + mContext, aPipelineId, aIndex, aAssignId, error.ToFFI()); + } + + error.CheckAndForward(this, 0); + return IPC_OK(); +} + +} // namespace webgpu +} // namespace mozilla |