diff --git a/dawn.json b/dawn.json index 1ef3fc19e9..884b5e6451 100644 --- a/dawn.json +++ b/dawn.json @@ -49,16 +49,14 @@ "request adapter options": { "category": "structure", "extensible": "in", - "tags": ["upstream"], "members": [ - {"name": "compatible surface", "type": "surface"}, - {"name": "power preference", "type": "power preference", "tags": ["upstream"]}, - {"name": "force fallback adapter", "type": "bool", "tags": ["upstream"]} + {"name": "compatible surface", "type": "surface", "optional": true}, + {"name": "power preference", "type": "power preference", "default": "undefined"}, + {"name": "force fallback adapter", "type": "bool", "default": "false"} ] }, "request adapter status": { "category": "enum", - "tags": ["upstream"], "emscripten_no_enum_table": true, "values": [ {"value": 0, "name": "success"}, @@ -69,29 +67,25 @@ }, "request adapter callback": { "category": "function pointer", - "tags": ["upstream"], "args": [ {"name": "status", "type": "request adapter status"}, {"name": "adapter", "type": "adapter"}, - {"name": "message", "type": "char", "annotation": "const*"}, + {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}, {"name": "userdata", "type": "void", "annotation": "*"} ] }, "adapter": { "category": "object", - "tags": ["upstream"], "methods": [ { "name": "get limits", "returns": "bool", - "tags": ["upstream"], "args": [ {"name": "limits", "type": "supported limits", "annotation": "*"} ] }, { "name": "get properties", - "tags": ["upstream"], "args": [ {"name": "properties", "type": "adapter properties", "annotation": "*"} ] @@ -99,7 +93,6 @@ { "name": "has feature", "returns": "bool", - "tags": ["upstream"], "args": [ {"name": "feature", "type": "feature name"} ] @@ -139,13 +132,11 @@ "device descriptor": { "category": "structure", "extensible": "in", - "tags": ["upstream"], - "_TODO": "Add requiredFeatures and requiredLimits support", "members": [ {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}, - {"name": "required features count", "type": "uint32_t"}, - {"name": "required features", "type": "feature name", "annotation": "const*", "length": "required features count"}, - {"name": "required limits", "type": "required limits", "annotation": "const*"} + {"name": "required features count", "type": "uint32_t", "default": 0}, + {"name": "required features", "type": "feature name", "annotation": "const*", "length": "required features count", "default": "nullptr"}, + {"name": "required limits", "type": "required limits", "annotation": "const*", "optional": true} ] }, "address mode": { @@ -1295,7 +1286,6 @@ }, "feature name": { "category": "enum", - "tags": ["upstream"], "values": [ {"value": 0, "name": "undefined", "jsrepr": "undefined"}, {"value": 1, "name": "depth clip control", "tags": ["upstream"]}, @@ -1369,7 +1359,6 @@ }, { "name": "request adapter", - "tags": ["upstream"], "args": [ {"name": "options", "type": "request adapter options", "annotation": "const*"}, {"name": "callback", "type": "request adapter callback"}, @@ -1475,7 +1464,6 @@ }, "power preference": { "category": "enum", - "tags": ["upstream"], "values": [ {"value": 0, "name": "undefined"}, {"value": 1, "name": "low power"}, @@ -1994,7 +1982,7 @@ "args": [ {"name": "status", "type": "request device status"}, {"name": "device", "type": "device"}, - {"name": "message", "type": "char", "annotation": "const*"}, + {"name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}, {"name": "userdata", "type": "void", "annotation": "*"} ] }, diff --git a/dawn_wire.json b/dawn_wire.json index 41abdd8a62..50837517c1 100644 --- a/dawn_wire.json +++ b/dawn_wire.json @@ -148,6 +148,10 @@ "SurfaceDescriptorFromWindowsSwapChainPanel" ], "client_side_commands": [ + "AdapterGetProperties", + "AdapterGetLimits", + "AdapterHasFeature", + "AdapterRequestDevice", "BufferMapAsync", "BufferGetConstMappedRange", "BufferGetMappedRange", @@ -159,6 +163,7 @@ "DeviceSetDeviceLostCallback", "DeviceSetUncapturedErrorCallback", "DeviceSetLoggingCallback", + "InstanceRequestAdapter", "ShaderModuleGetCompilationInfo", "QueueOnSubmittedWorkDone", "QueueWriteBuffer", @@ -173,8 +178,10 @@ "DevicePushErrorScope" ], "client_special_objects": [ + "Adapter", "Buffer", "Device", + "Instance", "Queue", "ShaderModule" ], diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h index f9b6bf6df1..d54dcc3349 100644 --- a/generator/templates/api_cpp.h +++ b/generator/templates/api_cpp.h @@ -140,7 +140,7 @@ namespace {{metadata.namespace}} { }; {% macro render_cpp_default_value(member, is_struct=True) -%} - {%- if member.annotation in ["*", "const*"] and member.optional -%} + {%- if member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%} {{" "}}= nullptr {%- elif member.type.category == "object" and member.optional and is_struct -%} {{" "}}= nullptr diff --git a/generator/templates/dawn_native/wgpu_structs.h b/generator/templates/dawn_native/wgpu_structs.h index acaed3a853..2249540788 100644 --- a/generator/templates/dawn_native/wgpu_structs.h +++ b/generator/templates/dawn_native/wgpu_structs.h @@ -21,7 +21,7 @@ namespace dawn_native { {% macro render_cpp_default_value(member) -%} - {%- if member.annotation in ["*", "const*"] and member.optional -%} + {%- if member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%} {{" "}}= nullptr {%- elif member.type.category == "object" and member.optional -%} {{" "}}= nullptr diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp index 77082d7071..c3ac8de5e1 100644 --- a/src/dawn_native/Adapter.cpp +++ b/src/dawn_native/Adapter.cpp @@ -69,6 +69,29 @@ namespace dawn_native { return {}; } + bool AdapterBase::APIGetLimits(SupportedLimits* limits) const { + return GetLimits(limits); + } + + void AdapterBase::APIGetProperties(AdapterProperties* properties) const { + properties->vendorID = mPCIInfo.vendorId; + properties->deviceID = mPCIInfo.deviceId; + properties->name = mPCIInfo.name.c_str(); + properties->driverDescription = mDriverDescription.c_str(); + properties->adapterType = mAdapterType; + properties->backendType = mBackend; + } + + bool AdapterBase::APIHasFeature(wgpu::FeatureName feature) const { + return mSupportedFeatures.IsEnabled(feature); + } + + void AdapterBase::APIRequestDevice(const DeviceDescriptor* descriptor, + WGPURequestDeviceCallback callback, + void* userdata) { + callback(WGPURequestDeviceStatus_Error, nullptr, "Not implemented", userdata); + } + wgpu::BackendType AdapterBase::GetBackendType() const { return mBackend; } diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h index 1b9286e873..36930db1eb 100644 --- a/src/dawn_native/Adapter.h +++ b/src/dawn_native/Adapter.h @@ -17,6 +17,7 @@ #include "dawn_native/DawnNative.h" +#include "common/RefCounted.h" #include "dawn_native/Error.h" #include "dawn_native/Features.h" #include "dawn_native/Limits.h" @@ -28,13 +29,21 @@ namespace dawn_native { class DeviceBase; - class AdapterBase { + class AdapterBase : public RefCounted { public: AdapterBase(InstanceBase* instance, wgpu::BackendType backend); virtual ~AdapterBase() = default; MaybeError Initialize(); + // WebGPU API + bool APIGetLimits(SupportedLimits* limits) const; + void APIGetProperties(AdapterProperties* properties) const; + bool APIHasFeature(wgpu::FeatureName feature) const; + void APIRequestDevice(const DeviceDescriptor* descriptor, + WGPURequestDeviceCallback callback, + void* userdata); + wgpu::BackendType GetBackendType() const; wgpu::AdapterType GetAdapterType() const; const std::string& GetDriverDescription() const; diff --git a/src/dawn_native/Features.cpp b/src/dawn_native/Features.cpp index b09caf20b1..ad427d3455 100644 --- a/src/dawn_native/Features.cpp +++ b/src/dawn_native/Features.cpp @@ -85,6 +85,34 @@ namespace dawn_native { "https://bugs.chromium.org/p/dawn/issues/detail?id=551"}, &WGPUDeviceProperties::multiPlanarFormats}}}; + Feature FromAPIFeature(wgpu::FeatureName feature) { + switch (feature) { + case wgpu::FeatureName::Undefined: + return Feature::InvalidEnum; + + case wgpu::FeatureName::TimestampQuery: + return Feature::TimestampQuery; + case wgpu::FeatureName::PipelineStatisticsQuery: + return Feature::PipelineStatisticsQuery; + case wgpu::FeatureName::TextureCompressionBC: + return Feature::TextureCompressionBC; + case wgpu::FeatureName::TextureCompressionETC2: + return Feature::TextureCompressionETC2; + case wgpu::FeatureName::TextureCompressionASTC: + return Feature::TextureCompressionASTC; + case wgpu::FeatureName::DepthClamping: + return Feature::DepthClamping; + case wgpu::FeatureName::Depth24UnormStencil8: + return Feature::Depth24UnormStencil8; + case wgpu::FeatureName::Depth32FloatStencil8: + return Feature::Depth32FloatStencil8; + + case wgpu::FeatureName::IndirectFirstInstance: + return Feature::InvalidEnum; + } + return Feature::InvalidEnum; + } + } // anonymous namespace void FeaturesSet::EnableFeature(Feature feature) { @@ -99,6 +127,11 @@ namespace dawn_native { return featuresBitSet[featureIndex]; } + bool FeaturesSet::IsEnabled(wgpu::FeatureName feature) const { + Feature f = FromAPIFeature(feature); + return f != Feature::InvalidEnum && IsEnabled(f); + } + std::vector FeaturesSet::GetEnabledFeatureNames() const { std::vector enabledFeatureNames(featuresBitSet.count()); diff --git a/src/dawn_native/Features.h b/src/dawn_native/Features.h index 699ddc794e..4c4a79aad7 100644 --- a/src/dawn_native/Features.h +++ b/src/dawn_native/Features.h @@ -19,6 +19,7 @@ #include #include +#include "dawn/webgpu_cpp.h" #include "dawn_native/DawnNative.h" namespace dawn_native { @@ -50,6 +51,7 @@ namespace dawn_native { void EnableFeature(Feature feature); bool IsEnabled(Feature feature) const; + bool IsEnabled(wgpu::FeatureName feature) const; std::vector GetEnabledFeatureNames() const; void InitializeDeviceProperties(WGPUDeviceProperties* properties) const; }; diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp index ce0d85bc42..d8e107f8f7 100644 --- a/src/dawn_native/Instance.cpp +++ b/src/dawn_native/Instance.cpp @@ -99,6 +99,12 @@ namespace dawn_native { return true; } + void InstanceBase::APIRequestAdapter(const RequestAdapterOptions* options, + WGPURequestAdapterCallback callback, + void* userdata) { + callback(WGPURequestAdapterStatus_Error, nullptr, "Not implemented", userdata); + } + void InstanceBase::DiscoverDefaultAdapters() { for (wgpu::BackendType b : IterateBitSet(GetEnabledBackends())) { EnsureBackendConnection(b); diff --git a/src/dawn_native/Instance.h b/src/dawn_native/Instance.h index a636875b25..a36255aa62 100644 --- a/src/dawn_native/Instance.h +++ b/src/dawn_native/Instance.h @@ -45,6 +45,10 @@ namespace dawn_native { public: static InstanceBase* Create(const InstanceDescriptor* descriptor = nullptr); + void APIRequestAdapter(const RequestAdapterOptions* options, + WGPURequestAdapterCallback callback, + void* userdata); + void DiscoverDefaultAdapters(); bool DiscoverAdapters(const AdapterDiscoveryOptionsBase* options); diff --git a/src/dawn_wire/BUILD.gn b/src/dawn_wire/BUILD.gn index b678fa10b5..4137652a5a 100644 --- a/src/dawn_wire/BUILD.gn +++ b/src/dawn_wire/BUILD.gn @@ -71,6 +71,8 @@ dawn_component("dawn_wire") { "WireDeserializeAllocator.h", "WireResult.h", "WireServer.cpp", + "client/Adapter.cpp", + "client/Adapter.h", "client/ApiObjects.h", "client/Buffer.cpp", "client/Buffer.h", @@ -80,6 +82,8 @@ dawn_component("dawn_wire") { "client/ClientInlineMemoryTransferService.cpp", "client/Device.cpp", "client/Device.h", + "client/Instance.cpp", + "client/Instance.h", "client/ObjectAllocator.h", "client/Queue.cpp", "client/Queue.h", diff --git a/src/dawn_wire/CMakeLists.txt b/src/dawn_wire/CMakeLists.txt index e970367758..8ba7571f0c 100644 --- a/src/dawn_wire/CMakeLists.txt +++ b/src/dawn_wire/CMakeLists.txt @@ -43,6 +43,8 @@ target_sources(dawn_wire PRIVATE "WireDeserializeAllocator.h" "WireResult.h" "WireServer.cpp" + "client/Adapter.cpp" + "client/Adapter.h" "client/ApiObjects.h" "client/Buffer.cpp" "client/Buffer.h" @@ -52,6 +54,8 @@ target_sources(dawn_wire PRIVATE "client/ClientInlineMemoryTransferService.cpp" "client/Device.cpp" "client/Device.h" + "client/Instance.cpp" + "client/Instance.h" "client/ObjectAllocator.h" "client/Queue.cpp" "client/Queue.h" diff --git a/src/dawn_wire/WireClient.cpp b/src/dawn_wire/WireClient.cpp index 01ab45beab..a23e2f7d45 100644 --- a/src/dawn_wire/WireClient.cpp +++ b/src/dawn_wire/WireClient.cpp @@ -41,6 +41,10 @@ namespace dawn_wire { return mImpl->ReserveDevice(); } + ReservedInstance WireClient::ReserveInstance() { + return mImpl->ReserveInstance(); + } + void WireClient::ReclaimTextureReservation(const ReservedTexture& reservation) { mImpl->ReclaimTextureReservation(reservation); } @@ -53,6 +57,10 @@ namespace dawn_wire { mImpl->ReclaimDeviceReservation(reservation); } + void WireClient::ReclaimInstanceReservation(const ReservedInstance& reservation) { + mImpl->ReclaimInstanceReservation(reservation); + } + void WireClient::Disconnect() { mImpl->Disconnect(); } diff --git a/src/dawn_wire/WireServer.cpp b/src/dawn_wire/WireServer.cpp index bad595760b..c998e447d1 100644 --- a/src/dawn_wire/WireServer.cpp +++ b/src/dawn_wire/WireServer.cpp @@ -51,6 +51,10 @@ namespace dawn_wire { return mImpl->InjectDevice(device, id, generation); } + bool WireServer::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) { + return mImpl->InjectInstance(instance, id, generation); + } + WGPUDevice WireServer::GetDevice(uint32_t id, uint32_t generation) { return mImpl->GetDevice(id, generation); } diff --git a/src/dawn_wire/client/Adapter.cpp b/src/dawn_wire/client/Adapter.cpp new file mode 100644 index 0000000000..ee789f9cdd --- /dev/null +++ b/src/dawn_wire/client/Adapter.cpp @@ -0,0 +1,37 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_wire/client/Adapter.h" + +namespace dawn_wire { namespace client { + + bool Adapter::GetLimits(WGPUSupportedLimits* limits) const { + UNREACHABLE(); + } + + void Adapter::GetProperties(WGPUAdapterProperties* properties) const { + UNREACHABLE(); + } + + bool Adapter::HasFeature(WGPUFeatureName feature) const { + UNREACHABLE(); + } + + void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor, + WGPURequestDeviceCallback callback, + void* userdata) { + callback(WGPURequestDeviceStatus_Error, nullptr, "Not implemented", nullptr); + } + +}} // namespace dawn_wire::client diff --git a/src/dawn_wire/client/Adapter.h b/src/dawn_wire/client/Adapter.h new file mode 100644 index 0000000000..d9392204bd --- /dev/null +++ b/src/dawn_wire/client/Adapter.h @@ -0,0 +1,39 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNWIRE_CLIENT_ADAPTER_H_ +#define DAWNWIRE_CLIENT_ADAPTER_H_ + +#include + +#include "dawn_wire/WireClient.h" +#include "dawn_wire/client/ObjectBase.h" + +namespace dawn_wire { namespace client { + + class Adapter final : public ObjectBase { + public: + using ObjectBase::ObjectBase; + + bool GetLimits(WGPUSupportedLimits* limits) const; + void GetProperties(WGPUAdapterProperties* properties) const; + bool HasFeature(WGPUFeatureName feature) const; + void RequestDevice(const WGPUDeviceDescriptor* descriptor, + WGPURequestDeviceCallback callback, + void* userdata); + }; + +}} // namespace dawn_wire::client + +#endif // DAWNWIRE_CLIENT_ADAPTER_H_ diff --git a/src/dawn_wire/client/ApiObjects.h b/src/dawn_wire/client/ApiObjects.h index 71dbc82dfe..cfe4cb5278 100644 --- a/src/dawn_wire/client/ApiObjects.h +++ b/src/dawn_wire/client/ApiObjects.h @@ -17,8 +17,10 @@ #include "dawn_wire/client/ObjectBase.h" +#include "dawn_wire/client/Adapter.h" #include "dawn_wire/client/Buffer.h" #include "dawn_wire/client/Device.h" +#include "dawn_wire/client/Instance.h" #include "dawn_wire/client/Queue.h" #include "dawn_wire/client/ShaderModule.h" diff --git a/src/dawn_wire/client/Client.cpp b/src/dawn_wire/client/Client.cpp index 2d4445e794..628232d391 100644 --- a/src/dawn_wire/client/Client.cpp +++ b/src/dawn_wire/client/Client.cpp @@ -118,6 +118,16 @@ namespace dawn_wire { namespace client { return result; } + ReservedInstance Client::ReserveInstance() { + auto* allocation = InstanceAllocator().New(this); + + ReservedInstance result; + result.instance = ToAPI(allocation->object.get()); + result.id = allocation->object->id; + result.generation = allocation->generation; + return result; + } + void Client::ReclaimTextureReservation(const ReservedTexture& reservation) { TextureAllocator().Free(FromAPI(reservation.texture)); } @@ -130,6 +140,10 @@ namespace dawn_wire { namespace client { DeviceAllocator().Free(FromAPI(reservation.device)); } + void Client::ReclaimInstanceReservation(const ReservedInstance& reservation) { + InstanceAllocator().Free(FromAPI(reservation.instance)); + } + void Client::Disconnect() { mDisconnected = true; mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance()); diff --git a/src/dawn_wire/client/Client.h b/src/dawn_wire/client/Client.h index fc3758a0d8..aebf9535b9 100644 --- a/src/dawn_wire/client/Client.h +++ b/src/dawn_wire/client/Client.h @@ -47,10 +47,12 @@ namespace dawn_wire { namespace client { ReservedTexture ReserveTexture(WGPUDevice device); ReservedSwapChain ReserveSwapChain(WGPUDevice device); ReservedDevice ReserveDevice(); + ReservedInstance ReserveInstance(); void ReclaimTextureReservation(const ReservedTexture& reservation); void ReclaimSwapChainReservation(const ReservedSwapChain& reservation); void ReclaimDeviceReservation(const ReservedDevice& reservation); + void ReclaimInstanceReservation(const ReservedInstance& reservation); template void SerializeCommand(const Cmd& cmd) { diff --git a/src/dawn_wire/client/Instance.cpp b/src/dawn_wire/client/Instance.cpp new file mode 100644 index 0000000000..74d0517e9f --- /dev/null +++ b/src/dawn_wire/client/Instance.cpp @@ -0,0 +1,25 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dawn_wire/client/Instance.h" + +namespace dawn_wire { namespace client { + + void Instance::RequestAdapter(const WGPURequestAdapterOptions* options, + WGPURequestAdapterCallback callback, + void* userdata) { + callback(WGPURequestAdapterStatus_Error, nullptr, "Not implemented", nullptr); + } + +}} // namespace dawn_wire::client diff --git a/src/dawn_wire/client/Instance.h b/src/dawn_wire/client/Instance.h new file mode 100644 index 0000000000..3d55ac9a6d --- /dev/null +++ b/src/dawn_wire/client/Instance.h @@ -0,0 +1,36 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DAWNWIRE_CLIENT_INSTANCE_H_ +#define DAWNWIRE_CLIENT_INSTANCE_H_ + +#include + +#include "dawn_wire/WireClient.h" +#include "dawn_wire/client/ObjectBase.h" + +namespace dawn_wire { namespace client { + + class Instance final : public ObjectBase { + public: + using ObjectBase::ObjectBase; + + void RequestAdapter(const WGPURequestAdapterOptions* options, + WGPURequestAdapterCallback callback, + void* userdata); + }; + +}} // namespace dawn_wire::client + +#endif // DAWNWIRE_CLIENT_INSTANCE_H_ diff --git a/src/dawn_wire/server/Server.cpp b/src/dawn_wire/server/Server.cpp index 8297cbdcf4..a4dbd8c8be 100644 --- a/src/dawn_wire/server/Server.cpp +++ b/src/dawn_wire/server/Server.cpp @@ -153,6 +153,24 @@ namespace dawn_wire { namespace server { return true; } + bool Server::InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation) { + ASSERT(instance != nullptr); + ObjectData* data = InstanceObjects().Allocate(id); + if (data == nullptr) { + return false; + } + + data->handle = instance; + data->generation = generation; + data->state = AllocationState::Allocated; + + // The instance is externally owned so it shouldn't be destroyed when we receive a destroy + // message from the client. Add a reference to counterbalance the eventual release. + mProcs.instanceReference(instance); + + return true; + } + WGPUDevice Server::GetDevice(uint32_t id, uint32_t generation) { ObjectData* data = DeviceObjects().Get(id); if (data == nullptr || data->generation != generation) { diff --git a/src/dawn_wire/server/Server.h b/src/dawn_wire/server/Server.h index b4429871f7..33b0e04abc 100644 --- a/src/dawn_wire/server/Server.h +++ b/src/dawn_wire/server/Server.h @@ -171,6 +171,8 @@ namespace dawn_wire { namespace server { bool InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation); + bool InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation); + WGPUDevice GetDevice(uint32_t id, uint32_t generation); template ReserveInstance(); + + WGPUInstance serverInstance = api.GetNewInstance(); + EXPECT_CALL(api, InstanceReference(serverInstance)); + ASSERT_TRUE( + GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); + + WGPUSurfaceDescriptor surfaceDesc = {}; + wgpuInstanceCreateSurface(reservation.instance, &surfaceDesc); + WGPUSurface serverSurface = api.GetNewSurface(); + EXPECT_CALL(api, InstanceCreateSurface(serverInstance, NotNull())).WillOnce(Return(serverSurface)); + FlushClient(); + } + + // Test that reserve correctly returns different IDs each time. + TEST_F(WireInjectInstanceTests, ReserveDifferentIDs) { + ReservedInstance reservation1 = GetWireClient()->ReserveInstance(); + ReservedInstance reservation2 = GetWireClient()->ReserveInstance(); + + ASSERT_NE(reservation1.id, reservation2.id); + ASSERT_NE(reservation1.instance, reservation2.instance); + } + + + // Test that injecting the same id fails. + TEST_F(WireInjectInstanceTests, InjectExistingID) { + ReservedInstance reservation = GetWireClient()->ReserveInstance(); + + WGPUInstance serverInstance = api.GetNewInstance(); + EXPECT_CALL(api, InstanceReference(serverInstance)); + ASSERT_TRUE( + GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); + + // ID already in use, call fails. + ASSERT_FALSE( + GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); + } + + // Test that the server only borrows the instance and does a single reference-release + TEST_F(WireInjectInstanceTests, InjectedInstanceLifetime) { + ReservedInstance reservation = GetWireClient()->ReserveInstance(); + + // Injecting the instance adds a reference + WGPUInstance serverInstance = api.GetNewInstance(); + EXPECT_CALL(api, InstanceReference(serverInstance)); + ASSERT_TRUE( + GetWireServer()->InjectInstance(serverInstance, reservation.id, reservation.generation)); + + // Releasing the instance removes a single reference. + wgpuInstanceRelease(reservation.instance); + EXPECT_CALL(api, InstanceRelease(serverInstance)); + FlushClient(); + + // Deleting the server doesn't release a second reference. + DeleteServer(); + Mock::VerifyAndClearExpectations(&api); + } + + // Test that a device reservation can be reclaimed. This is necessary to + // avoid leaking ObjectIDs for reservations that are never injected. + TEST_F(WireInjectInstanceTests, ReclaimInstanceReservation) { + // Test that doing a reservation and full release is an error. + { + ReservedInstance reservation = GetWireClient()->ReserveInstance(); + wgpuInstanceRelease(reservation.instance); + FlushClient(false); + } + + // Test that doing a reservation and then reclaiming it recycles the ID. + { + ReservedInstance reservation1 = GetWireClient()->ReserveInstance(); + GetWireClient()->ReclaimInstanceReservation(reservation1); + + ReservedInstance reservation2 = GetWireClient()->ReserveInstance(); + + // The ID is the same, but the generation is still different. + ASSERT_EQ(reservation1.id, reservation2.id); + ASSERT_NE(reservation1.generation, reservation2.generation); + + // No errors should occur. + FlushClient(); + } + } + +} // anonymous namespace