Hash :
3cfc0ce2
Author :
Date :
2025-03-24T07:41:33
Revert "Vulkan:Dont use Subject/Observer for SwapchainImageChanged" This reverts commit 48103cb2f2b292cb50cc5a29546b358b2e47fd29. Reason for revert: assert fails https://ci.chromium.org/ui/p/angle/builders/ci/android-arm64-exp-test/7085/overview I 22:27:33.697 77.533s _RunTestsOnDevice(17221FDF6000A4) [ RUN ] EGLAndroidAutoRefreshTest.SwapCPUThrottling/ES3_Vulkan_NoFixture INFO:root:ERR: SurfaceVk.cpp:3165 (getCurrentFramebuffer): ! Assert failed in getCurrentFramebuffer (../../src/libANGLE/renderer/vulkan/SurfaceVk.cpp:3165): mAcquireOperation.state == ImageAcquireState::Ready Original change's description: > Vulkan:Dont use Subject/Observer for SwapchainImageChanged > > Because we do deferred ANI (VkAcquireNextImage) call until image is > needed, we need a way to force Context to go through > FramebufferVk::syncState call (FramebufferVk::syncState calls > WindowSurfaceVk::getAttachmentRenderTarget, which end up calling ANI. > Right now we uses subject/observer mechanism, by sending > angle::SubjectMessage::SwapchainImageChanged to all observers of > WindowSurfaceVk. In this case it is egl::Surface. Then eglSurface > redirects this message to its observers, which are all gl::Framebuffer's > attachments: color, depth, stencil. Even though only color attachment > needs to be notified, but because we don't have a separate list of > observers, depth/stencil attachment also receive the notification and > they early out. Then gl::Framebuffer sets > DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 dirty bit and send the > angle::SubjectMessage::DirtyBitsFlagged to Context, which dirty DrawFBO > and ReadFBO and dirty cached state. Note that this is specific for swap > image changed case, there is no surface property change (surface > property change will still trigger the subject/observer message with > SubjectMessage::SubjectChanged message, but this occurs rarely). This > gets worse for apps that uses multiple contexts, for the example > pokemon_masters_ex has three contexts, each context has its own default > frame buffer that attach to the same surface, and we never remove > non-current context from the observer list. This end up with > egl::Surface has 12 observers and for every frame, it loop over the list > of 12 observers and send message (virtual function call) to each of > them. Color attachment also ends up sending two messages to Context, one > for Read FBO and another for Draw FBO. There are total 21 virtual > function calls. Even for single context usage, you have 6 virtual > function calls, for every frame. > > EGL spec says "an EGLSurface must be current on only one thread at a > time", any other context must call EGLMakeCurrent in order to use this > surface, which will add all necessary dirty bits at that time. So we > really only need to notify current context. In this CL, > SwapchainImageChanged no longer uses subject/observer mechanism, so this > message is removed. > > This CL still uses subject/observer mechanism to send DirtyBitsFlagged > from Framebuffer back to context. We could call setDrawFramebufferDirty > and setReadFramebufferDirty directly, but that will require to remove > the "const" decoration out of gl::Context which generates too much code > diff, so onStateChange(angle::SubjectMessage::DirtyBitsFlagged) is still > used. > > Bug: angleproject:400711938 > Change-Id: I61354516fd0aa307714b7abd30c6b6e45ff7b496 > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6319893 > Commit-Queue: Charlie Lao <cclao@google.com> > Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> > Reviewed-by: Yuxin Hu <yuxinhu@google.com> Bug: angleproject:400711938 Change-Id: Ib7899d1ac63a1f86af0953a1d25922578c470fc9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6387755 Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Commit-Queue: Yuly Novikov <ynovikov@chromium.org>
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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
//
// 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"
#include "libANGLE/Constants.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 program or pipeline is being re-linked. This is used to make sure the Context or
// ProgramPipeline that reference the program/pipeline wait for it to finish linking.
ProgramUnlinked,
// Indicates a program or pipeline was successfully re-linked.
ProgramRelinked,
// Indicates a separable program's sampler uniforms were updated.
SamplerUniformsUpdated,
// Indicates a program's uniform block binding has changed (one message per binding)
ProgramUniformBlockBindingZeroUpdated,
ProgramUniformBlockBindingLastUpdated = ProgramUniformBlockBindingZeroUpdated +
gl::IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS -
1,
// Indicates a Storage of back-end in gl::Texture has been released.
StorageReleased,
// Sent when the GLuint ID for a gl::Texture is being deleted via glDeleteTextures. The
// texture may stay alive due to orphaning, but will no longer be directly accessible by the GL
// API.
TextureIDDeleted,
// Indicates that all pending updates are complete in the subject.
InitializationComplete,
// Indicates a change in foveated rendering state in the subject.
FoveatedRenderingStateChanged,
};
inline bool IsProgramUniformBlockBindingUpdatedMessage(SubjectMessage message)
{
return message >= SubjectMessage::ProgramUniformBlockBindingZeroUpdated &&
message <= SubjectMessage::ProgramUniformBlockBindingLastUpdated;
}
inline SubjectMessage ProgramUniformBlockBindingUpdatedMessageFromIndex(uint32_t blockIndex)
{
return static_cast<SubjectMessage>(
static_cast<uint32_t>(SubjectMessage::ProgramUniformBlockBindingZeroUpdated) + blockIndex);
}
inline uint32_t ProgramUniformBlockBindingUpdatedMessageToIndex(SubjectMessage message)
{
return static_cast<uint32_t>(message) -
static_cast<uint32_t>(SubjectMessage::ProgramUniformBlockBindingZeroUpdated);
}
// 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_