summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/Observer.h
blob: a07a224b99d001d55fe40d993e1f0af15ce38ada (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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_