Remove Fences

Fences are no longer part of the WebGPU spec, and have been removed from
Blink.

Bug: dawn:22
Change-Id: I240c4c4107acfaf9facec88a43a38b5ff327c7a6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/50702
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Brandon Jones 2021-05-21 00:01:08 +00:00 committed by Dawn LUCI CQ
parent 36cb5a86de
commit a548578f67
28 changed files with 16 additions and 1707 deletions

View File

@ -951,47 +951,6 @@
{"name": "format", "type": "texture format"}
]
},
"fence": {
"category": "object",
"methods": [
{
"name": "get completed value",
"returns": "uint64_t"
},
{
"name": "on completion",
"args": [
{"name": "value", "type": "uint64_t"},
{"name": "callback", "type": "fence on completion callback"},
{"name": "userdata", "type": "void", "annotation": "*"}
]
}
]
},
"fence on completion callback": {
"category": "callback",
"args": [
{"name": "status", "type": "fence completion status"},
{"name": "userdata", "type": "void", "annotation": "*"}
]
},
"fence completion status": {
"category": "enum",
"values": [
{"value": 0, "name": "success"},
{"value": 1, "name": "error"},
{"value": 2, "name": "unknown"},
{"value": 3, "name": "device lost"}
]
},
"fence descriptor": {
"category": "structure",
"extensible": true,
"members": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
{"name": "initial value", "type": "uint64_t", "default": "0"}
]
},
"filter mode": {
"category": "enum",
"values": [
@ -1210,20 +1169,6 @@
{"name": "commands", "type": "command buffer", "annotation": "const*", "length": "command count"}
]
},
{
"name": "signal",
"args": [
{"name": "fence", "type": "fence"},
{"name": "signal value", "type": "uint64_t"}
]
},
{
"name": "create fence",
"returns": "fence",
"args": [
{"name": "descriptor", "type": "fence descriptor", "annotation": "const*", "optional": true}
]
},
{
"name": "on submitted work done",
"args": [

View File

@ -59,11 +59,6 @@
{ "name": "object type", "type": "ObjectType" },
{ "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 on submitted work done": [
{ "name": "queue id", "type": "ObjectId" },
{ "name": "signal value", "type": "uint64_t" },
@ -124,15 +119,6 @@
{ "name": "type", "type": "error type" },
{ "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": [
{ "name": "fence", "type": "ObjectHandle", "handle_type": "fence" },
{ "name": "value", "type": "uint64_t" }
],
"queue work done callback": [
{ "name": "queue", "type": "ObjectHandle", "handle_type": "queue" },
{ "name": "request serial", "type": "uint64_t" },
@ -162,8 +148,6 @@
"DevicePopErrorScope",
"DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback",
"FenceGetCompletedValue",
"FenceOnCompletion",
"ShaderModuleGetCompilationInfo",
"QueueOnSubmittedWorkDone",
"QueueWriteBuffer",
@ -176,13 +160,11 @@
"DeviceGetDefaultQueue",
"DeviceGetQueue",
"DeviceInjectError",
"DevicePushErrorScope",
"QueueCreateFence"
"DevicePushErrorScope"
],
"client_special_objects": [
"Buffer",
"Device",
"Fence",
"Queue",
"ShaderModule"
],
@ -194,7 +176,6 @@
"QueueSignal"
],
"server_reverse_lookup_objects": [
"Fence"
]
}
}

View File

@ -228,8 +228,6 @@ source_set("dawn_native_sources") {
"Extensions.h",
"ExternalTexture.cpp",
"ExternalTexture.h",
"Fence.cpp",
"Fence.h",
"Format.cpp",
"Format.h",
"Forward.h",

View File

@ -96,8 +96,6 @@ target_sources(dawn_native PRIVATE
"ExternalTexture.h"
"ObjectContentHasher.cpp"
"ObjectContentHasher.h"
"Fence.cpp"
"Fence.h"
"Format.cpp"
"Format.h"
"Forward.h"

View File

@ -30,7 +30,6 @@
#include "dawn_native/ErrorData.h"
#include "dawn_native/ErrorScope.h"
#include "dawn_native/ExternalTexture.h"
#include "dawn_native/Fence.h"
#include "dawn_native/Instance.h"
#include "dawn_native/InternalPipelineStore.h"
#include "dawn_native/PersistentCache.h"

View File

@ -1,159 +0,0 @@
// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/Fence.h"
#include "common/Assert.h"
#include "dawn_native/Device.h"
#include "dawn_native/Queue.h"
#include "dawn_native/ValidationUtils_autogen.h"
#include <utility>
namespace dawn_native {
struct FenceInFlight : QueueBase::TaskInFlight {
FenceInFlight(Ref<Fence> fence, FenceAPISerial value)
: fence(std::move(fence)), value(value) {
}
void Finish() override {
fence->SetCompletedValue(value, WGPUFenceCompletionStatus_Success);
}
void HandleDeviceLoss() override {
fence->SetCompletedValue(value, WGPUFenceCompletionStatus_DeviceLost);
}
~FenceInFlight() override = default;
private:
Ref<Fence> fence;
FenceAPISerial value;
};
MaybeError ValidateFenceDescriptor(const FenceDescriptor* descriptor) {
if (descriptor->nextInChain != nullptr) {
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
}
return {};
}
// Fence
Fence::Fence(QueueBase* queue, const FenceDescriptor* descriptor)
: ObjectBase(queue->GetDevice()),
mSignalValue(descriptor->initialValue),
mCompletedValue(descriptor->initialValue),
mQueue(queue) {
}
Fence::Fence(DeviceBase* device, ObjectBase::ErrorTag tag) : ObjectBase(device, tag) {
}
Fence::~Fence() {
for (auto& request : mRequests.IterateAll()) {
ASSERT(!IsError());
request.completionCallback(WGPUFenceCompletionStatus_Unknown, request.userdata);
}
mRequests.Clear();
}
// static
Fence* Fence::MakeError(DeviceBase* device) {
return new Fence(device, ObjectBase::kError);
}
uint64_t Fence::APIGetCompletedValue() const {
if (IsError()) {
return 0;
}
return uint64_t(mCompletedValue);
}
void Fence::APIOnCompletion(uint64_t apiValue,
wgpu::FenceOnCompletionCallback callback,
void* userdata) {
FenceAPISerial value(apiValue);
WGPUFenceCompletionStatus status;
if (GetDevice()->ConsumedError(ValidateOnCompletion(value, &status))) {
callback(status, userdata);
return;
}
ASSERT(!IsError());
if (value <= mCompletedValue) {
callback(WGPUFenceCompletionStatus_Success, userdata);
return;
}
OnCompletionData request;
request.completionCallback = callback;
request.userdata = userdata;
mRequests.Enqueue(std::move(request), value);
}
FenceAPISerial Fence::GetSignaledValue() const {
ASSERT(!IsError());
return mSignalValue;
}
const QueueBase* Fence::GetQueue() const {
ASSERT(!IsError());
return mQueue.Get();
}
void Fence::SetSignaledValue(FenceAPISerial signalValue) {
ASSERT(!IsError());
ASSERT(signalValue > mSignalValue);
mSignalValue = signalValue;
}
void Fence::SetCompletedValue(FenceAPISerial completedValue, WGPUFenceCompletionStatus status) {
ASSERT(!IsError());
ASSERT(completedValue <= mSignalValue);
ASSERT(completedValue > mCompletedValue);
mCompletedValue = completedValue;
for (auto& request : mRequests.IterateUpTo(mCompletedValue)) {
request.completionCallback(status, request.userdata);
}
mRequests.ClearUpTo(mCompletedValue);
}
void Fence::UpdateFenceOnComplete(Fence* fence, FenceAPISerial value) {
std::unique_ptr<FenceInFlight> fenceInFlight =
std::make_unique<FenceInFlight>(fence, value);
// TODO: use GetLastSubmittedCommandSerial in the future for perforamnce
GetDevice()->GetQueue()->TrackTask(std::move(fenceInFlight),
GetDevice()->GetPendingCommandSerial());
}
MaybeError Fence::ValidateOnCompletion(FenceAPISerial value,
WGPUFenceCompletionStatus* status) const {
*status = WGPUFenceCompletionStatus_DeviceLost;
DAWN_TRY(GetDevice()->ValidateIsAlive());
*status = WGPUFenceCompletionStatus_Error;
DAWN_TRY(GetDevice()->ValidateObject(this));
if (value > mSignalValue) {
return DAWN_VALIDATION_ERROR("Value greater than fence signaled value");
}
*status = WGPUFenceCompletionStatus_Success;
return {};
}
} // namespace dawn_native

View File

@ -1,74 +0,0 @@
// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_FENCE_H_
#define DAWNNATIVE_FENCE_H_
#include "common/SerialMap.h"
#include "dawn_native/Error.h"
#include "dawn_native/Forward.h"
#include "dawn_native/IntegerTypes.h"
#include "dawn_native/ObjectBase.h"
#include "dawn_native/dawn_platform.h"
#include <map>
namespace dawn_native {
MaybeError ValidateFenceDescriptor(const FenceDescriptor* descriptor);
class Fence final : public ObjectBase {
public:
Fence(QueueBase* queue, const FenceDescriptor* descriptor);
static Fence* MakeError(DeviceBase* device);
FenceAPISerial GetSignaledValue() const;
const QueueBase* GetQueue() const;
// Dawn API
uint64_t APIGetCompletedValue() const;
void APIOnCompletion(uint64_t value,
wgpu::FenceOnCompletionCallback callback,
void* userdata);
protected:
friend class QueueBase;
friend struct FenceInFlight;
void SetSignaledValue(FenceAPISerial signalValue);
void SetCompletedValue(FenceAPISerial completedValue, WGPUFenceCompletionStatus status);
void UpdateFenceOnComplete(Fence* fence, FenceAPISerial value);
private:
Fence(DeviceBase* device, ObjectBase::ErrorTag tag);
~Fence() override;
MaybeError ValidateOnCompletion(FenceAPISerial value,
WGPUFenceCompletionStatus* status) const;
struct OnCompletionData {
wgpu::FenceOnCompletionCallback completionCallback = nullptr;
void* userdata = nullptr;
};
FenceAPISerial mSignalValue;
FenceAPISerial mCompletedValue;
Ref<QueueBase> mQueue;
SerialMap<FenceAPISerial, OnCompletionData> mRequests;
};
} // namespace dawn_native
#endif // DAWNNATIVE_FENCE_H_

View File

@ -23,7 +23,6 @@
#include "dawn_native/CopyTextureForBrowserHelper.h"
#include "dawn_native/Device.h"
#include "dawn_native/DynamicUploader.h"
#include "dawn_native/Fence.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderPassEncoder.h"
#include "dawn_native/RenderPipeline.h"
@ -184,19 +183,6 @@ namespace dawn_native {
}
}
void QueueBase::APISignal(Fence* fence, uint64_t apiSignalValue) {
FenceAPISerial signalValue(apiSignalValue);
DeviceBase* device = GetDevice();
if (device->ConsumedError(ValidateSignal(fence, signalValue))) {
return;
}
ASSERT(!IsError());
fence->SetSignaledValue(signalValue);
fence->UpdateFenceOnComplete(fence, signalValue);
}
void QueueBase::APIOnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneCallback callback,
void* userdata) {
@ -246,22 +232,6 @@ namespace dawn_native {
mTasksInFlight.Clear();
}
Fence* QueueBase::APICreateFence(const FenceDescriptor* descriptor) {
// TODO(chromium:1177476): Remove once the deprecation period is finished.
GetDevice()->EmitDeprecationWarning(
"Fences are deprecated, use Queue::OnSubmittedWorkDone instead.");
if (GetDevice()->ConsumedError(ValidateCreateFence(descriptor))) {
return Fence::MakeError(GetDevice());
}
if (descriptor == nullptr) {
FenceDescriptor defaultDescriptor = {};
return new Fence(this, &defaultDescriptor);
}
return new Fence(this, descriptor);
}
void QueueBase::APIWriteBuffer(BufferBase* buffer,
uint64_t bufferOffset,
const void* data,
@ -437,21 +407,6 @@ namespace dawn_native {
return {};
}
MaybeError QueueBase::ValidateSignal(const Fence* fence, FenceAPISerial signalValue) const {
DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this));
DAWN_TRY(GetDevice()->ValidateObject(fence));
if (fence->GetQueue() != this) {
return DAWN_VALIDATION_ERROR(
"Fence must be signaled on the queue on which it was created.");
}
if (signalValue <= fence->GetSignaledValue()) {
return DAWN_VALIDATION_ERROR("Signal value less than or equal to fence signaled value");
}
return {};
}
MaybeError QueueBase::ValidateOnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneStatus* status) const {
*status = WGPUQueueWorkDoneStatus_DeviceLost;
@ -467,16 +422,6 @@ namespace dawn_native {
return {};
}
MaybeError QueueBase::ValidateCreateFence(const FenceDescriptor* descriptor) const {
DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this));
if (descriptor != nullptr) {
DAWN_TRY(ValidateFenceDescriptor(descriptor));
}
return {};
}
MaybeError QueueBase::ValidateWriteBuffer(const BufferBase* buffer,
uint64_t bufferOffset,
size_t size) const {

View File

@ -38,8 +38,6 @@ namespace dawn_native {
// Dawn API
void APISubmit(uint32_t commandCount, CommandBufferBase* const* commands);
void APISignal(Fence* fence, uint64_t signalValue);
Fence* APICreateFence(const FenceDescriptor* descriptor);
void APIOnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneCallback callback,
void* userdata);
@ -92,10 +90,8 @@ namespace dawn_native {
const Extent3D& writeSize);
MaybeError ValidateSubmit(uint32_t commandCount, CommandBufferBase* const* commands) const;
MaybeError ValidateSignal(const Fence* fence, FenceAPISerial signalValue) const;
MaybeError ValidateOnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneStatus* status) const;
MaybeError ValidateCreateFence(const FenceDescriptor* descriptor) const;
MaybeError ValidateWriteBuffer(const BufferBase* buffer,
uint64_t bufferOffset,
size_t size) const;

