Commit 6779e5e0 by Ben Clayton

Reimplement VkFence using sw::WaitGroup and sw::Event.

This change fixes the ASAN issue as described in b/133135427. Reproduction case: ./build/vk-unittests --gtest_repeat=-1 --gtest_filter=ComputeParams/SwiftShaderVulkanBufferToBufferComputeTest.Memcpy/0 Bug: b/133127573 Bug: b/133135427 Bug: swiftshader:130 Change-Id: I06fbf10ab042160e8ca481f2afaa30d4f676dc75 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31681 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Reviewed-by: 's avatarChris Forbes <chrisforbes@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent 6cd63a25
...@@ -405,7 +405,7 @@ namespace sw ...@@ -405,7 +405,7 @@ namespace sw
if(fence) if(fence)
{ {
fence->add(); fence->start();
} }
ASSERT(!draw->fence); ASSERT(!draw->fence);
draw->fence = fence; draw->fence = fence;
...@@ -891,7 +891,7 @@ namespace sw ...@@ -891,7 +891,7 @@ namespace sw
if(draw.fence) if(draw.fence)
{ {
draw.fence->done(); draw.fence->finish();
draw.fence = nullptr; draw.fence = nullptr;
} }
......
...@@ -119,6 +119,7 @@ VkQueue Device::getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const ...@@ -119,6 +119,7 @@ VkQueue Device::getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const
VkResult Device::waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout) VkResult Device::waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout)
{ {
using time_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>;
const time_point start = now(); const time_point start = now();
const uint64_t max_timeout = (LLONG_MAX - start.time_since_epoch().count()); const uint64_t max_timeout = (LLONG_MAX - start.time_since_epoch().count());
bool infiniteTimeout = (timeout > max_timeout); bool infiniteTimeout = (timeout > max_timeout);
...@@ -143,7 +144,7 @@ VkResult Device::waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBo ...@@ -143,7 +144,7 @@ VkResult Device::waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBo
} }
else else
{ {
if(Cast(pFences[i])->waitUntil(end_ns) != VK_SUCCESS) // At least one fence is not signaled if(Cast(pFences[i])->wait(end_ns) != VK_SUCCESS) // At least one fence is not signaled
{ {
return VK_TIMEOUT; return VK_TIMEOUT;
} }
...@@ -176,7 +177,7 @@ VkResult Device::waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBo ...@@ -176,7 +177,7 @@ VkResult Device::waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBo
} }
else else
{ {
if(Cast(pFences[i])->waitUntil(end_ns) == VK_SUCCESS) // At least one fence is signaled if(Cast(pFences[i])->wait(end_ns) == VK_SUCCESS) // At least one fence is signaled
{ {
return VK_SUCCESS; return VK_SUCCESS;
} }
......
...@@ -16,86 +16,68 @@ ...@@ -16,86 +16,68 @@
#define VK_FENCE_HPP_ #define VK_FENCE_HPP_
#include "VkObject.hpp" #include "VkObject.hpp"
#include <chrono> #include "System/Synchronization.hpp"
#include <condition_variable>
#include <mutex>
namespace vk namespace vk
{ {
using time_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>;
class Fence : public Object<Fence, VkFence> class Fence : public Object<Fence, VkFence>
{ {
public: public:
Fence() : status(VK_NOT_READY) {} Fence() : signaled(sw::Event::ClearMode::Manual, false) {}
Fence(const VkFenceCreateInfo* pCreateInfo, void* mem) : Fence(const VkFenceCreateInfo* pCreateInfo, void* mem) :
status((pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) ? VK_SUCCESS : VK_NOT_READY) signaled(sw::Event::ClearMode::Manual, (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) != 0) {}
{
}
static size_t ComputeRequiredAllocationSize(const VkFenceCreateInfo* pCreateInfo) static size_t ComputeRequiredAllocationSize(const VkFenceCreateInfo* pCreateInfo)
{ {
return 0; return 0;
} }
void add() void reset()
{ {
std::unique_lock<std::mutex> lock(mutex); ASSERT_MSG(wg.count() == 0, "Fence::reset() called when work is in flight");
++count; signaled.clear();
} }
void done() VkResult getStatus()
{ {
std::unique_lock<std::mutex> lock(mutex); return signaled ? VK_SUCCESS : VK_NOT_READY;
ASSERT(count > 0);
--count;
if(count == 0)
{
// signal the fence, without the unlock/lock required to call signal() here
status = VK_SUCCESS;
lock.unlock();
condition.notify_all();
}
} }
void reset() VkResult wait()
{ {
std::unique_lock<std::mutex> lock(mutex); signaled.wait();
ASSERT(count == 0); return VK_SUCCESS;
status = VK_NOT_READY;
} }
VkResult getStatus() template <class CLOCK, class DURATION>
VkResult wait(const std::chrono::time_point<CLOCK, DURATION>& timeout)
{ {
std::unique_lock<std::mutex> lock(mutex); return signaled.wait(timeout) ? VK_SUCCESS : VK_TIMEOUT;
auto out = status;
lock.unlock();
return out;
} }
VkResult wait() void start()
{ {
std::unique_lock<std::mutex> lock(mutex); ASSERT(!signaled);
condition.wait(lock, [this] { return status == VK_SUCCESS; }); wg.add();
auto out = status;
lock.unlock();
return out;
} }
VkResult waitUntil(const time_point& timeout_ns) void finish()
{ {
std::unique_lock<std::mutex> lock(mutex); ASSERT(!signaled);
return condition.wait_until(lock, timeout_ns, [this] { return status == VK_SUCCESS; }) ? if (wg.done())
VK_SUCCESS : VK_TIMEOUT; {
signaled.signal();
}
} }
private: private:
VkResult status = VK_NOT_READY; // guarded by mutex Fence(const Fence&) = delete;
int32_t count = 0; // guarded by mutex Fence& operator = (const Fence&) = delete;
std::mutex mutex;
std::condition_variable condition; sw::WaitGroup wg;
sw::Event signaled;
}; };
static inline Fence* Cast(VkFence object) static inline Fence* Cast(VkFence object)
......
...@@ -106,7 +106,7 @@ VkResult Queue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFen ...@@ -106,7 +106,7 @@ VkResult Queue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFen
if(task.fence) if(task.fence)
{ {
task.fence->add(); task.fence->start();
} }
pending.put(task); pending.put(task);
...@@ -155,7 +155,7 @@ void Queue::submitQueue(const Task& task) ...@@ -155,7 +155,7 @@ void Queue::submitQueue(const Task& task)
// TODO: fix renderer signaling so that work submitted separately from (but before) a fence // TODO: fix renderer signaling so that work submitted separately from (but before) a fence
// is guaranteed complete by the time the fence signals. // is guaranteed complete by the time the fence signals.
renderer->synchronize(); renderer->synchronize();
task.fence->done(); task.fence->finish();
} }
} }
...@@ -184,7 +184,7 @@ VkResult Queue::waitIdle() ...@@ -184,7 +184,7 @@ VkResult Queue::waitIdle()
{ {
// Wait for task queue to flush. // Wait for task queue to flush.
vk::Fence fence; vk::Fence fence;
fence.add(); fence.start();
Task task; Task task;
task.fence = &fence; task.fence = &fence;
......
...@@ -193,8 +193,8 @@ VkResult SwapchainKHR::getNextImage(uint64_t timeout, VkSemaphore semaphore, VkF ...@@ -193,8 +193,8 @@ VkResult SwapchainKHR::getNextImage(uint64_t timeout, VkSemaphore semaphore, VkF
if(fence) if(fence)
{ {
vk::Cast(fence)->add(); vk::Cast(fence)->start();
vk::Cast(fence)->done(); vk::Cast(fence)->finish();
} }
return VK_SUCCESS; return VK_SUCCESS;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment