This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Test FenceWaiterVK
and fix termination bugs
#45870
Merged
auto-submit
merged 25 commits into
flutter:main
from
matanlurey:impeller-vk-fence-contract
Sep 15, 2023
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
2ff38d2
[Impeller] transitioned mock vulkan context to the builder pattern
gaaclarke 60b871d
made creating a context with validation layers work
gaaclarke 67e9055
added capabilties asserts
gaaclarke ba4bc1e
moved to fml thread_local
gaaclarke 004f79b
removed strcpy
gaaclarke da1aada
switched to strncpy
gaaclarke 630f915
moved to sizeof since its a bit more robust
gaaclarke 10b7cdc
Merge branch 'mock-vulkan-context-builder' of https://github.com/gaac…
matanlurey c89d30d
Add MockFence and MockFence::SetStatus.
matanlurey ce6a1c5
Remove unused code.
matanlurey ac485e1
Add stub unit test, remove unused IsValid() method.
matanlurey 50ef1c0
Add unit tests, including those that fail.
matanlurey 94500af
Fix fence waiter and add tests.
matanlurey 3a01df4
Merge branch 'main' into impeller-vk-fence-contract
matanlurey 5540542
Fix buggy fence waiter test.
matanlurey 2efd5e8
Make mocks thread-safe and tweak.
matanlurey 79998e7
Merge.
matanlurey 4e1861c
Use atomics, delete unused code.
matanlurey 530af8d
Merge branch 'main' into impeller-vk-fence-contract
matanlurey 1460841
Tweak fence termination contract.
matanlurey 5bdcb65
false -> true
matanlurey e5ab21b
Address some comments and add a TODO.
matanlurey 110f745
Add FML_DCHECK.
matanlurey d973574
Address feedback.
matanlurey fe3c926
Address comments.
matanlurey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -377,10 +377,6 @@ void ContextVK::Setup(Settings settings) { | |
/// | ||
auto fence_waiter = | ||
std::shared_ptr<FenceWaiterVK>(new FenceWaiterVK(device_holder)); | ||
if (!fence_waiter->IsValid()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An invalid fence waiter will no longer invalidate the context now. In the future, if fence waiters cannot be created reliably, the call sites of the users will have to be patched. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no such thing as an invalid fence waiter, that is, there is no state that ever marks the fence waiter as invalid. I found it misleading that we check a boolean that is effectively constant true - let's it add it back if/when there is such a case? |
||
VALIDATION_LOG << "Could not create fence waiter."; | ||
return; | ||
} | ||
|
||
//---------------------------------------------------------------------------- | ||
/// Create the resource manager. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "fml/synchronization/waitable_event.h" | ||
#include "gtest/gtest.h" // IWYU pragma: keep | ||
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h" // IWYU pragma: keep | ||
#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" | ||
|
||
namespace impeller { | ||
namespace testing { | ||
|
||
TEST(FenceWaiterVKTest, IgnoresNullFence) { | ||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
EXPECT_FALSE(waiter->AddFence(vk::UniqueFence(), []() {})); | ||
} | ||
|
||
TEST(FenceWaiterVKTest, IgnoresNullCallback) { | ||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const device = context->GetDevice(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
|
||
auto fence = device.createFenceUnique({}).value; | ||
EXPECT_FALSE(waiter->AddFence(std::move(fence), nullptr)); | ||
} | ||
|
||
TEST(FenceWaiterVKTest, ExecutesFenceCallback) { | ||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const device = context->GetDevice(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
|
||
auto signal = fml::ManualResetWaitableEvent(); | ||
auto fence = device.createFenceUnique({}).value; | ||
waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); }); | ||
|
||
signal.Wait(); | ||
} | ||
|
||
TEST(FenceWaiterVKTest, ExecutesFenceCallbackX2) { | ||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const device = context->GetDevice(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
|
||
auto signal = fml::ManualResetWaitableEvent(); | ||
auto fence = device.createFenceUnique({}).value; | ||
waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); }); | ||
|
||
auto signal2 = fml::ManualResetWaitableEvent(); | ||
auto fence2 = device.createFenceUnique({}).value; | ||
waiter->AddFence(std::move(fence2), [&signal2]() { signal2.Signal(); }); | ||
|
||
signal.Wait(); | ||
signal2.Wait(); | ||
} | ||
|
||
TEST(FenceWaiterVKTest, ExecutesNewFenceThenOldFence) { | ||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const device = context->GetDevice(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
|
||
auto signal = fml::ManualResetWaitableEvent(); | ||
auto fence = device.createFenceUnique({}).value; | ||
MockFence::SetStatus(fence, vk::Result::eNotReady); | ||
auto raw_fence = MockFence::GetRawPointer(fence); | ||
waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); }); | ||
|
||
// The easiest way to verify that the callback was _not_ called is to wait | ||
// for a timeout, but that could introduce flakiness. Instead, we'll add a | ||
// second fence that will signal immediately, and wait for that one instead. | ||
{ | ||
auto signal2 = fml::ManualResetWaitableEvent(); | ||
auto fence2 = device.createFenceUnique({}).value; | ||
MockFence::SetStatus(fence2, vk::Result::eSuccess); | ||
waiter->AddFence(std::move(fence2), [&signal2]() { signal2.Signal(); }); | ||
signal2.Wait(); | ||
} | ||
|
||
// Now, we'll signal the first fence, and wait for the callback to be called. | ||
raw_fence->SetStatus(vk::Result::eSuccess); | ||
|
||
// Now, we'll signal the first fence, and wait for the callback to be called. | ||
signal.Wait(); | ||
} | ||
|
||
TEST(FenceWaiterVKTest, AddFenceDoesNothingIfTerminating) { | ||
auto signal = fml::ManualResetWaitableEvent(); | ||
|
||
{ | ||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const device = context->GetDevice(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
waiter->Terminate(); | ||
|
||
auto fence = device.createFenceUnique({}).value; | ||
waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); }); | ||
} | ||
|
||
// Ensure the fence did _not_ signal. | ||
EXPECT_TRUE(signal.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(100))); | ||
} | ||
|
||
TEST(FenceWaiterVKTest, InProgressFencesStillWaitIfTerminated) { | ||
MockFence* raw_fence = nullptr; | ||
auto signal = fml::ManualResetWaitableEvent(); | ||
|
||
auto const context = MockVulkanContextBuilder().Build(); | ||
auto const device = context->GetDevice(); | ||
auto const waiter = context->GetFenceWaiter(); | ||
|
||
// Add a fence that isn't signalled yet. | ||
auto fence = device.createFenceUnique({}).value; | ||
|
||
// Even if the fence is eSuccess, it's not guaranteed to be called in time. | ||
MockFence::SetStatus(fence, vk::Result::eNotReady); | ||
raw_fence = MockFence::GetRawPointer(fence); | ||
waiter->AddFence(std::move(fence), [&signal]() { signal.Signal(); }); | ||
|
||
// Terminate the waiter. | ||
waiter->Terminate(); | ||
|
||
// Signal the fence. | ||
raw_fence->SetStatus(vk::Result::eSuccess); | ||
|
||
// This will hang if the fence was not signalled. | ||
signal.Wait(); | ||
} | ||
|
||
} // namespace testing | ||
} // namespace impeller |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.