View File

@ -80,8 +80,6 @@ dawn_component("dawn_wire") {
"client/ClientInlineMemoryTransferService.cpp",
"client/Device.cpp",
"client/Device.h",
"client/Fence.cpp",
"client/Fence.h",
"client/ObjectAllocator.h",
"client/Queue.cpp",
"client/Queue.h",
@ -92,7 +90,6 @@ dawn_component("dawn_wire") {
"server/Server.h",
"server/ServerBuffer.cpp",
"server/ServerDevice.cpp",
"server/ServerFence.cpp",
"server/ServerInlineMemoryTransferService.cpp",
"server/ServerQueue.cpp",
"server/ServerShaderModule.cpp",

View File

@ -52,8 +52,6 @@ target_sources(dawn_wire PRIVATE
"client/ClientInlineMemoryTransferService.cpp"
"client/Device.cpp"
"client/Device.h"
"client/Fence.cpp"
"client/Fence.h"
"client/ObjectAllocator.h"
"client/Queue.cpp"
"client/Queue.h"
@ -64,7 +62,6 @@ target_sources(dawn_wire PRIVATE
"server/Server.h"
"server/ServerBuffer.cpp"
"server/ServerDevice.cpp"
"server/ServerFence.cpp"
"server/ServerInlineMemoryTransferService.cpp"
"server/ServerQueue.cpp"
"server/ServerShaderModule.cpp"

View File

@ -19,7 +19,6 @@
#include "dawn_wire/client/Buffer.h"
#include "dawn_wire/client/Device.h"
#include "dawn_wire/client/Fence.h"
#include "dawn_wire/client/Queue.h"
#include "dawn_wire/client/ShaderModule.h"

View File

@ -70,26 +70,6 @@ namespace dawn_wire { namespace client {
readInitialDataInfo);
}
bool Client::DoFenceUpdateCompletedValue(Fence* fence, uint64_t value) {
// The fence might have been deleted or recreated so this isn't an error.
if (fence == nullptr) {
return true;
}
fence->OnUpdateCompletedValueCallback(value);
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;
}
return fence->OnCompletionCallback(requestSerial, status);
}
bool Client::DoQueueWorkDoneCallback(Queue* queue,
uint64_t requestSerial,
WGPUQueueWorkDoneStatus status) {

View File

@ -1,89 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/client/Fence.h"
#include "dawn_wire/client/Client.h"
namespace dawn_wire { namespace client {
Fence::~Fence() {
// Callbacks need to be fired in all cases, as they can handle freeing resources
// so we call them with "Unknown" status.
for (auto& it : mOnCompletionRequests) {
if (it.second.callback) {
it.second.callback(WGPUFenceCompletionStatus_Unknown, it.second.userdata);
}
}
mOnCompletionRequests.clear();
}
void Fence::CancelCallbacksForDisconnect() {
for (auto& it : mOnCompletionRequests) {
if (it.second.callback) {
it.second.callback(WGPUFenceCompletionStatus_DeviceLost, it.second.userdata);
}
}
mOnCompletionRequests.clear();
}
void Fence::Initialize(const WGPUFenceDescriptor* descriptor) {
mCompletedValue = descriptor != nullptr ? descriptor->initialValue : 0u;
}
void Fence::OnCompletion(uint64_t value,
WGPUFenceOnCompletionCallback callback,
void* userdata) {
if (client->IsDisconnected()) {
callback(WGPUFenceCompletionStatus_DeviceLost, userdata);
return;
}
uint32_t serial = mOnCompletionRequestSerial++;
ASSERT(mOnCompletionRequests.find(serial) == mOnCompletionRequests.end());
FenceOnCompletionCmd cmd;
cmd.fenceId = this->id;
cmd.value = value;
cmd.requestSerial = serial;
mOnCompletionRequests[serial] = {callback, userdata};
client->SerializeCommand(cmd);
}
void Fence::OnUpdateCompletedValueCallback(uint64_t value) {
mCompletedValue = value;
}
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 {
return mCompletedValue;
}
}} // namespace dawn_wire::client

View File

@ -1,53 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_CLIENT_FENCE_H_
#define DAWNWIRE_CLIENT_FENCE_H_
#include <dawn/webgpu.h>
#include "common/SerialMap.h"
#include "dawn_wire/client/ObjectBase.h"
namespace dawn_wire { namespace client {
class Queue;
class Fence final : public ObjectBase {
public:
using ObjectBase::ObjectBase;
~Fence();
void Initialize(const WGPUFenceDescriptor* descriptor);
void CheckPassedFences();
void OnCompletion(uint64_t value, WGPUFenceOnCompletionCallback callback, void* userdata);
void OnUpdateCompletedValueCallback(uint64_t value);
bool OnCompletionCallback(uint64_t requestSerial, WGPUFenceCompletionStatus status);
uint64_t GetCompletedValue() const;
private:
void CancelCallbacksForDisconnect() override;
struct OnCompletionData {
WGPUFenceOnCompletionCallback callback = nullptr;
void* userdata = nullptr;
};
uint64_t mCompletedValue = 0;
uint64_t mOnCompletionRequestSerial = 0;
std::map<uint64_t, OnCompletionData> mOnCompletionRequests;
};
}} // namespace dawn_wire::client
#endif // DAWNWIRE_CLIENT_FENCE_H_

View File

@ -60,20 +60,6 @@ namespace dawn_wire { namespace client {
client->SerializeCommand(cmd);
}
WGPUFence Queue::CreateFence(WGPUFenceDescriptor const* descriptor) {
auto* allocation = client->FenceAllocator().New(client);
QueueCreateFenceCmd cmd;
cmd.self = ToAPI(this);
cmd.result = ObjectHandle{allocation->object->id, allocation->generation};
cmd.descriptor = descriptor;
client->SerializeCommand(cmd);
Fence* fence = allocation->object.get();
fence->Initialize(descriptor);
return ToAPI(fence);
}
void Queue::WriteBuffer(WGPUBuffer cBuffer,
uint64_t bufferOffset,
const void* data,

View File

@ -35,7 +35,6 @@ namespace dawn_wire { namespace client {
void OnSubmittedWorkDone(uint64_t signalValue,
WGPUQueueWorkDoneCallback callback,
void* userdata);
WGPUFence CreateFence(const WGPUFenceDescriptor* descriptor);
void WriteBuffer(WGPUBuffer cBuffer, uint64_t bufferOffset, const void* data, size_t size);
void WriteTexture(const WGPUImageCopyTexture* destination,
const void* data,

View File

@ -127,20 +127,6 @@ namespace dawn_wire { namespace server {
uint64_t requestSerial;
};
struct FenceCompletionUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle fence;
uint64_t value;
};
struct FenceOnCompletionUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
ObjectHandle fence;
uint64_t requestSerial;
};
struct ShaderModuleGetCompilationInfoUserdata : CallbackUserdata {
using CallbackUserdata::CallbackUserdata;
@ -218,10 +204,6 @@ namespace dawn_wire { namespace server {
const char* message,
ErrorScopeUserdata* userdata);
void OnBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, MapUserdata* userdata);
void OnFenceCompletedValueUpdated(WGPUFenceCompletionStatus status,
FenceCompletionUserdata* userdata);
void OnFenceOnCompletion(WGPUFenceCompletionStatus status,
FenceOnCompletionUserdata* userdata);
void OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* userdata);
void OnCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus status,
WGPUComputePipeline pipeline,

View File

@ -1,67 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_wire/server/Server.h"
#include <memory>
namespace dawn_wire { namespace server {
void Server::OnFenceCompletedValueUpdated(WGPUFenceCompletionStatus status,
FenceCompletionUserdata* data) {
if (status != WGPUFenceCompletionStatus_Success) {
return;
}
ReturnFenceUpdateCompletedValueCmd cmd;
cmd.fence = data->fence;
cmd.value = data->value;
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;
}
auto userdata = MakeUserdata<FenceOnCompletionUserdata>();
userdata->fence = ObjectHandle{fenceId, fence->generation};
userdata->requestSerial = requestSerial;
mProcs.fenceOnCompletion(
fence->handle, value,
ForwardToServer<decltype(
&Server::OnFenceOnCompletion)>::Func<&Server::OnFenceOnCompletion>(),
userdata.release());
return true;
}
void Server::OnFenceOnCompletion(WGPUFenceCompletionStatus status,
FenceOnCompletionUserdata* data) {
ReturnFenceOnCompletionCallbackCmd cmd;
cmd.fence = data->fence;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
SerializeCommand(cmd);
}
}} // namespace dawn_wire::server

View File

@ -17,29 +17,6 @@
namespace dawn_wire { namespace server {
bool Server::DoQueueSignal(WGPUQueue cSelf, WGPUFence cFence, uint64_t signalValue) {
if (cFence == nullptr) {
return false;
}
mProcs.queueSignal(cSelf, cFence, signalValue);
ObjectId fenceId = FenceObjectIdTable().Get(cFence);
ASSERT(fenceId != 0);
auto* fence = FenceObjects().Get(fenceId);
ASSERT(fence != nullptr);
auto userdata = MakeUserdata<FenceCompletionUserdata>();
userdata->fence = ObjectHandle{fenceId, fence->generation};
userdata->value = signalValue;
mProcs.fenceOnCompletion(
cFence, signalValue,
ForwardToServer<decltype(&Server::OnFenceCompletedValueUpdated)>::Func<
&Server::OnFenceCompletedValueUpdated>(),
userdata.release());
return true;
}
void Server::OnQueueWorkDone(WGPUQueueWorkDoneStatus status, QueueWorkDoneUserdata* data) {
ReturnQueueWorkDoneCallbackCmd cmd;
cmd.queue = data->queue;

View File

@ -197,7 +197,6 @@ test("dawn_unittests") {
"unittests/validation/DynamicStateCommandValidationTests.cpp",
"unittests/validation/ErrorScopeValidationTests.cpp",
"unittests/validation/ExternalTextureTests.cpp",
"unittests/validation/FenceValidationTests.cpp",
"unittests/validation/GetBindGroupLayoutValidationTests.cpp",
"unittests/validation/IndexBufferValidationTests.cpp",
"unittests/validation/MinimumBufferSizeValidationTests.cpp",
@ -232,7 +231,6 @@ test("dawn_unittests") {
"unittests/wire/WireDisconnectTests.cpp",
"unittests/wire/WireErrorCallbackTests.cpp",
"unittests/wire/WireExtensionTests.cpp",
"unittests/wire/WireFenceTests.cpp",
"unittests/wire/WireInjectDeviceTests.cpp",
"unittests/wire/WireInjectSwapChainTests.cpp",
"unittests/wire/WireInjectTextureTests.cpp",
@ -318,7 +316,6 @@ source_set("dawn_end2end_tests_sources") {
"end2end/DynamicBufferOffsetTests.cpp",
"end2end/EntryPointTests.cpp",
"end2end/ExternalTextureTests.cpp",
"end2end/FenceTests.cpp",
"end2end/FirstIndexOffsetTests.cpp",
"end2end/GpuMemorySynchronizationTests.cpp",
"end2end/IndexFormatTests.cpp",

View File

@ -188,11 +188,6 @@ TEST_P(DeprecationTests, BindGroupLayoutEntryViewDimensionDefaulting) {
}
}
// Test that fences are deprecated.
TEST_P(DeprecationTests, CreateFence) {
EXPECT_DEPRECATION_WARNING(queue.CreateFence());
}
DAWN_INSTANTIATE_TEST(DeprecationTests,
D3D12Backend(),
MetalBackend(),

View File

@ -35,23 +35,6 @@ static void ToMockDeviceLostCallback(const char* message, void* userdata) {
self->StartExpectDeviceError();
}
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletionFails(WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(WGPUFenceCompletionStatus_DeviceLost, status);
mockFenceOnCompletionCallback->Call(status, userdata);
mockFenceOnCompletionCallback = nullptr;
}
static void ToMockFenceOnCompletionSucceeds(WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(WGPUFenceCompletionStatus_Success, status);
mockFenceOnCompletionCallback->Call(status, userdata);
mockFenceOnCompletionCallback = nullptr;
}
class MockQueueWorkDoneCallback {
public:
MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
@ -70,13 +53,11 @@ class DeviceLostTest : public DawnTest {
DawnTest::SetUp();
DAWN_SKIP_TEST_IF(UsesWire());
mockDeviceLostCallback = std::make_unique<MockDeviceLostCallback>();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
}
void TearDown() override {
mockDeviceLostCallback = nullptr;
mockFenceOnCompletionCallback = nullptr;
mockQueueWorkDoneCallback = nullptr;
DawnTest::TearDown();
}
@ -416,67 +397,6 @@ TEST_P(DeviceLostTest, CommandEncoderFinishFails) {
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test that CreateFenceFails when device is lost
TEST_P(DeviceLostTest, CreateFenceFails) {
SetCallbackAndLoseForTesting();
EXPECT_DEPRECATION_WARNING(ASSERT_DEVICE_ERROR(queue.CreateFence()));
}
// Test that queue signal fails when device is lost
TEST_P(DeviceLostTest, QueueSignalFenceFails) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
SetCallbackAndLoseForTesting();
ASSERT_DEVICE_ERROR(queue.Signal(fence, 3));
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, nullptr))
.Times(1);
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr));
// completed value should not have changed from initial value
EXPECT_EQ(fence.GetCompletedValue(), 0u);
}
// Test that Fence On Completion fails after device is lost
TEST_P(DeviceLostTest, FenceOnCompletionFails) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
SetCallbackAndLoseForTesting();
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, nullptr))
.Times(1);
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr));
ASSERT_DEVICE_ERROR(device.Tick());
// completed value is the last value signaled (all previous GPU operations are as if completed)
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test that Fence::OnCompletion callbacks with device lost status when device is lost after calling
// OnCompletion
TEST_P(DeviceLostTest, FenceOnCompletionBeforeLossFails) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, nullptr))
.Times(1);
fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr);
SetCallbackAndLoseForTesting();
ASSERT_DEVICE_ERROR(device.Tick());
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test that QueueOnSubmittedWorkDone fails after device is lost.
TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneFails) {
SetCallbackAndLoseForTesting();
@ -499,36 +419,6 @@ TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneBeforeLossFails) {
ASSERT_DEVICE_ERROR(device.Tick());
}
// Regression test for the Null backend not properly setting the completedSerial when
// WaitForIdleForDestruction is called, causing the fence signaling to not be retired and an
// ASSERT to fire.
TEST_P(DeviceLostTest, AfterSubmitAndSerial) {
queue.Submit(0, nullptr);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
SetCallbackAndLoseForTesting();
}
// Test that when you Signal, then Tick, then device lost, the fence completed value would be 2
TEST_P(DeviceLostTest, FenceSignalTickOnCompletion) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
WaitForAllOperations();
// callback should have device lost status
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
fence.OnCompletion(2u, ToMockFenceOnCompletionSucceeds, nullptr);
SetCallbackAndLoseForTesting();
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test that LostForTesting can only be called on one time
TEST_P(DeviceLostTest, LoseForTestingOnce) {
// First LoseForTesting call should occur normally

View File

@ -1,277 +0,0 @@
// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gmock/gmock.h>
#include "tests/DawnTest.h"
#include <array>
#include <cstring>
using namespace testing;
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
mockFenceOnCompletionCallback->Call(status, userdata);
}
class MockPopErrorScopeCallback {
public:
MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
};
static std::unique_ptr<MockPopErrorScopeCallback> mockPopErrorScopeCallback;
static void ToMockPopErrorScopeCallback(WGPUErrorType type, const char* message, void* userdata) {
mockPopErrorScopeCallback->Call(type, message, userdata);
}
class FenceTests : public DawnTest {
private:
struct CallbackInfo {
FenceTests* test;
uint64_t value;
WGPUFenceCompletionStatus status;
int32_t callIndex = -1; // If this is -1, the callback was not called
void Update(WGPUFenceCompletionStatus status) {
this->callIndex = test->mCallIndex++;
this->status = status;
}
};
int32_t mCallIndex;
protected:
FenceTests() : mCallIndex(0) {
}
void SetUp() override {
DawnTest::SetUp();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
mockPopErrorScopeCallback = std::make_unique<MockPopErrorScopeCallback>();
}
void TearDown() override {
mockFenceOnCompletionCallback = nullptr;
mockPopErrorScopeCallback = nullptr;
DawnTest::TearDown();
}
void WaitForCompletedValue(wgpu::Fence fence, uint64_t completedValue) {
while (fence.GetCompletedValue() < completedValue) {
WaitABit();
}
}
};
// Test that signaling a fence updates the completed value
TEST_P(FenceTests, SimpleSignal) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1u;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// Completed value starts at initial value
EXPECT_EQ(fence.GetCompletedValue(), 1u);
queue.Signal(fence, 2);
WaitForCompletedValue(fence, 2);
// Completed value updates to signaled value
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
// Test callbacks are called in increasing order of fence completion value
TEST_P(FenceTests, OnCompletionOrdering) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 4);
{
testing::InSequence s;
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 1))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Success, this + 3))
.Times(1);
}
fence.OnCompletion(2u, ToMockFenceOnCompletion, this + 2);
fence.OnCompletion(0u, ToMockFenceOnCompletion, this + 0);
fence.OnCompletion(3u, ToMockFenceOnCompletion, this + 3);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 1);
WaitForCompletedValue(fence, 4);
}
// Test callbacks still occur if Queue::Signal happens multiple times
TEST_P(FenceTests, MultipleSignalOnCompletion) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
queue.Signal(fence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
fence.OnCompletion(3u, ToMockFenceOnCompletion, nullptr);
WaitForCompletedValue(fence, 4);
}
// Test callbacks still occur if Queue::Signal and fence::OnCompletion happens multiple times
TEST_P(FenceTests, SignalOnCompletionWait) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
queue.Signal(fence, 6);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 6))
.Times(1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 2);
fence.OnCompletion(5u, ToMockFenceOnCompletion, this + 6);
WaitForCompletedValue(fence, 6);
}
// Test callbacks still occur if Queue::Signal and fence::OnCompletion happens multiple times
TEST_P(FenceTests, SignalOnCompletionWaitStaggered) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 2);
queue.Signal(fence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 4))
.Times(1);
fence.OnCompletion(3u, ToMockFenceOnCompletion, this + 4);
WaitForCompletedValue(fence, 4);
}
// Test all callbacks are called if they are added for the same fence value
TEST_P(FenceTests, OnCompletionMultipleCallbacks) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 1))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 3))
.Times(1);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 0);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 1);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 2);
fence.OnCompletion(4u, ToMockFenceOnCompletion, this + 3);
WaitForCompletedValue(fence, 4u);
}
// TODO(enga): Enable when fence is removed from fence signal tracker
// Currently it holds a reference and is not destructed
TEST_P(FenceTests, DISABLED_DestroyBeforeOnCompletionEnd) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
// The fence in this block will be deleted when it goes out of scope
{
wgpu::Fence testFence;
EXPECT_DEPRECATION_WARNING(testFence = queue.CreateFence());
queue.Signal(testFence, 4);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 1))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback,
Call(WGPUFenceCompletionStatus_Unknown, this + 3))
.Times(1);
testFence.OnCompletion(1u, ToMockFenceOnCompletion, this + 0);
testFence.OnCompletion(2u, ToMockFenceOnCompletion, this + 1);
testFence.OnCompletion(2u, ToMockFenceOnCompletion, this + 2);
testFence.OnCompletion(3u, ToMockFenceOnCompletion, this + 3);
}
// Wait for another fence to be sure all callbacks have cleared
queue.Signal(fence, 1);
WaitForCompletedValue(fence, 1);
}
// Regression test that validation errors that are tracked client-side are captured
// in error scopes.
TEST_P(FenceTests, ClientValidationErrorInErrorScope) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 4);
device.PushErrorScope(wgpu::ErrorFilter::Validation);
queue.Signal(fence, 2);
EXPECT_CALL(*mockPopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1);
device.PopErrorScope(ToMockPopErrorScopeCallback, this);
WaitForCompletedValue(fence, 4);
}
DAWN_INSTANTIATE_TEST(FenceTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
VulkanBackend());

