| // Copyright 2019 The Dawn & Tint Authors | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are met: | |
| // | |
| // 1. Redistributions of source code must retain the above copyright notice, this | |
| // list of conditions and the following disclaimer. | |
| // | |
| // 2. Redistributions in binary form must reproduce the above copyright notice, | |
| // this list of conditions and the following disclaimer in the documentation | |
| // and/or other materials provided with the distribution. | |
| // | |
| // 3. Neither the name of the copyright holder nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| #include "src/dawn/wire/client/Client.h" | |
| #include <vector> | |
| #include "src/dawn/common/Compiler.h" | |
| #include "src/dawn/common/StringViewUtils.h" | |
| #include "src/dawn/wire/client/ClientInlineMemoryTransferService.h" | |
| #include "src/dawn/wire/client/Device.h" | |
| namespace dawn::wire::client { | |
| namespace { | |
| class NoopCommandSerializer final : public CommandSerializer { | |
| public: | |
| static NoopCommandSerializer* GetInstance() { | |
| static NoopCommandSerializer gNoopCommandSerializer; | |
| return &gNoopCommandSerializer; | |
| } | |
| ~NoopCommandSerializer() override = default; | |
| size_t GetMaximumAllocationSize() const final { | |
| // Return SIZE_MAX so ChunkedCommandSerializer won't unnecessarily try to chunk commands. | |
| return SIZE_MAX; | |
| } | |
| std::optional<std::span<volatile std::byte>> GetCommandSpace(size_t size) final { | |
| return std::nullopt; | |
| } | |
| bool Flush() final { return false; } | |
| }; | |
| } // anonymous namespace | |
| Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService) | |
| : ClientBase(), mSerializer(serializer), mMemoryTransferService(memoryTransferService) { | |
| if (mMemoryTransferService == nullptr) { | |
| // If a MemoryTransferService is not provided, fall back to inline memory. | |
| mOwnedMemoryTransferService = CreateInlineMemoryTransferService(); | |
| mMemoryTransferService = mOwnedMemoryTransferService.get(); | |
| } | |
| } | |
| Client::~Client() { | |
| // Keep a strong reference to all Instance objects during event manager teardown and object | |
| // unregistration. This prevents Instance (and its EventManager) from being destructed while | |
| // event callbacks are executing or before UnregisterAllObjects has set mClient = nullptr on all | |
| // client objects. | |
| std::vector<Ref<Instance>> instances; | |
| for (auto object : mObjects[ObjectType::Instance].GetAllObjects()) { | |
| if (object != nullptr) { | |
| instances.push_back(static_cast<Instance*>(object)); | |
| } | |
| } | |
| for (auto& instance : instances) { | |
| instance->GetEventManager().Destroy(); | |
| } | |
| UnregisterAllObjects(); | |
| } | |
| void Client::UnregisterAllObjects() { | |
| for (auto& objectList : mObjects) { | |
| for (auto object : objectList.GetAllObjects()) { | |
| if (object != nullptr) { | |
| object->Unregister(); | |
| } | |
| } | |
| } | |
| } | |
| ReservedBuffer Client::ReserveBuffer(Device* device, const BufferDescriptor* descriptor) { | |
| Ref<Buffer> buffer = Make<Buffer>(device->GetInstance(), device, descriptor); | |
| ReservedBuffer result; | |
| result.handle = buffer->GetWireHandle(this); | |
| result.deviceHandle = device->GetWireHandle(this); | |
| result.buffer = ToAPI(ReturnToAPI2(std::move(buffer))); | |
| return result; | |
| } | |
| ReservedTexture Client::ReserveTexture(Device* device, const TextureDescriptor* descriptor) { | |
| Ref<Texture> texture = Make<Texture>(device, descriptor); | |
| ReservedTexture result; | |
| result.handle = texture->GetWireHandle(this); | |
| result.deviceHandle = device->GetWireHandle(this); | |
| result.texture = ToAPI(ReturnToAPI2(std::move(texture))); | |
| return result; | |
| } | |
| ReservedSurface Client::ReserveSurface(Instance* instance, | |
| const SurfaceCapabilities* capabilities) { | |
| Ref<Surface> surface = Make<Surface>(capabilities); | |
| ReservedSurface result; | |
| result.handle = surface->GetWireHandle(this); | |
| result.instanceHandle = instance->GetWireHandle(this); | |
| result.surface = ToAPI(ReturnToAPI2(std::move(surface))); | |
| return result; | |
| } | |
| ReservedInstance Client::ReserveInstance(const InstanceDescriptor* descriptor) { | |
| Ref<Instance> instance = Make<Instance>(); | |
| if (instance->Initialize(descriptor) != WireResult::Success) { | |
| return {nullptr, {0, 0}}; | |
| } | |
| ReservedInstance result; | |
| result.handle = instance->GetWireHandle(this); | |
| result.instance = ToAPI(ReturnToAPI2(std::move(instance))); | |
| return result; | |
| } | |
| void Client::ReclaimBufferReservation(const ReservedBuffer& reservation) { | |
| ReclaimReservation(FromAPI(reservation.buffer)); | |
| } | |
| void Client::ReclaimTextureReservation(const ReservedTexture& reservation) { | |
| ReclaimReservation(FromAPI(reservation.texture)); | |
| } | |
| void Client::ReclaimSurfaceReservation(const ReservedSurface& reservation) { | |
| ReclaimReservation(FromAPI(reservation.surface)); | |
| } | |
| void Client::ReclaimInstanceReservation(const ReservedInstance& reservation) { | |
| ReclaimReservation(FromAPI(reservation.instance)); | |
| } | |
| void Client::Disconnect() { | |
| mDisconnected = true; | |
| mSerializer.SetCommandSerializerForDisconnect(NoopCommandSerializer::GetInstance()); | |
| // Destroy all event managers. | |
| for (auto object : mObjects[ObjectType::Instance].GetAllObjects()) { | |
| if (object != nullptr) { | |
| Ref<Instance> instance = static_cast<Instance*>(object); | |
| instance->GetEventManager().Destroy(); | |
| } | |
| } | |
| for (auto object : mObjects[ObjectType::Device].GetAllObjects()) { | |
| if (object != nullptr) { | |
| static_cast<Device*>(object)->HandleDeviceLost(wgpu::DeviceLostReason::Unknown, | |
| "GPU connection lost"); | |
| } | |
| } | |
| } | |
| bool Client::IsDisconnected() const { | |
| return mDisconnected; | |
| } | |
| void Client::Unregister(ObjectBase* obj, ObjectType type) { | |
| UnregisterObjectCmd cmd; | |
| cmd.objectType = type; | |
| cmd.objectId = obj->GetWireHandle(this).id; | |
| SerializeCommand(std::move(cmd)); | |
| ReclaimReservation(obj, type); | |
| } | |
| void Client::ReclaimReservation(ObjectBase* obj, ObjectType type) { | |
| mObjects[type].Remove(obj, this); | |
| } | |
| } // namespace dawn::wire::client |