System/Synchronization.hpp: Add the sw::TaskEvents interface
This is implemented by sw::WaitGroup, and vk::Fence.
The goal here is to abstract the underlying implementation of the task tracker. We currently (ab)use vk::Fence for queue tracking when a sw::WaitGroup could be used.
This also allows us to implement a task logger in the future that can show what's inflight at any time.
Bug: b/133127573
Change-Id: I0177b26e7577ffd5cb687a5105a69a22070a7ac6
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31682
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/System/Synchronization.hpp b/src/System/Synchronization.hpp
index a6d0df2..7988a59 100644
--- a/src/System/Synchronization.hpp
+++ b/src/System/Synchronization.hpp
@@ -24,13 +24,28 @@
namespace sw
{
+// TaskEvents is an interface for notifying when tasks begin and end.
+// Tasks can be nested and/or overlapping.
+// TaskEvents is used for task queue synchronization.
+class TaskEvents
+{
+public:
+ // start() is called before a task begins.
+ virtual void start() = 0;
+ // finish() is called after a task ends. finish() must only be called after
+ // a corresponding call to start().
+ virtual void finish() = 0;
+ // complete() is a helper for calling start() followed by finish().
+ inline void complete() { start(); finish(); }
+};
+
// WaitGroup is a synchronization primitive that allows you to wait for
// collection of asynchronous tasks to finish executing.
// Call add() before each task begins, and then call done() when after each task
// is finished.
// At the same time, wait() can be used to block until all tasks have finished.
// WaitGroup takes its name after Golang's sync.WaitGroup.
-class WaitGroup
+class WaitGroup : public TaskEvents
{
public:
// add() begins a new task.
@@ -82,6 +97,10 @@
return count_;
}
+ // TaskEvents compliance
+ void start() override { add(); }
+ void finish() override { done(); }
+
private:
int32_t count_ = 0; // guarded by mutex
std::mutex mutex;
diff --git a/src/Vulkan/VkFence.hpp b/src/Vulkan/VkFence.hpp
index d3951c4..b803230 100644
--- a/src/Vulkan/VkFence.hpp
+++ b/src/Vulkan/VkFence.hpp
@@ -21,7 +21,7 @@
namespace vk
{
-class Fence : public Object<Fence, VkFence>
+class Fence : public Object<Fence, VkFence>, public sw::TaskEvents
{
public:
Fence() : signaled(sw::Event::ClearMode::Manual, false) {}
@@ -57,13 +57,14 @@
return signaled.wait(timeout) ? VK_SUCCESS : VK_TIMEOUT;
}
- void start()
+ // TaskEvents compliance
+ void start() override
{
ASSERT(!signaled);
wg.add();
}
- void finish()
+ void finish() override
{
ASSERT(!signaled);
if (wg.done())
diff --git a/src/WSI/VkSwapchainKHR.cpp b/src/WSI/VkSwapchainKHR.cpp
index 54cea09..bdd459e 100644
--- a/src/WSI/VkSwapchainKHR.cpp
+++ b/src/WSI/VkSwapchainKHR.cpp
@@ -193,8 +193,7 @@
if(fence)
{
- vk::Cast(fence)->start();
- vk::Cast(fence)->finish();
+ vk::Cast(fence)->complete();
}
return VK_SUCCESS;