View File

@ -28,17 +28,6 @@ static void ToMockMapCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
mockMapCallback->Call(status, userdata);
}
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(status, WGPUFenceCompletionStatus_Success);
mockFenceOnCompletionCallback->Call(status, userdata);
}
class MockQueueWorkDoneCallback {
public:
MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
@ -55,7 +44,6 @@ class QueueTimelineTests : public DawnTest {
DawnTest::SetUp();
mockMapCallback = std::make_unique<MockMapCallback>();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
wgpu::BufferDescriptor descriptor;
@ -66,7 +54,6 @@ class QueueTimelineTests : public DawnTest {
void TearDown() override {
mockMapCallback = nullptr;
mockFenceOnCompletionCallback = nullptr;
mockQueueWorkDoneCallback = nullptr;
DawnTest::TearDown();
}
@ -74,27 +61,6 @@ class QueueTimelineTests : public DawnTest {
wgpu::Buffer mMapReadBuffer;
};
// Test that mMapReadBuffer.MapAsync callback happens before fence.OnCompletion callback
// when queue.Signal is called after mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
TEST_P(QueueTimelineTests, MapReadSignalOnComplete) {
testing::InSequence sequence;
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.Times(1);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
// Test that mMapReadBuffer.MapAsync callback happens before queue.OnWorkDone callback
// when queue.OnSubmittedWorkDone is called after mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
@ -111,26 +77,6 @@ TEST_P(QueueTimelineTests, MapRead_OnWorkDone) {
mMapReadBuffer.Unmap();
}
// Test that fence.OnCompletion callback happens before mMapReadBuffer.MapAsync callback when
// queue.OnSubmittedWorkDone is called before mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
TEST_P(QueueTimelineTests, SignalMapReadOnComplete) {
testing::InSequence sequence;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.Times(1);
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
fence.OnCompletion(2u, ToMockFenceOnCompletion, this);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
// Test that queue.OnWorkDone callback happens before mMapReadBuffer.MapAsync callback when
// queue.Signal is called before mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called.
@ -147,65 +93,6 @@ TEST_P(QueueTimelineTests, OnWorkDone_MapRead) {
mMapReadBuffer.Unmap();
}
// Test that fence.OnCompletion callback happens before mMapReadBuffer.MapAsync callback when
// queue.Signal is called before mMapReadBuffer.MapAsync. The callback order should
// happen in the order the functions are called
TEST_P(QueueTimelineTests, SignalOnCompleteMapRead) {
testing::InSequence sequence;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this))
.Times(1);
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
fence.OnCompletion(2u, ToMockFenceOnCompletion, this);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
// Test a complicated case with many signals surrounding a buffer mapping.
TEST_P(QueueTimelineTests, SurroundWithFenceSignals) {
testing::InSequence sequence;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 2))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 3))
.Times(1);
EXPECT_CALL(*mockMapCallback, Call(WGPUBufferMapAsyncStatus_Success, this)).Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 5))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 6))
.Times(1);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 8))
.Times(1);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 2);
queue.Signal(fence, 4);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 0);
fence.OnCompletion(2u, ToMockFenceOnCompletion, this + 2);
mMapReadBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, ToMockMapCallback, this);
queue.Signal(fence, 6);
fence.OnCompletion(3u, ToMockFenceOnCompletion, this + 3);
fence.OnCompletion(5u, ToMockFenceOnCompletion, this + 5);
fence.OnCompletion(6u, ToMockFenceOnCompletion, this + 6);
queue.Signal(fence, 8);
fence.OnCompletion(8u, ToMockFenceOnCompletion, this + 8);
WaitForAllOperations();
mMapReadBuffer.Unmap();
}
DAWN_INSTANTIATE_TEST(QueueTimelineTests,
D3D12Backend(),
MetalBackend(),

View File

@ -31,11 +31,22 @@ static void ToMockDevicePopErrorScopeCallback(WGPUErrorType type,
mockDevicePopErrorScopeCallback->Call(type, message, userdata);
}
class MockQueueWorkDoneCallback {
public:
MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
};
static std::unique_ptr<MockQueueWorkDoneCallback> mockQueueWorkDoneCallback;
static void ToMockQueueWorkDone(WGPUQueueWorkDoneStatus status, void* userdata) {
mockQueueWorkDoneCallback->Call(status, userdata);
}
class ErrorScopeValidationTest : public ValidationTest {
private:
void SetUp() override {
ValidationTest::SetUp();
mockDevicePopErrorScopeCallback = std::make_unique<MockDevicePopErrorScopeCallback>();
mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
}
void TearDown() override {
@ -43,6 +54,7 @@ class ErrorScopeValidationTest : public ValidationTest {
// Delete mocks so that expectations are checked
mockDevicePopErrorScopeCallback = nullptr;
mockQueueWorkDoneCallback = nullptr;
}
};
@ -141,31 +153,6 @@ TEST_F(ErrorScopeValidationTest, PushPopBalanced) {
}
}
// Test that error scopes call their callbacks before an enclosed Queue::Submit
// completes
TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmit) {
wgpu::Queue queue = device.GetQueue();
device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
queue.Submit(0, nullptr);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
testing::Sequence seq;
MockCallback<WGPUFenceOnCompletionCallback> fenceCallback;
fence.OnCompletion(1, fenceCallback.Callback(), fenceCallback.MakeUserdata(this));
MockCallback<WGPUErrorCallback> errorScopeCallback;
EXPECT_CALL(errorScopeCallback, Call(WGPUErrorType_NoError, _, this + 1)).InSequence(seq);
device.PopErrorScope(errorScopeCallback.Callback(), errorScopeCallback.MakeUserdata(this + 1));
EXPECT_CALL(fenceCallback, Call(WGPUFenceCompletionStatus_Success, this)).InSequence(seq);
WaitForAllOperations(device);
}
// Test that parent error scopes also call their callbacks before an enclosed Queue::Submit
// completes
TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
@ -175,15 +162,10 @@ TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
queue.Submit(0, nullptr);
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
queue.Signal(fence, 1);
queue.OnSubmittedWorkDone(0u, ToMockQueueWorkDone, this);
testing::Sequence seq;
MockCallback<WGPUFenceOnCompletionCallback> fenceCallback;
fence.OnCompletion(1, fenceCallback.Callback(), fenceCallback.MakeUserdata(this));
MockCallback<WGPUErrorCallback> errorScopeCallback2;
EXPECT_CALL(errorScopeCallback2, Call(WGPUErrorType_NoError, _, this + 1)).InSequence(seq);
device.PopErrorScope(errorScopeCallback2.Callback(),
@ -194,7 +176,8 @@ TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
device.PopErrorScope(errorScopeCallback1.Callback(),
errorScopeCallback1.MakeUserdata(this + 2));
EXPECT_CALL(fenceCallback, Call(WGPUFenceCompletionStatus_Success, this)).InSequence(seq);
EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_Success, this))
.InSequence(seq);
WaitForAllOperations(device);
}

