Observer.h (5742B)
1 // 2 // Copyright 2016 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 // Observer: 7 // Implements the Observer pattern for sending state change notifications 8 // from Subject objects to dependent Observer objects. 9 // 10 // See design document: 11 // https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/ 12 13 #ifndef LIBANGLE_OBSERVER_H_ 14 #define LIBANGLE_OBSERVER_H_ 15 16 #include "common/FastVector.h" 17 #include "common/angleutils.h" 18 19 namespace angle 20 { 21 template <typename HaystackT, typename NeedleT> 22 bool IsInContainer(const HaystackT &haystack, const NeedleT &needle) 23 { 24 return std::find(haystack.begin(), haystack.end(), needle) != haystack.end(); 25 } 26 27 using SubjectIndex = size_t; 28 29 // Messages are used to distinguish different Subject events that get sent to a single Observer. 30 // It could be possible to improve the handling by using different callback functions instead 31 // of a single handler function. But in some cases we want to share a single binding between 32 // Observer and Subject and handle different types of events. 33 enum class SubjectMessage 34 { 35 // Used by gl::VertexArray to notify gl::Context of a gl::Buffer binding count change. Triggers 36 // a validation cache update. Also used by gl::Texture to notify gl::Framebuffer of loops. 37 BindingChanged, 38 39 // Only the contents (pixels, bytes, etc) changed in this Subject. Distinct from the object 40 // storage. 41 ContentsChanged, 42 43 // Sent by gl::Sampler, gl::Texture, gl::Framebuffer and others to notifiy gl::Context. This 44 // flag indicates to call syncState before next use. 45 DirtyBitsFlagged, 46 47 // Generic state change message. Used in multiple places for different purposes. 48 SubjectChanged, 49 50 // Indicates a bound gl::Buffer is now mapped or unmapped. Passed from gl::Buffer, through 51 // gl::VertexArray, into gl::Context. Used to track validation. 52 SubjectMapped, 53 SubjectUnmapped, 54 // Indicates a bound buffer's storage was reallocated due to glBufferData call or optimizations 55 // to prevent having to flush pending commands and waiting for the GPU to become idle. 56 InternalMemoryAllocationChanged, 57 58 // Indicates an external change to the default framebuffer. 59 SurfaceChanged, 60 // Indicates the system framebuffer's swapchain changed, i.e. color buffer changed but no 61 // depth/stencil buffer change. 62 SwapchainImageChanged, 63 64 // Indicates a separable program's textures or images changed in the ProgramExecutable. 65 ProgramTextureOrImageBindingChanged, 66 // Indicates a separable program was successfully re-linked. 67 ProgramRelinked, 68 // Indicates a separable program's sampler uniforms were updated. 69 SamplerUniformsUpdated, 70 // Other types of uniform change. 71 ProgramUniformUpdated, 72 73 // Indicates a Storage of back-end in gl::Texture has been released. 74 StorageReleased, 75 76 // Indicates that all pending updates are complete in the subject. 77 InitializationComplete, 78 }; 79 80 // The observing class inherits from this interface class. 81 class ObserverInterface 82 { 83 public: 84 virtual ~ObserverInterface(); 85 virtual void onSubjectStateChange(SubjectIndex index, SubjectMessage message) = 0; 86 }; 87 88 class ObserverBindingBase 89 { 90 public: 91 ObserverBindingBase(ObserverInterface *observer, SubjectIndex subjectIndex) 92 : mObserver(observer), mIndex(subjectIndex) 93 {} 94 virtual ~ObserverBindingBase() {} 95 96 ObserverBindingBase(const ObserverBindingBase &other) = default; 97 ObserverBindingBase &operator=(const ObserverBindingBase &other) = default; 98 99 ObserverInterface *getObserver() const { return mObserver; } 100 SubjectIndex getSubjectIndex() const { return mIndex; } 101 102 virtual void onSubjectReset() {} 103 104 private: 105 ObserverInterface *mObserver; 106 SubjectIndex mIndex; 107 }; 108 109 constexpr size_t kMaxFixedObservers = 8; 110 111 // Maintains a list of observer bindings. Sends update messages to the observer. 112 class Subject : NonCopyable 113 { 114 public: 115 Subject(); 116 virtual ~Subject(); 117 118 void onStateChange(SubjectMessage message) const; 119 bool hasObservers() const; 120 void resetObservers(); 121 ANGLE_INLINE size_t getObserversCount() const { return mObservers.size(); } 122 123 ANGLE_INLINE void addObserver(ObserverBindingBase *observer) 124 { 125 ASSERT(!IsInContainer(mObservers, observer)); 126 mObservers.push_back(observer); 127 } 128 ANGLE_INLINE void removeObserver(ObserverBindingBase *observer) 129 { 130 ASSERT(IsInContainer(mObservers, observer)); 131 mObservers.remove_and_permute(observer); 132 } 133 134 private: 135 // Keep a short list of observers so we can allocate/free them quickly. But since we support 136 // unlimited bindings, have a spill-over list of that uses dynamic allocation. 137 angle::FastVector<ObserverBindingBase *, kMaxFixedObservers> mObservers; 138 }; 139 140 // Keeps a binding between a Subject and Observer, with a specific subject index. 141 class ObserverBinding final : public ObserverBindingBase 142 { 143 public: 144 ObserverBinding(); 145 ObserverBinding(ObserverInterface *observer, SubjectIndex index); 146 ~ObserverBinding() override; 147 ObserverBinding(const ObserverBinding &other); 148 ObserverBinding &operator=(const ObserverBinding &other); 149 150 void bind(Subject *subject); 151 152 ANGLE_INLINE void reset() { bind(nullptr); } 153 154 void onStateChange(SubjectMessage message) const; 155 void onSubjectReset() override; 156 157 ANGLE_INLINE const Subject *getSubject() const { return mSubject; } 158 159 ANGLE_INLINE void assignSubject(Subject *subject) { mSubject = subject; } 160 161 private: 162 Subject *mSubject; 163 }; 164 165 } // namespace angle 166 167 #endif // LIBANGLE_OBSERVER_H_