Add basic or stub implementations of upstream instance/adapter APIs
Adds upstream instance/adapter APIs. In dawn_native, the basic APIs to get limits and properties are implemented, but requestAdapter and requestDevice are not. In dawn_wire, nothing is implemented, but the stub definitions are put in place, as well the mechanism to inject WGPUInstance into the wire. There is a lifetime concern with WGPUInstance and WGPUAdapter on the wire in that we need to ensure that the client cannot free the instance or adapter while they are in use. In the near term, this is not a problem because Chromium will always hold ownership of the instance and adapters outside of the wire - i.e. it won't inject and then release ownership. Bug: dawn:160, dawn:689 Change-Id: Id904272983f23babc9177bc163d78c4fa1044da0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71520 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:
parent
0e6f443359
commit
5397f9f9d0
28
dawn.json
28
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": "*"}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<const char*> FeaturesSet::GetEnabledFeatureNames() const {
|
||||
std::vector<const char*> enabledFeatureNames(featuresBitSet.count());
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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<const char*> GetEnabledFeatureNames() const;
|
||||
void InitializeDeviceProperties(WGPUDeviceProperties* properties) const;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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 <dawn/webgpu.h>
|
||||
|
||||
#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_
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 <typename Cmd>
|
||||
void SerializeCommand(const Cmd& cmd) {
|
||||
|
|
|
@ -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
|
|
@ -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 <dawn/webgpu.h>
|
||||
|
||||
#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_
|
|
@ -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<WGPUInstance>* 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<WGPUDevice>* data = DeviceObjects().Get(id);
|
||||
if (data == nullptr || data->generation != generation) {
|
||||
|
|
|
@ -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 <typename T,
|
||||
|
|
|
@ -52,6 +52,12 @@ namespace dawn_wire {
|
|||
uint32_t generation;
|
||||
};
|
||||
|
||||
struct ReservedInstance {
|
||||
WGPUInstance instance;
|
||||
uint32_t id;
|
||||
uint32_t generation;
|
||||
};
|
||||
|
||||
struct DAWN_WIRE_EXPORT WireClientDescriptor {
|
||||
CommandSerializer* serializer;
|
||||
client::MemoryTransferService* memoryTransferService = nullptr;
|
||||
|
@ -68,10 +74,12 @@ namespace dawn_wire {
|
|||
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);
|
||||
|
||||
// Disconnects the client.
|
||||
// Commands allocated after this point will not be sent.
|
||||
|
|
|
@ -55,6 +55,8 @@ namespace dawn_wire {
|
|||
|
||||
bool InjectDevice(WGPUDevice device, uint32_t id, uint32_t generation);
|
||||
|
||||
bool InjectInstance(WGPUInstance instance, uint32_t id, uint32_t generation);
|
||||
|
||||
// Look up a device by (id, generation) pair. Returns nullptr if the generation
|
||||
// has expired or the id is not found.
|
||||
// The Wire does not have destroy hooks to allow an embedder to observe when an object
|
||||
|
|
|
@ -281,6 +281,7 @@ test("dawn_unittests") {
|
|||
"unittests/wire/WireErrorCallbackTests.cpp",
|
||||
"unittests/wire/WireExtensionTests.cpp",
|
||||
"unittests/wire/WireInjectDeviceTests.cpp",
|
||||
"unittests/wire/WireInjectInstanceTests.cpp",
|
||||
"unittests/wire/WireInjectSwapChainTests.cpp",
|
||||
"unittests/wire/WireInjectTextureTests.cpp",
|
||||
"unittests/wire/WireMemoryTransferServiceTests.cpp",
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
// 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 "tests/unittests/wire/WireTest.h"
|
||||
|
||||
#include "dawn_wire/WireClient.h"
|
||||
#include "dawn_wire/WireServer.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace dawn_wire;
|
||||
|
||||
namespace {
|
||||
|
||||
class WireInjectInstanceTests : public WireTest {
|
||||
public:
|
||||
WireInjectInstanceTests() {
|
||||
}
|
||||
~WireInjectInstanceTests() override = default;
|
||||
};
|
||||
|
||||
// Test that reserving and injecting an instance makes calls on the client object forward to the
|
||||
// server object correctly.
|
||||
TEST_F(WireInjectInstanceTests, CallAfterReserveInject) {
|
||||
ReservedInstance reservation = GetWireClient()->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
|
Loading…
Reference in New Issue