View File

@ -1,235 +0,0 @@
// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "tests/unittests/validation/ValidationTest.h"
#include <gmock/gmock.h>
using namespace testing;
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
struct FenceOnCompletionExpectation {
wgpu::Fence fence;
uint64_t value;
WGPUFenceCompletionStatus status;
};
static std::unique_ptr<MockFenceOnCompletionCallback> mockFenceOnCompletionCallback;
static void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
mockFenceOnCompletionCallback->Call(status, userdata);
}
class FenceValidationTest : public ValidationTest {
protected:
void TestOnCompletion(wgpu::Fence fence, uint64_t value, WGPUFenceCompletionStatus status) {
FenceOnCompletionExpectation* expectation = new FenceOnCompletionExpectation;
expectation->fence = fence;
expectation->value = value;
expectation->status = status;
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(status, expectation)).Times(1);
fence.OnCompletion(value, ToMockFenceOnCompletion, expectation);
}
wgpu::Queue queue;
private:
void SetUp() override {
ValidationTest::SetUp();
mockFenceOnCompletionCallback = std::make_unique<MockFenceOnCompletionCallback>();
queue = device.GetQueue();
}
void TearDown() override {
// Delete mocks so that expectations are checked
mockFenceOnCompletionCallback = nullptr;
ValidationTest::TearDown();
}
};
// Test cases where creation should succeed
TEST_F(FenceValidationTest, CreationSuccess) {
// Success
{
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 0;
EXPECT_DEPRECATION_WARNING(queue.CreateFence(&descriptor));
}
}
// Creation succeeds if no descriptor is provided
TEST_F(FenceValidationTest, DefaultDescriptor) {
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence());
EXPECT_EQ(fence.GetCompletedValue(), 0u);
}
TEST_F(FenceValidationTest, GetCompletedValue) {
// Starts at initial value
{
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
EXPECT_EQ(fence.GetCompletedValue(), 1u);
}
}
// Test that OnCompletion handlers are called immediately for
// already completed fence values
TEST_F(FenceValidationTest, OnCompletionImmediate) {
// TODO(crbug.com/dawn/653): This has wrong different behavior on the wire, but fences will be
// removed soon.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 0))
.Times(1);
fence.OnCompletion(0u, ToMockFenceOnCompletion, this + 0);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, this + 1))
.Times(1);
fence.OnCompletion(1u, ToMockFenceOnCompletion, this + 1);
}
// Test setting OnCompletion handlers for values > signaled value
TEST_F(FenceValidationTest, OnCompletionLargerThanSignaled) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// Cannot signal for values > signaled value
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Error, nullptr))
.Times(1);
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr));
// Can set handler after signaling
queue.Signal(fence, 2);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr);
WaitForAllOperations(device);
}
TEST_F(FenceValidationTest, GetCompletedValueInsideCallback) {
// TODO(crbug.com/dawn/653): This has wrong different behavior on the wire, but fences will be
// removed soon.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
queue.Signal(fence, 3);
fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.WillOnce(Invoke([&](WGPUFenceCompletionStatus status, void* userdata) {
EXPECT_EQ(fence.GetCompletedValue(), 3u);
}));
WaitForAllOperations(device);
}
TEST_F(FenceValidationTest, GetCompletedValueAfterCallback) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
queue.Signal(fence, 2);
fence.OnCompletion(2u, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, nullptr))
.Times(1);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}
TEST_F(FenceValidationTest, SignalError) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// value < fence signaled value
ASSERT_DEVICE_ERROR(queue.Signal(fence, 0));
// value == fence signaled value
ASSERT_DEVICE_ERROR(queue.Signal(fence, 1));
}
TEST_F(FenceValidationTest, SignalSuccess) {
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
// Success
queue.Signal(fence, 2);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 2u);
// Success increasing fence value by more than 1
queue.Signal(fence, 6);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 6u);
}
// Test it is invalid to signal a fence on a different queue than it was created on
// DISABLED until we have support for multiple queues
TEST_F(FenceValidationTest, DISABLED_SignalWrongQueue) {
wgpu::Queue queue2 = device.GetQueue();
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
ASSERT_DEVICE_ERROR(queue2.Signal(fence, 2));
}
// Test that signaling a fence on a wrong queue does not update fence signaled value
// DISABLED until we have support for multiple queues
TEST_F(FenceValidationTest, DISABLED_SignalWrongQueueDoesNotUpdateValue) {
wgpu::Queue queue2 = device.GetQueue();
wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1;
wgpu::Fence fence;
EXPECT_DEPRECATION_WARNING(fence = queue.CreateFence(&descriptor));
ASSERT_DEVICE_ERROR(queue2.Signal(fence, 2));
// Fence value should be unchanged.
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 1u);
// Signaling with 2 on the correct queue should succeed
queue.Signal(fence, 2);
WaitForAllOperations(device);
EXPECT_EQ(fence.GetCompletedValue(), 2u);
}

