Move client-side OnCompletion callbacks to the server.
We need callbacks to be processed server-side so that callback ordering can be made consistent. Bug: dawn:516 Change-Id: Ie5590ca33fce6bda431f93ae9ff8e832468109c1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/27481 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
9ed8d518ca
commit
0b89b27263
|
@ -47,6 +47,11 @@
|
||||||
{ "name": "object type", "type": "ObjectType" },
|
{ "name": "object type", "type": "ObjectType" },
|
||||||
{ "name": "object id", "type": "ObjectId" }
|
{ "name": "object id", "type": "ObjectId" }
|
||||||
],
|
],
|
||||||
|
"fence on completion": [
|
||||||
|
{ "name": "fence id", "type": "ObjectId" },
|
||||||
|
{ "name": "value", "type": "uint64_t" },
|
||||||
|
{ "name": "request serial", "type": "uint64_t" }
|
||||||
|
],
|
||||||
"queue write buffer internal": [
|
"queue write buffer internal": [
|
||||||
{"name": "queue id", "type": "ObjectId" },
|
{"name": "queue id", "type": "ObjectId" },
|
||||||
{"name": "buffer id", "type": "ObjectId" },
|
{"name": "buffer id", "type": "ObjectId" },
|
||||||
|
@ -83,6 +88,11 @@
|
||||||
{ "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" }
|
||||||
],
|
],
|
||||||
|
"fence on completion callback": [
|
||||||
|
{ "name": "fence", "type": "ObjectHandle", "handle_type": "fence" },
|
||||||
|
{ "name": "request serial", "type": "uint64_t" },
|
||||||
|
{ "name": "status", "type": "fence completion status" }
|
||||||
|
],
|
||||||
"fence update completed value": [
|
"fence update completed value": [
|
||||||
{ "name": "fence", "type": "ObjectHandle", "handle_type": "fence" },
|
{ "name": "fence", "type": "ObjectHandle", "handle_type": "fence" },
|
||||||
{ "name": "value", "type": "uint64_t" }
|
{ "name": "value", "type": "uint64_t" }
|
||||||
|
@ -114,8 +124,7 @@
|
||||||
"DeviceGetDefaultQueue",
|
"DeviceGetDefaultQueue",
|
||||||
"DeviceInjectError",
|
"DeviceInjectError",
|
||||||
"DevicePushErrorScope",
|
"DevicePushErrorScope",
|
||||||
"QueueCreateFence",
|
"QueueCreateFence"
|
||||||
"QueueSignal"
|
|
||||||
],
|
],
|
||||||
"client_special_objects": [
|
"client_special_objects": [
|
||||||
"Buffer",
|
"Buffer",
|
||||||
|
|
|
@ -70,4 +70,16 @@ namespace dawn_wire { namespace client {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::DoFenceOnCompletionCallback(Fence* fence,
|
||||||
|
uint64_t requestSerial,
|
||||||
|
WGPUFenceCompletionStatus status) {
|
||||||
|
// The fence might have been deleted or recreated so this isn't an error.
|
||||||
|
if (fence == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fence->OnCompletionCallback(requestSerial, status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "dawn_wire/client/Fence.h"
|
#include "dawn_wire/client/Fence.h"
|
||||||
|
|
||||||
|
#include "dawn_wire/client/Client.h"
|
||||||
#include "dawn_wire/client/Device.h"
|
#include "dawn_wire/client/Device.h"
|
||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
@ -21,67 +22,61 @@ namespace dawn_wire { namespace client {
|
||||||
Fence::~Fence() {
|
Fence::~Fence() {
|
||||||
// Callbacks need to be fired in all cases, as they can handle freeing resources
|
// Callbacks need to be fired in all cases, as they can handle freeing resources
|
||||||
// so we call them with "Unknown" status.
|
// so we call them with "Unknown" status.
|
||||||
for (auto& request : mRequests.IterateAll()) {
|
for (auto& it : mOnCompletionRequests) {
|
||||||
request.completionCallback(WGPUFenceCompletionStatus_Unknown, request.userdata);
|
if (it.second.callback) {
|
||||||
|
it.second.callback(WGPUFenceCompletionStatus_Unknown, it.second.userdata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mRequests.Clear();
|
mOnCompletionRequests.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fence::Initialize(Queue* queue, const WGPUFenceDescriptor* descriptor) {
|
void Fence::Initialize(Queue* queue, const WGPUFenceDescriptor* descriptor) {
|
||||||
mQueue = queue;
|
mQueue = queue;
|
||||||
|
|
||||||
uint64_t initialValue = descriptor != nullptr ? descriptor->initialValue : 0u;
|
mCompletedValue = descriptor != nullptr ? descriptor->initialValue : 0u;
|
||||||
mSignaledValue = initialValue;
|
|
||||||
mCompletedValue = initialValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fence::CheckPassedFences() {
|
|
||||||
for (auto& request : mRequests.IterateUpTo(mCompletedValue)) {
|
|
||||||
request.completionCallback(WGPUFenceCompletionStatus_Success, request.userdata);
|
|
||||||
}
|
|
||||||
mRequests.ClearUpTo(mCompletedValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fence::OnCompletion(uint64_t value,
|
void Fence::OnCompletion(uint64_t value,
|
||||||
WGPUFenceOnCompletionCallback callback,
|
WGPUFenceOnCompletionCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
if (value > mSignaledValue) {
|
uint32_t serial = mOnCompletionRequestSerial++;
|
||||||
device->InjectError(WGPUErrorType_Validation,
|
ASSERT(mOnCompletionRequests.find(serial) == mOnCompletionRequests.end());
|
||||||
"Value greater than fence signaled value");
|
|
||||||
callback(WGPUFenceCompletionStatus_Error, userdata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value <= mCompletedValue) {
|
FenceOnCompletionCmd cmd;
|
||||||
callback(WGPUFenceCompletionStatus_Success, userdata);
|
cmd.fenceId = this->id;
|
||||||
return;
|
cmd.value = value;
|
||||||
}
|
cmd.requestSerial = serial;
|
||||||
|
|
||||||
Fence::OnCompletionData request;
|
mOnCompletionRequests[serial] = {callback, userdata};
|
||||||
request.completionCallback = callback;
|
|
||||||
request.userdata = userdata;
|
this->device->GetClient()->SerializeCommand(cmd);
|
||||||
mRequests.Enqueue(std::move(request), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fence::OnUpdateCompletedValueCallback(uint64_t value) {
|
void Fence::OnUpdateCompletedValueCallback(uint64_t value) {
|
||||||
mCompletedValue = value;
|
mCompletedValue = value;
|
||||||
CheckPassedFences();
|
}
|
||||||
|
|
||||||
|
bool Fence::OnCompletionCallback(uint64_t requestSerial, WGPUFenceCompletionStatus status) {
|
||||||
|
auto requestIt = mOnCompletionRequests.find(requestSerial);
|
||||||
|
if (requestIt == mOnCompletionRequests.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the request data so that the callback cannot be called again.
|
||||||
|
// ex.) inside the callback: if the fence is deleted, all callbacks reject.
|
||||||
|
OnCompletionData request = std::move(requestIt->second);
|
||||||
|
mOnCompletionRequests.erase(requestIt);
|
||||||
|
|
||||||
|
request.callback(status, request.userdata);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Fence::GetCompletedValue() const {
|
uint64_t Fence::GetCompletedValue() const {
|
||||||
return mCompletedValue;
|
return mCompletedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Fence::GetSignaledValue() const {
|
|
||||||
return mSignaledValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Queue* Fence::GetQueue() const {
|
Queue* Fence::GetQueue() const {
|
||||||
return mQueue;
|
return mQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fence::SetSignaledValue(uint64_t value) {
|
|
||||||
mSignaledValue = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -33,22 +33,20 @@ namespace dawn_wire { namespace client {
|
||||||
void CheckPassedFences();
|
void CheckPassedFences();
|
||||||
void OnCompletion(uint64_t value, WGPUFenceOnCompletionCallback callback, void* userdata);
|
void OnCompletion(uint64_t value, WGPUFenceOnCompletionCallback callback, void* userdata);
|
||||||
void OnUpdateCompletedValueCallback(uint64_t value);
|
void OnUpdateCompletedValueCallback(uint64_t value);
|
||||||
|
bool OnCompletionCallback(uint64_t requestSerial, WGPUFenceCompletionStatus status);
|
||||||
|
|
||||||
uint64_t GetCompletedValue() const;
|
uint64_t GetCompletedValue() const;
|
||||||
uint64_t GetSignaledValue() const;
|
|
||||||
Queue* GetQueue() const;
|
Queue* GetQueue() const;
|
||||||
|
|
||||||
void SetSignaledValue(uint64_t value);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct OnCompletionData {
|
struct OnCompletionData {
|
||||||
WGPUFenceOnCompletionCallback completionCallback = nullptr;
|
WGPUFenceOnCompletionCallback callback = nullptr;
|
||||||
void* userdata = nullptr;
|
void* userdata = nullptr;
|
||||||
};
|
};
|
||||||
Queue* mQueue = nullptr;
|
Queue* mQueue = nullptr;
|
||||||
uint64_t mSignaledValue = 0;
|
|
||||||
uint64_t mCompletedValue = 0;
|
uint64_t mCompletedValue = 0;
|
||||||
SerialMap<OnCompletionData> mRequests;
|
uint64_t mOnCompletionRequestSerial = 0;
|
||||||
|
std::map<uint64_t, OnCompletionData> mOnCompletionRequests;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
|
@ -33,29 +33,6 @@ namespace dawn_wire { namespace client {
|
||||||
return ToAPI(fence);
|
return ToAPI(fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::Signal(WGPUFence cFence, uint64_t signalValue) {
|
|
||||||
Fence* fence = FromAPI(cFence);
|
|
||||||
if (fence->GetQueue() != this) {
|
|
||||||
device->InjectError(WGPUErrorType_Validation,
|
|
||||||
"Fence must be signaled on the queue on which it was created.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (signalValue <= fence->GetSignaledValue()) {
|
|
||||||
device->InjectError(WGPUErrorType_Validation,
|
|
||||||
"Fence value less than or equal to signaled value");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fence->SetSignaledValue(signalValue);
|
|
||||||
|
|
||||||
QueueSignalCmd cmd;
|
|
||||||
cmd.self = ToAPI(this);
|
|
||||||
cmd.fence = cFence;
|
|
||||||
cmd.signalValue = signalValue;
|
|
||||||
|
|
||||||
device->GetClient()->SerializeCommand(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Queue::WriteBuffer(WGPUBuffer cBuffer,
|
void Queue::WriteBuffer(WGPUBuffer cBuffer,
|
||||||
uint64_t bufferOffset,
|
uint64_t bufferOffset,
|
||||||
const void* data,
|
const void* data,
|
||||||
|
|
|
@ -29,7 +29,6 @@ namespace dawn_wire { namespace client {
|
||||||
using ObjectBase::ObjectBase;
|
using ObjectBase::ObjectBase;
|
||||||
|
|
||||||
WGPUFence CreateFence(const WGPUFenceDescriptor* descriptor);
|
WGPUFence CreateFence(const WGPUFenceDescriptor* descriptor);
|
||||||
void Signal(WGPUFence fence, uint64_t signalValue);
|
|
||||||
void WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* data, size_t size);
|
void WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* data, size_t size);
|
||||||
void WriteTexture(const WGPUTextureCopyView* destination,
|
void WriteTexture(const WGPUTextureCopyView* destination,
|
||||||
const void* data,
|
const void* data,
|
||||||
|
|
|
@ -48,6 +48,12 @@ namespace dawn_wire { namespace server {
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FenceOnCompletionUserdata {
|
||||||
|
Server* server;
|
||||||
|
ObjectHandle fence;
|
||||||
|
uint64_t requestSerial;
|
||||||
|
};
|
||||||
|
|
||||||
class Server : public ServerBase {
|
class Server : public ServerBase {
|
||||||
public:
|
public:
|
||||||
Server(WGPUDevice device,
|
Server(WGPUDevice device,
|
||||||
|
@ -77,6 +83,7 @@ namespace dawn_wire { namespace server {
|
||||||
static void ForwardPopErrorScope(WGPUErrorType type, const char* message, void* userdata);
|
static void ForwardPopErrorScope(WGPUErrorType type, const char* message, void* userdata);
|
||||||
static void ForwardBufferMapAsync(WGPUBufferMapAsyncStatus status, void* userdata);
|
static void ForwardBufferMapAsync(WGPUBufferMapAsyncStatus status, void* userdata);
|
||||||
static void ForwardFenceCompletedValue(WGPUFenceCompletionStatus status, void* userdata);
|
static void ForwardFenceCompletedValue(WGPUFenceCompletionStatus status, void* userdata);
|
||||||
|
static void ForwardFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata);
|
||||||
|
|
||||||
// Error callbacks
|
// Error callbacks
|
||||||
void OnUncapturedError(WGPUErrorType type, const char* message);
|
void OnUncapturedError(WGPUErrorType type, const char* message);
|
||||||
|
@ -87,6 +94,8 @@ namespace dawn_wire { namespace server {
|
||||||
void OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* userdata);
|
void OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* userdata);
|
||||||
void OnFenceCompletedValueUpdated(WGPUFenceCompletionStatus status,
|
void OnFenceCompletedValueUpdated(WGPUFenceCompletionStatus status,
|
||||||
FenceCompletionUserdata* userdata);
|
FenceCompletionUserdata* userdata);
|
||||||
|
void OnFenceOnCompletion(WGPUFenceCompletionStatus status,
|
||||||
|
FenceOnCompletionUserdata* userdata);
|
||||||
|
|
||||||
#include "dawn_wire/server/ServerPrototypes_autogen.inc"
|
#include "dawn_wire/server/ServerPrototypes_autogen.inc"
|
||||||
|
|
||||||
|
|
|
@ -38,4 +38,42 @@ namespace dawn_wire { namespace server {
|
||||||
SerializeCommand(cmd);
|
SerializeCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Server::DoFenceOnCompletion(ObjectId fenceId, uint64_t value, uint64_t requestSerial) {
|
||||||
|
// The null object isn't valid as `self`
|
||||||
|
if (fenceId == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* fence = FenceObjects().Get(fenceId);
|
||||||
|
if (fence == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FenceOnCompletionUserdata* userdata = new FenceOnCompletionUserdata;
|
||||||
|
userdata->server = this;
|
||||||
|
userdata->fence = ObjectHandle{fenceId, fence->generation};
|
||||||
|
userdata->requestSerial = requestSerial;
|
||||||
|
|
||||||
|
mProcs.fenceOnCompletion(fence->handle, value, ForwardFenceOnCompletion, userdata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void Server::ForwardFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
|
||||||
|
auto* data = reinterpret_cast<FenceOnCompletionUserdata*>(userdata);
|
||||||
|
data->server->OnFenceOnCompletion(status, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::OnFenceOnCompletion(WGPUFenceCompletionStatus status,
|
||||||
|
FenceOnCompletionUserdata* userdata) {
|
||||||
|
std::unique_ptr<FenceOnCompletionUserdata> data{userdata};
|
||||||
|
|
||||||
|
ReturnFenceOnCompletionCallbackCmd cmd;
|
||||||
|
cmd.fence = data->fence;
|
||||||
|
cmd.requestSerial = data->requestSerial;
|
||||||
|
cmd.status = status;
|
||||||
|
|
||||||
|
SerializeCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_wire::server
|
}} // namespace dawn_wire::server
|
||||||
|
|
|
@ -21,7 +21,6 @@ namespace dawn_wire { namespace server {
|
||||||
if (cFence == nullptr) {
|
if (cFence == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mProcs.queueSignal(cSelf, cFence, signalValue);
|
mProcs.queueSignal(cSelf, cFence, signalValue);
|
||||||
|
|
||||||
ObjectId fenceId = FenceObjectIdTable().Get(cFence);
|
ObjectId fenceId = FenceObjectIdTable().Get(cFence);
|
||||||
|
|
|
@ -68,16 +68,17 @@ class WireFenceTests : public WireTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DoQueueSignal(uint64_t signalValue) {
|
void DoQueueSignal(uint64_t signalValue,
|
||||||
|
WGPUFenceCompletionStatus status = WGPUFenceCompletionStatus_Success) {
|
||||||
wgpuQueueSignal(queue, fence, signalValue);
|
wgpuQueueSignal(queue, fence, signalValue);
|
||||||
EXPECT_CALL(api, QueueSignal(apiQueue, apiFence, signalValue)).Times(1);
|
EXPECT_CALL(api, QueueSignal(apiQueue, apiFence, signalValue)).Times(1);
|
||||||
|
|
||||||
// This callback is generated to update the completedValue of the fence
|
// This callback is generated to update the completedValue of the fence
|
||||||
// on the client
|
// on the client
|
||||||
EXPECT_CALL(api, OnFenceOnCompletionCallback(apiFence, signalValue, _, _))
|
EXPECT_CALL(api, OnFenceOnCompletionCallback(apiFence, signalValue, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(
|
||||||
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
|
InvokeWithoutArgs([=]() { api.CallFenceOnCompletionCallback(apiFence, status); }))
|
||||||
}));
|
.RetiresOnSaturation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// A successfully created fence
|
// A successfully created fence
|
||||||
|
@ -87,79 +88,58 @@ class WireFenceTests : public WireTest {
|
||||||
|
|
||||||
// Check that signaling a fence succeeds
|
// Check that signaling a fence succeeds
|
||||||
TEST_F(WireFenceTests, QueueSignalSuccess) {
|
TEST_F(WireFenceTests, QueueSignalSuccess) {
|
||||||
|
DoQueueSignal(2u);
|
||||||
|
FlushClient();
|
||||||
|
FlushServer();
|
||||||
|
|
||||||
|
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that signaling a fence twice succeeds
|
||||||
|
TEST_F(WireFenceTests, QueueSignalIncreasing) {
|
||||||
DoQueueSignal(2u);
|
DoQueueSignal(2u);
|
||||||
DoQueueSignal(3u);
|
DoQueueSignal(3u);
|
||||||
FlushClient();
|
FlushClient();
|
||||||
FlushServer();
|
FlushServer();
|
||||||
|
|
||||||
|
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errors should be generated when signaling a value less
|
// Check that an error in queue signal does not update the completed value.
|
||||||
// than or equal to the current signaled value
|
|
||||||
TEST_F(WireFenceTests, QueueSignalValidationError) {
|
TEST_F(WireFenceTests, QueueSignalValidationError) {
|
||||||
wgpuQueueSignal(queue, fence, 0u); // Error
|
DoQueueSignal(2u);
|
||||||
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
|
DoQueueSignal(1u, WGPUFenceCompletionStatus_Error);
|
||||||
.Times(1);
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
FlushServer();
|
||||||
|
|
||||||
wgpuQueueSignal(queue, fence, 1u); // Error
|
// Value should stay at 2 and not be updated to 1.
|
||||||
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
|
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
|
||||||
.Times(1);
|
|
||||||
FlushClient();
|
|
||||||
|
|
||||||
DoQueueSignal(4u); // Success
|
|
||||||
FlushClient();
|
|
||||||
|
|
||||||
wgpuQueueSignal(queue, fence, 3u); // Error
|
|
||||||
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
|
|
||||||
.Times(1);
|
|
||||||
FlushClient();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that callbacks are immediately called if the fence is already finished
|
// Check that a success in the on completion callback is forwarded to the client.
|
||||||
TEST_F(WireFenceTests, OnCompletionImmediate) {
|
TEST_F(WireFenceTests, OnCompletionSuccess) {
|
||||||
// Can call on value < (initial) signaled value happens immediately
|
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletionCallback, nullptr);
|
||||||
{
|
EXPECT_CALL(api, OnFenceOnCompletionCallback(apiFence, 0u, _, _))
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, _))
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
.Times(1);
|
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
|
||||||
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletionCallback, nullptr);
|
}));
|
||||||
}
|
FlushClient();
|
||||||
|
|
||||||
// Can call on value == (initial) signaled value happens immediately
|
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, _))
|
||||||
{
|
.Times(1);
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, _))
|
FlushServer();
|
||||||
.Times(1);
|
|
||||||
wgpuFenceOnCompletion(fence, 1, ToMockFenceOnCompletionCallback, nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all passed client completion callbacks are called
|
// Check that an error in the on completion callback is forwarded to the client.
|
||||||
TEST_F(WireFenceTests, OnCompletionMultiple) {
|
TEST_F(WireFenceTests, OnCompletionError) {
|
||||||
DoQueueSignal(3u);
|
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletionCallback, nullptr);
|
||||||
DoQueueSignal(6u);
|
EXPECT_CALL(api, OnFenceOnCompletionCallback(apiFence, 0u, _, _))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
// Add callbacks in a non-monotonic order. They should still be called
|
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Error);
|
||||||
// in order of increasing fence value.
|
}));
|
||||||
// Add multiple callbacks for the same value.
|
|
||||||
wgpuFenceOnCompletion(fence, 6, ToMockFenceOnCompletionCallback, this + 0);
|
|
||||||
wgpuFenceOnCompletion(fence, 2, ToMockFenceOnCompletionCallback, this + 1);
|
|
||||||
wgpuFenceOnCompletion(fence, 3, ToMockFenceOnCompletionCallback, this + 2);
|
|
||||||
wgpuFenceOnCompletion(fence, 2, ToMockFenceOnCompletionCallback, this + 3);
|
|
||||||
|
|
||||||
Sequence s1, s2;
|
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 1))
|
|
||||||
.Times(1)
|
|
||||||
.InSequence(s1);
|
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 3))
|
|
||||||
.Times(1)
|
|
||||||
.InSequence(s2);
|
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
|
|
||||||
.Times(1)
|
|
||||||
.InSequence(s1, s2);
|
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
|
|
||||||
.Times(1)
|
|
||||||
.InSequence(s1, s2);
|
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Error, _)).Times(1);
|
||||||
FlushServer();
|
FlushServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,19 +155,6 @@ TEST_F(WireFenceTests, OnCompletionSynchronousValidationSuccess) {
|
||||||
.Times(3);
|
.Times(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errors should be generated when waiting on a value greater
|
|
||||||
// than the last signaled value
|
|
||||||
TEST_F(WireFenceTests, OnCompletionValidationError) {
|
|
||||||
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Error, this + 0))
|
|
||||||
.Times(1);
|
|
||||||
|
|
||||||
wgpuFenceOnCompletion(fence, 2u, ToMockFenceOnCompletionCallback, this + 0);
|
|
||||||
|
|
||||||
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
|
|
||||||
.Times(1);
|
|
||||||
FlushClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the fence completed value is initialized
|
// Check that the fence completed value is initialized
|
||||||
TEST_F(WireFenceTests, GetCompletedValueInitialization) {
|
TEST_F(WireFenceTests, GetCompletedValueInitialization) {
|
||||||
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
|
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
|
||||||
|
@ -202,6 +169,26 @@ TEST_F(WireFenceTests, GetCompletedValueUpdate) {
|
||||||
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u);
|
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the fence completed value updates after signaling the fence
|
||||||
|
TEST_F(WireFenceTests, GetCompletedValueUpdateInCallback) {
|
||||||
|
// Signal the fence
|
||||||
|
DoQueueSignal(3u);
|
||||||
|
|
||||||
|
// Register the callback
|
||||||
|
wgpuFenceOnCompletion(fence, 3u, ToMockFenceOnCompletionCallback, this);
|
||||||
|
EXPECT_CALL(api, OnFenceOnCompletionCallback(apiFence, 3u, _, _))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
|
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
|
||||||
|
}))
|
||||||
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() { EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u); }));
|
||||||
|
FlushServer();
|
||||||
|
}
|
||||||
|
|
||||||
// Check that the fence completed value does not update without a flush
|
// Check that the fence completed value does not update without a flush
|
||||||
TEST_F(WireFenceTests, GetCompletedValueNoUpdate) {
|
TEST_F(WireFenceTests, GetCompletedValueNoUpdate) {
|
||||||
wgpuQueueSignal(queue, fence, 3u);
|
wgpuQueueSignal(queue, fence, 3u);
|
||||||
|
|
Loading…
Reference in New Issue