mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-13 19:01:24 +00:00
dawn_wire: Make all objects owned by the client
This removes the logic where the Client owns the Device and the Device owns all other objects. Ownership should be tracked in dawn_native either with refcounting or validation to disallow operations after an object's parent has been destroyed. This simplifies the wire client code in that the client only tracks allocated handles and does not manage parent/child lifetimes. This is an important simplification so we can support multiple WebGPU instances, adapters, and devices on a single wire. Bug: dawn:384 Change-Id: I8ecc7c368130b8917202150c467b5f0e7d4b753e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/37000 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
f6ef7530ab
commit
f0d7cc4f5a
@ -34,14 +34,14 @@ namespace dawn_wire { namespace client {
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% for type in by_category["object"] %}
|
{% for type in by_category["object"] %}
|
||||||
DAWN_DECLARE_UNUSED bool DeviceMatches(const Device* device, const {{as_cType(type.name)}} obj) {
|
DAWN_DECLARE_UNUSED bool ClientMatches(const Client* client, const {{as_cType(type.name)}} obj) {
|
||||||
return device == reinterpret_cast<const {{as_wireType(type)}}>(obj)->device;
|
return client == reinterpret_cast<const {{as_wireType(type)}}>(obj)->client;
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_DECLARE_UNUSED bool DeviceMatches(const Device* device, const {{as_cType(type.name)}} *const obj, uint32_t count = 1) {
|
DAWN_DECLARE_UNUSED bool ClientMatches(const Client* client, const {{as_cType(type.name)}} *const obj, uint32_t count = 1) {
|
||||||
ASSERT(count == 0 || obj != nullptr);
|
ASSERT(count == 0 || obj != nullptr);
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
if (!DeviceMatches(device, obj[i])) {
|
if (!ClientMatches(client, obj[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,12 +49,12 @@ namespace dawn_wire { namespace client {
|
|||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
bool DeviceMatches(const Device* device, WGPUChainedStruct const* chainedStruct);
|
bool ClientMatches(const Client* client, WGPUChainedStruct const* chainedStruct);
|
||||||
|
|
||||||
{% for type in by_category["structure"] if type.may_have_dawn_object %}
|
{% for type in by_category["structure"] if type.may_have_dawn_object %}
|
||||||
DAWN_DECLARE_UNUSED bool DeviceMatches(const Device* device, const {{as_cType(type.name)}}& obj) {
|
DAWN_DECLARE_UNUSED bool ClientMatches(const Client* client, const {{as_cType(type.name)}}& obj) {
|
||||||
{% if type.extensible %}
|
{% if type.extensible %}
|
||||||
if (!DeviceMatches(device, obj.nextInChain)) {
|
if (!ClientMatches(client, obj.nextInChain)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -63,7 +63,7 @@ namespace dawn_wire { namespace client {
|
|||||||
if (obj.{{as_varName(member.name)}} != nullptr)
|
if (obj.{{as_varName(member.name)}} != nullptr)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{
|
{
|
||||||
if (!DeviceMatches(device, obj.{{as_varName(member.name)}}
|
if (!ClientMatches(client, obj.{{as_varName(member.name)}}
|
||||||
{%- if member.annotation != "value" and member.length != "strlen" -%}
|
{%- if member.annotation != "value" and member.length != "strlen" -%}
|
||||||
, {{member_length(member, "obj.")}}
|
, {{member_length(member, "obj.")}}
|
||||||
{%- endif -%})) {
|
{%- endif -%})) {
|
||||||
@ -74,9 +74,9 @@ namespace dawn_wire { namespace client {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_DECLARE_UNUSED bool DeviceMatches(const Device* device, const {{as_cType(type.name)}} *const obj, uint32_t count = 1) {
|
DAWN_DECLARE_UNUSED bool ClientMatches(const Client* client, const {{as_cType(type.name)}} *const obj, uint32_t count = 1) {
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
if (!DeviceMatches(device, obj[i])) {
|
if (!ClientMatches(client, obj[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,14 +84,14 @@ namespace dawn_wire { namespace client {
|
|||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
bool DeviceMatches(const Device* device, WGPUChainedStruct const* chainedStruct) {
|
bool ClientMatches(const Client* client, WGPUChainedStruct const* chainedStruct) {
|
||||||
while (chainedStruct != nullptr) {
|
while (chainedStruct != nullptr) {
|
||||||
switch (chainedStruct->sType) {
|
switch (chainedStruct->sType) {
|
||||||
{% for sType in types["s type"].values if sType.valid %}
|
{% for sType in types["s type"].values if sType.valid %}
|
||||||
{% set CType = as_cType(sType.name) %}
|
{% set CType = as_cType(sType.name) %}
|
||||||
case {{as_cEnum(types["s type"].name, sType.name)}}: {
|
case {{as_cEnum(types["s type"].name, sType.name)}}: {
|
||||||
{% if types[sType.name.get()].may_have_dawn_object %}
|
{% if types[sType.name.get()].may_have_dawn_object %}
|
||||||
if (!DeviceMatches(device, reinterpret_cast<const {{CType}}*>(chainedStruct))) {
|
if (!ClientMatches(client, reinterpret_cast<const {{CType}}*>(chainedStruct))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -103,7 +103,7 @@ namespace dawn_wire { namespace client {
|
|||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
dawn::WarningLog()
|
dawn::WarningLog()
|
||||||
<< "All objects may not be from the same device. "
|
<< "All objects may not be from the same client. "
|
||||||
<< "Unknown sType " << chainedStruct->sType << " discarded.";
|
<< "Unknown sType " << chainedStruct->sType << " discarded.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -133,10 +133,10 @@ namespace dawn_wire { namespace client {
|
|||||||
) {
|
) {
|
||||||
{% if len(method.arguments) > 0 %}
|
{% if len(method.arguments) > 0 %}
|
||||||
{
|
{
|
||||||
bool sameDevice = true;
|
bool sameClient = true;
|
||||||
auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
|
auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
|
||||||
Device* device = self->device;
|
Client* client = self->client;
|
||||||
DAWN_UNUSED(device);
|
DAWN_UNUSED(client);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
{% for arg in method.arguments if arg.type.may_have_dawn_object or arg.type.category == "object" %}
|
{% for arg in method.arguments if arg.type.may_have_dawn_object or arg.type.category == "object" %}
|
||||||
@ -144,26 +144,26 @@ namespace dawn_wire { namespace client {
|
|||||||
if ({{as_varName(arg.name)}} != nullptr)
|
if ({{as_varName(arg.name)}} != nullptr)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{
|
{
|
||||||
if (!DeviceMatches(device, {{as_varName(arg.name)}}
|
if (!ClientMatches(client, {{as_varName(arg.name)}}
|
||||||
{%- if arg.annotation != "value" and arg.length != "strlen" -%}
|
{%- if arg.annotation != "value" and arg.length != "strlen" -%}
|
||||||
, {{member_length(arg, "")}}
|
, {{member_length(arg, "")}}
|
||||||
{%- endif -%})) {
|
{%- endif -%})) {
|
||||||
sameDevice = false;
|
sameClient = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
if (DAWN_UNLIKELY(!sameDevice)) {
|
if (DAWN_UNLIKELY(!sameClient)) {
|
||||||
device->InjectError(WGPUErrorType_Validation,
|
reinterpret_cast<Device*>(client->GetDevice())->InjectError(WGPUErrorType_Validation,
|
||||||
"All objects must be from the same device.");
|
"All objects must be from the same device.");
|
||||||
{% if method.return_type.category == "object" %}
|
{% if method.return_type.category == "object" %}
|
||||||
// Allocate an object without registering it on the server. This is backed by a real allocation on
|
// Allocate an object without registering it on the server. This is backed by a real allocation on
|
||||||
// the client so commands can be sent with it. But because it's not allocated on the server, it will
|
// the client so commands can be sent with it. But because it's not allocated on the server, it will
|
||||||
// be a fatal error to use it.
|
// be a fatal error to use it.
|
||||||
auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
|
auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
|
||||||
auto* allocation = self->device->GetClient()->{{method.return_type.name.CamelCase()}}Allocator().New(self->device);
|
auto* allocation = self->client->{{method.return_type.name.CamelCase()}}Allocator().New(self->client);
|
||||||
return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
|
return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
|
||||||
{% elif method.return_type.name.canonical_case() == "void" %}
|
{% elif method.return_type.name.canonical_case() == "void" %}
|
||||||
return;
|
return;
|
||||||
@ -176,7 +176,6 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
|
auto self = reinterpret_cast<{{as_wireType(type)}}>(cSelf);
|
||||||
{% if Suffix not in client_handwritten_commands %}
|
{% if Suffix not in client_handwritten_commands %}
|
||||||
Device* device = self->device;
|
|
||||||
{{Suffix}}Cmd cmd;
|
{{Suffix}}Cmd cmd;
|
||||||
|
|
||||||
//* Create the structure going on the wire on the stack and fill it with the value
|
//* Create the structure going on the wire on the stack and fill it with the value
|
||||||
@ -185,7 +184,7 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
//* For object creation, store the object ID the client will use for the result.
|
//* For object creation, store the object ID the client will use for the result.
|
||||||
{% if method.return_type.category == "object" %}
|
{% if method.return_type.category == "object" %}
|
||||||
auto* allocation = self->device->GetClient()->{{method.return_type.name.CamelCase()}}Allocator().New(self->device);
|
auto* allocation = self->client->{{method.return_type.name.CamelCase()}}Allocator().New(self->client);
|
||||||
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@ -194,7 +193,7 @@ namespace dawn_wire { namespace client {
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
//* Allocate space to send the command and copy the value args over.
|
//* Allocate space to send the command and copy the value args over.
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
self->client->SerializeCommand(cmd);
|
||||||
|
|
||||||
{% if method.return_type.category == "object" %}
|
{% if method.return_type.category == "object" %}
|
||||||
return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
|
return reinterpret_cast<{{as_cType(method.return_type.name)}}>(allocation->object.get());
|
||||||
@ -222,8 +221,8 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.objectType = ObjectType::{{type.name.CamelCase()}};
|
cmd.objectType = ObjectType::{{type.name.CamelCase()}};
|
||||||
cmd.objectId = obj->id;
|
cmd.objectId = obj->id;
|
||||||
|
|
||||||
obj->device->GetClient()->SerializeCommand(cmd);
|
obj->client->SerializeCommand(cmd);
|
||||||
obj->device->GetClient()->{{type.name.CamelCase()}}Allocator().Free(obj);
|
obj->client->{{type.name.CamelCase()}}Allocator().Free(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) {
|
void Client{{as_MethodSuffix(type.name, Name("reference"))}}({{cType}} cObj) {
|
||||||
|
@ -20,15 +20,15 @@
|
|||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
// static
|
// static
|
||||||
WGPUBuffer Buffer::Create(Device* device_, const WGPUBufferDescriptor* descriptor) {
|
WGPUBuffer Buffer::Create(Device* device, const WGPUBufferDescriptor* descriptor) {
|
||||||
Client* wireClient = device_->GetClient();
|
Client* wireClient = device->client;
|
||||||
|
|
||||||
bool mappable =
|
bool mappable =
|
||||||
(descriptor->usage & (WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite)) != 0 ||
|
(descriptor->usage & (WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite)) != 0 ||
|
||||||
descriptor->mappedAtCreation;
|
descriptor->mappedAtCreation;
|
||||||
if (mappable && descriptor->size >= std::numeric_limits<size_t>::max()) {
|
if (mappable && descriptor->size >= std::numeric_limits<size_t>::max()) {
|
||||||
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer is too large for map usage");
|
device->InjectError(WGPUErrorType_OutOfMemory, "Buffer is too large for map usage");
|
||||||
return device_->CreateErrorBuffer();
|
return device->CreateErrorBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
|
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
|
||||||
@ -42,16 +42,16 @@ namespace dawn_wire { namespace client {
|
|||||||
writeHandle.reset(
|
writeHandle.reset(
|
||||||
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size));
|
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size));
|
||||||
if (writeHandle == nullptr) {
|
if (writeHandle == nullptr) {
|
||||||
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
|
device->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
|
||||||
return device_->CreateErrorBuffer();
|
return device->CreateErrorBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the handle, it may fail by returning a nullptr in writeData.
|
// Open the handle, it may fail by returning a nullptr in writeData.
|
||||||
size_t writeDataLength = 0;
|
size_t writeDataLength = 0;
|
||||||
std::tie(writeData, writeDataLength) = writeHandle->Open();
|
std::tie(writeData, writeDataLength) = writeHandle->Open();
|
||||||
if (writeData == nullptr) {
|
if (writeData == nullptr) {
|
||||||
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
|
device->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
|
||||||
return device_->CreateErrorBuffer();
|
return device->CreateErrorBuffer();
|
||||||
}
|
}
|
||||||
ASSERT(writeDataLength == descriptor->size);
|
ASSERT(writeDataLength == descriptor->size);
|
||||||
|
|
||||||
@ -60,12 +60,13 @@ namespace dawn_wire { namespace client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the buffer and send the creation command.
|
// Create the buffer and send the creation command.
|
||||||
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device_);
|
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(wireClient);
|
||||||
Buffer* buffer = bufferObjectAndSerial->object.get();
|
Buffer* buffer = bufferObjectAndSerial->object.get();
|
||||||
|
buffer->mDevice = device;
|
||||||
buffer->mSize = descriptor->size;
|
buffer->mSize = descriptor->size;
|
||||||
|
|
||||||
DeviceCreateBufferCmd cmd;
|
DeviceCreateBufferCmd cmd;
|
||||||
cmd.device = ToAPI(device_);
|
cmd.device = ToAPI(device);
|
||||||
cmd.descriptor = descriptor;
|
cmd.descriptor = descriptor;
|
||||||
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation};
|
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation};
|
||||||
cmd.handleCreateInfoLength = writeHandleCreateInfoLength;
|
cmd.handleCreateInfoLength = writeHandleCreateInfoLength;
|
||||||
@ -88,13 +89,14 @@ namespace dawn_wire { namespace client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
WGPUBuffer Buffer::CreateError(Device* device_) {
|
WGPUBuffer Buffer::CreateError(Device* device) {
|
||||||
auto* allocation = device_->GetClient()->BufferAllocator().New(device_);
|
auto* allocation = device->client->BufferAllocator().New(device->client);
|
||||||
|
allocation->object->mDevice = device;
|
||||||
|
|
||||||
DeviceCreateErrorBufferCmd cmd;
|
DeviceCreateErrorBufferCmd cmd;
|
||||||
cmd.self = ToAPI(device_);
|
cmd.self = ToAPI(device);
|
||||||
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
||||||
device_->GetClient()->SerializeCommand(cmd);
|
device->client->SerializeCommand(cmd);
|
||||||
|
|
||||||
return ToAPI(allocation->object.get());
|
return ToAPI(allocation->object.get());
|
||||||
}
|
}
|
||||||
@ -124,7 +126,7 @@ namespace dawn_wire { namespace client {
|
|||||||
size_t size,
|
size_t size,
|
||||||
WGPUBufferMapCallback callback,
|
WGPUBufferMapCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
if (device->GetClient()->IsDisconnected()) {
|
if (client->IsDisconnected()) {
|
||||||
return callback(WGPUBufferMapAsyncStatus_DeviceLost, userdata);
|
return callback(WGPUBufferMapAsyncStatus_DeviceLost, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +140,8 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
// Step 1. Do early validation of READ ^ WRITE because the server rejects mode = 0.
|
// Step 1. Do early validation of READ ^ WRITE because the server rejects mode = 0.
|
||||||
if (!(isReadMode ^ isWriteMode)) {
|
if (!(isReadMode ^ isWriteMode)) {
|
||||||
device->InjectError(WGPUErrorType_Validation, "MapAsync error (you figure out :P)");
|
mDevice->InjectError(WGPUErrorType_Validation,
|
||||||
|
"MapAsync mode must be exactly one of Read or Write");
|
||||||
if (callback != nullptr) {
|
if (callback != nullptr) {
|
||||||
callback(WGPUBufferMapAsyncStatus_Error, userdata);
|
callback(WGPUBufferMapAsyncStatus_Error, userdata);
|
||||||
}
|
}
|
||||||
@ -158,19 +161,17 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
// Step 2a: Create the read / write handles for this request.
|
// Step 2a: Create the read / write handles for this request.
|
||||||
if (isReadMode) {
|
if (isReadMode) {
|
||||||
request.readHandle.reset(
|
request.readHandle.reset(client->GetMemoryTransferService()->CreateReadHandle(size));
|
||||||
device->GetClient()->GetMemoryTransferService()->CreateReadHandle(size));
|
|
||||||
if (request.readHandle == nullptr) {
|
if (request.readHandle == nullptr) {
|
||||||
device->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping");
|
mDevice->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping");
|
||||||
callback(WGPUBufferMapAsyncStatus_Error, userdata);
|
callback(WGPUBufferMapAsyncStatus_Error, userdata);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ASSERT(isWriteMode);
|
ASSERT(isWriteMode);
|
||||||
request.writeHandle.reset(
|
request.writeHandle.reset(client->GetMemoryTransferService()->CreateWriteHandle(size));
|
||||||
device->GetClient()->GetMemoryTransferService()->CreateWriteHandle(size));
|
|
||||||
if (request.writeHandle == nullptr) {
|
if (request.writeHandle == nullptr) {
|
||||||
device->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping");
|
mDevice->InjectError(WGPUErrorType_OutOfMemory, "Failed to create buffer mapping");
|
||||||
callback(WGPUBufferMapAsyncStatus_Error, userdata);
|
callback(WGPUBufferMapAsyncStatus_Error, userdata);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -188,15 +189,15 @@ namespace dawn_wire { namespace client {
|
|||||||
// Step 3a. Fill the handle create info in the command.
|
// Step 3a. Fill the handle create info in the command.
|
||||||
if (isReadMode) {
|
if (isReadMode) {
|
||||||
cmd.handleCreateInfoLength = request.readHandle->SerializeCreateSize();
|
cmd.handleCreateInfoLength = request.readHandle->SerializeCreateSize();
|
||||||
device->GetClient()->SerializeCommand(
|
client->SerializeCommand(cmd, cmd.handleCreateInfoLength, [&](char* cmdSpace) {
|
||||||
cmd, cmd.handleCreateInfoLength,
|
request.readHandle->SerializeCreate(cmdSpace);
|
||||||
[&](char* cmdSpace) { request.readHandle->SerializeCreate(cmdSpace); });
|
});
|
||||||
} else {
|
} else {
|
||||||
ASSERT(isWriteMode);
|
ASSERT(isWriteMode);
|
||||||
cmd.handleCreateInfoLength = request.writeHandle->SerializeCreateSize();
|
cmd.handleCreateInfoLength = request.writeHandle->SerializeCreateSize();
|
||||||
device->GetClient()->SerializeCommand(
|
client->SerializeCommand(cmd, cmd.handleCreateInfoLength, [&](char* cmdSpace) {
|
||||||
cmd, cmd.handleCreateInfoLength,
|
request.writeHandle->SerializeCreate(cmdSpace);
|
||||||
[&](char* cmdSpace) { request.writeHandle->SerializeCreate(cmdSpace); });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4. Register this request so that we can retrieve it from its serial when the server
|
// Step 4. Register this request so that we can retrieve it from its serial when the server
|
||||||
@ -323,7 +324,7 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.writeFlushInfoLength = writeFlushInfoLength;
|
cmd.writeFlushInfoLength = writeFlushInfoLength;
|
||||||
cmd.writeFlushInfo = nullptr;
|
cmd.writeFlushInfo = nullptr;
|
||||||
|
|
||||||
device->GetClient()->SerializeCommand(cmd, writeFlushInfoLength, [&](char* cmdSpace) {
|
client->SerializeCommand(cmd, writeFlushInfoLength, [&](char* cmdSpace) {
|
||||||
// Serialize flush metadata into the space after the command.
|
// Serialize flush metadata into the space after the command.
|
||||||
// This closes the handle for writing.
|
// This closes the handle for writing.
|
||||||
mWriteHandle->SerializeFlush(cmdSpace);
|
mWriteHandle->SerializeFlush(cmdSpace);
|
||||||
@ -347,7 +348,7 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
BufferUnmapCmd cmd;
|
BufferUnmapCmd cmd;
|
||||||
cmd.self = ToAPI(this);
|
cmd.self = ToAPI(this);
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::Destroy() {
|
void Buffer::Destroy() {
|
||||||
@ -365,7 +366,7 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
BufferDestroyCmd cmd;
|
BufferDestroyCmd cmd;
|
||||||
cmd.self = ToAPI(this);
|
cmd.self = ToAPI(this);
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::IsMappedForReading() const {
|
bool Buffer::IsMappedForReading() const {
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
|
class Device;
|
||||||
|
|
||||||
class Buffer final : public ObjectBase {
|
class Buffer final : public ObjectBase {
|
||||||
public:
|
public:
|
||||||
using ObjectBase::ObjectBase;
|
using ObjectBase::ObjectBase;
|
||||||
@ -55,6 +57,8 @@ namespace dawn_wire { namespace client {
|
|||||||
bool IsMappedForWriting() const;
|
bool IsMappedForWriting() const;
|
||||||
bool CheckGetMappedRangeOffsetSize(size_t offset, size_t size) const;
|
bool CheckGetMappedRangeOffsetSize(size_t offset, size_t size) const;
|
||||||
|
|
||||||
|
Device* mDevice;
|
||||||
|
|
||||||
// We want to defer all the validation to the server, which means we could have multiple
|
// We want to defer all the validation to the server, which means we could have multiple
|
||||||
// map request in flight at a single time and need to track them separately.
|
// map request in flight at a single time and need to track them separately.
|
||||||
// On well-behaved applications, only one request should exist at a single time.
|
// On well-behaved applications, only one request should exist at a single time.
|
||||||
|
@ -57,10 +57,23 @@ namespace dawn_wire { namespace client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::DestroyAllObjects() {
|
void Client::DestroyAllObjects() {
|
||||||
while (!mDevices.empty()) {
|
for (auto& objectList : mObjects) {
|
||||||
// Note: We don't send a DestroyObject command for the device
|
ObjectType objectType = static_cast<ObjectType>(&objectList - mObjects.data());
|
||||||
// since freeing a device object is done out of band.
|
while (!objectList.empty()) {
|
||||||
DeviceAllocator().Free(static_cast<Device*>(mDevices.head()->value()));
|
ObjectBase* object = objectList.head()->value();
|
||||||
|
if (object == mDevice) {
|
||||||
|
// Note: We don't send a DestroyObject command for the device
|
||||||
|
// since freeing a device object is done out of band.
|
||||||
|
DeviceAllocator().Free(mDevice);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyObjectCmd cmd;
|
||||||
|
cmd.objectType = objectType;
|
||||||
|
cmd.objectId = object->id;
|
||||||
|
SerializeCommand(cmd);
|
||||||
|
FreeObject(objectType, object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,9 +84,8 @@ namespace dawn_wire { namespace client {
|
|||||||
return reinterpret_cast<WGPUDeviceImpl*>(mDevice);
|
return reinterpret_cast<WGPUDeviceImpl*>(mDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReservedTexture Client::ReserveTexture(WGPUDevice cDevice) {
|
ReservedTexture Client::ReserveTexture(WGPUDevice device) {
|
||||||
Device* device = FromAPI(cDevice);
|
auto* allocation = TextureAllocator().New(this);
|
||||||
auto* allocation = TextureAllocator().New(device);
|
|
||||||
|
|
||||||
ReservedTexture result;
|
ReservedTexture result;
|
||||||
result.texture = ToAPI(allocation->object.get());
|
result.texture = ToAPI(allocation->object.get());
|
||||||
@ -87,12 +99,14 @@ namespace dawn_wire { namespace client {
|
|||||||
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
|
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
|
||||||
if (mDevice != nullptr) {
|
if (mDevice != nullptr) {
|
||||||
mDevice->HandleDeviceLost("GPU connection lost");
|
mDevice->HandleDeviceLost("GPU connection lost");
|
||||||
mDevice->CancelCallbacksForDisconnect();
|
|
||||||
}
|
}
|
||||||
}
|
for (auto& objectList : mObjects) {
|
||||||
|
LinkNode<ObjectBase>* object = objectList.head();
|
||||||
void Client::TrackObject(Device* device) {
|
while (object != objectList.end()) {
|
||||||
mDevices.Append(device);
|
object->value()->CancelCallbacksForDisconnect();
|
||||||
|
object = object->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::IsDisconnected() const {
|
bool Client::IsDisconnected() const {
|
||||||
|
@ -62,7 +62,10 @@ namespace dawn_wire { namespace client {
|
|||||||
void Disconnect();
|
void Disconnect();
|
||||||
bool IsDisconnected() const;
|
bool IsDisconnected() const;
|
||||||
|
|
||||||
void TrackObject(Device* device);
|
template <typename T>
|
||||||
|
void TrackObject(T* object) {
|
||||||
|
mObjects[ObjectTypeToTypeEnum<T>::value].Append(object);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DestroyAllObjects();
|
void DestroyAllObjects();
|
||||||
@ -75,7 +78,7 @@ namespace dawn_wire { namespace client {
|
|||||||
MemoryTransferService* mMemoryTransferService = nullptr;
|
MemoryTransferService* mMemoryTransferService = nullptr;
|
||||||
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
|
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
|
||||||
|
|
||||||
LinkedList<ObjectBase> mDevices;
|
PerObjectType<LinkedList<ObjectBase>> mObjects;
|
||||||
bool mDisconnected = false;
|
bool mDisconnected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
Device::Device(Client* client, uint32_t initialRefcount, uint32_t initialId)
|
Device::Device(Client* clientIn, uint32_t initialRefcount, uint32_t initialId)
|
||||||
: ObjectBase(this, initialRefcount, initialId), mClient(client) {
|
: ObjectBase(clientIn, initialRefcount, initialId) {
|
||||||
#if defined(DAWN_ENABLE_ASSERTS)
|
#if defined(DAWN_ENABLE_ASSERTS)
|
||||||
mErrorCallback = [](WGPUErrorType, char const*, void*) {
|
mErrorCallback = [](WGPUErrorType, char const*, void*) {
|
||||||
static bool calledOnce = false;
|
static bool calledOnce = false;
|
||||||
@ -46,14 +46,14 @@ namespace dawn_wire { namespace client {
|
|||||||
};
|
};
|
||||||
#endif // DAWN_ENABLE_ASSERTS
|
#endif // DAWN_ENABLE_ASSERTS
|
||||||
// Get the default queue for this device.
|
// Get the default queue for this device.
|
||||||
auto* allocation = mClient->QueueAllocator().New(this);
|
auto* allocation = client->QueueAllocator().New(client);
|
||||||
mDefaultQueue = allocation->object.get();
|
mDefaultQueue = allocation->object.get();
|
||||||
|
|
||||||
DeviceGetDefaultQueueCmd cmd;
|
DeviceGetDefaultQueueCmd cmd;
|
||||||
cmd.self = ToAPI(this);
|
cmd.self = ToAPI(this);
|
||||||
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
||||||
|
|
||||||
mClient->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device() {
|
Device::~Device() {
|
||||||
@ -77,27 +77,6 @@ namespace dawn_wire { namespace client {
|
|||||||
"Device destroyed before callback", it.second.userdata);
|
"Device destroyed before callback", it.second.userdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DestroyAllObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::DestroyAllObjects() {
|
|
||||||
for (auto& objectList : mObjects) {
|
|
||||||
ObjectType objectType = static_cast<ObjectType>(&objectList - mObjects.data());
|
|
||||||
while (!objectList.empty()) {
|
|
||||||
ObjectBase* object = objectList.head()->value();
|
|
||||||
|
|
||||||
DestroyObjectCmd cmd;
|
|
||||||
cmd.objectType = objectType;
|
|
||||||
cmd.objectId = object->id;
|
|
||||||
mClient->SerializeCommand(cmd);
|
|
||||||
mClient->FreeObject(objectType, object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Client* Device::GetClient() {
|
|
||||||
return mClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::HandleError(WGPUErrorType errorType, const char* message) {
|
void Device::HandleError(WGPUErrorType errorType, const char* message) {
|
||||||
@ -133,14 +112,6 @@ namespace dawn_wire { namespace client {
|
|||||||
it.second.callback(WGPUErrorType_DeviceLost, "Device lost", it.second.userdata);
|
it.second.callback(WGPUErrorType_DeviceLost, "Device lost", it.second.userdata);
|
||||||
}
|
}
|
||||||
mErrorScopes.clear();
|
mErrorScopes.clear();
|
||||||
|
|
||||||
for (auto& objectList : mObjects) {
|
|
||||||
LinkNode<ObjectBase>* object = objectList.head();
|
|
||||||
while (object != objectList.end()) {
|
|
||||||
object->value()->CancelCallbacksForDisconnect();
|
|
||||||
object = object->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata) {
|
void Device::SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata) {
|
||||||
@ -160,7 +131,7 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.self = ToAPI(this);
|
cmd.self = ToAPI(this);
|
||||||
cmd.filter = filter;
|
cmd.filter = filter;
|
||||||
|
|
||||||
mClient->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
|
bool Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
|
||||||
@ -169,7 +140,7 @@ namespace dawn_wire { namespace client {
|
|||||||
}
|
}
|
||||||
mErrorScopeStackSize--;
|
mErrorScopeStackSize--;
|
||||||
|
|
||||||
if (GetClient()->IsDisconnected()) {
|
if (client->IsDisconnected()) {
|
||||||
callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
|
callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -183,7 +154,7 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.device = ToAPI(this);
|
cmd.device = ToAPI(this);
|
||||||
cmd.requestSerial = serial;
|
cmd.requestSerial = serial;
|
||||||
|
|
||||||
mClient->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -219,7 +190,7 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.self = ToAPI(this);
|
cmd.self = ToAPI(this);
|
||||||
cmd.type = type;
|
cmd.type = type;
|
||||||
cmd.message = message;
|
cmd.message = message;
|
||||||
mClient->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
|
WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
|
||||||
@ -238,7 +209,7 @@ namespace dawn_wire { namespace client {
|
|||||||
void Device::CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor,
|
void Device::CreateReadyComputePipeline(WGPUComputePipelineDescriptor const* descriptor,
|
||||||
WGPUCreateReadyComputePipelineCallback callback,
|
WGPUCreateReadyComputePipelineCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
if (device->GetClient()->IsDisconnected()) {
|
if (client->IsDisconnected()) {
|
||||||
return callback(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr,
|
return callback(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr,
|
||||||
"GPU device disconnected", userdata);
|
"GPU device disconnected", userdata);
|
||||||
}
|
}
|
||||||
@ -251,14 +222,14 @@ namespace dawn_wire { namespace client {
|
|||||||
ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
|
ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
|
||||||
cmd.requestSerial = serial;
|
cmd.requestSerial = serial;
|
||||||
|
|
||||||
auto* allocation = GetClient()->ComputePipelineAllocator().New(this);
|
auto* allocation = client->ComputePipelineAllocator().New(client);
|
||||||
CreateReadyPipelineRequest request = {};
|
CreateReadyPipelineRequest request = {};
|
||||||
request.createReadyComputePipelineCallback = callback;
|
request.createReadyComputePipelineCallback = callback;
|
||||||
request.userdata = userdata;
|
request.userdata = userdata;
|
||||||
request.pipelineObjectID = allocation->object->id;
|
request.pipelineObjectID = allocation->object->id;
|
||||||
|
|
||||||
cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
|
cmd.pipelineObjectHandle = ObjectHandle{allocation->object->id, allocation->generation};
|
||||||
GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
|
|
||||||
mCreateReadyPipelineRequests[serial] = std::move(request);
|
mCreateReadyPipelineRequests[serial] = std::move(request);
|
||||||
}
|
}
|
||||||
@ -275,12 +246,12 @@ namespace dawn_wire { namespace client {
|
|||||||
mCreateReadyPipelineRequests.erase(requestIt);
|
mCreateReadyPipelineRequests.erase(requestIt);
|
||||||
|
|
||||||
auto pipelineAllocation =
|
auto pipelineAllocation =
|
||||||
GetClient()->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
|
client->ComputePipelineAllocator().GetObject(request.pipelineObjectID);
|
||||||
|
|
||||||
// If the return status is a failure we should give a null pipeline to the callback and
|
// 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 both on the client side and the server side.
|
||||||
if (status != WGPUCreateReadyPipelineStatus_Success) {
|
if (status != WGPUCreateReadyPipelineStatus_Success) {
|
||||||
GetClient()->ComputePipelineAllocator().Free(pipelineAllocation);
|
client->ComputePipelineAllocator().Free(pipelineAllocation);
|
||||||
request.createReadyComputePipelineCallback(status, nullptr, message, request.userdata);
|
request.createReadyComputePipelineCallback(status, nullptr, message, request.userdata);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -294,7 +265,7 @@ namespace dawn_wire { namespace client {
|
|||||||
void Device::CreateReadyRenderPipeline(WGPURenderPipelineDescriptor const* descriptor,
|
void Device::CreateReadyRenderPipeline(WGPURenderPipelineDescriptor const* descriptor,
|
||||||
WGPUCreateReadyRenderPipelineCallback callback,
|
WGPUCreateReadyRenderPipelineCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
if (GetClient()->IsDisconnected()) {
|
if (client->IsDisconnected()) {
|
||||||
return callback(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr,
|
return callback(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr,
|
||||||
"GPU device disconnected", userdata);
|
"GPU device disconnected", userdata);
|
||||||
}
|
}
|
||||||
@ -306,14 +277,14 @@ namespace dawn_wire { namespace client {
|
|||||||
ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
|
ASSERT(mCreateReadyPipelineRequests.find(serial) == mCreateReadyPipelineRequests.end());
|
||||||
cmd.requestSerial = serial;
|
cmd.requestSerial = serial;
|
||||||
|
|
||||||
auto* allocation = GetClient()->RenderPipelineAllocator().New(this);
|
auto* allocation = client->RenderPipelineAllocator().New(client);
|
||||||
CreateReadyPipelineRequest request = {};
|
CreateReadyPipelineRequest request = {};
|
||||||
request.createReadyRenderPipelineCallback = callback;
|
request.createReadyRenderPipelineCallback = callback;
|
||||||
request.userdata = userdata;
|
request.userdata = userdata;
|
||||||
request.pipelineObjectID = allocation->object->id;
|
request.pipelineObjectID = allocation->object->id;
|
||||||
|
|
||||||
cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
|
cmd.pipelineObjectHandle = ObjectHandle(allocation->object->id, allocation->generation);
|
||||||
GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
|
|
||||||
mCreateReadyPipelineRequests[serial] = std::move(request);
|
mCreateReadyPipelineRequests[serial] = std::move(request);
|
||||||
}
|
}
|
||||||
@ -330,12 +301,12 @@ namespace dawn_wire { namespace client {
|
|||||||
mCreateReadyPipelineRequests.erase(requestIt);
|
mCreateReadyPipelineRequests.erase(requestIt);
|
||||||
|
|
||||||
auto pipelineAllocation =
|
auto pipelineAllocation =
|
||||||
GetClient()->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
|
client->RenderPipelineAllocator().GetObject(request.pipelineObjectID);
|
||||||
|
|
||||||
// If the return status is a failure we should give a null pipeline to the callback and
|
// 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 both on the client side and the server side.
|
||||||
if (status != WGPUCreateReadyPipelineStatus_Success) {
|
if (status != WGPUCreateReadyPipelineStatus_Success) {
|
||||||
GetClient()->RenderPipelineAllocator().Free(pipelineAllocation);
|
client->RenderPipelineAllocator().Free(pipelineAllocation);
|
||||||
request.createReadyRenderPipelineCallback(status, nullptr, message, request.userdata);
|
request.createReadyRenderPipelineCallback(status, nullptr, message, request.userdata);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ namespace dawn_wire { namespace client {
|
|||||||
Device(Client* client, uint32_t refcount, uint32_t id);
|
Device(Client* client, uint32_t refcount, uint32_t id);
|
||||||
~Device();
|
~Device();
|
||||||
|
|
||||||
Client* GetClient();
|
|
||||||
void SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata);
|
void SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata);
|
||||||
void SetDeviceLostCallback(WGPUDeviceLostCallback errorCallback, void* errorUserdata);
|
void SetDeviceLostCallback(WGPUDeviceLostCallback errorCallback, void* errorUserdata);
|
||||||
void InjectError(WGPUErrorType type, const char* message);
|
void InjectError(WGPUErrorType type, const char* message);
|
||||||
@ -63,16 +62,9 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
WGPUQueue GetDefaultQueue();
|
WGPUQueue GetDefaultQueue();
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void TrackObject(T* object) {
|
|
||||||
mObjects[ObjectTypeToTypeEnum<T>::value].Append(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CancelCallbacksForDisconnect() override;
|
void CancelCallbacksForDisconnect() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DestroyAllObjects();
|
|
||||||
|
|
||||||
struct ErrorScopeData {
|
struct ErrorScopeData {
|
||||||
WGPUErrorCallback callback = nullptr;
|
WGPUErrorCallback callback = nullptr;
|
||||||
void* userdata = nullptr;
|
void* userdata = nullptr;
|
||||||
@ -90,7 +82,6 @@ namespace dawn_wire { namespace client {
|
|||||||
std::map<uint64_t, CreateReadyPipelineRequest> mCreateReadyPipelineRequests;
|
std::map<uint64_t, CreateReadyPipelineRequest> mCreateReadyPipelineRequests;
|
||||||
uint64_t mCreateReadyPipelineRequestSerial = 0;
|
uint64_t mCreateReadyPipelineRequestSerial = 0;
|
||||||
|
|
||||||
Client* mClient = nullptr;
|
|
||||||
WGPUErrorCallback mErrorCallback = nullptr;
|
WGPUErrorCallback mErrorCallback = nullptr;
|
||||||
WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
|
WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
|
||||||
bool mDidRunLostCallback = false;
|
bool mDidRunLostCallback = false;
|
||||||
@ -98,8 +89,6 @@ namespace dawn_wire { namespace client {
|
|||||||
void* mDeviceLostUserdata = nullptr;
|
void* mDeviceLostUserdata = nullptr;
|
||||||
|
|
||||||
Queue* mDefaultQueue = nullptr;
|
Queue* mDefaultQueue = nullptr;
|
||||||
|
|
||||||
PerObjectType<LinkedList<ObjectBase>> mObjects;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include "dawn_wire/client/Fence.h"
|
#include "dawn_wire/client/Fence.h"
|
||||||
|
|
||||||
#include "dawn_wire/client/Client.h"
|
#include "dawn_wire/client/Client.h"
|
||||||
#include "dawn_wire/client/Device.h"
|
|
||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ namespace dawn_wire { namespace client {
|
|||||||
void Fence::OnCompletion(uint64_t value,
|
void Fence::OnCompletion(uint64_t value,
|
||||||
WGPUFenceOnCompletionCallback callback,
|
WGPUFenceOnCompletionCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
if (device->GetClient()->IsDisconnected()) {
|
if (client->IsDisconnected()) {
|
||||||
return callback(WGPUFenceCompletionStatus_DeviceLost, userdata);
|
return callback(WGPUFenceCompletionStatus_DeviceLost, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
mOnCompletionRequests[serial] = {callback, userdata};
|
mOnCompletionRequests[serial] = {callback, userdata};
|
||||||
|
|
||||||
this->device->GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fence::OnUpdateCompletedValueCallback(uint64_t value) {
|
void Fence::OnUpdateCompletedValueCallback(uint64_t value) {
|
||||||
|
@ -25,14 +25,8 @@
|
|||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
class Client;
|
|
||||||
class Device;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ObjectAllocator {
|
class ObjectAllocator {
|
||||||
using ObjectOwner =
|
|
||||||
typename std::conditional<std::is_same<T, Device>::value, Client, Device>::type;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct ObjectAndSerial {
|
struct ObjectAndSerial {
|
||||||
ObjectAndSerial(std::unique_ptr<T> object, uint32_t generation)
|
ObjectAndSerial(std::unique_ptr<T> object, uint32_t generation)
|
||||||
@ -47,10 +41,11 @@ namespace dawn_wire { namespace client {
|
|||||||
mObjects.emplace_back(nullptr, 0);
|
mObjects.emplace_back(nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectAndSerial* New(ObjectOwner* owner) {
|
template <typename Client>
|
||||||
|
ObjectAndSerial* New(Client* client) {
|
||||||
uint32_t id = GetNewId();
|
uint32_t id = GetNewId();
|
||||||
auto object = std::make_unique<T>(owner, 1, id);
|
auto object = std::make_unique<T>(client, 1, id);
|
||||||
owner->TrackObject(object.get());
|
client->TrackObject(object.get());
|
||||||
|
|
||||||
if (id >= mObjects.size()) {
|
if (id >= mObjects.size()) {
|
||||||
ASSERT(id == mObjects.size());
|
ASSERT(id == mObjects.size());
|
||||||
@ -109,7 +104,6 @@ namespace dawn_wire { namespace client {
|
|||||||
uint32_t mCurrentId = 1;
|
uint32_t mCurrentId = 1;
|
||||||
std::vector<uint32_t> mFreeIds;
|
std::vector<uint32_t> mFreeIds;
|
||||||
std::vector<ObjectAndSerial> mObjects;
|
std::vector<ObjectAndSerial> mObjects;
|
||||||
Device* mDevice;
|
|
||||||
};
|
};
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
||||||
|
@ -22,16 +22,16 @@
|
|||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
class Device;
|
class Client;
|
||||||
|
|
||||||
// All non-Device objects of the client side have:
|
// All objects on the client side have:
|
||||||
// - A pointer to the device to get where to serialize commands
|
// - A pointer to the Client to get where to serialize commands
|
||||||
// - The external reference count
|
// - The external reference count
|
||||||
// - An ID that is used to refer to this object when talking with the server side
|
// - An ID that is used to refer to this object when talking with the server side
|
||||||
// - A next/prev pointer. They are part of a linked list of objects of the same type.
|
// - A next/prev pointer. They are part of a linked list of objects of the same type.
|
||||||
struct ObjectBase : public LinkNode<ObjectBase> {
|
struct ObjectBase : public LinkNode<ObjectBase> {
|
||||||
ObjectBase(Device* device, uint32_t refcount, uint32_t id)
|
ObjectBase(Client* client, uint32_t refcount, uint32_t id)
|
||||||
: device(device), refcount(refcount), id(id) {
|
: client(client), refcount(refcount), id(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~ObjectBase() {
|
~ObjectBase() {
|
||||||
@ -41,7 +41,7 @@ namespace dawn_wire { namespace client {
|
|||||||
virtual void CancelCallbacksForDisconnect() {
|
virtual void CancelCallbacksForDisconnect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Device* const device;
|
Client* const client;
|
||||||
uint32_t refcount;
|
uint32_t refcount;
|
||||||
const uint32_t id;
|
const uint32_t id;
|
||||||
};
|
};
|
||||||
|
@ -20,13 +20,13 @@
|
|||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
WGPUFence Queue::CreateFence(WGPUFenceDescriptor const* descriptor) {
|
WGPUFence Queue::CreateFence(WGPUFenceDescriptor const* descriptor) {
|
||||||
auto* allocation = device->GetClient()->FenceAllocator().New(device);
|
auto* allocation = client->FenceAllocator().New(client);
|
||||||
|
|
||||||
QueueCreateFenceCmd cmd;
|
QueueCreateFenceCmd cmd;
|
||||||
cmd.self = ToAPI(this);
|
cmd.self = ToAPI(this);
|
||||||
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
|
||||||
cmd.descriptor = descriptor;
|
cmd.descriptor = descriptor;
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
|
|
||||||
Fence* fence = allocation->object.get();
|
Fence* fence = allocation->object.get();
|
||||||
fence->Initialize(this, descriptor);
|
fence->Initialize(this, descriptor);
|
||||||
@ -46,7 +46,7 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.data = static_cast<const uint8_t*>(data);
|
cmd.data = static_cast<const uint8_t*>(data);
|
||||||
cmd.size = size;
|
cmd.size = size;
|
||||||
|
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::WriteTexture(const WGPUTextureCopyView* destination,
|
void Queue::WriteTexture(const WGPUTextureCopyView* destination,
|
||||||
@ -62,7 +62,7 @@ namespace dawn_wire { namespace client {
|
|||||||
cmd.dataLayout = dataLayout;
|
cmd.dataLayout = dataLayout;
|
||||||
cmd.writeSize = writeSize;
|
cmd.writeSize = writeSize;
|
||||||
|
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
Loading…
x
Reference in New Issue
Block a user