View File

@ -1,268 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "tests/unittests/wire/WireTest.h"
#include "dawn_wire/WireClient.h"
using namespace testing;
using namespace dawn_wire;
namespace {
class MockFenceOnCompletionCallback {
public:
MOCK_METHOD(void, Call, (WGPUFenceCompletionStatus status, void* userdata));
};
std::unique_ptr<StrictMock<MockFenceOnCompletionCallback>> mockFenceOnCompletionCallback;
void ToMockFenceOnCompletion(WGPUFenceCompletionStatus status, void* userdata) {
mockFenceOnCompletionCallback->Call(status, userdata);
}
} // anonymous namespace
class WireFenceTests : public WireTest {
public:
WireFenceTests() {
}
~WireFenceTests() override = default;
void SetUp() override {
WireTest::SetUp();
mockFenceOnCompletionCallback =
std::make_unique<StrictMock<MockFenceOnCompletionCallback>>();
{
WGPUFenceDescriptor descriptor = {};
descriptor.initialValue = 1;
apiFence = api.GetNewFence();
fence = wgpuQueueCreateFence(queue, &descriptor);
EXPECT_CALL(api, QueueCreateFence(apiQueue, _)).WillOnce(Return(apiFence));
FlushClient();
}
}
void TearDown() override {
WireTest::TearDown();
mockFenceOnCompletionCallback = nullptr;
}
void FlushServer() {
WireTest::FlushServer();
Mock::VerifyAndClearExpectations(&mockFenceOnCompletionCallback);
}
protected:
void DoQueueSignal(uint64_t signalValue,
WGPUFenceCompletionStatus status = WGPUFenceCompletionStatus_Success) {
wgpuQueueSignal(queue, fence, signalValue);
EXPECT_CALL(api, QueueSignal(apiQueue, apiFence, signalValue)).Times(1);
// This callback is generated to update the completedValue of the fence
// on the client
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, signalValue, _, _))
.WillOnce(
InvokeWithoutArgs([=]() { api.CallFenceOnCompletionCallback(apiFence, status); }))
.RetiresOnSaturation();
}
// A successfully created fence
WGPUFence fence;
WGPUFence apiFence;
};
// Check that signaling a fence succeeds
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(3u);
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 3u);
}
// Check that an error in queue signal does not update the completed value.
TEST_F(WireFenceTests, QueueSignalValidationError) {
DoQueueSignal(2u);
DoQueueSignal(1u, WGPUFenceCompletionStatus_Error);
FlushClient();
FlushServer();
// Value should stay at 2 and not be updated to 1.
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
}
// Check that a success in the on completion callback is forwarded to the client.
TEST_F(WireFenceTests, OnCompletionSuccess) {
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 0u, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
}));
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Success, _))
.Times(1);
FlushServer();
}
// Check that an error in the on completion callback is forwarded to the client.
TEST_F(WireFenceTests, OnCompletionError) {
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 0u, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Error);
}));
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Error, _)).Times(1);
FlushServer();
}
// Test that registering a callback then wire disconnect calls the callback with
// DeviceLost.
TEST_F(WireFenceTests, OnCompletionThenDisconnect) {
wgpuFenceOnCompletion(fence, 0, ToMockFenceOnCompletion, this);
EXPECT_CALL(api, OnFenceOnCompletion(apiFence, 0u, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallFenceOnCompletionCallback(apiFence, WGPUFenceCompletionStatus_Success);
}));
FlushClient();
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_DeviceLost, this))
.Times(1);
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, ToMockFenceOnCompletion, this);
}
// Without any flushes, it is valid to wait on a value less than or equal to
// the last signaled value
TEST_F(WireFenceTests, OnCompletionSynchronousValidationSuccess) {
wgpuQueueSignal(queue, fence, 4u);
wgpuFenceOnCompletion(fence, 2u, ToMockFenceOnCompletion, 0);
wgpuFenceOnCompletion(fence, 3u, ToMockFenceOnCompletion, 0);
wgpuFenceOnCompletion(fence, 4u, ToMockFenceOnCompletion, 0);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Unknown, _))
.Times(3);
}
// Check that the fence completed value is initialized
TEST_F(WireFenceTests, GetCompletedValueInitialization) {
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
}
// Check that the fence completed value updates after signaling the fence
TEST_F(WireFenceTests, GetCompletedValueUpdate) {
DoQueueSignal(3u);
FlushClient();
FlushServer();
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, ToMockFenceOnCompletion, this);
EXPECT_CALL(api, OnFenceOnCompletion(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
TEST_F(WireFenceTests, GetCompletedValueNoUpdate) {
wgpuQueueSignal(queue, fence, 3u);
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
}
// Check that the callback is called with UNKNOWN when the fence is destroyed
// before the completed value is updated
TEST_F(WireFenceTests, DestroyBeforeOnCompletionEnd) {
wgpuQueueSignal(queue, fence, 3u);
wgpuFenceOnCompletion(fence, 2u, ToMockFenceOnCompletion, nullptr);
EXPECT_CALL(*mockFenceOnCompletionCallback, Call(WGPUFenceCompletionStatus_Unknown, _))
.Times(1);
}
// Test that signaling a fence on a wrong queue is invalid
// DISABLED until we have support for multiple queues.
TEST_F(WireFenceTests, DISABLED_SignalWrongQueue) {
WGPUQueue queue2 = wgpuDeviceGetQueue(device);
WGPUQueue apiQueue2 = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetQueue(apiDevice)).WillOnce(Return(apiQueue2));
FlushClient();
wgpuQueueSignal(queue2, fence, 2u); // error
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
.Times(1);
FlushClient();
}
// Test that signaling a fence on a wrong queue does not update fence signaled value
// DISABLED until we have support for multiple queues.
TEST_F(WireFenceTests, DISABLED_SignalWrongQueueDoesNotUpdateValue) {
WGPUQueue queue2 = wgpuDeviceGetQueue(device);
WGPUQueue apiQueue2 = api.GetNewQueue();
EXPECT_CALL(api, DeviceGetQueue(apiDevice)).WillOnce(Return(apiQueue2));
FlushClient();
wgpuQueueSignal(queue2, fence, 2u); // error
EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_Validation, ValidStringMessage()))
.Times(1);
FlushClient();
// Fence value should be unchanged.
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 1u);
// Signaling with 2 on the correct queue should succeed
DoQueueSignal(2u); // success
FlushClient();
FlushServer();
EXPECT_EQ(wgpuFenceGetCompletedValue(fence), 2u);
}