Adds destroy handling for BindGroupLayout without new backend changes yet.
- Start tracking BindGroupLayout objects at construction - Utilizes untrack tag for blueprint layouts for caching purposes - Adds dawn native test file for testing utilities that require static dawn native lib - Adds testing macros and mocks for simple sanity unit testing Bug: dawn:628 Change-Id: Ic85b60e9574e67cc5fc1804cc5300cd1f3a0f6fd Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65862 Commit-Queue: Loko Kung <lokokung@google.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
fc5a7d414f
commit
2f3fe95ad5
|
@ -360,7 +360,8 @@ namespace dawn_native {
|
|||
|
||||
BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken)
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken,
|
||||
ApiObjectBase::UntrackedByDeviceTag tag)
|
||||
: ApiObjectBase(device, kLabelNotImplemented),
|
||||
mBindingInfo(BindingIndex(descriptor->entryCount)),
|
||||
mPipelineCompatibilityToken(pipelineCompatibilityToken) {
|
||||
|
@ -387,15 +388,31 @@ namespace dawn_native {
|
|||
ASSERT(mBindingInfo.size() <= kMaxBindingsPerPipelineLayoutTyped);
|
||||
}
|
||||
|
||||
BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken)
|
||||
: BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken, kUntrackedByDevice) {
|
||||
TrackInDevice();
|
||||
}
|
||||
|
||||
BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
||||
: ApiObjectBase(device, tag) {
|
||||
}
|
||||
|
||||
BindGroupLayoutBase::~BindGroupLayoutBase() {
|
||||
// Do not uncache the actual cached object if we are a blueprint
|
||||
if (IsCachedReference()) {
|
||||
GetDevice()->UncacheBindGroupLayout(this);
|
||||
BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device)
|
||||
: ApiObjectBase(device, kLabelNotImplemented) {
|
||||
TrackInDevice();
|
||||
}
|
||||
|
||||
bool BindGroupLayoutBase::DestroyApiObject() {
|
||||
bool wasDestroyed = ApiObjectBase::DestroyApiObject();
|
||||
if (wasDestroyed) {
|
||||
// Do not uncache the actual cached object if we are a blueprint
|
||||
if (IsCachedReference()) {
|
||||
GetDevice()->UncacheBindGroupLayout(this);
|
||||
}
|
||||
}
|
||||
return wasDestroyed;
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -42,13 +42,17 @@ namespace dawn_native {
|
|||
// into a packed range of |BindingIndex| integers.
|
||||
class BindGroupLayoutBase : public ApiObjectBase, public CachedObject {
|
||||
public:
|
||||
BindGroupLayoutBase(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken,
|
||||
ApiObjectBase::UntrackedByDeviceTag tag);
|
||||
BindGroupLayoutBase(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||
~BindGroupLayoutBase() override;
|
||||
|
||||
static BindGroupLayoutBase* MakeError(DeviceBase* device);
|
||||
|
||||
bool DestroyApiObject() override;
|
||||
ObjectType GetType() const override;
|
||||
|
||||
// A map from the BindingNumber to its packed BindingIndex.
|
||||
|
@ -85,7 +89,6 @@ namespace dawn_native {
|
|||
// ignoring their compatibility groups.
|
||||
bool IsLayoutEqual(const BindGroupLayoutBase* other,
|
||||
bool excludePipelineCompatibiltyToken = false) const;
|
||||
|
||||
PipelineCompatibilityToken GetPipelineCompatibilityToken() const;
|
||||
|
||||
struct BufferBindingData {
|
||||
|
@ -110,6 +113,9 @@ namespace dawn_native {
|
|||
BindingDataPointers ComputeBindingDataPointers(void* dataStart) const;
|
||||
|
||||
protected:
|
||||
// Constructor used only for mocking and testing.
|
||||
BindGroupLayoutBase(DeviceBase* device);
|
||||
|
||||
template <typename BindGroup>
|
||||
SlabAllocator<BindGroup> MakeFrontendBindGroupAllocator(size_t size) {
|
||||
return SlabAllocator<BindGroup>(
|
||||
|
|
|
@ -200,6 +200,10 @@ namespace dawn_native {
|
|||
}
|
||||
}
|
||||
|
||||
DeviceBase::DeviceBase() : mState(State::Alive) {
|
||||
mCaches = std::make_unique<DeviceBase::Caches>();
|
||||
}
|
||||
|
||||
DeviceBase::~DeviceBase() = default;
|
||||
|
||||
MaybeError DeviceBase::Initialize(QueueBase* defaultQueue) {
|
||||
|
@ -270,7 +274,9 @@ namespace dawn_native {
|
|||
// that this only considers the immediate frontend dependencies, while backend objects could
|
||||
// add complications and extra dependencies.
|
||||
// TODO(dawn/628) Add types into the array as they are implemented.
|
||||
static constexpr std::array<ObjectType, 0> kObjectTypeDependencyOrder = {};
|
||||
static constexpr std::array<ObjectType, 1> kObjectTypeDependencyOrder = {
|
||||
ObjectType::BindGroupLayout,
|
||||
};
|
||||
|
||||
// We first move all objects out from the tracking list into a separate list so that we can
|
||||
// avoid locking the same mutex twice. We can then iterate across the separate list to call
|
||||
|
@ -631,7 +637,8 @@ namespace dawn_native {
|
|||
ResultOrError<Ref<BindGroupLayoutBase>> DeviceBase::GetOrCreateBindGroupLayout(
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken) {
|
||||
BindGroupLayoutBase blueprint(this, descriptor, pipelineCompatibilityToken);
|
||||
BindGroupLayoutBase blueprint(this, descriptor, pipelineCompatibilityToken,
|
||||
ApiObjectBase::kUntrackedByDevice);
|
||||
|
||||
const size_t blueprintHash = blueprint.ComputeContentHash();
|
||||
blueprint.SetContentHash(blueprintHash);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "dawn_native/Limits.h"
|
||||
#include "dawn_native/ObjectBase.h"
|
||||
#include "dawn_native/ObjectType_autogen.h"
|
||||
#include "dawn_native/RenderPipeline.h"
|
||||
#include "dawn_native/StagingBuffer.h"
|
||||
#include "dawn_native/Toggles.h"
|
||||
|
||||
|
@ -354,6 +355,9 @@ namespace dawn_native {
|
|||
void APISetLabel(const char* label);
|
||||
|
||||
protected:
|
||||
// Constructor used only for mocking and testing.
|
||||
DeviceBase();
|
||||
|
||||
void SetToggle(Toggle toggle, bool isEnabled);
|
||||
void ForceSetToggle(Toggle toggle, bool isEnabled);
|
||||
|
||||
|
|
|
@ -135,13 +135,52 @@ namespace dawn_native {
|
|||
|
||||
// DAWN_TRY_ASSIGN is the same as DAWN_TRY for ResultOrError and assigns the success value, if
|
||||
// any, to VAR.
|
||||
#define DAWN_TRY_ASSIGN(VAR, EXPR) \
|
||||
#define DAWN_TRY_ASSIGN(VAR, EXPR) DAWN_TRY_ASSIGN_WITH_CLEANUP(VAR, EXPR, {})
|
||||
|
||||
// Argument helpers are used to determine which macro implementations should be called when
|
||||
// overloading with different number of variables.
|
||||
#define DAWN_ERROR_UNIMPLEMENTED_MACRO_(...) UNREACHABLE()
|
||||
#define DAWN_ERROR_GET_5TH_ARG_HELPER_(_1, _2, _3, _4, NAME, ...) NAME
|
||||
#define DAWN_ERROR_GET_5TH_ARG_(args) DAWN_ERROR_GET_5TH_ARG_HELPER_ args
|
||||
|
||||
// DAWN_TRY_ASSIGN_WITH_CLEANUP is overloaded with 2 version so that users can override the
|
||||
// return value of the macro when necessary. This is particularly useful if the function
|
||||
// calling the macro may want to return void instead of the error, i.e. in a test where we may
|
||||
// just want to assert and fail if the assign cannot go through. In both the cleanup and return
|
||||
// clauses, users can use the `error` variable to access the pointer to the acquired error.
|
||||
//
|
||||
// Example usages:
|
||||
// 3 Argument Case:
|
||||
// Result res;
|
||||
// DAWN_TRY_ASSIGN_WITH_CLEANUP(
|
||||
// res, GetResultOrErrorFunction(), { AddAdditionalErrorInformation(error.get()); }
|
||||
// );
|
||||
//
|
||||
// 4 Argument Case:
|
||||
// bool FunctionThatReturnsBool() {
|
||||
// DAWN_TRY_ASSIGN_WITH_CLEANUP(
|
||||
// res, GetResultOrErrorFunction(),
|
||||
// { AddAdditionalErrorInformation(error.get()); },
|
||||
// false
|
||||
// );
|
||||
// }
|
||||
#define DAWN_TRY_ASSIGN_WITH_CLEANUP(...) \
|
||||
DAWN_ERROR_GET_5TH_ARG_((__VA_ARGS__, DAWN_TRY_ASSIGN_WITH_CLEANUP_IMPL_4_, \
|
||||
DAWN_TRY_ASSIGN_WITH_CLEANUP_IMPL_3_, \
|
||||
DAWN_ERROR_UNIMPLEMENTED_MACRO_)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
#define DAWN_TRY_ASSIGN_WITH_CLEANUP_IMPL_3_(VAR, EXPR, BODY) \
|
||||
DAWN_TRY_ASSIGN_WITH_CLEANUP_IMPL_4_(VAR, EXPR, BODY, std::move(error))
|
||||
|
||||
#define DAWN_TRY_ASSIGN_WITH_CLEANUP_IMPL_4_(VAR, EXPR, BODY, RET) \
|
||||
{ \
|
||||
auto DAWN_LOCAL_VAR = EXPR; \
|
||||
if (DAWN_UNLIKELY(DAWN_LOCAL_VAR.IsError())) { \
|
||||
std::unique_ptr<ErrorData> error = DAWN_LOCAL_VAR.AcquireError(); \
|
||||
{BODY} /* comment to force the formatter to insert a newline */ \
|
||||
error->AppendBacktrace(__FILE__, __func__, __LINE__); \
|
||||
return {std::move(error)}; \
|
||||
return (RET); \
|
||||
} \
|
||||
VAR = DAWN_LOCAL_VAR.AcquireSuccess(); \
|
||||
} \
|
||||
|
|
|
@ -45,6 +45,8 @@ namespace dawn_native {
|
|||
public:
|
||||
struct LabelNotImplementedTag {};
|
||||
static constexpr LabelNotImplementedTag kLabelNotImplemented = {};
|
||||
struct UntrackedByDeviceTag {};
|
||||
static constexpr UntrackedByDeviceTag kUntrackedByDevice = {};
|
||||
|
||||
ApiObjectBase(DeviceBase* device, LabelNotImplementedTag tag);
|
||||
ApiObjectBase(DeviceBase* device, const char* label);
|
||||
|
|
|
@ -131,6 +131,10 @@ namespace dawn_native { namespace d3d12 {
|
|||
device->GetSamplerStagingDescriptorAllocator(GetSamplerDescriptorCount());
|
||||
}
|
||||
|
||||
BindGroupLayout::~BindGroupLayout() {
|
||||
DestroyApiObject();
|
||||
}
|
||||
|
||||
ResultOrError<Ref<BindGroup>> BindGroupLayout::AllocateBindGroup(
|
||||
Device* device,
|
||||
const BindGroupDescriptor* descriptor) {
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
BindGroupLayout(Device* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||
~BindGroupLayout() override = default;
|
||||
~BindGroupLayout() override;
|
||||
|
||||
// Contains the offset into the descriptor heap for the given resource view. Samplers and
|
||||
// non-samplers are stored in separate descriptor heaps, so the offsets should be unique
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace dawn_native { namespace metal {
|
|||
BindGroupLayout(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||
~BindGroupLayout() override = default;
|
||||
~BindGroupLayout() override;
|
||||
|
||||
SlabAllocator<BindGroup> mBindGroupAllocator;
|
||||
};
|
||||
|
|
|
@ -33,6 +33,10 @@ namespace dawn_native { namespace metal {
|
|||
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
|
||||
}
|
||||
|
||||
BindGroupLayout::~BindGroupLayout() {
|
||||
DestroyApiObject();
|
||||
}
|
||||
|
||||
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
|
||||
const BindGroupDescriptor* descriptor) {
|
||||
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
|
||||
|
|
|
@ -263,6 +263,18 @@ namespace dawn_native { namespace null {
|
|||
BindGroupBase(device, descriptor, mBindingDataAllocation) {
|
||||
}
|
||||
|
||||
// BindGroupLayout
|
||||
|
||||
BindGroupLayout::BindGroupLayout(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken)
|
||||
: BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken) {
|
||||
}
|
||||
|
||||
BindGroupLayout::~BindGroupLayout() {
|
||||
DestroyApiObject();
|
||||
}
|
||||
|
||||
// Buffer
|
||||
|
||||
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace dawn_native { namespace null {
|
|||
|
||||
class Adapter;
|
||||
class BindGroup;
|
||||
using BindGroupLayout = BindGroupLayoutBase;
|
||||
class BindGroupLayout;
|
||||
class Buffer;
|
||||
class CommandBuffer;
|
||||
using ComputePipeline = ComputePipelineBase;
|
||||
|
@ -200,6 +200,16 @@ namespace dawn_native { namespace null {
|
|||
~BindGroup() override = default;
|
||||
};
|
||||
|
||||
class BindGroupLayout final : public BindGroupLayoutBase {
|
||||
public:
|
||||
BindGroupLayout(DeviceBase* device,
|
||||
const BindGroupLayoutDescriptor* descriptor,
|
||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||
|
||||
private:
|
||||
~BindGroupLayout() override;
|
||||
};
|
||||
|
||||
class Buffer final : public BufferBase {
|
||||
public:
|
||||
Buffer(Device* device, const BufferDescriptor* descriptor);
|
||||
|
|
|
@ -25,6 +25,10 @@ namespace dawn_native { namespace opengl {
|
|||
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
|
||||
}
|
||||
|
||||
BindGroupLayout::~BindGroupLayout() {
|
||||
DestroyApiObject();
|
||||
}
|
||||
|
||||
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
|
||||
const BindGroupDescriptor* descriptor) {
|
||||
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace dawn_native { namespace opengl {
|
|||
void DeallocateBindGroup(BindGroup* bindGroup);
|
||||
|
||||
private:
|
||||
~BindGroupLayout() override = default;
|
||||
~BindGroupLayout() override;
|
||||
SlabAllocator<BindGroup> mBindGroupAllocator;
|
||||
};
|
||||
|
||||
|
|
|
@ -161,6 +161,7 @@ namespace dawn_native { namespace vulkan {
|
|||
device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), mHandle, nullptr);
|
||||
mHandle = VK_NULL_HANDLE;
|
||||
}
|
||||
DestroyApiObject();
|
||||
}
|
||||
|
||||
VkDescriptorSetLayout BindGroupLayout::GetHandle() const {
|
||||
|
|
|
@ -126,10 +126,29 @@ dawn_json_generator("mock_webgpu_gen") {
|
|||
]
|
||||
}
|
||||
|
||||
# Source code for mocks used for unit testing are separated from the rest of
|
||||
# sources so that they aren't included in non-test builds.
|
||||
source_set("dawn_native_mocks_sources") {
|
||||
testonly = true
|
||||
|
||||
deps = [
|
||||
":gmock_and_gtest",
|
||||
"${dawn_root}/src/dawn_native:dawn_native_sources",
|
||||
"${dawn_root}/src/dawn_native:dawn_native_static",
|
||||
"${dawn_root}/src/utils:dawn_utils",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"unittests/native/mocks/BindGroupLayoutMock.h",
|
||||
"unittests/native/mocks/DeviceMock.h",
|
||||
]
|
||||
}
|
||||
|
||||
test("dawn_unittests") {
|
||||
configs += [ "${dawn_root}/src/common:dawn_internal" ]
|
||||
|
||||
deps = [
|
||||
":dawn_native_mocks_sources",
|
||||
":gmock_and_gtest",
|
||||
":mock_webgpu_gen",
|
||||
"${dawn_root}/src/common",
|
||||
|
@ -150,6 +169,8 @@ test("dawn_unittests") {
|
|||
"${dawn_root}/src/dawn_wire/client/ClientMemoryTransferService_mock.h",
|
||||
"${dawn_root}/src/dawn_wire/server/ServerMemoryTransferService_mock.cpp",
|
||||
"${dawn_root}/src/dawn_wire/server/ServerMemoryTransferService_mock.h",
|
||||
"DawnNativeTest.cpp",
|
||||
"DawnNativeTest.h",
|
||||
"MockCallback.h",
|
||||
"ToggleParser.cpp",
|
||||
"ToggleParser.h",
|
||||
|
@ -188,6 +209,7 @@ test("dawn_unittests") {
|
|||
"unittests/SystemUtilsTests.cpp",
|
||||
"unittests/ToBackendTests.cpp",
|
||||
"unittests/TypedIntegerTests.cpp",
|
||||
"unittests/native/DestroyObjectTests.cpp",
|
||||
"unittests/validation/BindGroupValidationTests.cpp",
|
||||
"unittests/validation/BufferValidationTests.cpp",
|
||||
"unittests/validation/CommandBufferValidationTests.cpp",
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2021 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 <gtest/gtest.h>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "dawn_native/ErrorData.h"
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
void AddFatalDawnFailure(const char* expression, const ErrorData* error) {
|
||||
const auto& backtrace = error->GetBacktrace();
|
||||
GTEST_MESSAGE_AT_(
|
||||
backtrace.at(0).file, backtrace.at(0).line,
|
||||
absl::StrCat(expression, " returned error: ", error->GetMessage()).c_str(),
|
||||
::testing::TestPartResult::kFatalFailure);
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2021 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 TESTS_DAWNNATIVETEST_H_
|
||||
#define TESTS_DAWNNATIVETEST_H_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "dawn_native/ErrorData.h"
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
// This is similar to DAWN_TRY_ASSIGN but produces a fatal GTest error if EXPR is an error.
|
||||
#define DAWN_ASSERT_AND_ASSIGN(VAR, EXPR) \
|
||||
DAWN_TRY_ASSIGN_WITH_CLEANUP(VAR, EXPR, {}, AddFatalDawnFailure(#EXPR, error.get()))
|
||||
|
||||
void AddFatalDawnFailure(const char* expression, const ErrorData* error);
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // TESTS_DAWNNATIVETEST_H_
|
|
@ -243,6 +243,78 @@ namespace {
|
|||
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
|
||||
}
|
||||
|
||||
// Check DAWN_TRY_ASSIGN handles successes correctly.
|
||||
TEST(ErrorTests, TRY_RESULT_CLEANUP_Success) {
|
||||
auto ReturnSuccess = []() -> ResultOrError<int*> { return &dummySuccess; };
|
||||
|
||||
// We need to check that DAWN_TRY_ASSIGN_WITH_CLEANUP doesn't return on successes and the
|
||||
// cleanup is not called.
|
||||
bool tryReturned = true;
|
||||
bool tryCleanup = false;
|
||||
|
||||
auto Try = [ReturnSuccess, &tryReturned, &tryCleanup]() -> ResultOrError<int*> {
|
||||
int* result = nullptr;
|
||||
DAWN_TRY_ASSIGN_WITH_CLEANUP(result, ReturnSuccess(), { tryCleanup = true; });
|
||||
tryReturned = false;
|
||||
|
||||
EXPECT_EQ(result, &dummySuccess);
|
||||
return result;
|
||||
};
|
||||
|
||||
ResultOrError<int*> result = Try();
|
||||
ASSERT_TRUE(result.IsSuccess());
|
||||
ASSERT_FALSE(tryReturned);
|
||||
ASSERT_FALSE(tryCleanup);
|
||||
ASSERT_EQ(result.AcquireSuccess(), &dummySuccess);
|
||||
}
|
||||
|
||||
// Check DAWN_TRY_ASSIGN handles cleanups.
|
||||
TEST(ErrorTests, TRY_RESULT_CLEANUP_Cleanup) {
|
||||
auto ReturnError = []() -> ResultOrError<int*> {
|
||||
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
|
||||
};
|
||||
|
||||
// We need to check that DAWN_TRY_ASSIGN_WITH_CLEANUP calls cleanup when error.
|
||||
bool tryCleanup = false;
|
||||
|
||||
auto Try = [ReturnError, &tryCleanup]() -> ResultOrError<int*> {
|
||||
int* result = nullptr;
|
||||
DAWN_TRY_ASSIGN_WITH_CLEANUP(result, ReturnError(), { tryCleanup = true; });
|
||||
DAWN_UNUSED(result);
|
||||
|
||||
// DAWN_TRY_ASSIGN_WITH_CLEANUP should return before this point
|
||||
EXPECT_FALSE(true);
|
||||
return &dummySuccess;
|
||||
};
|
||||
|
||||
ResultOrError<int*> result = Try();
|
||||
ASSERT_TRUE(result.IsError());
|
||||
|
||||
std::unique_ptr<ErrorData> errorData = result.AcquireError();
|
||||
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
|
||||
ASSERT_TRUE(tryCleanup);
|
||||
}
|
||||
|
||||
// Check DAWN_TRY_ASSIGN can override return value when needed.
|
||||
TEST(ErrorTests, TRY_RESULT_CLEANUP_OverrideReturn) {
|
||||
auto ReturnError = []() -> ResultOrError<int*> {
|
||||
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
|
||||
};
|
||||
|
||||
auto Try = [ReturnError]() -> bool {
|
||||
int* result = nullptr;
|
||||
DAWN_TRY_ASSIGN_WITH_CLEANUP(result, ReturnError(), {}, true);
|
||||
DAWN_UNUSED(result);
|
||||
|
||||
// DAWN_TRY_ASSIGN_WITH_CLEANUP should return before this point
|
||||
EXPECT_FALSE(true);
|
||||
return false;
|
||||
};
|
||||
|
||||
bool result = Try();
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
// Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError
|
||||
// Check DAWN_TRY handles errors correctly.
|
||||
TEST(ErrorTests, TRY_ConversionToErrorOrResult) {
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2021 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 <gtest/gtest.h>
|
||||
|
||||
#include "dawn_native/Toggles.h"
|
||||
#include "mocks/BindGroupLayoutMock.h"
|
||||
#include "mocks/DeviceMock.h"
|
||||
#include "tests/DawnNativeTest.h"
|
||||
|
||||
namespace dawn_native { namespace {
|
||||
|
||||
using ::testing::ByMove;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::Return;
|
||||
|
||||
TEST(DestroyObjectTests, BindGroupLayout) {
|
||||
// Skipping validation on descriptors as coverage for validation is already present.
|
||||
DeviceMock device;
|
||||
device.SetToggle(Toggle::SkipValidation, true);
|
||||
|
||||
BindGroupLayoutMock* bindGroupLayoutMock = new BindGroupLayoutMock(&device);
|
||||
EXPECT_CALL(*bindGroupLayoutMock, DestroyApiObjectImpl).Times(1);
|
||||
|
||||
BindGroupLayoutDescriptor desc = {};
|
||||
Ref<BindGroupLayoutBase> bindGroupLayout;
|
||||
EXPECT_CALL(device, CreateBindGroupLayoutImpl)
|
||||
.WillOnce(Return(ByMove(AcquireRef(bindGroupLayoutMock))));
|
||||
DAWN_ASSERT_AND_ASSIGN(bindGroupLayout, device.CreateBindGroupLayout(&desc));
|
||||
|
||||
EXPECT_TRUE(bindGroupLayout->IsAlive());
|
||||
EXPECT_TRUE(bindGroupLayout->IsCachedReference());
|
||||
|
||||
bindGroupLayout->DestroyApiObject();
|
||||
EXPECT_FALSE(bindGroupLayout->IsAlive());
|
||||
}
|
||||
|
||||
// Destroying the objects on the device should result in all created objects being destroyed in
|
||||
// order.
|
||||
TEST(DestroyObjectTests, DestroyObjects) {
|
||||
DeviceMock device;
|
||||
device.SetToggle(Toggle::SkipValidation, true);
|
||||
|
||||
BindGroupLayoutMock* bindGroupLayoutMock = new BindGroupLayoutMock(&device);
|
||||
{
|
||||
InSequence seq;
|
||||
EXPECT_CALL(*bindGroupLayoutMock, DestroyApiObjectImpl).Times(1);
|
||||
}
|
||||
|
||||
BindGroupLayoutDescriptor desc = {};
|
||||
Ref<BindGroupLayoutBase> bindGroupLayout;
|
||||
EXPECT_CALL(device, CreateBindGroupLayoutImpl)
|
||||
.WillOnce(Return(ByMove(AcquireRef(bindGroupLayoutMock))));
|
||||
DAWN_ASSERT_AND_ASSIGN(bindGroupLayout, device.CreateBindGroupLayout(&desc));
|
||||
EXPECT_TRUE(bindGroupLayout->IsAlive());
|
||||
EXPECT_TRUE(bindGroupLayout->IsCachedReference());
|
||||
|
||||
device.DestroyObjects();
|
||||
EXPECT_FALSE(bindGroupLayout->IsAlive());
|
||||
}
|
||||
|
||||
}} // namespace dawn_native::
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2021 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 TESTS_UNITTESTS_NATIVE_MOCKS_BINDGROUPLAYOUT_MOCK_H_
|
||||
#define TESTS_UNITTESTS_NATIVE_MOCKS_BINDGROUPLAYOUT_MOCK_H_
|
||||
|
||||
#include "dawn_native/BindGroupLayout.h"
|
||||
#include "dawn_native/Device.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
class BindGroupLayoutMock final : public BindGroupLayoutBase {
|
||||
public:
|
||||
BindGroupLayoutMock(DeviceBase* device) : BindGroupLayoutBase(device) {
|
||||
}
|
||||
~BindGroupLayoutMock() override {
|
||||
DestroyApiObject();
|
||||
}
|
||||
|
||||
MOCK_METHOD(void, DestroyApiObjectImpl, (), (override));
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // TESTS_UNITTESTS_NATIVE_MOCKS_BINDGROUPLAYOUT_MOCK_H_
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2021 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 TESTS_UNITTESTS_NATIVE_MOCKS_DEVICE_MOCK_H_
|
||||
#define TESTS_UNITTESTS_NATIVE_MOCKS_DEVICE_MOCK_H_
|
||||
|
||||
#include "dawn_native/Device.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
class DeviceMock : public DeviceBase {
|
||||
public:
|
||||
// Exposes some protected functions for testing purposes.
|
||||
using DeviceBase::DestroyObjects;
|
||||
using DeviceBase::SetToggle;
|
||||
|
||||
MOCK_METHOD(ResultOrError<Ref<CommandBufferBase>>,
|
||||
CreateCommandBuffer,
|
||||
(CommandEncoder*, const CommandBufferDescriptor*),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(ResultOrError<std::unique_ptr<StagingBufferBase>>,
|
||||
CreateStagingBuffer,
|
||||
(size_t),
|
||||
(override));
|
||||
MOCK_METHOD(MaybeError,
|
||||
CopyFromStagingToBuffer,
|
||||
(StagingBufferBase*, uint64_t, BufferBase*, uint64_t, uint64_t),
|
||||
(override));
|
||||
MOCK_METHOD(
|
||||
MaybeError,
|
||||
CopyFromStagingToTexture,
|
||||
(const StagingBufferBase*, const TextureDataLayout&, TextureCopy*, const Extent3D&),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(uint32_t, GetOptimalBytesPerRowAlignment, (), (const, override));
|
||||
MOCK_METHOD(uint64_t, GetOptimalBufferToTextureCopyOffsetAlignment, (), (const, override));
|
||||
|
||||
MOCK_METHOD(float, GetTimestampPeriodInNS, (), (const, override));
|
||||
|
||||
MOCK_METHOD(ResultOrError<Ref<BindGroupBase>>,
|
||||
CreateBindGroupImpl,
|
||||
(const BindGroupDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<BindGroupLayoutBase>>,
|
||||
CreateBindGroupLayoutImpl,
|
||||
(const BindGroupLayoutDescriptor*, PipelineCompatibilityToken),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<BufferBase>>,
|
||||
CreateBufferImpl,
|
||||
(const BufferDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<ComputePipelineBase>>,
|
||||
CreateComputePipelineImpl,
|
||||
(const ComputePipelineDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<PipelineLayoutBase>>,
|
||||
CreatePipelineLayoutImpl,
|
||||
(const PipelineLayoutDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<QuerySetBase>>,
|
||||
CreateQuerySetImpl,
|
||||
(const QuerySetDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(Ref<RenderPipelineBase>,
|
||||
CreateUninitializedRenderPipelineImpl,
|
||||
(const RenderPipelineDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<SamplerBase>>,
|
||||
CreateSamplerImpl,
|
||||
(const SamplerDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<ShaderModuleBase>>,
|
||||
CreateShaderModuleImpl,
|
||||
(const ShaderModuleDescriptor*, ShaderModuleParseResult*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<SwapChainBase>>,
|
||||
CreateSwapChainImpl,
|
||||
(const SwapChainDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<NewSwapChainBase>>,
|
||||
CreateSwapChainImpl,
|
||||
(Surface*, NewSwapChainBase*, const SwapChainDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<TextureBase>>,
|
||||
CreateTextureImpl,
|
||||
(const TextureDescriptor*),
|
||||
(override));
|
||||
MOCK_METHOD(ResultOrError<Ref<TextureViewBase>>,
|
||||
CreateTextureViewImpl,
|
||||
(TextureBase*, const TextureViewDescriptor*),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(MaybeError, TickImpl, (), (override));
|
||||
|
||||
MOCK_METHOD(ResultOrError<ExecutionSerial>, CheckAndUpdateCompletedSerials, (), (override));
|
||||
MOCK_METHOD(void, DestroyImpl, (), (override));
|
||||
MOCK_METHOD(MaybeError, WaitForIdleForDestruction, (), (override));
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // TESTS_UNITTESTS_NATIVE_MOCKS_DEVICE_MOCK_H_
|
Loading…
Reference in New Issue