dawn_wire: Reject new callbacks if the client is disconnected
If the wire client is disconnected, it will not receive any messages from the server. Reject all callbacks that are created. Bug: dawn:556 Change-Id: I2eb2c449b1ca6c8ea3e74040ef095abfc46a9061 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31161 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
parent
01e969da33
commit
7ceffe8511
|
@ -124,6 +124,10 @@ namespace dawn_wire { namespace client {
|
||||||
size_t size,
|
size_t size,
|
||||||
WGPUBufferMapCallback callback,
|
WGPUBufferMapCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
|
if (device->GetClient()->IsDisconnected()) {
|
||||||
|
return callback(WGPUBufferMapAsyncStatus_DeviceLost, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle the defaulting of size required by WebGPU.
|
// Handle the defaulting of size required by WebGPU.
|
||||||
if (size == 0 && offset < mSize) {
|
if (size == 0 && offset < mSize) {
|
||||||
size = mSize - offset;
|
size = mSize - offset;
|
||||||
|
|
|
@ -83,6 +83,7 @@ namespace dawn_wire { namespace client {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Disconnect() {
|
void Client::Disconnect() {
|
||||||
|
mDisconnected = true;
|
||||||
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
|
mSerializer = ChunkedCommandSerializer(NoopCommandSerializer::GetInstance());
|
||||||
if (mDevice != nullptr) {
|
if (mDevice != nullptr) {
|
||||||
mDevice->HandleDeviceLost("GPU connection lost");
|
mDevice->HandleDeviceLost("GPU connection lost");
|
||||||
|
@ -94,4 +95,8 @@ namespace dawn_wire { namespace client {
|
||||||
mDevices.Append(device);
|
mDevices.Append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::IsDisconnected() const {
|
||||||
|
return mDisconnected;
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace dawn_wire { namespace client {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
bool IsDisconnected() const;
|
||||||
|
|
||||||
void TrackObject(Device* device);
|
void TrackObject(Device* device);
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ namespace dawn_wire { namespace client {
|
||||||
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
|
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
|
||||||
|
|
||||||
LinkedList<ObjectBase> mDevices;
|
LinkedList<ObjectBase> mDevices;
|
||||||
|
bool mDisconnected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService();
|
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService();
|
||||||
|
|
|
@ -147,6 +147,11 @@ namespace dawn_wire { namespace client {
|
||||||
}
|
}
|
||||||
mErrorScopeStackSize--;
|
mErrorScopeStackSize--;
|
||||||
|
|
||||||
|
if (GetClient()->IsDisconnected()) {
|
||||||
|
callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t serial = mErrorScopeRequestSerial++;
|
uint64_t serial = mErrorScopeRequestSerial++;
|
||||||
ASSERT(mErrorScopes.find(serial) == mErrorScopes.end());
|
ASSERT(mErrorScopes.find(serial) == mErrorScopes.end());
|
||||||
|
|
||||||
|
@ -211,6 +216,11 @@ 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()) {
|
||||||
|
return callback(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr,
|
||||||
|
"GPU device disconnected", userdata);
|
||||||
|
}
|
||||||
|
|
||||||
DeviceCreateReadyComputePipelineCmd cmd;
|
DeviceCreateReadyComputePipelineCmd cmd;
|
||||||
cmd.device = ToAPI(this);
|
cmd.device = ToAPI(this);
|
||||||
cmd.descriptor = descriptor;
|
cmd.descriptor = descriptor;
|
||||||
|
@ -262,6 +272,10 @@ 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()) {
|
||||||
|
return callback(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr,
|
||||||
|
"GPU device disconnected", userdata);
|
||||||
|
}
|
||||||
DeviceCreateReadyRenderPipelineCmd cmd;
|
DeviceCreateReadyRenderPipelineCmd cmd;
|
||||||
cmd.device = ToAPI(this);
|
cmd.device = ToAPI(this);
|
||||||
cmd.descriptor = descriptor;
|
cmd.descriptor = descriptor;
|
||||||
|
|
|
@ -48,6 +48,10 @@ 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()) {
|
||||||
|
return callback(WGPUFenceCompletionStatus_DeviceLost, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t serial = mOnCompletionRequestSerial++;
|
uint32_t serial = mOnCompletionRequestSerial++;
|
||||||
ASSERT(mOnCompletionRequests.find(serial) == mOnCompletionRequests.end());
|
ASSERT(mOnCompletionRequests.find(serial) == mOnCompletionRequests.end());
|
||||||
|
|
||||||
|
|
|
@ -692,3 +692,12 @@ TEST_F(WireBufferMappingTests, MapThenDisconnect) {
|
||||||
EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this)).Times(1);
|
EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this)).Times(1);
|
||||||
GetWireClient()->Disconnect();
|
GetWireClient()->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that registering a callback after wire disconnect calls the callback with
|
||||||
|
// DeviceLost.
|
||||||
|
TEST_F(WireBufferMappingTests, MapAfterDisconnect) {
|
||||||
|
GetWireClient()->Disconnect();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this)).Times(1);
|
||||||
|
wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, this);
|
||||||
|
}
|
||||||
|
|
|
@ -276,3 +276,55 @@ TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineThenDisconnect) {
|
||||||
.Times(1);
|
.Times(1);
|
||||||
GetWireClient()->Disconnect();
|
GetWireClient()->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that registering a callback after wire disconnect calls the callback with
|
||||||
|
// DeviceLost.
|
||||||
|
TEST_F(WireCreateReadyPipelineTest, CreateReadyRenderPipelineAfterDisconnect) {
|
||||||
|
WGPUShaderModuleDescriptor vertexDescriptor = {};
|
||||||
|
WGPUShaderModule vsModule = wgpuDeviceCreateShaderModule(device, &vertexDescriptor);
|
||||||
|
WGPUShaderModule apiVsModule = api.GetNewShaderModule();
|
||||||
|
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiVsModule));
|
||||||
|
|
||||||
|
WGPUProgrammableStageDescriptor fragmentStage = {};
|
||||||
|
fragmentStage.module = vsModule;
|
||||||
|
fragmentStage.entryPoint = "main";
|
||||||
|
|
||||||
|
WGPURenderPipelineDescriptor pipelineDescriptor{};
|
||||||
|
pipelineDescriptor.vertexStage.module = vsModule;
|
||||||
|
pipelineDescriptor.vertexStage.entryPoint = "main";
|
||||||
|
pipelineDescriptor.fragmentStage = &fragmentStage;
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
GetWireClient()->Disconnect();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockCreateReadyRenderPipelineCallback,
|
||||||
|
Call(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr, _, this))
|
||||||
|
.Times(1);
|
||||||
|
wgpuDeviceCreateReadyRenderPipeline(device, &pipelineDescriptor,
|
||||||
|
ToMockCreateReadyRenderPipelineCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that registering a callback after wire disconnect calls the callback with
|
||||||
|
// DeviceLost.
|
||||||
|
TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineAfterDisconnect) {
|
||||||
|
WGPUShaderModuleDescriptor csDescriptor{};
|
||||||
|
WGPUShaderModule csModule = wgpuDeviceCreateShaderModule(device, &csDescriptor);
|
||||||
|
WGPUShaderModule apiCsModule = api.GetNewShaderModule();
|
||||||
|
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiCsModule));
|
||||||
|
|
||||||
|
WGPUComputePipelineDescriptor descriptor{};
|
||||||
|
descriptor.computeStage.module = csModule;
|
||||||
|
descriptor.computeStage.entryPoint = "main";
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
GetWireClient()->Disconnect();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockCreateReadyComputePipelineCallback,
|
||||||
|
Call(WGPUCreateReadyPipelineStatus_DeviceLost, nullptr, _, this))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
||||||
|
ToMockCreateReadyComputePipelineCallback, this);
|
||||||
|
}
|
||||||
|
|
|
@ -235,6 +235,22 @@ TEST_F(WireErrorCallbackTests, PopErrorScopeThenDisconnect) {
|
||||||
GetWireClient()->Disconnect();
|
GetWireClient()->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that registering a callback after wire disconnect calls the callback with
|
||||||
|
// DeviceLost.
|
||||||
|
TEST_F(WireErrorCallbackTests, PopErrorScopeAfterDisconnect) {
|
||||||
|
wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
|
||||||
|
EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
GetWireClient()->Disconnect();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockDevicePopErrorScopeCallback,
|
||||||
|
Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
|
||||||
|
.Times(1);
|
||||||
|
EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
|
||||||
|
}
|
||||||
|
|
||||||
// Test that PopErrorScope returns false if there are no error scopes.
|
// Test that PopErrorScope returns false if there are no error scopes.
|
||||||
TEST_F(WireErrorCallbackTests, PopErrorScopeEmptyStack) {
|
TEST_F(WireErrorCallbackTests, PopErrorScopeEmptyStack) {
|
||||||
// Empty stack
|
// Empty stack
|
||||||
|
|
|
@ -160,6 +160,16 @@ TEST_F(WireFenceTests, OnCompletionThenDisconnect) {
|
||||||
GetWireClient()->Disconnect();
|
GetWireClient()->Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that registering a callback after wire disconnect calls the callback with
|
||||||
|
// DeviceLost.
|
||||||
|
TEST_F(WireFenceTests, OnCompletionAfterDisconnect) {
|
||||||
|
GetWireClient()->Disconnect();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, this))
|
||||||
|
.Times(1);
|
||||||
|
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletionCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
// Without any flushes, it is valid to wait on a value less than or equal to
|
// Without any flushes, it is valid to wait on a value less than or equal to
|
||||||
// the last signaled value
|
// the last signaled value
|
||||||
TEST_F(WireFenceTests, OnCompletionSynchronousValidationSuccess) {
|
TEST_F(WireFenceTests, OnCompletionSynchronousValidationSuccess) {
|
||||||
|
|
Loading…
Reference in New Issue