Special-case GetDefaultQueue in the wire

Reland with a fix where commands only start being serialized by the
device after the first GetDevice() is called, not in the constructor.

This makes it so calling GetDefaultQueue always returns the same
object. It required updating various WireTests to account for the
additional wire calls.

Bug: dawn:22
Change-Id: Ibe43d84b25100f58a9ec5029a9341e400aec97f6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/19982
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Corentin Wallez 2020-04-23 21:21:52 +00:00 committed by Commit Bot service account
parent b46d002057
commit 409cf67207
12 changed files with 94 additions and 37 deletions

View File

@ -101,6 +101,7 @@
"BufferUnmap", "BufferUnmap",
"DeviceCreateBuffer", "DeviceCreateBuffer",
"DeviceCreateBufferMapped", "DeviceCreateBufferMapped",
"DeviceGetDefaultQueue",
"DevicePushErrorScope", "DevicePushErrorScope",
"QueueCreateFence", "QueueCreateFence",
"QueueSignal" "QueueSignal"

View File

@ -370,6 +370,11 @@ namespace dawn_wire { namespace client {
void ClientDeviceRelease(WGPUDevice) { void ClientDeviceRelease(WGPUDevice) {
} }
WGPUQueue ClientHandwrittenDeviceGetDefaultQueue(WGPUDevice cSelf) {
Device* device = reinterpret_cast<Device*>(cSelf);
return device->GetDefaultQueue();
}
void ClientHandwrittenDeviceSetUncapturedErrorCallback(WGPUDevice cSelf, void ClientHandwrittenDeviceSetUncapturedErrorCallback(WGPUDevice cSelf,
WGPUErrorCallback callback, WGPUErrorCallback callback,
void* userdata) { void* userdata) {

View File

@ -21,7 +21,6 @@ namespace dawn_wire { namespace client {
Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService) Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService)
: ClientBase(), : ClientBase(),
mDevice(DeviceAllocator().New(this)->object.get()),
mSerializer(serializer), mSerializer(serializer),
mMemoryTransferService(memoryTransferService) { mMemoryTransferService(memoryTransferService) {
if (mMemoryTransferService == nullptr) { if (mMemoryTransferService == nullptr) {
@ -32,7 +31,16 @@ namespace dawn_wire { namespace client {
} }
Client::~Client() { Client::~Client() {
DeviceAllocator().Free(mDevice); if (mDevice != nullptr) {
DeviceAllocator().Free(mDevice);
}
}
WGPUDevice Client::GetDevice() {
if (mDevice == nullptr) {
mDevice = DeviceAllocator().New(this)->object.get();
}
return reinterpret_cast<WGPUDeviceImpl*>(mDevice);
} }
ReservedTexture Client::ReserveTexture(WGPUDevice cDevice) { ReservedTexture Client::ReserveTexture(WGPUDevice cDevice) {
@ -57,8 +65,12 @@ namespace dawn_wire { namespace client {
} }
void Client::Disconnect() { void Client::Disconnect() {
if (!mIsDisconnected) { if (mIsDisconnected) {
mIsDisconnected = true; return;
}
mIsDisconnected = true;
if (mDevice != nullptr) {
mDevice->HandleDeviceLost("GPU connection lost"); mDevice->HandleDeviceLost("GPU connection lost");
} }
} }

View File

@ -33,9 +33,7 @@ namespace dawn_wire { namespace client {
Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService); Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService);
~Client(); ~Client();
WGPUDevice GetDevice() const { WGPUDevice GetDevice();
return reinterpret_cast<WGPUDeviceImpl*>(mDevice);
}
MemoryTransferService* GetMemoryTransferService() const { MemoryTransferService* GetMemoryTransferService() const {
return mMemoryTransferService; return mMemoryTransferService;

View File

@ -16,20 +16,46 @@
#include "common/Assert.h" #include "common/Assert.h"
#include "dawn_wire/WireCmd_autogen.h" #include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/ApiObjects_autogen.h"
#include "dawn_wire/client/Client.h" #include "dawn_wire/client/Client.h"
#include "dawn_wire/client/ObjectAllocator.h"
namespace dawn_wire { namespace client { namespace dawn_wire { namespace client {
Device::Device(Client* client, uint32_t initialRefcount, uint32_t initialId) Device::Device(Client* client, uint32_t initialRefcount, uint32_t initialId)
: ObjectBase(this, initialRefcount, initialId), mClient(client) { : ObjectBase(this, initialRefcount, initialId), mClient(client) {
this->device = this; this->device = this;
// Get the default queue for this device.
ObjectAllocator<Queue>::ObjectAndSerial* allocation = mClient->QueueAllocator().New(this);
mDefaultQueue = allocation->object.get();
DeviceGetDefaultQueueCmd cmd;
cmd.self = reinterpret_cast<WGPUDevice>(this);
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer = static_cast<char*>(mClient->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer, *mClient);
} }
Device::~Device() { Device::~Device() {
// Fire pending error scopes
auto errorScopes = std::move(mErrorScopes); auto errorScopes = std::move(mErrorScopes);
for (const auto& it : errorScopes) { for (const auto& it : errorScopes) {
it.second.callback(WGPUErrorType_Unknown, "Device destroyed", it.second.userdata); it.second.callback(WGPUErrorType_Unknown, "Device destroyed", it.second.userdata);
} }
// Destroy the default queue
DestroyObjectCmd cmd;
cmd.objectType = ObjectType::Queue;
cmd.objectId = mDefaultQueue->id;
size_t requiredSize = cmd.GetRequiredSize();
char* allocatedBuffer = static_cast<char*>(mClient->GetCmdSpace(requiredSize));
cmd.Serialize(allocatedBuffer);
mClient->QueueAllocator().Free(mDefaultQueue);
} }
Client* Device::GetClient() { Client* Device::GetClient() {
@ -119,4 +145,9 @@ namespace dawn_wire { namespace client {
return true; return true;
} }
WGPUQueue Device::GetDefaultQueue() {
mDefaultQueue->refcount++;
return reinterpret_cast<WGPUQueue>(mDefaultQueue);
}
}} // namespace dawn_wire::client }} // namespace dawn_wire::client

View File

@ -24,6 +24,7 @@
namespace dawn_wire { namespace client { namespace dawn_wire { namespace client {
class Client; class Client;
struct Queue;
class Device : public ObjectBase { class Device : public ObjectBase {
public: public:
@ -40,6 +41,8 @@ namespace dawn_wire { namespace client {
bool RequestPopErrorScope(WGPUErrorCallback callback, void* userdata); bool RequestPopErrorScope(WGPUErrorCallback callback, void* userdata);
bool PopErrorScope(uint64_t requestSerial, WGPUErrorType type, const char* message); bool PopErrorScope(uint64_t requestSerial, WGPUErrorType type, const char* message);
WGPUQueue GetDefaultQueue();
private: private:
struct ErrorScopeData { struct ErrorScopeData {
WGPUErrorCallback callback = nullptr; WGPUErrorCallback callback = nullptr;
@ -53,8 +56,10 @@ namespace dawn_wire { namespace client {
WGPUErrorCallback mErrorCallback = nullptr; WGPUErrorCallback mErrorCallback = nullptr;
WGPUDeviceLostCallback mDeviceLostCallback = nullptr; WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
bool mDidRunLostCallback = false; bool mDidRunLostCallback = false;
void* mErrorUserdata; void* mErrorUserdata = nullptr;
void* mDeviceLostUserdata; void* mDeviceLostUserdata = nullptr;
Queue* mDefaultQueue = nullptr;
}; };
}} // namespace dawn_wire::client }} // namespace dawn_wire::client

View File

@ -25,7 +25,7 @@ class QueueTests : public DawnTest {};
TEST_P(QueueTests, GetDefaultQueueSameObject) { TEST_P(QueueTests, GetDefaultQueueSameObject) {
wgpu::Queue q1 = device.GetDefaultQueue(); wgpu::Queue q1 = device.GetDefaultQueue();
wgpu::Queue q2 = device.GetDefaultQueue(); wgpu::Queue q2 = device.GetDefaultQueue();
EXPECT_EQ(q1.Get() == q2.Get(), !UsesWire()); EXPECT_EQ(q1.Get(), q2.Get());
} }
DAWN_INSTANTIATE_TEST(QueueTests, DAWN_INSTANTIATE_TEST(QueueTests,

View File

@ -231,11 +231,6 @@ TEST_F(WireArgumentTests, ObjectsAsPointerArgument) {
.WillOnce(Return(apiCmdBufs[i])); .WillOnce(Return(apiCmdBufs[i]));
} }
// Create queue
WGPUQueue queue = wgpuDeviceGetDefaultQueue(device);
WGPUQueue apiQueue = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue));
// Submit command buffer and check we got a call with both API-side command buffers // Submit command buffer and check we got a call with both API-side command buffers
wgpuQueueSubmit(queue, 2, cmdBufs); wgpuQueueSubmit(queue, 2, cmdBufs);

View File

@ -43,12 +43,6 @@ class WireFenceTests : public WireTest {
mockFenceOnCompletionCallback = mockFenceOnCompletionCallback =
std::make_unique<StrictMock<MockFenceOnCompletionCallback>>(); std::make_unique<StrictMock<MockFenceOnCompletionCallback>>();
{
queue = wgpuDeviceGetDefaultQueue(device);
apiQueue = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue));
FlushClient();
}
{ {
WGPUFenceDescriptor descriptor = {}; WGPUFenceDescriptor descriptor = {};
descriptor.initialValue = 1; descriptor.initialValue = 1;
@ -89,9 +83,6 @@ class WireFenceTests : public WireTest {
// A successfully created fence // A successfully created fence
WGPUFence fence; WGPUFence fence;
WGPUFence apiFence; WGPUFence apiFence;
WGPUQueue queue;
WGPUQueue apiQueue;
}; };
// Check that signaling a fence succeeds // Check that signaling a fence succeeds
@ -227,7 +218,8 @@ TEST_F(WireFenceTests, DestroyBeforeOnCompletionEnd) {
} }
// Test that signaling a fence on a wrong queue is invalid // Test that signaling a fence on a wrong queue is invalid
TEST_F(WireFenceTests, SignalWrongQueue) { // DISABLED until we have support for multiple queues.
TEST_F(WireFenceTests, DISABLED_SignalWrongQueue) {
WGPUQueue queue2 = wgpuDeviceGetDefaultQueue(device); WGPUQueue queue2 = wgpuDeviceGetDefaultQueue(device);
WGPUQueue apiQueue2 = api.GetNewQueue(); WGPUQueue apiQueue2 = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue2)); EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue2));
@ -240,7 +232,8 @@ TEST_F(WireFenceTests, SignalWrongQueue) {
} }
// Test that signaling a fence on a wrong queue does not update fence signaled value // Test that signaling a fence on a wrong queue does not update fence signaled value
TEST_F(WireFenceTests, SignalWrongQueueDoesNotUpdateValue) { // DISABLED until we have support for multiple queues.
TEST_F(WireFenceTests, DISABLED_SignalWrongQueueDoesNotUpdateValue) {
WGPUQueue queue2 = wgpuDeviceGetDefaultQueue(device); WGPUQueue queue2 = wgpuDeviceGetDefaultQueue(device);
WGPUQueue apiQueue2 = api.GetNewQueue(); WGPUQueue apiQueue2 = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue2)); EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue2));

View File

@ -69,6 +69,12 @@ class WireMultipleDeviceTests : public testing::Test {
mS2cBuf->SetHandler(mWireClient.get()); mS2cBuf->SetHandler(mWireClient.get());
mClientDevice = mWireClient->GetDevice(); mClientDevice = mWireClient->GetDevice();
// The GetDefaultQueue is done on WireClient startup so we expect it now.
mClientQueue = wgpuDeviceGetDefaultQueue(mClientDevice);
mServerQueue = mApi.GetNewQueue();
EXPECT_CALL(mApi, DeviceGetDefaultQueue(mServerDevice)).WillOnce(Return(mServerQueue));
FlushClient();
} }
~WireHolder() { ~WireHolder() {
@ -97,6 +103,14 @@ class WireMultipleDeviceTests : public testing::Test {
return mServerDevice; return mServerDevice;
} }
WGPUQueue ClientQueue() {
return mClientQueue;
}
WGPUQueue ServerQueue() {
return mServerQueue;
}
private: private:
testing::StrictMock<MockProcTable> mApi; testing::StrictMock<MockProcTable> mApi;
std::unique_ptr<dawn_wire::WireServer> mWireServer; std::unique_ptr<dawn_wire::WireServer> mWireServer;
@ -105,6 +119,8 @@ class WireMultipleDeviceTests : public testing::Test {
std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf; std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf;
WGPUDevice mServerDevice; WGPUDevice mServerDevice;
WGPUDevice mClientDevice; WGPUDevice mClientDevice;
WGPUQueue mServerQueue;
WGPUQueue mClientQueue;
}; };
void ExpectInjectedError(WireHolder* wire) { void ExpectInjectedError(WireHolder* wire) {
@ -134,20 +150,12 @@ TEST_F(WireMultipleDeviceTests, ValidatesSameDevice) {
WireHolder wireA; WireHolder wireA;
WireHolder wireB; WireHolder wireB;
// Create the objects // Create the fence
WGPUQueue queueA = wgpuDeviceGetDefaultQueue(wireA.ClientDevice());
WGPUQueue queueB = wgpuDeviceGetDefaultQueue(wireB.ClientDevice());
WGPUFenceDescriptor desc = {}; WGPUFenceDescriptor desc = {};
WGPUFence fenceA = wgpuQueueCreateFence(queueA, &desc); WGPUFence fenceA = wgpuQueueCreateFence(wireA.ClientQueue(), &desc);
// Flush on wire B. We should see the queue created.
EXPECT_CALL(*wireB.Api(), DeviceGetDefaultQueue(wireB.ServerDevice()))
.WillOnce(Return(wireB.Api()->GetNewQueue()));
wireB.FlushClient();
// Signal with a fence from a different wire. // Signal with a fence from a different wire.
wgpuQueueSignal(queueB, fenceA, 1u); wgpuQueueSignal(wireB.ClientQueue(), fenceA, 1u);
// We should inject an error into the server. // We should inject an error into the server.
ExpectInjectedError(&wireB); ExpectInjectedError(&wireB);

View File

@ -70,6 +70,12 @@ void WireTest::SetUp() {
dawnProcSetProcs(&clientProcs); dawnProcSetProcs(&clientProcs);
apiDevice = mockDevice; apiDevice = mockDevice;
// The GetDefaultQueue is done on WireClient startup so we expect it now.
queue = wgpuDeviceGetDefaultQueue(device);
apiQueue = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetDefaultQueue(apiDevice)).WillOnce(Return(apiQueue));
FlushClient();
} }
void WireTest::TearDown() { void WireTest::TearDown() {
@ -104,6 +110,7 @@ dawn_wire::WireClient* WireTest::GetWireClient() {
} }
void WireTest::DeleteServer() { void WireTest::DeleteServer() {
EXPECT_CALL(api, QueueRelease(apiQueue)).Times(1);
mWireServer = nullptr; mWireServer = nullptr;
} }

View File

@ -123,7 +123,9 @@ class WireTest : public testing::Test {
testing::StrictMock<MockProcTable> api; testing::StrictMock<MockProcTable> api;
WGPUDevice apiDevice; WGPUDevice apiDevice;
WGPUQueue apiQueue;
WGPUDevice device; WGPUDevice device;
WGPUQueue queue;
dawn_wire::WireServer* GetWireServer(); dawn_wire::WireServer* GetWireServer();
dawn_wire::WireClient* GetWireClient(); dawn_wire::WireClient* GetWireClient();