dawn_wire: Implement requestAdapter and requestDevice
This implements requestAdapter and requestDevice by
forwarding commands the the server and relaying back
replies. After an adapter or device is created,
limits/properties/features are queried and also sent
back to the client.
Bug: dawn:689
Change-Id: Ie0c2984b8ebb661efb0c284a14ae8b74ae4af2ea
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71522
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/dawn_wire.json b/dawn_wire.json
index 4bd03a1..497a0eb 100644
--- a/dawn_wire.json
+++ b/dawn_wire.json
@@ -84,6 +84,18 @@
"shader module get compilation info": [
{ "name": "shader module id", "type": "ObjectId" },
{ "name": "request serial", "type": "uint64_t" }
+ ],
+ "instance request adapter": [
+ { "name": "instance id", "type": "ObjectId" },
+ { "name": "request serial", "type": "uint64_t" },
+ { "name": "adapter object handle", "type": "ObjectHandle", "handle_type": "adapter"},
+ { "name": "options", "type": "request adapter options", "annotation": "const*" }
+ ],
+ "adapter request device": [
+ { "name": "adapter id", "type": "ObjectId" },
+ { "name": "request serial", "type": "uint64_t" },
+ { "name": "device object handle", "type": "ObjectHandle", "handle_type": "device"},
+ { "name": "descriptor", "type": "device descriptor", "annotation": "const*" }
]
},
"return commands": {
@@ -137,6 +149,25 @@
{ "name": "request serial", "type": "uint64_t" },
{ "name": "status", "type": "compilation info request status" },
{ "name": "info", "type": "compilation info", "annotation": "const*", "optional": true }
+ ],
+ "instance request adapter callback": [
+ { "name": "instance", "type": "ObjectHandle", "handle_type": "instance" },
+ { "name": "request serial", "type": "uint64_t" },
+ { "name": "status", "type": "request adapter status" },
+ { "name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true },
+ { "name": "properties", "type": "adapter properties", "annotation": "const*", "optional": "true" },
+ { "name": "limits", "type": "supported limits", "annotation": "const*", "optional": "true" },
+ { "name": "features count", "type": "uint32_t"},
+ { "name": "features", "type": "feature name", "annotation": "const*", "length": "features count"}
+ ],
+ "adapter request device callback": [
+ { "name": "adapter", "type": "ObjectHandle", "handle_type": "adapter" },
+ { "name": "request serial", "type": "uint64_t" },
+ { "name": "status", "type": "request device status" },
+ { "name": "message", "type": "char", "annotation": "const*", "length": "strlen", "optional": true },
+ { "name": "limits", "type": "supported limits", "annotation": "const*", "optional": "true" },
+ { "name": "features count", "type": "uint32_t"},
+ { "name": "features", "type": "feature name", "annotation": "const*", "length": "features count"}
]
},
"special items": {
diff --git a/src/dawn_wire/BUILD.gn b/src/dawn_wire/BUILD.gn
index 4137652..cfebb57 100644
--- a/src/dawn_wire/BUILD.gn
+++ b/src/dawn_wire/BUILD.gn
@@ -65,6 +65,8 @@
"ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp",
"ChunkedCommandSerializer.h",
+ "SupportedFeatures.cpp",
+ "SupportedFeatures.h",
"Wire.cpp",
"WireClient.cpp",
"WireDeserializeAllocator.cpp",
@@ -84,6 +86,8 @@
"client/Device.h",
"client/Instance.cpp",
"client/Instance.h",
+ "client/LimitsAndFeatures.cpp",
+ "client/LimitsAndFeatures.h",
"client/ObjectAllocator.h",
"client/Queue.cpp",
"client/Queue.h",
@@ -93,9 +97,11 @@
"server/ObjectStorage.h",
"server/Server.cpp",
"server/Server.h",
+ "server/ServerAdapter.cpp",
"server/ServerBuffer.cpp",
"server/ServerDevice.cpp",
"server/ServerInlineMemoryTransferService.cpp",
+ "server/ServerInstance.cpp",
"server/ServerQueue.cpp",
"server/ServerShaderModule.cpp",
]
diff --git a/src/dawn_wire/CMakeLists.txt b/src/dawn_wire/CMakeLists.txt
index 8ba7571..f0b6a7e 100644
--- a/src/dawn_wire/CMakeLists.txt
+++ b/src/dawn_wire/CMakeLists.txt
@@ -37,6 +37,8 @@
"ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp"
"ChunkedCommandSerializer.h"
+ "SupportedFeatures.cpp"
+ "SupportedFeatures.h"
"Wire.cpp"
"WireClient.cpp"
"WireDeserializeAllocator.cpp"
@@ -56,6 +58,8 @@
"client/Device.h"
"client/Instance.cpp"
"client/Instance.h"
+ "client/LimitsAndFeatures.cpp"
+ "client/LimitsAndFeatures.h"
"client/ObjectAllocator.h"
"client/Queue.cpp"
"client/Queue.h"
@@ -65,9 +69,11 @@
"server/ObjectStorage.h"
"server/Server.cpp"
"server/Server.h"
+ "server/ServerAdapter.cpp"
"server/ServerBuffer.cpp"
"server/ServerDevice.cpp"
"server/ServerInlineMemoryTransferService.cpp"
+ "server/ServerInstance.cpp"
"server/ServerQueue.cpp"
"server/ServerShaderModule.cpp"
)
diff --git a/src/dawn_wire/SupportedFeatures.cpp b/src/dawn_wire/SupportedFeatures.cpp
new file mode 100644
index 0000000..a1d4006
--- /dev/null
+++ b/src/dawn_wire/SupportedFeatures.cpp
@@ -0,0 +1,48 @@
+// 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/SupportedFeatures.h"
+
+namespace dawn_wire {
+
+ // Note: Upon updating this list, please also update serialization/deserialization
+ // of limit structs on Adapter/Device initialization.
+ bool IsFeatureSupported(WGPUFeatureName feature) {
+ switch (feature) {
+ case WGPUFeatureName_Undefined:
+ case WGPUFeatureName_Force32:
+ return false;
+ case WGPUFeatureName_Depth24UnormStencil8:
+ case WGPUFeatureName_Depth32FloatStencil8:
+ case WGPUFeatureName_TimestampQuery:
+ case WGPUFeatureName_PipelineStatisticsQuery:
+ case WGPUFeatureName_TextureCompressionBC:
+ case WGPUFeatureName_TextureCompressionETC2:
+ case WGPUFeatureName_TextureCompressionASTC:
+ case WGPUFeatureName_IndirectFirstInstance:
+ case WGPUFeatureName_DepthClamping:
+ case WGPUFeatureName_DawnShaderFloat16:
+ case WGPUFeatureName_DawnInternalUsages:
+ case WGPUFeatureName_DawnMultiPlanarFormats:
+ return true;
+ }
+
+ // Catch-all, for unsupported features.
+ // "default:" is not used so we get compiler errors for
+ // newly added, unhandled features, but still catch completely
+ // unknown enums.
+ return false;
+ }
+
+} // namespace dawn_wire
diff --git a/src/dawn_wire/SupportedFeatures.h b/src/dawn_wire/SupportedFeatures.h
new file mode 100644
index 0000000..5405ad4
--- /dev/null
+++ b/src/dawn_wire/SupportedFeatures.h
@@ -0,0 +1,26 @@
+// 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_SUPPORTEDFEATURES_H_
+#define DAWNWIRE_SUPPORTEDFEATURES_H_
+
+#include <dawn/webgpu.h>
+
+namespace dawn_wire {
+
+ bool IsFeatureSupported(WGPUFeatureName feature);
+
+} // namespace dawn_wire
+
+#endif // DAWNWIRE_SUPPORTEDFEATURES_H_
diff --git a/src/dawn_wire/client/Adapter.cpp b/src/dawn_wire/client/Adapter.cpp
index f3e46ef..fd5daf7 100644
--- a/src/dawn_wire/client/Adapter.cpp
+++ b/src/dawn_wire/client/Adapter.cpp
@@ -14,28 +14,114 @@
#include "dawn_wire/client/Adapter.h"
+#include "dawn_wire/client/Client.h"
+
namespace dawn_wire { namespace client {
- bool Adapter::GetLimits(WGPUSupportedLimits* limits) const {
- UNREACHABLE();
+ Adapter::~Adapter() {
+ mRequestDeviceRequests.CloseAll([](RequestDeviceData* request) {
+ request->callback(WGPURequestDeviceStatus_Unknown, nullptr,
+ "Adapter destroyed before callback", request->userdata);
+ });
}
- void Adapter::GetProperties(WGPUAdapterProperties* properties) const {
- UNREACHABLE();
+ void Adapter::CancelCallbacksForDisconnect() {
+ mRequestDeviceRequests.CloseAll([](RequestDeviceData* request) {
+ request->callback(WGPURequestDeviceStatus_Unknown, nullptr, "GPU connection lost",
+ request->userdata);
+ });
+ }
+
+ bool Adapter::GetLimits(WGPUSupportedLimits* limits) const {
+ return mLimitsAndFeatures.GetLimits(limits);
}
bool Adapter::HasFeature(WGPUFeatureName feature) const {
- UNREACHABLE();
+ return mLimitsAndFeatures.HasFeature(feature);
}
uint32_t Adapter::EnumerateFeatures(WGPUFeatureName* features) const {
- UNREACHABLE();
+ return mLimitsAndFeatures.EnumerateFeatures(features);
+ }
+
+ void Adapter::SetLimits(const WGPUSupportedLimits* limits) {
+ return mLimitsAndFeatures.SetLimits(limits);
+ }
+
+ void Adapter::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
+ return mLimitsAndFeatures.SetFeatures(features, featuresCount);
+ }
+
+ void Adapter::SetProperties(const WGPUAdapterProperties* properties) {
+ mProperties = *properties;
+ mProperties.nextInChain = nullptr;
+ }
+
+ void Adapter::GetProperties(WGPUAdapterProperties* properties) const {
+ *properties = mProperties;
}
void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback,
void* userdata) {
- callback(WGPURequestDeviceStatus_Error, nullptr, "Not implemented", nullptr);
+ if (client->IsDisconnected()) {
+ callback(WGPURequestDeviceStatus_Error, nullptr, "GPU connection lost", userdata);
+ return;
+ }
+
+ auto* allocation = client->DeviceAllocator().New(client);
+ uint64_t serial = mRequestDeviceRequests.Add({callback, allocation->object->id, userdata});
+
+ AdapterRequestDeviceCmd cmd;
+ cmd.adapterId = this->id;
+ cmd.requestSerial = serial;
+ cmd.deviceObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
+ cmd.descriptor = descriptor;
+
+ client->SerializeCommand(cmd);
+ }
+
+ bool Client::DoAdapterRequestDeviceCallback(Adapter* adapter,
+ uint64_t requestSerial,
+ WGPURequestDeviceStatus status,
+ const char* message,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features) {
+ // May have been deleted or recreated so this isn't an error.
+ if (adapter == nullptr) {
+ return true;
+ }
+ return adapter->OnRequestDeviceCallback(requestSerial, status, message, limits,
+ featuresCount, features);
+ }
+
+ bool Adapter::OnRequestDeviceCallback(uint64_t requestSerial,
+ WGPURequestDeviceStatus status,
+ const char* message,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features) {
+ RequestDeviceData request;
+ if (!mRequestDeviceRequests.Acquire(requestSerial, &request)) {
+ return false;
+ }
+
+ Device* device = client->DeviceAllocator().GetObject(request.deviceObjectId);
+
+ // If the return status is a failure we should give a null device to the callback and
+ // free the allocation.
+ if (status != WGPURequestDeviceStatus_Success) {
+ client->DeviceAllocator().Free(device);
+ request.callback(status, nullptr, message, request.userdata);
+ return true;
+ }
+
+ device->SetLimits(limits);
+ device->SetFeatures(features, featuresCount);
+
+ request.callback(status, ToAPI(device), message, request.userdata);
+ return true;
}
}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Adapter.h b/src/dawn_wire/client/Adapter.h
index 58c5d0f..e6f77dc 100644
--- a/src/dawn_wire/client/Adapter.h
+++ b/src/dawn_wire/client/Adapter.h
@@ -18,7 +18,10 @@
#include <dawn/webgpu.h>
#include "dawn_wire/WireClient.h"
+#include "dawn_wire/WireCmd_autogen.h"
+#include "dawn_wire/client/LimitsAndFeatures.h"
#include "dawn_wire/client/ObjectBase.h"
+#include "dawn_wire/client/RequestTracker.h"
namespace dawn_wire { namespace client {
@@ -26,13 +29,37 @@
public:
using ObjectBase::ObjectBase;
+ ~Adapter();
+ void CancelCallbacksForDisconnect() override;
+
bool GetLimits(WGPUSupportedLimits* limits) const;
- void GetProperties(WGPUAdapterProperties* properties) const;
bool HasFeature(WGPUFeatureName feature) const;
uint32_t EnumerateFeatures(WGPUFeatureName* features) const;
+ void SetLimits(const WGPUSupportedLimits* limits);
+ void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
+ void SetProperties(const WGPUAdapterProperties* properties);
+ void GetProperties(WGPUAdapterProperties* properties) const;
void RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback,
void* userdata);
+
+ bool OnRequestDeviceCallback(uint64_t requestSerial,
+ WGPURequestDeviceStatus status,
+ const char* message,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features);
+
+ private:
+ LimitsAndFeatures mLimitsAndFeatures;
+ WGPUAdapterProperties mProperties;
+
+ struct RequestDeviceData {
+ WGPURequestDeviceCallback callback = nullptr;
+ ObjectId deviceObjectId;
+ void* userdata = nullptr;
+ };
+ RequestTracker<RequestDeviceData> mRequestDeviceRequests;
};
}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Device.cpp b/src/dawn_wire/client/Device.cpp
index 57e6599..54d1053 100644
--- a/src/dawn_wire/client/Device.cpp
+++ b/src/dawn_wire/client/Device.cpp
@@ -67,6 +67,26 @@
});
}
+ bool Device::GetLimits(WGPUSupportedLimits* limits) const {
+ return mLimitsAndFeatures.GetLimits(limits);
+ }
+
+ bool Device::HasFeature(WGPUFeatureName feature) const {
+ return mLimitsAndFeatures.HasFeature(feature);
+ }
+
+ uint32_t Device::EnumerateFeatures(WGPUFeatureName* features) const {
+ return mLimitsAndFeatures.EnumerateFeatures(features);
+ }
+
+ void Device::SetLimits(const WGPUSupportedLimits* limits) {
+ return mLimitsAndFeatures.SetLimits(limits);
+ }
+
+ void Device::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
+ return mLimitsAndFeatures.SetFeatures(features, featuresCount);
+ }
+
void Device::HandleError(WGPUErrorType errorType, const char* message) {
if (mErrorCallback) {
mErrorCallback(errorType, message, mErrorUserdata);
@@ -196,20 +216,6 @@
return Buffer::CreateError(this);
}
- bool Device::GetLimits(WGPUSupportedLimits* limits) const {
- // Not implemented in the wire.
- UNREACHABLE();
- return false;
- }
-
- bool Device::HasFeature(WGPUFeatureName feature) const {
- UNREACHABLE();
- }
-
- uint32_t Device::EnumerateFeatures(WGPUFeatureName* features) const {
- UNREACHABLE();
- }
-
WGPUQueue Device::GetQueue() {
// The queue is lazily created because if a Device is created by
// Reserve/Inject, we cannot send the GetQueue message until
@@ -269,7 +275,7 @@
client->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
- // free the allocation both on the client side and the server side.
+ // free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
client->ComputePipelineAllocator().Free(pipelineAllocation);
request.createComputePipelineAsyncCallback(status, nullptr, message, request.userdata);
@@ -320,7 +326,7 @@
client->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
// If the return status is a failure we should give a null pipeline to the callback and
- // free the allocation both on the client side and the server side.
+ // free the allocation.
if (status != WGPUCreatePipelineAsyncStatus_Success) {
client->RenderPipelineAllocator().Free(pipelineAllocation);
request.createRenderPipelineAsyncCallback(status, nullptr, message, request.userdata);
diff --git a/src/dawn_wire/client/Device.h b/src/dawn_wire/client/Device.h
index fff5cf8..58be198 100644
--- a/src/dawn_wire/client/Device.h
+++ b/src/dawn_wire/client/Device.h
@@ -20,6 +20,7 @@
#include "common/LinkedList.h"
#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ApiObjects_autogen.h"
+#include "dawn_wire/client/LimitsAndFeatures.h"
#include "dawn_wire/client/ObjectBase.h"
#include "dawn_wire/client/RequestTracker.h"
@@ -67,6 +68,9 @@
bool GetLimits(WGPUSupportedLimits* limits) const;
bool HasFeature(WGPUFeatureName feature) const;
uint32_t EnumerateFeatures(WGPUFeatureName* features) const;
+ void SetLimits(const WGPUSupportedLimits* limits);
+ void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
+
WGPUQueue GetQueue();
void CancelCallbacksForDisconnect() override;
@@ -74,6 +78,7 @@
std::weak_ptr<bool> GetAliveWeakPtr();
private:
+ LimitsAndFeatures mLimitsAndFeatures;
struct ErrorScopeData {
WGPUErrorCallback callback = nullptr;
void* userdata = nullptr;
diff --git a/src/dawn_wire/client/Instance.cpp b/src/dawn_wire/client/Instance.cpp
index 74d0517..cf3976c 100644
--- a/src/dawn_wire/client/Instance.cpp
+++ b/src/dawn_wire/client/Instance.cpp
@@ -14,12 +14,88 @@
#include "dawn_wire/client/Instance.h"
+#include "dawn_wire/client/Client.h"
+
namespace dawn_wire { namespace client {
+ Instance::~Instance() {
+ mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
+ request->callback(WGPURequestAdapterStatus_Unknown, nullptr,
+ "Instance destroyed before callback", request->userdata);
+ });
+ }
+
+ void Instance::CancelCallbacksForDisconnect() {
+ mRequestAdapterRequests.CloseAll([](RequestAdapterData* request) {
+ request->callback(WGPURequestAdapterStatus_Unknown, nullptr, "GPU connection lost",
+ request->userdata);
+ });
+ }
+
void Instance::RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata) {
- callback(WGPURequestAdapterStatus_Error, nullptr, "Not implemented", nullptr);
+ if (client->IsDisconnected()) {
+ callback(WGPURequestAdapterStatus_Error, nullptr, "GPU connection lost", userdata);
+ return;
+ }
+
+ auto* allocation = client->AdapterAllocator().New(client);
+ uint64_t serial = mRequestAdapterRequests.Add({callback, allocation->object->id, userdata});
+
+ InstanceRequestAdapterCmd cmd;
+ cmd.instanceId = this->id;
+ cmd.requestSerial = serial;
+ cmd.adapterObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
+ cmd.options = options;
+
+ client->SerializeCommand(cmd);
+ }
+
+ bool Client::DoInstanceRequestAdapterCallback(Instance* instance,
+ uint64_t requestSerial,
+ WGPURequestAdapterStatus status,
+ const char* message,
+ const WGPUAdapterProperties* properties,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features) {
+ // May have been deleted or recreated so this isn't an error.
+ if (instance == nullptr) {
+ return true;
+ }
+ return instance->OnRequestAdapterCallback(requestSerial, status, message, properties,
+ limits, featuresCount, features);
+ }
+
+ bool Instance::OnRequestAdapterCallback(uint64_t requestSerial,
+ WGPURequestAdapterStatus status,
+ const char* message,
+ const WGPUAdapterProperties* properties,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features) {
+ RequestAdapterData request;
+ if (!mRequestAdapterRequests.Acquire(requestSerial, &request)) {
+ return false;
+ }
+
+ Adapter* adapter = client->AdapterAllocator().GetObject(request.adapterObjectId);
+
+ // If the return status is a failure we should give a null adapter to the callback and
+ // free the allocation.
+ if (status != WGPURequestAdapterStatus_Success) {
+ client->AdapterAllocator().Free(adapter);
+ request.callback(status, nullptr, message, request.userdata);
+ return true;
+ }
+
+ adapter->SetProperties(properties);
+ adapter->SetLimits(limits);
+ adapter->SetFeatures(features, featuresCount);
+
+ request.callback(status, ToAPI(adapter), message, request.userdata);
+ return true;
}
}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/Instance.h b/src/dawn_wire/client/Instance.h
index 3d55ac9..2733b9c 100644
--- a/src/dawn_wire/client/Instance.h
+++ b/src/dawn_wire/client/Instance.h
@@ -18,7 +18,9 @@
#include <dawn/webgpu.h>
#include "dawn_wire/WireClient.h"
+#include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ObjectBase.h"
+#include "dawn_wire/client/RequestTracker.h"
namespace dawn_wire { namespace client {
@@ -26,9 +28,27 @@
public:
using ObjectBase::ObjectBase;
+ ~Instance();
+ void CancelCallbacksForDisconnect() override;
+
void RequestAdapter(const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback,
void* userdata);
+ bool OnRequestAdapterCallback(uint64_t requestSerial,
+ WGPURequestAdapterStatus status,
+ const char* message,
+ const WGPUAdapterProperties* properties,
+ const WGPUSupportedLimits* limits,
+ uint32_t featuresCount,
+ const WGPUFeatureName* features);
+
+ private:
+ struct RequestAdapterData {
+ WGPURequestAdapterCallback callback = nullptr;
+ ObjectId adapterObjectId;
+ void* userdata = nullptr;
+ };
+ RequestTracker<RequestAdapterData> mRequestAdapterRequests;
};
}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/LimitsAndFeatures.cpp b/src/dawn_wire/client/LimitsAndFeatures.cpp
new file mode 100644
index 0000000..c4b4656
--- /dev/null
+++ b/src/dawn_wire/client/LimitsAndFeatures.cpp
@@ -0,0 +1,63 @@
+// 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/LimitsAndFeatures.h"
+
+#include "common/Assert.h"
+#include "dawn_wire/SupportedFeatures.h"
+
+namespace dawn_wire { namespace client {
+
+ bool LimitsAndFeatures::GetLimits(WGPUSupportedLimits* limits) const {
+ ASSERT(limits != nullptr);
+ if (limits->nextInChain != nullptr) {
+ return false;
+ }
+ *limits = mLimits;
+ return true;
+ }
+
+ bool LimitsAndFeatures::HasFeature(WGPUFeatureName feature) const {
+ return mFeatures.count(feature) != 0;
+ }
+
+ uint32_t LimitsAndFeatures::EnumerateFeatures(WGPUFeatureName* features) const {
+ if (features != nullptr) {
+ for (WGPUFeatureName f : mFeatures) {
+ *features = f;
+ ++features;
+ }
+ }
+ return mFeatures.size();
+ }
+
+ void LimitsAndFeatures::SetLimits(const WGPUSupportedLimits* limits) {
+ ASSERT(limits != nullptr);
+ mLimits = *limits;
+ mLimits.nextInChain = nullptr;
+ }
+
+ void LimitsAndFeatures::SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount) {
+ ASSERT(features != nullptr || featuresCount == 0);
+ for (uint32_t i = 0; i < featuresCount; ++i) {
+ // Filter out features that the server supports, but the client does not.
+ // (Could be different versions)
+ if (!IsFeatureSupported(features[i])) {
+ continue;
+ }
+ mFeatures.insert(features[i]);
+ }
+ }
+
+}} // namespace dawn_wire::client
diff --git a/src/dawn_wire/client/LimitsAndFeatures.h b/src/dawn_wire/client/LimitsAndFeatures.h
new file mode 100644
index 0000000..996dbdb
--- /dev/null
+++ b/src/dawn_wire/client/LimitsAndFeatures.h
@@ -0,0 +1,40 @@
+// 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_LIMITSANDFEATURES_H_
+#define DAWNWIRE_CLIENT_LIMITSANDFEATURES_H_
+
+#include <dawn/webgpu.h>
+
+#include <unordered_set>
+
+namespace dawn_wire { namespace client {
+
+ class LimitsAndFeatures {
+ public:
+ bool GetLimits(WGPUSupportedLimits* limits) const;
+ bool HasFeature(WGPUFeatureName feature) const;
+ uint32_t EnumerateFeatures(WGPUFeatureName* features) const;
+
+ void SetLimits(const WGPUSupportedLimits* limits);
+ void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
+
+ private:
+ WGPUSupportedLimits mLimits;
+ std::unordered_set<WGPUFeatureName> mFeatures;
+ };
+
+}} // namespace dawn_wire::client
+
+#endif // DAWNWIRE_CLIENT_LIMITSANDFEATURES_H_
diff --git a/src/dawn_wire/server/Server.cpp b/src/dawn_wire/server/Server.cpp
index a4dbd8c..6fea9fc 100644
--- a/src/dawn_wire/server/Server.cpp
+++ b/src/dawn_wire/server/Server.cpp
@@ -122,34 +122,7 @@
mProcs.deviceReference(device);
// Set callbacks to forward errors to the client.
- // Note: these callbacks are manually inlined here since they do not acquire and
- // free their userdata. Also unlike other callbacks, these are cleared and unset when
- // the server is destroyed, so we don't need to check if the server is still alive
- // inside them.
- mProcs.deviceSetUncapturedErrorCallback(
- device,
- [](WGPUErrorType type, const char* message, void* userdata) {
- DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
- info->server->OnUncapturedError(info->self, type, message);
- },
- data->info.get());
- // Set callback to post warning and other infomation to client.
- // Almost the same with UncapturedError.
- mProcs.deviceSetLoggingCallback(
- device,
- [](WGPULoggingType type, const char* message, void* userdata) {
- DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
- info->server->OnLogging(info->self, type, message);
- },
- data->info.get());
- mProcs.deviceSetDeviceLostCallback(
- device,
- [](WGPUDeviceLostReason reason, const char* message, void* userdata) {
- DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
- info->server->OnDeviceLost(info->self, reason, message);
- },
- data->info.get());
-
+ SetForwardingDeviceCallbacks(data);
return true;
}
@@ -179,6 +152,36 @@
return data->handle;
}
+ void Server::SetForwardingDeviceCallbacks(ObjectData<WGPUDevice>* deviceObject) {
+ // Note: these callbacks are manually inlined here since they do not acquire and
+ // free their userdata. Also unlike other callbacks, these are cleared and unset when
+ // the server is destroyed, so we don't need to check if the server is still alive
+ // inside them.
+ mProcs.deviceSetUncapturedErrorCallback(
+ deviceObject->handle,
+ [](WGPUErrorType type, const char* message, void* userdata) {
+ DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
+ info->server->OnUncapturedError(info->self, type, message);
+ },
+ deviceObject->info.get());
+ // Set callback to post warning and other infomation to client.
+ // Almost the same with UncapturedError.
+ mProcs.deviceSetLoggingCallback(
+ deviceObject->handle,
+ [](WGPULoggingType type, const char* message, void* userdata) {
+ DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
+ info->server->OnLogging(info->self, type, message);
+ },
+ deviceObject->info.get());
+ mProcs.deviceSetDeviceLostCallback(
+ deviceObject->handle,
+ [](WGPUDeviceLostReason reason, const char* message, void* userdata) {
+ DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
+ info->server->OnDeviceLost(info->self, reason, message);
+ },
+ deviceObject->info.get());
+ }
+
void Server::ClearDeviceCallbacks(WGPUDevice device) {
// Un-set the error and lost callbacks since we cannot forward them
// after the server has been destroyed.
diff --git a/src/dawn_wire/server/Server.h b/src/dawn_wire/server/Server.h
index 33b0e04..1b685c7 100644
--- a/src/dawn_wire/server/Server.h
+++ b/src/dawn_wire/server/Server.h
@@ -146,6 +146,22 @@
ObjectId pipelineObjectID;
};
+ struct RequestAdapterUserdata : CallbackUserdata {
+ using CallbackUserdata::CallbackUserdata;
+
+ ObjectHandle instance;
+ uint64_t requestSerial;
+ ObjectId adapterObjectId;
+ };
+
+ struct RequestDeviceUserdata : CallbackUserdata {
+ using CallbackUserdata::CallbackUserdata;
+
+ ObjectHandle adapter;
+ uint64_t requestSerial;
+ ObjectId deviceObjectId;
+ };
+
class Server : public ServerBase {
public:
Server(const DawnProcTable& procs,
@@ -194,6 +210,7 @@
mSerializer.SerializeCommand(cmd, extraSize, SerializeExtraSize);
}
+ void SetForwardingDeviceCallbacks(ObjectData<WGPUDevice>* deviceObject);
void ClearDeviceCallbacks(WGPUDevice device);
// Error callbacks
@@ -216,6 +233,14 @@
void OnShaderModuleGetCompilationInfo(WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info,
ShaderModuleGetCompilationInfoUserdata* userdata);
+ void OnRequestAdapterCallback(WGPURequestAdapterStatus status,
+ WGPUAdapter adapter,
+ const char* message,
+ RequestAdapterUserdata* userdata);
+ void OnRequestDeviceCallback(WGPURequestDeviceStatus status,
+ WGPUDevice device,
+ const char* message,
+ RequestDeviceUserdata* userdata);
#include "dawn_wire/server/ServerPrototypes_autogen.inc"
diff --git a/src/dawn_wire/server/ServerAdapter.cpp b/src/dawn_wire/server/ServerAdapter.cpp
new file mode 100644
index 0000000..652d86d
--- /dev/null
+++ b/src/dawn_wire/server/ServerAdapter.cpp
@@ -0,0 +1,112 @@
+// 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/server/Server.h"
+
+#include "dawn_wire/SupportedFeatures.h"
+
+namespace dawn_wire { namespace server {
+
+ bool Server::DoAdapterRequestDevice(ObjectId adapterId,
+ uint64_t requestSerial,
+ ObjectHandle deviceHandle,
+ const WGPUDeviceDescriptor* descriptor) {
+ auto* adapter = AdapterObjects().Get(adapterId);
+ if (adapter == nullptr) {
+ return false;
+ }
+
+ auto* resultData = DeviceObjects().Allocate(deviceHandle.id, AllocationState::Reserved);
+ if (resultData == nullptr) {
+ return false;
+ }
+
+ resultData->generation = deviceHandle.generation;
+
+ auto userdata = MakeUserdata<RequestDeviceUserdata>();
+ userdata->adapter = ObjectHandle{adapterId, adapter->generation};
+ userdata->requestSerial = requestSerial;
+ userdata->deviceObjectId = deviceHandle.id;
+
+ mProcs.adapterRequestDevice(
+ adapter->handle, descriptor,
+ ForwardToServer<decltype(
+ &Server::OnRequestDeviceCallback)>::Func<&Server::OnRequestDeviceCallback>(),
+ userdata.release());
+ return true;
+ }
+
+ void Server::OnRequestDeviceCallback(WGPURequestDeviceStatus status,
+ WGPUDevice device,
+ const char* message,
+ RequestDeviceUserdata* data) {
+ auto* deviceObject = DeviceObjects().Get(data->deviceObjectId, AllocationState::Reserved);
+ // Should be impossible to fail. ObjectIds can't be freed by a destroy command until
+ // they move from Reserved to Allocated, or if they are destroyed here.
+ ASSERT(deviceObject != nullptr);
+
+ ReturnAdapterRequestDeviceCallbackCmd cmd = {};
+ cmd.adapter = data->adapter;
+ cmd.requestSerial = data->requestSerial;
+ cmd.status = status;
+ cmd.message = message;
+
+ if (status != WGPURequestDeviceStatus_Success) {
+ // Free the ObjectId which will make it unusable.
+ DeviceObjects().Free(data->deviceObjectId);
+ ASSERT(device == nullptr);
+ SerializeCommand(cmd);
+ return;
+ }
+
+ std::vector<WGPUFeatureName> features;
+
+ uint32_t featuresCount = mProcs.deviceEnumerateFeatures(device, nullptr);
+ features.resize(featuresCount);
+ mProcs.deviceEnumerateFeatures(device, features.data());
+
+ // The client should only be able to request supported features, so all enumerated
+ // features that were enabled must also be supported by the wire.
+ // Note: We fail the callback here, instead of immediately upon receiving
+ // the request to preserve callback ordering.
+ for (WGPUFeatureName f : features) {
+ if (!IsFeatureSupported(f)) {
+ // Release the device.
+ mProcs.deviceRelease(device);
+ // Free the ObjectId which will make it unusable.
+ DeviceObjects().Free(data->deviceObjectId);
+
+ cmd.status = WGPURequestDeviceStatus_Error;
+ cmd.message = "Requested feature not supported.";
+ SerializeCommand(cmd);
+ return;
+ }
+ }
+
+ cmd.featuresCount = features.size();
+ cmd.features = features.data();
+
+ WGPUSupportedLimits limits = {};
+ mProcs.deviceGetLimits(device, &limits);
+ cmd.limits = &limits;
+
+ // Assign the handle and allocated status if the device is created successfully.
+ deviceObject->state = AllocationState::Allocated;
+ deviceObject->handle = device;
+ SetForwardingDeviceCallbacks(deviceObject);
+
+ SerializeCommand(cmd);
+ }
+
+}} // namespace dawn_wire::server
diff --git a/src/dawn_wire/server/ServerInstance.cpp b/src/dawn_wire/server/ServerInstance.cpp
new file mode 100644
index 0000000..0fb35c0
--- /dev/null
+++ b/src/dawn_wire/server/ServerInstance.cpp
@@ -0,0 +1,102 @@
+// 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/server/Server.h"
+
+#include "dawn_wire/SupportedFeatures.h"
+
+#include <algorithm>
+
+namespace dawn_wire { namespace server {
+
+ bool Server::DoInstanceRequestAdapter(ObjectId instanceId,
+ uint64_t requestSerial,
+ ObjectHandle adapterHandle,
+ const WGPURequestAdapterOptions* options) {
+ auto* instance = InstanceObjects().Get(instanceId);
+ if (instance == nullptr) {
+ return false;
+ }
+
+ auto* resultData = AdapterObjects().Allocate(adapterHandle.id, AllocationState::Reserved);
+ if (resultData == nullptr) {
+ return false;
+ }
+
+ resultData->generation = adapterHandle.generation;
+
+ auto userdata = MakeUserdata<RequestAdapterUserdata>();
+ userdata->instance = ObjectHandle{instanceId, instance->generation};
+ userdata->requestSerial = requestSerial;
+ userdata->adapterObjectId = adapterHandle.id;
+
+ mProcs.instanceRequestAdapter(
+ instance->handle, options,
+ ForwardToServer<decltype(
+ &Server::OnRequestAdapterCallback)>::Func<&Server::OnRequestAdapterCallback>(),
+ userdata.release());
+ return true;
+ }
+
+ void Server::OnRequestAdapterCallback(WGPURequestAdapterStatus status,
+ WGPUAdapter adapter,
+ const char* message,
+ RequestAdapterUserdata* data) {
+ auto* adapterObject =
+ AdapterObjects().Get(data->adapterObjectId, AllocationState::Reserved);
+ // Should be impossible to fail. ObjectIds can't be freed by a destroy command until
+ // they move from Reserved to Allocated, or if they are destroyed here.
+ ASSERT(adapterObject != nullptr);
+
+ ReturnInstanceRequestAdapterCallbackCmd cmd = {};
+ cmd.instance = data->instance;
+ cmd.requestSerial = data->requestSerial;
+ cmd.status = status;
+ cmd.message = message;
+
+ if (status != WGPURequestAdapterStatus_Success) {
+ // Free the ObjectId which will make it unusable.
+ AdapterObjects().Free(data->adapterObjectId);
+ ASSERT(adapter == nullptr);
+ SerializeCommand(cmd);
+ return;
+ }
+
+ WGPUAdapterProperties properties = {};
+ WGPUSupportedLimits limits = {};
+ std::vector<WGPUFeatureName> features;
+
+ // Assign the handle and allocated status if the adapter is created successfully.
+ adapterObject->state = AllocationState::Allocated;
+ adapterObject->handle = adapter;
+
+ uint32_t featuresCount = mProcs.adapterEnumerateFeatures(adapter, nullptr);
+ features.resize(featuresCount);
+ mProcs.adapterEnumerateFeatures(adapter, features.data());
+
+ // Hide features the wire cannot support.
+ auto it = std::partition(features.begin(), features.end(), IsFeatureSupported);
+
+ cmd.featuresCount = std::distance(features.begin(), it);
+ cmd.features = features.data();
+
+ mProcs.adapterGetProperties(adapter, &properties);
+ mProcs.adapterGetLimits(adapter, &limits);
+ cmd.properties = &properties;
+ cmd.limits = &limits;
+
+ SerializeCommand(cmd);
+ }
+
+}} // namespace dawn_wire::server