diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/Observer.h')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/Observer.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/Observer.h b/gfx/angle/checkout/src/libANGLE/Observer.h new file mode 100644 index 0000000000..a07a224b99 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/Observer.h @@ -0,0 +1,167 @@ +// +// 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. +// +// Observer: +// Implements the Observer pattern for sending state change notifications +// from Subject objects to dependent Observer objects. +// +// See design document: +// https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/ + +#ifndef LIBANGLE_OBSERVER_H_ +#define LIBANGLE_OBSERVER_H_ + +#include "common/FastVector.h" +#include "common/angleutils.h" + +namespace angle +{ +template <typename HaystackT, typename NeedleT> +bool IsInContainer(const HaystackT &haystack, const NeedleT &needle) +{ + return std::find(haystack.begin(), haystack.end(), needle) != haystack.end(); +} + +using SubjectIndex = size_t; + +// Messages are used to distinguish different Subject events that get sent to a single Observer. +// It could be possible to improve the handling by using different callback functions instead +// of a single handler function. But in some cases we want to share a single binding between +// Observer and Subject and handle different types of events. +enum class SubjectMessage +{ + // Used by gl::VertexArray to notify gl::Context of a gl::Buffer binding count change. Triggers + // a validation cache update. Also used by gl::Texture to notify gl::Framebuffer of loops. + BindingChanged, + + // Only the contents (pixels, bytes, etc) changed in this Subject. Distinct from the object + // storage. + ContentsChanged, + + // Sent by gl::Sampler, gl::Texture, gl::Framebuffer and others to notifiy gl::Context. This + // flag indicates to call syncState before next use. + DirtyBitsFlagged, + + // Generic state change message. Used in multiple places for different purposes. + SubjectChanged, + + // Indicates a bound gl::Buffer is now mapped or unmapped. Passed from gl::Buffer, through + // gl::VertexArray, into gl::Context. Used to track validation. + SubjectMapped, + SubjectUnmapped, + // Indicates a bound buffer's storage was reallocated due to glBufferData call or optimizations + // to prevent having to flush pending commands and waiting for the GPU to become idle. + InternalMemoryAllocationChanged, + + // Indicates an external change to the default framebuffer. + SurfaceChanged, + // Indicates the system framebuffer's swapchain changed, i.e. color buffer changed but no + // depth/stencil buffer change. + SwapchainImageChanged, + + // Indicates a separable program's textures or images changed in the ProgramExecutable. + ProgramTextureOrImageBindingChanged, + // Indicates a separable program was successfully re-linked. + ProgramRelinked, + // Indicates a separable program's sampler uniforms were updated. + SamplerUniformsUpdated, + // Other types of uniform change. + ProgramUniformUpdated, + + // Indicates a Storage of back-end in gl::Texture has been released. + StorageReleased, + + // Indicates that all pending updates are complete in the subject. + InitializationComplete, +}; + +// The observing class inherits from this interface class. +class ObserverInterface +{ + public: + virtual ~ObserverInterface(); + virtual void onSubjectStateChange(SubjectIndex index, SubjectMessage message) = 0; +}; + +class ObserverBindingBase +{ + public: + ObserverBindingBase(ObserverInterface *observer, SubjectIndex subjectIndex) + : mObserver(observer), mIndex(subjectIndex) + {} + virtual ~ObserverBindingBase() {} + + ObserverBindingBase(const ObserverBindingBase &other) = default; + ObserverBindingBase &operator=(const ObserverBindingBase &other) = default; + + ObserverInterface *getObserver() const { return mObserver; } + SubjectIndex getSubjectIndex() const { return mIndex; } + + virtual void onSubjectReset() {} + + private: + ObserverInterface *mObserver; + SubjectIndex mIndex; +}; + +constexpr size_t kMaxFixedObservers = 8; + +// Maintains a list of observer bindings. Sends update messages to the observer. +class Subject : NonCopyable +{ + public: + Subject(); + virtual ~Subject(); + + void onStateChange(SubjectMessage message) const; + bool hasObservers() const; + void resetObservers(); + ANGLE_INLINE size_t getObserversCount() const { return mObservers.size(); } + + ANGLE_INLINE void addObserver(ObserverBindingBase *observer) + { + ASSERT(!IsInContainer(mObservers, observer)); + mObservers.push_back(observer); + } + ANGLE_INLINE void removeObserver(ObserverBindingBase *observer) + { + ASSERT(IsInContainer(mObservers, observer)); + mObservers.remove_and_permute(observer); + } + + private: + // Keep a short list of observers so we can allocate/free them quickly. But since we support + // unlimited bindings, have a spill-over list of that uses dynamic allocation. + angle::FastVector<ObserverBindingBase *, kMaxFixedObservers> mObservers; +}; + +// Keeps a binding between a Subject and Observer, with a specific subject index. +class ObserverBinding final : public ObserverBindingBase +{ + public: + ObserverBinding(); + ObserverBinding(ObserverInterface *observer, SubjectIndex index); + ~ObserverBinding() override; + ObserverBinding(const ObserverBinding &other); + ObserverBinding &operator=(const ObserverBinding &other); + + void bind(Subject *subject); + + ANGLE_INLINE void reset() { bind(nullptr); } + + void onStateChange(SubjectMessage message) const; + void onSubjectReset() override; + + ANGLE_INLINE const Subject *getSubject() const { return mSubject; } + + ANGLE_INLINE void assignSubject(Subject *subject) { mSubject = subject; } + + private: + Subject *mSubject; +}; + +} // namespace angle + +#endif // LIBANGLE_OBSERVER_H_ |