dawn_wire: Implement device-related callbacks for multiple devices
Bug: dawn:565 Change-Id: Ic80a3bc1bbfd479af04e77afa0eb3f4ca3387ecd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38282 Reviewed-by: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
f1f8394de0
commit
4d66fb2d61
|
@ -52,7 +52,7 @@
|
||||||
{ "name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"}
|
{ "name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"}
|
||||||
],
|
],
|
||||||
"device pop error scope": [
|
"device pop error scope": [
|
||||||
{ "name": "device", "type": "device" },
|
{ "name": "device id", "type": "ObjectId" },
|
||||||
{ "name": "request serial", "type": "uint64_t" }
|
{ "name": "request serial", "type": "uint64_t" }
|
||||||
],
|
],
|
||||||
"destroy object": [
|
"destroy object": [
|
||||||
|
@ -89,23 +89,28 @@
|
||||||
{ "name": "read initial data info", "type": "uint8_t", "annotation": "const*", "length": "read initial data info length", "skip_serialize": true }
|
{ "name": "read initial data info", "type": "uint8_t", "annotation": "const*", "length": "read initial data info length", "skip_serialize": true }
|
||||||
],
|
],
|
||||||
"device create ready compute pipeline callback": [
|
"device create ready compute pipeline callback": [
|
||||||
|
{ "name": "device", "type": "ObjectHandle", "handle_type": "device" },
|
||||||
{ "name": "request serial", "type": "uint64_t" },
|
{ "name": "request serial", "type": "uint64_t" },
|
||||||
{ "name": "status", "type": "create ready pipeline status" },
|
{ "name": "status", "type": "create ready pipeline status" },
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
],
|
],
|
||||||
"device create ready render pipeline callback": [
|
"device create ready render pipeline callback": [
|
||||||
|
{ "name": "device", "type": "ObjectHandle", "handle_type": "device" },
|
||||||
{ "name": "request serial", "type": "uint64_t" },
|
{ "name": "request serial", "type": "uint64_t" },
|
||||||
{ "name": "status", "type": "create ready pipeline status" },
|
{ "name": "status", "type": "create ready pipeline status" },
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
],
|
],
|
||||||
"device uncaptured error callback": [
|
"device uncaptured error callback": [
|
||||||
|
{ "name": "device", "type": "ObjectHandle", "handle_type": "device" },
|
||||||
{ "name": "type", "type": "error type"},
|
{ "name": "type", "type": "error type"},
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
],
|
],
|
||||||
"device lost callback" : [
|
"device lost callback" : [
|
||||||
|
{ "name": "device", "type": "ObjectHandle", "handle_type": "device" },
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
],
|
],
|
||||||
"device pop error scope callback": [
|
"device pop error scope callback": [
|
||||||
|
{ "name": "device", "type": "ObjectHandle", "handle_type": "device" },
|
||||||
{ "name": "request serial", "type": "uint64_t" },
|
{ "name": "request serial", "type": "uint64_t" },
|
||||||
{ "name": "type", "type": "error type" },
|
{ "name": "type", "type": "error type" },
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
|
|
|
@ -129,14 +129,18 @@ namespace dawn_wire { namespace client {
|
||||||
void Client::Disconnect() {
|
void Client::Disconnect() {
|
||||||
mDisconnected = true;
|
mDisconnected = true;
|
||||||
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
|
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
|
||||||
if (mDevice != nullptr) {
|
|
||||||
mDevice->HandleDeviceLost("GPU connection lost");
|
auto& deviceList = mObjects[ObjectType::Device];
|
||||||
|
{
|
||||||
|
for (LinkNode<ObjectBase>* device = deviceList.head(); device != deviceList.end();
|
||||||
|
device = device->next()) {
|
||||||
|
static_cast<Device*>(device->value())->HandleDeviceLost("GPU connection lost");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto& objectList : mObjects) {
|
for (auto& objectList : mObjects) {
|
||||||
LinkNode<ObjectBase>* object = objectList.head();
|
for (LinkNode<ObjectBase>* object = objectList.head(); object != objectList.end();
|
||||||
while (object != objectList.end()) {
|
object = object->next()) {
|
||||||
object->value()->CancelCallbacksForDisconnect();
|
object->value()->CancelCallbacksForDisconnect();
|
||||||
object = object->next();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
bool Client::DoDeviceUncapturedErrorCallback(WGPUErrorType errorType, const char* message) {
|
bool Client::DoDeviceUncapturedErrorCallback(Device* device,
|
||||||
|
WGPUErrorType errorType,
|
||||||
|
const char* message) {
|
||||||
switch (errorType) {
|
switch (errorType) {
|
||||||
case WGPUErrorType_NoError:
|
case WGPUErrorType_NoError:
|
||||||
case WGPUErrorType_Validation:
|
case WGPUErrorType_Validation:
|
||||||
|
@ -31,19 +33,20 @@ namespace dawn_wire { namespace client {
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mDevice->HandleError(errorType, message);
|
device->HandleError(errorType, message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoDeviceLostCallback(char const* message) {
|
bool Client::DoDeviceLostCallback(Device* device, char const* message) {
|
||||||
mDevice->HandleDeviceLost(message);
|
device->HandleDeviceLost(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoDevicePopErrorScopeCallback(uint64_t requestSerial,
|
bool Client::DoDevicePopErrorScopeCallback(Device* device,
|
||||||
|
uint64_t requestSerial,
|
||||||
WGPUErrorType errorType,
|
WGPUErrorType errorType,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
return mDevice->OnPopErrorScopeCallback(requestSerial, errorType, message);
|
return device->OnPopErrorScopeCallback(requestSerial, errorType, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoBufferMapAsyncCallback(Buffer* buffer,
|
bool Client::DoBufferMapAsyncCallback(Buffer* buffer,
|
||||||
|
@ -82,16 +85,26 @@ namespace dawn_wire { namespace client {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoDeviceCreateReadyComputePipelineCallback(uint64_t requestSerial,
|
bool Client::DoDeviceCreateReadyComputePipelineCallback(Device* device,
|
||||||
|
uint64_t requestSerial,
|
||||||
WGPUCreateReadyPipelineStatus status,
|
WGPUCreateReadyPipelineStatus status,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
return mDevice->OnCreateReadyComputePipelineCallback(requestSerial, status, message);
|
// The device might have been deleted or recreated so this isn't an error.
|
||||||
|
if (device == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return device->OnCreateReadyComputePipelineCallback(requestSerial, status, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoDeviceCreateReadyRenderPipelineCallback(uint64_t requestSerial,
|
bool Client::DoDeviceCreateReadyRenderPipelineCallback(Device* device,
|
||||||
|
uint64_t requestSerial,
|
||||||
WGPUCreateReadyPipelineStatus status,
|
WGPUCreateReadyPipelineStatus status,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
return mDevice->OnCreateReadyRenderPipelineCallback(requestSerial, status, message);
|
// The device might have been deleted or recreated so this isn't an error.
|
||||||
|
if (device == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return device->OnCreateReadyRenderPipelineCallback(requestSerial, status, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -146,7 +146,7 @@ namespace dawn_wire { namespace client {
|
||||||
mErrorScopes[serial] = {callback, userdata};
|
mErrorScopes[serial] = {callback, userdata};
|
||||||
|
|
||||||
DevicePopErrorScopeCmd cmd;
|
DevicePopErrorScopeCmd cmd;
|
||||||
cmd.device = ToAPI(this);
|
cmd.deviceId = this->id;
|
||||||
cmd.requestSerial = serial;
|
cmd.requestSerial = serial;
|
||||||
|
|
||||||
client->SerializeCommand(cmd);
|
client->SerializeCommand(cmd);
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace dawn_wire { namespace server {
|
||||||
|
|
||||||
struct DeviceInfo {
|
struct DeviceInfo {
|
||||||
std::unordered_set<uint64_t> childObjectTypesAndIds;
|
std::unordered_set<uint64_t> childObjectTypesAndIds;
|
||||||
|
Server* server;
|
||||||
|
ObjectHandle self;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -90,6 +90,8 @@ namespace dawn_wire { namespace server {
|
||||||
data->handle = device;
|
data->handle = device;
|
||||||
data->generation = generation;
|
data->generation = generation;
|
||||||
data->allocated = true;
|
data->allocated = true;
|
||||||
|
data->info->server = this;
|
||||||
|
data->info->self = ObjectHandle{id, generation};
|
||||||
|
|
||||||
// The device is externally owned so it shouldn't be destroyed when we receive a destroy
|
// The device 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.
|
// message from the client. Add a reference to counterbalance the eventual release.
|
||||||
|
@ -97,21 +99,23 @@ namespace dawn_wire { namespace server {
|
||||||
|
|
||||||
// Set callbacks to forward errors to the client.
|
// Set callbacks to forward errors to the client.
|
||||||
// Note: these callbacks are manually inlined here since they do not acquire and
|
// Note: these callbacks are manually inlined here since they do not acquire and
|
||||||
// free their userdata.
|
// 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(
|
mProcs.deviceSetUncapturedErrorCallback(
|
||||||
device,
|
device,
|
||||||
[](WGPUErrorType type, const char* message, void* userdata) {
|
[](WGPUErrorType type, const char* message, void* userdata) {
|
||||||
Server* server = static_cast<Server*>(userdata);
|
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
|
||||||
server->OnUncapturedError(type, message);
|
info->server->OnUncapturedError(info->self, type, message);
|
||||||
},
|
},
|
||||||
this);
|
data->info.get());
|
||||||
mProcs.deviceSetDeviceLostCallback(
|
mProcs.deviceSetDeviceLostCallback(
|
||||||
device,
|
device,
|
||||||
[](const char* message, void* userdata) {
|
[](const char* message, void* userdata) {
|
||||||
Server* server = static_cast<Server*>(userdata);
|
DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
|
||||||
server->OnDeviceLost(message);
|
info->server->OnDeviceLost(info->self, message);
|
||||||
},
|
},
|
||||||
this);
|
data->info.get());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,8 +123,7 @@ namespace dawn_wire { namespace server {
|
||||||
struct ErrorScopeUserdata : CallbackUserdata {
|
struct ErrorScopeUserdata : CallbackUserdata {
|
||||||
using CallbackUserdata::CallbackUserdata;
|
using CallbackUserdata::CallbackUserdata;
|
||||||
|
|
||||||
// TODO(enga): ObjectHandle device;
|
ObjectHandle device;
|
||||||
// when the wire supports multiple devices.
|
|
||||||
uint64_t requestSerial;
|
uint64_t requestSerial;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,6 +144,7 @@ namespace dawn_wire { namespace server {
|
||||||
struct CreateReadyPipelineUserData : CallbackUserdata {
|
struct CreateReadyPipelineUserData : CallbackUserdata {
|
||||||
using CallbackUserdata::CallbackUserdata;
|
using CallbackUserdata::CallbackUserdata;
|
||||||
|
|
||||||
|
ObjectHandle device;
|
||||||
uint64_t requestSerial;
|
uint64_t requestSerial;
|
||||||
ObjectId pipelineObjectID;
|
ObjectId pipelineObjectID;
|
||||||
};
|
};
|
||||||
|
@ -193,8 +193,8 @@ namespace dawn_wire { namespace server {
|
||||||
void ClearDeviceCallbacks(WGPUDevice device);
|
void ClearDeviceCallbacks(WGPUDevice device);
|
||||||
|
|
||||||
// Error callbacks
|
// Error callbacks
|
||||||
void OnUncapturedError(WGPUErrorType type, const char* message);
|
void OnUncapturedError(ObjectHandle device, WGPUErrorType type, const char* message);
|
||||||
void OnDeviceLost(const char* message);
|
void OnDeviceLost(ObjectHandle device, const char* message);
|
||||||
void OnDevicePopErrorScope(WGPUErrorType type,
|
void OnDevicePopErrorScope(WGPUErrorType type,
|
||||||
const char* message,
|
const char* message,
|
||||||
ErrorScopeUserdata* userdata);
|
ErrorScopeUserdata* userdata);
|
||||||
|
|
|
@ -16,28 +16,62 @@
|
||||||
|
|
||||||
namespace dawn_wire { namespace server {
|
namespace dawn_wire { namespace server {
|
||||||
|
|
||||||
void Server::OnUncapturedError(WGPUErrorType type, const char* message) {
|
namespace {
|
||||||
|
|
||||||
|
template <ObjectType objectType, typename Pipeline>
|
||||||
|
void HandleCreateReadyRenderPipelineCallbackResult(KnownObjects<Pipeline>* knownObjects,
|
||||||
|
WGPUCreateReadyPipelineStatus status,
|
||||||
|
Pipeline pipeline,
|
||||||
|
const char* message,
|
||||||
|
CreateReadyPipelineUserData* data) {
|
||||||
|
auto* pipelineObject = knownObjects->Get(data->pipelineObjectID);
|
||||||
|
|
||||||
|
if (status == WGPUCreateReadyPipelineStatus_Success) {
|
||||||
|
ASSERT(pipelineObject != nullptr);
|
||||||
|
pipelineObject->handle = pipeline;
|
||||||
|
} else if (pipelineObject != nullptr) {
|
||||||
|
// May be null if the device was destroyed. Device destruction destroys child
|
||||||
|
// objects on the wire.
|
||||||
|
if (!UntrackDeviceChild(pipelineObject->deviceInfo, objectType,
|
||||||
|
data->pipelineObjectID)) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
knownObjects->Free(data->pipelineObjectID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void Server::OnUncapturedError(ObjectHandle device, WGPUErrorType type, const char* message) {
|
||||||
ReturnDeviceUncapturedErrorCallbackCmd cmd;
|
ReturnDeviceUncapturedErrorCallbackCmd cmd;
|
||||||
|
cmd.device = device;
|
||||||
cmd.type = type;
|
cmd.type = type;
|
||||||
cmd.message = message;
|
cmd.message = message;
|
||||||
|
|
||||||
SerializeCommand(cmd);
|
SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::OnDeviceLost(const char* message) {
|
void Server::OnDeviceLost(ObjectHandle device, const char* message) {
|
||||||
ReturnDeviceLostCallbackCmd cmd;
|
ReturnDeviceLostCallbackCmd cmd;
|
||||||
|
cmd.device = device;
|
||||||
cmd.message = message;
|
cmd.message = message;
|
||||||
|
|
||||||
SerializeCommand(cmd);
|
SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Server::DoDevicePopErrorScope(WGPUDevice cDevice, uint64_t requestSerial) {
|
bool Server::DoDevicePopErrorScope(ObjectId deviceId, uint64_t requestSerial) {
|
||||||
|
auto* device = DeviceObjects().Get(deviceId);
|
||||||
|
if (device == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto userdata = MakeUserdata<ErrorScopeUserdata>();
|
auto userdata = MakeUserdata<ErrorScopeUserdata>();
|
||||||
userdata->requestSerial = requestSerial;
|
userdata->requestSerial = requestSerial;
|
||||||
|
userdata->device = ObjectHandle{deviceId, device->generation};
|
||||||
|
|
||||||
ErrorScopeUserdata* unownedUserdata = userdata.release();
|
ErrorScopeUserdata* unownedUserdata = userdata.release();
|
||||||
bool success = mProcs.devicePopErrorScope(
|
bool success = mProcs.devicePopErrorScope(
|
||||||
cDevice,
|
device->handle,
|
||||||
ForwardToServer<decltype(
|
ForwardToServer<decltype(
|
||||||
&Server::OnDevicePopErrorScope)>::Func<&Server::OnDevicePopErrorScope>(),
|
&Server::OnDevicePopErrorScope)>::Func<&Server::OnDevicePopErrorScope>(),
|
||||||
unownedUserdata);
|
unownedUserdata);
|
||||||
|
@ -51,6 +85,7 @@ namespace dawn_wire { namespace server {
|
||||||
const char* message,
|
const char* message,
|
||||||
ErrorScopeUserdata* userdata) {
|
ErrorScopeUserdata* userdata) {
|
||||||
ReturnDevicePopErrorScopeCallbackCmd cmd;
|
ReturnDevicePopErrorScopeCallbackCmd cmd;
|
||||||
|
cmd.device = userdata->device;
|
||||||
cmd.requestSerial = userdata->requestSerial;
|
cmd.requestSerial = userdata->requestSerial;
|
||||||
cmd.type = type;
|
cmd.type = type;
|
||||||
cmd.message = message;
|
cmd.message = message;
|
||||||
|
@ -81,6 +116,7 @@ namespace dawn_wire { namespace server {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto userdata = MakeUserdata<CreateReadyPipelineUserData>();
|
auto userdata = MakeUserdata<CreateReadyPipelineUserData>();
|
||||||
|
userdata->device = ObjectHandle{deviceId, device->generation};
|
||||||
userdata->requestSerial = requestSerial;
|
userdata->requestSerial = requestSerial;
|
||||||
userdata->pipelineObjectID = pipelineObjectHandle.id;
|
userdata->pipelineObjectID = pipelineObjectHandle.id;
|
||||||
|
|
||||||
|
@ -96,29 +132,11 @@ namespace dawn_wire { namespace server {
|
||||||
WGPUComputePipeline pipeline,
|
WGPUComputePipeline pipeline,
|
||||||
const char* message,
|
const char* message,
|
||||||
CreateReadyPipelineUserData* data) {
|
CreateReadyPipelineUserData* data) {
|
||||||
auto* computePipelineObject = ComputePipelineObjects().Get(data->pipelineObjectID);
|
HandleCreateReadyRenderPipelineCallbackResult<ObjectType::ComputePipeline>(
|
||||||
ASSERT(computePipelineObject != nullptr);
|
&ComputePipelineObjects(), status, pipeline, message, data);
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case WGPUCreateReadyPipelineStatus_Success:
|
|
||||||
computePipelineObject->handle = pipeline;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGPUCreateReadyPipelineStatus_Error:
|
|
||||||
ComputePipelineObjects().Free(data->pipelineObjectID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Currently this code is unreachable because WireServer is always deleted before the
|
|
||||||
// removal of the device. In the future this logic may be changed when we decide to
|
|
||||||
// support sharing one pair of WireServer/WireClient to multiple devices.
|
|
||||||
case WGPUCreateReadyPipelineStatus_DeviceLost:
|
|
||||||
case WGPUCreateReadyPipelineStatus_DeviceDestroyed:
|
|
||||||
case WGPUCreateReadyPipelineStatus_Unknown:
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnDeviceCreateReadyComputePipelineCallbackCmd cmd;
|
ReturnDeviceCreateReadyComputePipelineCallbackCmd cmd;
|
||||||
|
cmd.device = data->device;
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
cmd.requestSerial = data->requestSerial;
|
cmd.requestSerial = data->requestSerial;
|
||||||
cmd.message = message;
|
cmd.message = message;
|
||||||
|
@ -148,6 +166,7 @@ namespace dawn_wire { namespace server {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto userdata = MakeUserdata<CreateReadyPipelineUserData>();
|
auto userdata = MakeUserdata<CreateReadyPipelineUserData>();
|
||||||
|
userdata->device = ObjectHandle{deviceId, device->generation};
|
||||||
userdata->requestSerial = requestSerial;
|
userdata->requestSerial = requestSerial;
|
||||||
userdata->pipelineObjectID = pipelineObjectHandle.id;
|
userdata->pipelineObjectID = pipelineObjectHandle.id;
|
||||||
|
|
||||||
|
@ -163,29 +182,11 @@ namespace dawn_wire { namespace server {
|
||||||
WGPURenderPipeline pipeline,
|
WGPURenderPipeline pipeline,
|
||||||
const char* message,
|
const char* message,
|
||||||
CreateReadyPipelineUserData* data) {
|
CreateReadyPipelineUserData* data) {
|
||||||
auto* renderPipelineObject = RenderPipelineObjects().Get(data->pipelineObjectID);
|
HandleCreateReadyRenderPipelineCallbackResult<ObjectType::RenderPipeline>(
|
||||||
ASSERT(renderPipelineObject != nullptr);
|
&RenderPipelineObjects(), status, pipeline, message, data);
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case WGPUCreateReadyPipelineStatus_Success:
|
|
||||||
renderPipelineObject->handle = pipeline;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGPUCreateReadyPipelineStatus_Error:
|
|
||||||
RenderPipelineObjects().Free(data->pipelineObjectID);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Currently this code is unreachable because WireServer is always deleted before the
|
|
||||||
// removal of the device. In the future this logic may be changed when we decide to
|
|
||||||
// support sharing one pair of WireServer/WireClient to multiple devices.
|
|
||||||
case WGPUCreateReadyPipelineStatus_DeviceLost:
|
|
||||||
case WGPUCreateReadyPipelineStatus_DeviceDestroyed:
|
|
||||||
case WGPUCreateReadyPipelineStatus_Unknown:
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnDeviceCreateReadyRenderPipelineCallbackCmd cmd;
|
ReturnDeviceCreateReadyRenderPipelineCallbackCmd cmd;
|
||||||
|
cmd.device = data->device;
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
cmd.requestSerial = data->requestSerial;
|
cmd.requestSerial = data->requestSerial;
|
||||||
cmd.message = message;
|
cmd.message = message;
|
||||||
|
|
|
@ -328,3 +328,46 @@ TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineAfterDisconnect) {
|
||||||
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
||||||
ToMockCreateReadyComputePipelineCallback, this);
|
ToMockCreateReadyComputePipelineCallback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WireCreateReadyPipelineTest, DeviceDeletedBeforeCallback) {
|
||||||
|
WGPUShaderModuleDescriptor vertexDescriptor = {};
|
||||||
|
WGPUShaderModule module = wgpuDeviceCreateShaderModule(device, &vertexDescriptor);
|
||||||
|
WGPUShaderModule apiModule = api.GetNewShaderModule();
|
||||||
|
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiModule));
|
||||||
|
|
||||||
|
WGPURenderPipelineDescriptor pipelineDescriptor{};
|
||||||
|
pipelineDescriptor.vertexStage.module = module;
|
||||||
|
pipelineDescriptor.vertexStage.entryPoint = "main";
|
||||||
|
|
||||||
|
WGPUProgrammableStageDescriptor fragmentStage = {};
|
||||||
|
fragmentStage.module = module;
|
||||||
|
fragmentStage.entryPoint = "main";
|
||||||
|
pipelineDescriptor.fragmentStage = &fragmentStage;
|
||||||
|
|
||||||
|
wgpuDeviceCreateReadyRenderPipeline(device, &pipelineDescriptor,
|
||||||
|
ToMockCreateReadyRenderPipelineCallback, this);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, OnDeviceCreateReadyRenderPipeline(apiDevice, _, _, _));
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockCreateReadyRenderPipelineCallback,
|
||||||
|
Call(WGPUCreateReadyPipelineStatus_DeviceDestroyed, nullptr, _, this))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
wgpuDeviceRelease(device);
|
||||||
|
|
||||||
|
// Expect release on all objects created by the client.
|
||||||
|
Sequence s1, s2;
|
||||||
|
EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1).InSequence(s1);
|
||||||
|
EXPECT_CALL(api, ShaderModuleRelease(apiModule)).Times(1).InSequence(s2);
|
||||||
|
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
|
||||||
|
.Times(1)
|
||||||
|
.InSequence(s1, s2);
|
||||||
|
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr))
|
||||||
|
.Times(1)
|
||||||
|
.InSequence(s1, s2);
|
||||||
|
EXPECT_CALL(api, DeviceRelease(apiDevice)).Times(1).InSequence(s1, s2);
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
DefaultApiDeviceWasReleased();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue