diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/WorkerThread.h')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/WorkerThread.h | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/WorkerThread.h b/src/3rdparty/angle/src/libANGLE/WorkerThread.h new file mode 100644 index 0000000000..f6b81dce21 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/WorkerThread.h @@ -0,0 +1,284 @@ +// +// Copyright 2016 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WorkerThread: +// Asychronous tasks/threads for ANGLE, similar to a TaskRunner in Chromium. +// Can be implemented as different targets, depending on platform. +// + +#ifndef LIBANGLE_WORKER_THREAD_H_ +#define LIBANGLE_WORKER_THREAD_H_ + +#include <array> +#include <vector> + +#include "common/debug.h" +#include "libANGLE/features.h" + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +#include <future> +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +namespace angle +{ +// Indicates whether a WaitableEvent should automatically reset the event state after a single +// waiting thread has been released or remain signaled until reset() is manually invoked. +enum class EventResetPolicy +{ + Manual, + Automatic +}; + +// Specify the initial state on creation. +enum class EventInitialState +{ + NonSignaled, + Signaled +}; + +// A callback function with no return value and no arguments. +class Closure +{ + public: + virtual ~Closure() = default; + virtual void operator()() = 0; +}; + +namespace priv +{ +// An event that we can wait on, useful for joining worker threads. +template <typename Impl> +class WaitableEventBase : angle::NonCopyable +{ + public: + WaitableEventBase(EventResetPolicy resetPolicy, EventInitialState initialState); + + WaitableEventBase(WaitableEventBase &&other); + + // Puts the event in the un-signaled state. + void reset(); + + // Waits indefinitely for the event to be signaled. + void wait(); + + // Puts the event in the signaled state, causing any thread blocked on Wait to be woken up. + // The event state is reset to non-signaled after a waiting thread has been released. + void signal(); + + protected: + Impl ©Base(Impl &&other); + + template <size_t Count> + static size_t WaitManyBase(std::array<Impl, Count> *waitables); + + EventResetPolicy mResetPolicy; + bool mSignaled; +}; + +template <typename Impl> +WaitableEventBase<Impl>::WaitableEventBase(EventResetPolicy resetPolicy, + EventInitialState initialState) + : mResetPolicy(resetPolicy), mSignaled(initialState == EventInitialState::Signaled) +{ +} + +template <typename Impl> +WaitableEventBase<Impl>::WaitableEventBase(WaitableEventBase &&other) + : mResetPolicy(other.mResetPolicy), mSignaled(other.mSignaled) +{ +} + +template <typename Impl> +void WaitableEventBase<Impl>::reset() +{ + static_cast<Impl *>(this)->resetImpl(); +} + +template <typename Impl> +void WaitableEventBase<Impl>::wait() +{ + static_cast<Impl *>(this)->waitImpl(); +} + +template <typename Impl> +void WaitableEventBase<Impl>::signal() +{ + static_cast<Impl *>(this)->signalImpl(); +} + +template <typename Impl> +template <size_t Count> +// static +size_t WaitableEventBase<Impl>::WaitManyBase(std::array<Impl, Count> *waitables) +{ + ASSERT(Count > 0); + + for (size_t index = 0; index < Count; ++index) + { + (*waitables)[index].wait(); + } + + return 0; +} + +template <typename Impl> +Impl &WaitableEventBase<Impl>::copyBase(Impl &&other) +{ + std::swap(mSignaled, other.mSignaled); + std::swap(mResetPolicy, other.mResetPolicy); + return *static_cast<Impl *>(this); +} + +class SingleThreadedWaitableEvent : public WaitableEventBase<SingleThreadedWaitableEvent> +{ + public: + SingleThreadedWaitableEvent(); + SingleThreadedWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState); + ~SingleThreadedWaitableEvent(); + + SingleThreadedWaitableEvent(SingleThreadedWaitableEvent &&other); + SingleThreadedWaitableEvent &operator=(SingleThreadedWaitableEvent &&other); + + void resetImpl(); + void waitImpl(); + void signalImpl(); + + // Wait, synchronously, on multiple events. + // returns the index of a WaitableEvent which has been signaled. + template <size_t Count> + static size_t WaitMany(std::array<SingleThreadedWaitableEvent, Count> *waitables); +}; + +template <size_t Count> +// static +size_t SingleThreadedWaitableEvent::WaitMany( + std::array<SingleThreadedWaitableEvent, Count> *waitables) +{ + return WaitableEventBase<SingleThreadedWaitableEvent>::WaitManyBase(waitables); +} + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWaitableEvent : public WaitableEventBase<AsyncWaitableEvent> +{ + public: + AsyncWaitableEvent(); + AsyncWaitableEvent(EventResetPolicy resetPolicy, EventInitialState initialState); + ~AsyncWaitableEvent(); + + AsyncWaitableEvent(AsyncWaitableEvent &&other); + AsyncWaitableEvent &operator=(AsyncWaitableEvent &&other); + + void resetImpl(); + void waitImpl(); + void signalImpl(); + + // Wait, synchronously, on multiple events. + // returns the index of a WaitableEvent which has been signaled. + template <size_t Count> + static size_t WaitMany(std::array<AsyncWaitableEvent, Count> *waitables); + + private: + friend class AsyncWorkerPool; + void setFuture(std::future<void> &&future); + + std::future<void> mFuture; +}; + +template <size_t Count> +// static +size_t AsyncWaitableEvent::WaitMany(std::array<AsyncWaitableEvent, Count> *waitables) +{ + return WaitableEventBase<AsyncWaitableEvent>::WaitManyBase(waitables); +} +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +// The traits class allows the the thread pool to return the "Typed" waitable event from postTask. +// Otherwise postTask would always think it returns the current active type, so the unit tests +// could not run on multiple worker types in the same compilation. +template <typename Impl> +struct WorkerThreadPoolTraits; + +class SingleThreadedWorkerPool; +template <> +struct WorkerThreadPoolTraits<SingleThreadedWorkerPool> +{ + using WaitableEventType = SingleThreadedWaitableEvent; +}; + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWorkerPool; +template <> +struct WorkerThreadPoolTraits<AsyncWorkerPool> +{ + using WaitableEventType = AsyncWaitableEvent; +}; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +// Request WorkerThreads from the WorkerThreadPool. Each pool can keep worker threads around so +// we avoid the costly spin up and spin down time. +template <typename Impl> +class WorkerThreadPoolBase : angle::NonCopyable +{ + public: + WorkerThreadPoolBase(size_t maxThreads); + ~WorkerThreadPoolBase(); + + using WaitableEventType = typename WorkerThreadPoolTraits<Impl>::WaitableEventType; + + // Returns an event to wait on for the task to finish. + // If the pool fails to create the task, returns null. + WaitableEventType postWorkerTask(Closure *task); +}; + +template <typename Impl> +WorkerThreadPoolBase<Impl>::WorkerThreadPoolBase(size_t maxThreads) +{ +} + +template <typename Impl> +WorkerThreadPoolBase<Impl>::~WorkerThreadPoolBase() +{ +} + +template <typename Impl> +typename WorkerThreadPoolBase<Impl>::WaitableEventType WorkerThreadPoolBase<Impl>::postWorkerTask( + Closure *task) +{ + return static_cast<Impl *>(this)->postWorkerTaskImpl(task); +} + +class SingleThreadedWorkerPool : public WorkerThreadPoolBase<SingleThreadedWorkerPool> +{ + public: + SingleThreadedWorkerPool(size_t maxThreads); + ~SingleThreadedWorkerPool(); + + SingleThreadedWaitableEvent postWorkerTaskImpl(Closure *task); +}; + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +class AsyncWorkerPool : public WorkerThreadPoolBase<AsyncWorkerPool> +{ + public: + AsyncWorkerPool(size_t maxThreads); + ~AsyncWorkerPool(); + + AsyncWaitableEvent postWorkerTaskImpl(Closure *task); +}; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace priv + +#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) +using WaitableEvent = priv::AsyncWaitableEvent; +using WorkerThreadPool = priv::AsyncWorkerPool; +#else +using WaitableEvent = priv::SingleThreadedWaitableEvent; +using WorkerThreadPool = priv::SingleThreadedWorkerPool; +#endif // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED) + +} // namespace angle + +#endif // LIBANGLE_WORKER_THREAD_H_ |