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>
This commit is contained in:
Austin Eng 2021-12-15 21:52:17 +00:00 committed by Dawn LUCI CQ
parent 736dd07303
commit 07e766728a
17 changed files with 735 additions and 53 deletions

View File

@ -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": {

View File

@ -65,6 +65,8 @@ dawn_component("dawn_wire") {
"ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp",
"ChunkedCommandSerializer.h",
"SupportedFeatures.cpp",
"SupportedFeatures.h",
"Wire.cpp",
"WireClient.cpp",
"WireDeserializeAllocator.cpp",
@ -84,6 +86,8 @@ dawn_component("dawn_wire") {
"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 @@ dawn_component("dawn_wire") {
"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",
]

View File

@ -37,6 +37,8 @@ target_sources(dawn_wire PRIVATE
"ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp"
"ChunkedCommandSerializer.h"
"SupportedFeatures.cpp"
"SupportedFeatures.h"
"Wire.cpp"
"WireClient.cpp"
"WireDeserializeAllocator.cpp"
@ -56,6 +58,8 @@ target_sources(dawn_wire PRIVATE
"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 @@ target_sources(dawn_wire PRIVATE
"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"
)

View File

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

View File

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

View File

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

View File

@ -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 @@ namespace dawn_wire { namespace client {
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

View File

@ -67,6 +67,26 @@ namespace dawn_wire { namespace client {
});
}
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 @@ namespace dawn_wire { namespace client {
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 @@ namespace dawn_wire { namespace client {
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 @@ namespace dawn_wire { namespace client {
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);

View File

@ -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 @@ namespace dawn_wire { namespace client {
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 @@ namespace dawn_wire { namespace client {
std::weak_ptr<bool> GetAliveWeakPtr();
private:
LimitsAndFeatures mLimitsAndFeatures;
struct ErrorScopeData {
WGPUErrorCallback callback = nullptr;
void* userdata = nullptr;

View File

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

View File

@ -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 @@ namespace dawn_wire { namespace client {
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

View File

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

View File

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

View File

@ -122,34 +122,7 @@ namespace dawn_wire { namespace server {
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 @@ namespace dawn_wire { namespace server {
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.

View File

@ -146,6 +146,22 @@ namespace dawn_wire { namespace server {
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 @@ namespace dawn_wire { namespace server {
mSerializer.SerializeCommand(cmd, extraSize, SerializeExtraSize);
}
void SetForwardingDeviceCallbacks(ObjectData<WGPUDevice>* deviceObject);
void ClearDeviceCallbacks(WGPUDevice device);
// Error callbacks
@ -216,6 +233,14 @@ namespace dawn_wire { namespace server {
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"

View File

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

View File

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