Commit d444255a by Jamie Madill Committed by Commit Bot

Refactor signal utils into Observer pattern.

These types were over-generalized. All use cases featured arrays of resources attached to single parent resources. The channel ID is sufficient to identify the child resource in the parent, and having variadic template arguments wasn't necessary. Futhermore we can rename these types to use the common Observer pattern. This should make them more readable to new developers. Also update some classes to inherit from Subject instead of having a member Subject. This cleans up the code in a few places. This should lead to a simpler refactor to allow dependent dirty bits notifications in the Vulkan back-end. In the following patch the signal_utils files will be renamed. They are not renamed in this patch to ensure git history is preserved. Bug: angleproject:2372 Change-Id: I17a3f2c8d92afd4bb3cba2d378c3a2e8a6d7fb11 Reviewed-on: https://chromium-review.googlesource.com/936690Reviewed-by: 's avatarLuc Ferron <lucferron@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 2f3a0dc5
...@@ -2625,10 +2625,10 @@ void Context::requestExtension(const char *name) ...@@ -2625,10 +2625,10 @@ void Context::requestExtension(const char *name)
// Invalidate all textures and framebuffer. Some extensions make new formats renderable or // Invalidate all textures and framebuffer. Some extensions make new formats renderable or
// sampleable. // sampleable.
mState.mTextures->signalAllTexturesDirty(); mState.mTextures->signalAllTexturesDirty(this);
for (auto &zeroTexture : mZeroTextures) for (auto &zeroTexture : mZeroTextures)
{ {
zeroTexture.second->signalDirty(InitState::Initialized); zeroTexture.second->signalDirty(this, InitState::Initialized);
} }
mState.mFramebuffers->invalidateFramebufferComplenessCache(); mState.mFramebuffers->invalidateFramebufferComplenessCache();
......
...@@ -133,7 +133,7 @@ class FramebufferState final : angle::NonCopyable ...@@ -133,7 +133,7 @@ class FramebufferState final : angle::NonCopyable
angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 2> mResourceNeedsInit; angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 2> mResourceNeedsInit;
}; };
class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver class Framebuffer final : public LabeledObject, public angle::ObserverInterface
{ {
public: public:
// Constructor to build application-defined framebuffers // Constructor to build application-defined framebuffers
...@@ -250,22 +250,22 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -250,22 +250,22 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
Error invalidateSub(const Context *context, Error invalidateSub(const Context *context,
size_t count, size_t count,
const GLenum *attachments, const GLenum *attachments,
const gl::Rectangle &area); const Rectangle &area);
Error clear(const gl::Context *context, GLbitfield mask); Error clear(const Context *context, GLbitfield mask);
Error clearBufferfv(const gl::Context *context, Error clearBufferfv(const Context *context,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLfloat *values); const GLfloat *values);
Error clearBufferuiv(const gl::Context *context, Error clearBufferuiv(const Context *context,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLuint *values); const GLuint *values);
Error clearBufferiv(const gl::Context *context, Error clearBufferiv(const Context *context,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLint *values); const GLint *values);
Error clearBufferfi(const gl::Context *context, Error clearBufferfi(const Context *context,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
GLfloat depth, GLfloat depth,
...@@ -273,13 +273,13 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -273,13 +273,13 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
GLenum getImplementationColorReadFormat(const Context *context) const; GLenum getImplementationColorReadFormat(const Context *context) const;
GLenum getImplementationColorReadType(const Context *context) const; GLenum getImplementationColorReadType(const Context *context) const;
Error readPixels(const gl::Context *context, Error readPixels(const Context *context,
const gl::Rectangle &area, const Rectangle &area,
GLenum format, GLenum format,
GLenum type, GLenum type,
void *pixels); void *pixels);
Error blit(const gl::Context *context, Error blit(const Context *context,
const Rectangle &sourceArea, const Rectangle &sourceArea,
const Rectangle &destArea, const Rectangle &destArea,
GLbitfield mask, GLbitfield mask,
...@@ -289,7 +289,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -289,7 +289,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
{ {
DIRTY_BIT_COLOR_ATTACHMENT_0, DIRTY_BIT_COLOR_ATTACHMENT_0,
DIRTY_BIT_COLOR_ATTACHMENT_MAX = DIRTY_BIT_COLOR_ATTACHMENT_MAX =
DIRTY_BIT_COLOR_ATTACHMENT_0 + gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS, DIRTY_BIT_COLOR_ATTACHMENT_0 + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS,
DIRTY_BIT_DEPTH_ATTACHMENT = DIRTY_BIT_COLOR_ATTACHMENT_MAX, DIRTY_BIT_DEPTH_ATTACHMENT = DIRTY_BIT_COLOR_ATTACHMENT_MAX,
DIRTY_BIT_STENCIL_ATTACHMENT, DIRTY_BIT_STENCIL_ATTACHMENT,
DIRTY_BIT_DRAW_BUFFERS, DIRTY_BIT_DRAW_BUFFERS,
...@@ -307,8 +307,10 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -307,8 +307,10 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
void syncState(const Context *context); void syncState(const Context *context);
// OnAttachmentChangedReceiver implementation // Observer implementation
void signal(size_t dirtyBit, InitState state) override; void onSubjectStateChange(const Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
bool formsRenderingFeedbackLoopWith(const State &state) const; bool formsRenderingFeedbackLoopWith(const State &state) const;
bool formsCopyingFeedbackLoopWith(GLuint copyTextureID, bool formsCopyingFeedbackLoopWith(GLuint copyTextureID,
...@@ -355,7 +357,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -355,7 +357,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
void updateAttachment(const Context *context, void updateAttachment(const Context *context,
FramebufferAttachment *attachment, FramebufferAttachment *attachment,
size_t dirtyBit, size_t dirtyBit,
OnAttachmentDirtyBinding *onDirtyBinding, angle::ObserverBinding *onDirtyBinding,
GLenum type, GLenum type,
GLenum binding, GLenum binding,
const ImageIndex &textureIndex, const ImageIndex &textureIndex,
...@@ -376,14 +378,16 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -376,14 +378,16 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
bool partialClearNeedsInit(const Context *context, bool color, bool depth, bool stencil); bool partialClearNeedsInit(const Context *context, bool color, bool depth, bool stencil);
bool partialBufferClearNeedsInit(const Context *context, GLenum bufferType); bool partialBufferClearNeedsInit(const Context *context, GLenum bufferType);
FramebufferAttachment *getAttachmentFromSubjectIndex(angle::SubjectIndex index);
FramebufferState mState; FramebufferState mState;
rx::FramebufferImpl *mImpl; rx::FramebufferImpl *mImpl;
GLuint mId; GLuint mId;
Optional<GLenum> mCachedStatus; Optional<GLenum> mCachedStatus;
std::vector<OnAttachmentDirtyBinding> mDirtyColorAttachmentBindings; std::vector<angle::ObserverBinding> mDirtyColorAttachmentBindings;
OnAttachmentDirtyBinding mDirtyDepthAttachmentBinding; angle::ObserverBinding mDirtyDepthAttachmentBinding;
OnAttachmentDirtyBinding mDirtyStencilAttachmentBinding; angle::ObserverBinding mDirtyStencilAttachmentBinding;
DirtyBits mDirtyBits; DirtyBits mDirtyBits;
......
...@@ -353,11 +353,6 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget( ...@@ -353,11 +353,6 @@ Error FramebufferAttachmentObject::getAttachmentRenderTarget(
return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut); return getAttachmentImpl()->getAttachmentRenderTarget(context, binding, imageIndex, rtOut);
} }
OnAttachmentDirtyChannel *FramebufferAttachmentObject::getDirtyChannel()
{
return &mDirtyChannel;
}
Error FramebufferAttachmentObject::initializeContents(const Context *context, Error FramebufferAttachmentObject::initializeContents(const Context *context,
const ImageIndex &imageIndex) const ImageIndex &imageIndex)
{ {
......
...@@ -49,10 +49,6 @@ enum class InitState ...@@ -49,10 +49,6 @@ enum class InitState
Initialized, Initialized,
}; };
using OnAttachmentDirtyBinding = angle::ChannelBinding<size_t, InitState>;
using OnAttachmentDirtyChannel = angle::BroadcastChannel<size_t, InitState>;
using OnAttachmentDirtyReceiver = angle::SignalReceiver<size_t, InitState>;
// FramebufferAttachment implements a GL framebuffer attachment. // FramebufferAttachment implements a GL framebuffer attachment.
// Attachments are "light" containers, which store pointers to ref-counted GL objects. // Attachments are "light" containers, which store pointers to ref-counted GL objects.
// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. // We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments.
...@@ -184,7 +180,7 @@ class FramebufferAttachment final ...@@ -184,7 +180,7 @@ class FramebufferAttachment final
}; };
// A base class for objects that FBO Attachments may point to. // A base class for objects that FBO Attachments may point to.
class FramebufferAttachmentObject class FramebufferAttachmentObject : public angle::Subject
{ {
public: public:
FramebufferAttachmentObject(); FramebufferAttachmentObject();
...@@ -210,12 +206,8 @@ class FramebufferAttachmentObject ...@@ -210,12 +206,8 @@ class FramebufferAttachmentObject
Error initializeContents(const Context *context, const ImageIndex &imageIndex); Error initializeContents(const Context *context, const ImageIndex &imageIndex);
OnAttachmentDirtyChannel *getDirtyChannel();
protected: protected:
virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0; virtual rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const = 0;
OnAttachmentDirtyChannel mDirtyChannel;
}; };
inline Extents FramebufferAttachment::getSize() const inline Extents FramebufferAttachment::getSize() const
......
...@@ -109,7 +109,7 @@ Error Renderbuffer::setStorage(const Context *context, ...@@ -109,7 +109,7 @@ Error Renderbuffer::setStorage(const Context *context,
mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat), mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat),
0, InitState::MayNeedInit); 0, InitState::MayNeedInit);
mDirtyChannel.signal(mState.mInitState); onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
return NoError(); return NoError();
} }
...@@ -126,7 +126,7 @@ Error Renderbuffer::setStorageMultisample(const Context *context, ...@@ -126,7 +126,7 @@ Error Renderbuffer::setStorageMultisample(const Context *context,
mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat), mState.update(static_cast<GLsizei>(width), static_cast<GLsizei>(height), Format(internalformat),
static_cast<GLsizei>(samples), InitState::MayNeedInit); static_cast<GLsizei>(samples), InitState::MayNeedInit);
mDirtyChannel.signal(mState.mInitState); onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
return NoError(); return NoError();
} }
...@@ -140,7 +140,7 @@ Error Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image ...@@ -140,7 +140,7 @@ Error Renderbuffer::setStorageEGLImageTarget(const Context *context, egl::Image
mState.update(static_cast<GLsizei>(image->getWidth()), static_cast<GLsizei>(image->getHeight()), mState.update(static_cast<GLsizei>(image->getWidth()), static_cast<GLsizei>(image->getHeight()),
Format(image->getFormat()), 0, image->sourceInitState()); Format(image->getFormat()), 0, image->sourceInitState());
mDirtyChannel.signal(mState.mInitState); onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
return NoError(); return NoError();
} }
......
...@@ -247,7 +247,7 @@ Texture *TextureManager::getTexture(GLuint handle) const ...@@ -247,7 +247,7 @@ Texture *TextureManager::getTexture(GLuint handle) const
return mObjectMap.query(handle); return mObjectMap.query(handle);
} }
void TextureManager::signalAllTexturesDirty() const void TextureManager::signalAllTexturesDirty(const Context *context) const
{ {
for (const auto &texture : mObjectMap) for (const auto &texture : mObjectMap)
{ {
...@@ -255,7 +255,7 @@ void TextureManager::signalAllTexturesDirty() const ...@@ -255,7 +255,7 @@ void TextureManager::signalAllTexturesDirty() const
{ {
// We don't know if the Texture needs init, but that's ok, since it will only force // We don't know if the Texture needs init, but that's ok, since it will only force
// a re-check, and will not initialize the pixels if it's not needed. // a re-check, and will not initialize the pixels if it's not needed.
texture.second->signalDirty(InitState::MayNeedInit); texture.second->signalDirty(context, InitState::MayNeedInit);
} }
} }
} }
......
...@@ -157,7 +157,7 @@ class TextureManager : public TypedResourceManager<Texture, HandleAllocator, Tex ...@@ -157,7 +157,7 @@ class TextureManager : public TypedResourceManager<Texture, HandleAllocator, Tex
GLuint createTexture(); GLuint createTexture();
Texture *getTexture(GLuint handle) const; Texture *getTexture(GLuint handle) const;
void signalAllTexturesDirty() const; void signalAllTexturesDirty(const Context *context) const;
Texture *checkTextureAllocation(rx::GLImplFactory *factory, GLuint handle, GLenum target) Texture *checkTextureAllocation(rx::GLImplFactory *factory, GLuint handle, GLenum target)
{ {
......
...@@ -180,7 +180,7 @@ void State::initialize(const Context *context, ...@@ -180,7 +180,7 @@ void State::initialize(const Context *context,
for (uint32_t textureIndex = 0; textureIndex < caps.maxCombinedTextureImageUnits; for (uint32_t textureIndex = 0; textureIndex < caps.maxCombinedTextureImageUnits;
++textureIndex) ++textureIndex)
{ {
mCompleteTextureBindings.emplace_back(OnAttachmentDirtyBinding(this, textureIndex)); mCompleteTextureBindings.emplace_back(this, textureIndex);
} }
mSamplers.resize(caps.maxCombinedTextureImageUnits); mSamplers.resize(caps.maxCombinedTextureImageUnits);
...@@ -2320,7 +2320,7 @@ void State::syncProgramTextures(const Context *context) ...@@ -2320,7 +2320,7 @@ void State::syncProgramTextures(const Context *context)
} }
// Bind the texture unconditionally, to recieve completeness change notifications. // Bind the texture unconditionally, to recieve completeness change notifications.
mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel()); mCompleteTextureBindings[textureUnitIndex].bind(texture);
mActiveTexturesMask.set(textureUnitIndex); mActiveTexturesMask.set(textureUnitIndex);
newActiveTextures.set(textureUnitIndex); newActiveTextures.set(textureUnitIndex);
...@@ -2440,13 +2440,16 @@ const ImageUnit &State::getImageUnit(GLuint unit) const ...@@ -2440,13 +2440,16 @@ const ImageUnit &State::getImageUnit(GLuint unit) const
} }
// Handle a dirty texture event. // Handle a dirty texture event.
void State::signal(size_t textureIndex, InitState initState) void State::onSubjectStateChange(const Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{ {
// Conservatively assume all textures are dirty. // Conservatively assume all textures are dirty.
// TODO(jmadill): More fine-grained update. // TODO(jmadill): More fine-grained update.
mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES); mDirtyObjects.set(DIRTY_OBJECT_PROGRAM_TEXTURES);
if (initState == InitState::MayNeedInit) if (!mCompleteTextureCache[index] ||
mCompleteTextureCache[index]->initState() == InitState::MayNeedInit)
{ {
mCachedTexturesInitState = InitState::MayNeedInit; mCachedTexturesInitState = InitState::MayNeedInit;
} }
......
...@@ -34,7 +34,7 @@ class VertexArray; ...@@ -34,7 +34,7 @@ class VertexArray;
class Context; class Context;
struct Caps; struct Caps;
class State : public OnAttachmentDirtyReceiver, angle::NonCopyable class State : public angle::ObserverInterface, angle::NonCopyable
{ {
public: public:
State(); State();
...@@ -462,8 +462,10 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable ...@@ -462,8 +462,10 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
const std::vector<Texture *> &getCompleteTextureCache() const { return mCompleteTextureCache; } const std::vector<Texture *> &getCompleteTextureCache() const { return mCompleteTextureCache; }
ComponentTypeMask getCurrentValuesTypeMask() const { return mCurrentValuesTypeMask; } ComponentTypeMask getCurrentValuesTypeMask() const { return mCurrentValuesTypeMask; }
// Handle a dirty texture event. // Observer implementation.
void signal(size_t textureIndex, InitState initState) override; void onSubjectStateChange(const Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
Error clearUnclearedActiveTextures(const Context *context); Error clearUnclearedActiveTextures(const Context *context);
...@@ -527,11 +529,10 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable ...@@ -527,11 +529,10 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
// Texture Completeness Caching // Texture Completeness Caching
// ---------------------------- // ----------------------------
// The texture completeness cache uses dirty bits to avoid having to scan the list // The texture completeness cache uses dirty bits to avoid having to scan the list of textures
// of textures each draw call. This gl::State class implements OnAttachmentDirtyReceiver, // each draw call. This gl::State class implements angle::Observer interface. When subject
// and keeps an array of bindings to the Texture class. When the Textures are marked dirty, // Textures have state changes, messages reach 'State' (also any observing Framebuffers) via the
// they send messages to the State class (and any Framebuffers they're attached to) via the // onSubjectStateChange method (above). This then invalidates the completeness cache.
// State::signal method (see above). Internally this then invalidates the completeness cache.
// //
// Note this requires that we also invalidate the completeness cache manually on events like // Note this requires that we also invalidate the completeness cache manually on events like
// re-binding textures/samplers or a change in the program. For more information see the // re-binding textures/samplers or a change in the program. For more information see the
...@@ -541,7 +542,7 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable ...@@ -541,7 +542,7 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
// Don't use BindingPointer because this cache is only valid within a draw call. // Don't use BindingPointer because this cache is only valid within a draw call.
// Also stores a notification channel to the texture itself to handle texture change events. // Also stores a notification channel to the texture itself to handle texture change events.
std::vector<Texture *> mCompleteTextureCache; std::vector<Texture *> mCompleteTextureCache;
std::vector<OnAttachmentDirtyBinding> mCompleteTextureBindings; std::vector<angle::ObserverBinding> mCompleteTextureBindings;
InitState mCachedTexturesInitState; InitState mCachedTexturesInitState;
using ActiveTextureMask = angle::BitSet<IMPLEMENTATION_MAX_ACTIVE_TEXTURES>; using ActiveTextureMask = angle::BitSet<IMPLEMENTATION_MAX_ACTIVE_TEXTURES>;
ActiveTextureMask mActiveTexturesMask; ActiveTextureMask mActiveTexturesMask;
......
...@@ -151,12 +151,12 @@ Error Surface::destroyImpl(const Display *display) ...@@ -151,12 +151,12 @@ Error Surface::destroyImpl(const Display *display)
return NoError(); return NoError();
} }
void Surface::postSwap() void Surface::postSwap(const gl::Context *context)
{ {
if (mRobustResourceInitialization && mSwapBehavior != EGL_BUFFER_PRESERVED) if (mRobustResourceInitialization && mSwapBehavior != EGL_BUFFER_PRESERVED)
{ {
mInitState = gl::InitState::MayNeedInit; mInitState = gl::InitState::MayNeedInit;
mDirtyChannel.signal(mInitState); onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
} }
} }
...@@ -231,14 +231,14 @@ EGLint Surface::getType() const ...@@ -231,14 +231,14 @@ EGLint Surface::getType() const
Error Surface::swap(const gl::Context *context) Error Surface::swap(const gl::Context *context)
{ {
ANGLE_TRY(mImplementation->swap(context)); ANGLE_TRY(mImplementation->swap(context));
postSwap(); postSwap(context);
return NoError(); return NoError();
} }
Error Surface::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) Error Surface::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects)
{ {
ANGLE_TRY(mImplementation->swapWithDamage(context, rects, n_rects)); ANGLE_TRY(mImplementation->swapWithDamage(context, rects, n_rects));
postSwap(); postSwap(context);
return NoError(); return NoError();
} }
......
...@@ -187,7 +187,7 @@ class Surface : public gl::FramebufferAttachmentObject ...@@ -187,7 +187,7 @@ class Surface : public gl::FramebufferAttachmentObject
private: private:
Error destroyImpl(const Display *display); Error destroyImpl(const Display *display);
void postSwap(); void postSwap(const gl::Context *context);
gl::InitState mInitState; gl::InitState mInitState;
}; };
......
...@@ -913,9 +913,10 @@ egl::Stream *Texture::getBoundStream() const ...@@ -913,9 +913,10 @@ egl::Stream *Texture::getBoundStream() const
return mBoundStream; return mBoundStream;
} }
void Texture::signalDirty(InitState initState) const void Texture::signalDirty(const Context *context, InitState initState)
{ {
mDirtyChannel.signal(initState); mState.mInitState = initState;
onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
invalidateCompletenessCache(); invalidateCompletenessCache();
} }
...@@ -941,7 +942,7 @@ Error Texture::setImage(const Context *context, ...@@ -941,7 +942,7 @@ Error Texture::setImage(const Context *context,
InitState initState = DetermineInitState(context, pixels); InitState initState = DetermineInitState(context, pixels);
mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState)); mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
signalDirty(initState); signalDirty(context, initState);
return NoError(); return NoError();
} }
...@@ -984,7 +985,7 @@ Error Texture::setCompressedImage(const Context *context, ...@@ -984,7 +985,7 @@ Error Texture::setCompressedImage(const Context *context,
InitState initState = DetermineInitState(context, pixels); InitState initState = DetermineInitState(context, pixels);
mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState)); mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
signalDirty(initState); signalDirty(context, initState);
return NoError(); return NoError();
} }
...@@ -1038,7 +1039,7 @@ Error Texture::copyImage(const Context *context, ...@@ -1038,7 +1039,7 @@ Error Texture::copyImage(const Context *context,
Format(internalFormatInfo), InitState::Initialized)); Format(internalFormatInfo), InitState::Initialized));
// We need to initialize this texture only if the source attachment is not initialized. // We need to initialize this texture only if the source attachment is not initialized.
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1094,7 +1095,7 @@ Error Texture::copyTexture(const Context *context, ...@@ -1094,7 +1095,7 @@ Error Texture::copyTexture(const Context *context,
target, level, target, level,
ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized)); ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1166,7 +1167,7 @@ Error Texture::setStorage(const Context *context, ...@@ -1166,7 +1167,7 @@ Error Texture::setStorage(const Context *context,
mDirtyBits.set(DIRTY_BIT_BASE_LEVEL); mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
mDirtyBits.set(DIRTY_BIT_MAX_LEVEL); mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
signalDirty(InitState::MayNeedInit); signalDirty(context, InitState::MayNeedInit);
return NoError(); return NoError();
} }
...@@ -1193,7 +1194,7 @@ Error Texture::setStorageMultisample(const Context *context, ...@@ -1193,7 +1194,7 @@ Error Texture::setStorageMultisample(const Context *context,
mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations, mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
InitState::MayNeedInit); InitState::MayNeedInit);
signalDirty(InitState::MayNeedInit); signalDirty(context, InitState::MayNeedInit);
return NoError(); return NoError();
} }
...@@ -1233,7 +1234,7 @@ Error Texture::generateMipmap(const Context *context) ...@@ -1233,7 +1234,7 @@ Error Texture::generateMipmap(const Context *context)
InitState::Initialized); InitState::Initialized);
} }
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1255,7 +1256,7 @@ Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *sur ...@@ -1255,7 +1256,7 @@ Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *sur
Extents size(surface->getWidth(), surface->getHeight(), 1); Extents size(surface->getWidth(), surface->getHeight(), 1);
ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized); ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
mState.setImageDesc(mState.mTarget, 0, desc); mState.setImageDesc(mState.mTarget, 0, desc);
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1268,7 +1269,7 @@ Error Texture::releaseTexImageFromSurface(const Context *context) ...@@ -1268,7 +1269,7 @@ Error Texture::releaseTexImageFromSurface(const Context *context)
// Erase the image info for level 0 // Erase the image info for level 0
ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
mState.clearImageDesc(mState.mTarget, 0); mState.clearImageDesc(mState.mTarget, 0);
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1299,7 +1300,7 @@ Error Texture::acquireImageFromStream(const Context *context, ...@@ -1299,7 +1300,7 @@ Error Texture::acquireImageFromStream(const Context *context,
Extents size(desc.width, desc.height, 1); Extents size(desc.width, desc.height, 1);
mState.setImageDesc(mState.mTarget, 0, mState.setImageDesc(mState.mTarget, 0,
ImageDesc(size, Format(desc.internalFormat), InitState::Initialized)); ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1311,7 +1312,7 @@ Error Texture::releaseImageFromStream(const Context *context) ...@@ -1311,7 +1312,7 @@ Error Texture::releaseImageFromStream(const Context *context)
// Set to incomplete // Set to incomplete
mState.clearImageDesc(mState.mTarget, 0); mState.clearImageDesc(mState.mTarget, 0);
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
return NoError(); return NoError();
} }
...@@ -1348,7 +1349,7 @@ Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Ima ...@@ -1348,7 +1349,7 @@ Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Ima
mState.clearImageDescs(); mState.clearImageDescs();
mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat(), initState)); mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat(), initState));
signalDirty(initState); signalDirty(context, initState);
return NoError(); return NoError();
} }
...@@ -1445,7 +1446,7 @@ Error Texture::ensureInitialized(const Context *context) ...@@ -1445,7 +1446,7 @@ Error Texture::ensureInitialized(const Context *context)
} }
if (anyDirty) if (anyDirty)
{ {
signalDirty(InitState::Initialized); signalDirty(context, InitState::Initialized);
} }
mState.mInitState = InitState::Initialized; mState.mInitState = InitState::Initialized;
......
...@@ -349,7 +349,7 @@ class Texture final : public egl::ImageSibling, ...@@ -349,7 +349,7 @@ class Texture final : public egl::ImageSibling,
egl::Surface *getBoundSurface() const; egl::Surface *getBoundSurface() const;
egl::Stream *getBoundStream() const; egl::Stream *getBoundStream() const;
void signalDirty(InitState initState) const; void signalDirty(const Context *context, InitState initState);
bool isSamplerComplete(const Context *context, const Sampler *optionalSampler); bool isSamplerComplete(const Context *context, const Sampler *optionalSampler);
......
...@@ -144,9 +144,7 @@ class Buffer11::BufferStorage : angle::NonCopyable ...@@ -144,9 +144,7 @@ class Buffer11::BufferStorage : angle::NonCopyable
class Buffer11::NativeStorage : public Buffer11::BufferStorage class Buffer11::NativeStorage : public Buffer11::BufferStorage
{ {
public: public:
NativeStorage(Renderer11 *renderer, NativeStorage(Renderer11 *renderer, BufferUsage usage, const angle::Subject *onStorageChanged);
BufferUsage usage,
const OnBufferDataDirtyChannel *onStorageChanged);
~NativeStorage() override; ~NativeStorage() override;
bool isCPUAccessible(GLbitfield access) const override; bool isCPUAccessible(GLbitfield access) const override;
...@@ -177,7 +175,7 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage ...@@ -177,7 +175,7 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
void clearSRVs(); void clearSRVs();
d3d11::Buffer mBuffer; d3d11::Buffer mBuffer;
const OnBufferDataDirtyChannel *mOnStorageChanged; const angle::Subject *mOnStorageChanged;
std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews; std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews;
}; };
...@@ -403,7 +401,7 @@ gl::Error Buffer11::setSubData(const gl::Context *context, ...@@ -403,7 +401,7 @@ gl::Error Buffer11::setSubData(const gl::Context *context,
// Notify any vertex arrays that we have dirty data. // Notify any vertex arrays that we have dirty data.
// TODO(jmadill): Use a more fine grained notification for data updates. // TODO(jmadill): Use a more fine grained notification for data updates.
mDirectBroadcastChannel.signal(context); mDirectSubject.onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
} }
mSize = std::max(mSize, requiredSize); mSize = std::max(mSize, requiredSize);
...@@ -474,7 +472,7 @@ gl::Error Buffer11::copySubData(const gl::Context *context, ...@@ -474,7 +472,7 @@ gl::Error Buffer11::copySubData(const gl::Context *context,
invalidateStaticData(context); invalidateStaticData(context);
// Also notify that direct buffers are dirty. // Also notify that direct buffers are dirty.
mDirectBroadcastChannel.signal(context); mDirectSubject.onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
return gl::NoError(); return gl::NoError();
} }
...@@ -760,7 +758,7 @@ Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage) ...@@ -760,7 +758,7 @@ Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
return new EmulatedIndexedStorage(mRenderer); return new EmulatedIndexedStorage(mRenderer);
case BUFFER_USAGE_INDEX: case BUFFER_USAGE_INDEX:
case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel); return new NativeStorage(mRenderer, usage, &mDirectSubject);
default: default:
return new NativeStorage(mRenderer, usage, nullptr); return new NativeStorage(mRenderer, usage, nullptr);
} }
...@@ -923,7 +921,7 @@ void Buffer11::initializeStaticData(const gl::Context *context) ...@@ -923,7 +921,7 @@ void Buffer11::initializeStaticData(const gl::Context *context)
BufferD3D::initializeStaticData(context); BufferD3D::initializeStaticData(context);
// Notify when static data changes. // Notify when static data changes.
mStaticBroadcastChannel.signal(context); mStaticSubject.onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
} }
void Buffer11::invalidateStaticData(const gl::Context *context) void Buffer11::invalidateStaticData(const gl::Context *context)
...@@ -931,17 +929,17 @@ void Buffer11::invalidateStaticData(const gl::Context *context) ...@@ -931,17 +929,17 @@ void Buffer11::invalidateStaticData(const gl::Context *context)
BufferD3D::invalidateStaticData(context); BufferD3D::invalidateStaticData(context);
// Notify when static data changes. // Notify when static data changes.
mStaticBroadcastChannel.signal(context); mStaticSubject.onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
} }
OnBufferDataDirtyChannel *Buffer11::getStaticBroadcastChannel() angle::Subject *Buffer11::getStaticSubject()
{ {
return &mStaticBroadcastChannel; return &mStaticSubject;
} }
OnBufferDataDirtyChannel *Buffer11::getDirectBroadcastChannel() angle::Subject *Buffer11::getDirectSubject()
{ {
return &mDirectBroadcastChannel; return &mDirectSubject;
} }
void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source) void Buffer11::onCopyStorage(BufferStorage *dest, BufferStorage *source)
...@@ -991,7 +989,7 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s ...@@ -991,7 +989,7 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
BufferUsage usage, BufferUsage usage,
const OnBufferDataDirtyChannel *onStorageChanged) const angle::Subject *onStorageChanged)
: BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged) : BufferStorage(renderer, usage), mBuffer(), mOnStorageChanged(onStorageChanged)
{ {
} }
...@@ -1111,7 +1109,7 @@ gl::Error Buffer11::NativeStorage::resize(const gl::Context *context, ...@@ -1111,7 +1109,7 @@ gl::Error Buffer11::NativeStorage::resize(const gl::Context *context,
// Notify that the storage has changed. // Notify that the storage has changed.
if (mOnStorageChanged) if (mOnStorageChanged)
{ {
mOnStorageChanged->signal(context); mOnStorageChanged->onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
} }
return gl::NoError(); return gl::NoError();
......
...@@ -107,8 +107,8 @@ class Buffer11 : public BufferD3D ...@@ -107,8 +107,8 @@ class Buffer11 : public BufferD3D
// We use two set of dirty events. Static buffers are marked dirty whenever // We use two set of dirty events. Static buffers are marked dirty whenever
// data changes, because they must be re-translated. Direct buffers only need to be // data changes, because they must be re-translated. Direct buffers only need to be
// updated when the underlying ID3D11Buffer pointer changes - hopefully far less often. // updated when the underlying ID3D11Buffer pointer changes - hopefully far less often.
OnBufferDataDirtyChannel *getStaticBroadcastChannel(); angle::Subject *getStaticSubject();
OnBufferDataDirtyChannel *getDirectBroadcastChannel(); angle::Subject *getDirectSubject();
private: private:
class BufferStorage; class BufferStorage;
...@@ -180,8 +180,8 @@ class Buffer11 : public BufferD3D ...@@ -180,8 +180,8 @@ class Buffer11 : public BufferD3D
size_t mConstantBufferStorageAdditionalSize; size_t mConstantBufferStorageAdditionalSize;
unsigned int mMaxConstantBufferLruCount; unsigned int mMaxConstantBufferLruCount;
OnBufferDataDirtyChannel mStaticBroadcastChannel; angle::Subject mStaticSubject;
OnBufferDataDirtyChannel mDirectBroadcastChannel; angle::Subject mDirectSubject;
}; };
} // namespace rx } // namespace rx
......
...@@ -57,7 +57,7 @@ gl::Error MarkAttachmentsDirty(const gl::Context *context, ...@@ -57,7 +57,7 @@ gl::Error MarkAttachmentsDirty(const gl::Context *context,
void UpdateCachedRenderTarget(const gl::Context *context, void UpdateCachedRenderTarget(const gl::Context *context,
const gl::FramebufferAttachment *attachment, const gl::FramebufferAttachment *attachment,
RenderTarget11 *&cachedRenderTarget, RenderTarget11 *&cachedRenderTarget,
OnRenderTargetDirtyBinding *channelBinding) angle::ObserverBinding *channelBinding)
{ {
RenderTarget11 *newRenderTarget = nullptr; RenderTarget11 *newRenderTarget = nullptr;
if (attachment) if (attachment)
...@@ -71,9 +71,7 @@ void UpdateCachedRenderTarget(const gl::Context *context, ...@@ -71,9 +71,7 @@ void UpdateCachedRenderTarget(const gl::Context *context,
} }
if (newRenderTarget != cachedRenderTarget) if (newRenderTarget != cachedRenderTarget)
{ {
OnRenderTargetDirtyChannel *channel = channelBinding->bind(newRenderTarget);
(newRenderTarget ? newRenderTarget->getBroadcastChannel() : nullptr);
channelBinding->bind(channel);
cachedRenderTarget = newRenderTarget; cachedRenderTarget = newRenderTarget;
} }
} }
...@@ -451,9 +449,11 @@ void Framebuffer11::syncState(const gl::Context *context, ...@@ -451,9 +449,11 @@ void Framebuffer11::syncState(const gl::Context *context,
} }
} }
void Framebuffer11::signal(size_t channelID, const gl::Context *context) void Framebuffer11::onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{ {
if (channelID == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS) if (index == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
{ {
// Stencil is redundant in this case. // Stencil is redundant in this case.
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT); mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT);
...@@ -461,8 +461,8 @@ void Framebuffer11::signal(size_t channelID, const gl::Context *context) ...@@ -461,8 +461,8 @@ void Framebuffer11::signal(size_t channelID, const gl::Context *context)
} }
else else
{ {
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + channelID); mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + index);
mCachedColorRenderTargets[channelID] = nullptr; mCachedColorRenderTargets[index] = nullptr;
} }
// Notify the context we need to re-validate the RenderTarget. // Notify the context we need to re-validate the RenderTarget.
......
...@@ -17,7 +17,7 @@ namespace rx ...@@ -17,7 +17,7 @@ namespace rx
{ {
class Renderer11; class Renderer11;
class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver class Framebuffer11 : public FramebufferD3D, public angle::ObserverInterface
{ {
public: public:
Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer); Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer);
...@@ -52,7 +52,10 @@ class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver ...@@ -52,7 +52,10 @@ class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver
bool hasAnyInternalDirtyBit() const; bool hasAnyInternalDirtyBit() const;
void syncInternalState(const gl::Context *context); void syncInternalState(const gl::Context *context);
void signal(size_t channelID, const gl::Context *context) override; // Observer implementation.
void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
gl::Error getSamplePosition(size_t index, GLfloat *xy) const override; gl::Error getSamplePosition(size_t index, GLfloat *xy) const override;
...@@ -93,8 +96,8 @@ class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver ...@@ -93,8 +96,8 @@ class Framebuffer11 : public FramebufferD3D, public OnRenderTargetDirtyReceiver
RenderTargetArray mCachedColorRenderTargets; RenderTargetArray mCachedColorRenderTargets;
RenderTarget11 *mCachedDepthStencilRenderTarget; RenderTarget11 *mCachedDepthStencilRenderTarget;
std::vector<OnRenderTargetDirtyBinding> mColorRenderTargetsDirty; std::vector<angle::ObserverBinding> mColorRenderTargetsDirty;
OnRenderTargetDirtyBinding mDepthStencilRenderTargetDirty; angle::ObserverBinding mDepthStencilRenderTargetDirty;
gl::Framebuffer::DirtyBits mInternalDirtyBits; gl::Framebuffer::DirtyBits mInternalDirtyBits;
}; };
......
...@@ -200,15 +200,15 @@ RenderTarget11::RenderTarget11(const d3d11::Format &formatSet) : mFormatSet(form ...@@ -200,15 +200,15 @@ RenderTarget11::RenderTarget11(const d3d11::Format &formatSet) : mFormatSet(form
RenderTarget11::~RenderTarget11() RenderTarget11::~RenderTarget11()
{ {
ASSERT(mBroadcastChannel.empty()); ASSERT(!hasObservers());
} }
void RenderTarget11::signalDirty(const gl::Context *context) void RenderTarget11::signalDirty(const gl::Context *context)
{ {
mBroadcastChannel.signal(context); onStateChange(context, angle::SubjectMessage::STATE_CHANGE);
// Clear the list. We can't do this in the receiver because it would mutate during iteration. // Clear the list. We can't do this in the receiver because it would mutate during iteration.
mBroadcastChannel.reset(); resetObservers();
} }
TextureRenderTarget11::TextureRenderTarget11(d3d11::RenderTargetView &&rtv, TextureRenderTarget11::TextureRenderTarget11(d3d11::RenderTargetView &&rtv,
......
...@@ -20,7 +20,7 @@ namespace rx ...@@ -20,7 +20,7 @@ namespace rx
class SwapChain11; class SwapChain11;
class Renderer11; class Renderer11;
class RenderTarget11 : public RenderTargetD3D class RenderTarget11 : public RenderTargetD3D, public angle::Subject
{ {
public: public:
RenderTarget11(const d3d11::Format &formatSet); RenderTarget11(const d3d11::Format &formatSet);
...@@ -35,12 +35,10 @@ class RenderTarget11 : public RenderTargetD3D ...@@ -35,12 +35,10 @@ class RenderTarget11 : public RenderTargetD3D
virtual unsigned int getSubresourceIndex() const = 0; virtual unsigned int getSubresourceIndex() const = 0;
void signalDirty(const gl::Context *context) override; void signalDirty(const gl::Context *context) override;
OnRenderTargetDirtyChannel *getBroadcastChannel() { return &mBroadcastChannel; }
const d3d11::Format &getFormatSet() const { return mFormatSet; } const d3d11::Format &getFormatSet() const { return mFormatSet; }
protected: protected:
OnRenderTargetDirtyChannel mBroadcastChannel;
const d3d11::Format &mFormatSet; const d3d11::Format &mFormatSet;
}; };
......
...@@ -3263,8 +3263,10 @@ StateManager11::OnConstantBufferDirtyReceiver::~OnConstantBufferDirtyReceiver() ...@@ -3263,8 +3263,10 @@ StateManager11::OnConstantBufferDirtyReceiver::~OnConstantBufferDirtyReceiver()
{ {
} }
void StateManager11::OnConstantBufferDirtyReceiver::signal(size_t messageID, void StateManager11::OnConstantBufferDirtyReceiver::onSubjectStateChange(
const gl::Context *context) const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{ {
StateManager11 *stateManager = GetImplAs<Context11>(context)->getRenderer()->getStateManager(); StateManager11 *stateManager = GetImplAs<Context11>(context)->getRenderer()->getStateManager();
stateManager->invalidateProgramUniformBuffers(); stateManager->invalidateProgramUniformBuffers();
...@@ -3274,24 +3276,24 @@ void StateManager11::OnConstantBufferDirtyReceiver::bindVS(size_t index, Buffer1 ...@@ -3274,24 +3276,24 @@ void StateManager11::OnConstantBufferDirtyReceiver::bindVS(size_t index, Buffer1
{ {
ASSERT(buffer); ASSERT(buffer);
ASSERT(index < mBindingsVS.size()); ASSERT(index < mBindingsVS.size());
mBindingsVS[index].bind(buffer->getDirectBroadcastChannel()); mBindingsVS[index].bind(buffer->getDirectSubject());
} }
void StateManager11::OnConstantBufferDirtyReceiver::bindPS(size_t index, Buffer11 *buffer) void StateManager11::OnConstantBufferDirtyReceiver::bindPS(size_t index, Buffer11 *buffer)
{ {
ASSERT(buffer); ASSERT(buffer);
ASSERT(index < mBindingsPS.size()); ASSERT(index < mBindingsPS.size());
mBindingsPS[index].bind(buffer->getDirectBroadcastChannel()); mBindingsPS[index].bind(buffer->getDirectSubject());
} }
void StateManager11::OnConstantBufferDirtyReceiver::reset() void StateManager11::OnConstantBufferDirtyReceiver::reset()
{ {
for (OnBufferDataDirtyBinding &vsBinding : mBindingsVS) for (angle::ObserverBinding &vsBinding : mBindingsVS)
{ {
vsBinding.bind(nullptr); vsBinding.bind(nullptr);
} }
for (OnBufferDataDirtyBinding &psBinding : mBindingsPS) for (angle::ObserverBinding &psBinding : mBindingsPS)
{ {
psBinding.bind(nullptr); psBinding.bind(nullptr);
} }
......
...@@ -566,21 +566,23 @@ class StateManager11 final : angle::NonCopyable ...@@ -566,21 +566,23 @@ class StateManager11 final : angle::NonCopyable
FragmentConstantBufferArray<GLintptr> mCurrentConstantBufferPSOffset; FragmentConstantBufferArray<GLintptr> mCurrentConstantBufferPSOffset;
FragmentConstantBufferArray<GLsizeiptr> mCurrentConstantBufferPSSize; FragmentConstantBufferArray<GLsizeiptr> mCurrentConstantBufferPSSize;
class OnConstantBufferDirtyReceiver : public OnBufferDataDirtyReceiver class OnConstantBufferDirtyReceiver : public angle::ObserverInterface
{ {
public: public:
OnConstantBufferDirtyReceiver(); OnConstantBufferDirtyReceiver();
~OnConstantBufferDirtyReceiver() override; ~OnConstantBufferDirtyReceiver() override;
void signal(size_t messageID, const gl::Context *context) override; void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
void reset(); void reset();
void bindVS(size_t index, Buffer11 *buffer); void bindVS(size_t index, Buffer11 *buffer);
void bindPS(size_t index, Buffer11 *buffer); void bindPS(size_t index, Buffer11 *buffer);
private: private:
std::vector<OnBufferDataDirtyBinding> mBindingsVS; std::vector<angle::ObserverBinding> mBindingsVS;
std::vector<OnBufferDataDirtyBinding> mBindingsPS; std::vector<angle::ObserverBinding> mBindingsPS;
}; };
OnConstantBufferDirtyReceiver mOnConstantBufferDirtyReceiver; OnConstantBufferDirtyReceiver mOnConstantBufferDirtyReceiver;
......
...@@ -21,17 +21,16 @@ namespace rx ...@@ -21,17 +21,16 @@ namespace rx
namespace namespace
{ {
OnBufferDataDirtyChannel *GetBufferBroadcastChannel(Buffer11 *buffer11, angle::Subject *GetBufferSubject(Buffer11 *buffer11, IndexStorageType storageType)
IndexStorageType storageType)
{ {
switch (storageType) switch (storageType)
{ {
case IndexStorageType::Direct: case IndexStorageType::Direct:
return buffer11->getDirectBroadcastChannel(); return buffer11->getDirectSubject();
case IndexStorageType::Static: case IndexStorageType::Static:
return buffer11->getStaticBroadcastChannel(); return buffer11->getStaticSubject();
case IndexStorageType::Dynamic: case IndexStorageType::Dynamic:
return buffer11 ? buffer11->getStaticBroadcastChannel() : nullptr; return buffer11 ? buffer11->getStaticSubject() : nullptr;
default: default:
UNREACHABLE(); UNREACHABLE();
return nullptr; return nullptr;
...@@ -157,10 +156,10 @@ bool VertexArray11::updateElementArrayStorage(const gl::Context *context, ...@@ -157,10 +156,10 @@ bool VertexArray11::updateElementArrayStorage(const gl::Context *context,
{ {
Buffer11 *newBuffer11 = SafeGetImplAs<Buffer11>(newBuffer); Buffer11 *newBuffer11 = SafeGetImplAs<Buffer11>(newBuffer);
auto *newChannel = GetBufferBroadcastChannel(newBuffer11, newStorageType); angle::Subject *subject = GetBufferSubject(newBuffer11, newStorageType);
mCurrentElementArrayStorage = newStorageType; mCurrentElementArrayStorage = newStorageType;
mOnElementArrayBufferDataDirty.bind(newChannel); mOnElementArrayBufferDataDirty.bind(subject);
needsTranslation = true; needsTranslation = true;
} }
...@@ -222,7 +221,7 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t ...@@ -222,7 +221,7 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t
if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType) if (oldBuffer11 != newBuffer11 || oldStorageType != newStorageType)
{ {
OnBufferDataDirtyChannel *newChannel = nullptr; angle::Subject *subject = nullptr;
if (newStorageType == VertexStorageType::CURRENT_VALUE) if (newStorageType == VertexStorageType::CURRENT_VALUE)
{ {
...@@ -235,11 +234,11 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t ...@@ -235,11 +234,11 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t
switch (newStorageType) switch (newStorageType)
{ {
case VertexStorageType::DIRECT: case VertexStorageType::DIRECT:
newChannel = newBuffer11->getDirectBroadcastChannel(); subject = newBuffer11->getDirectSubject();
break; break;
case VertexStorageType::STATIC: case VertexStorageType::STATIC:
case VertexStorageType::DYNAMIC: case VertexStorageType::DYNAMIC:
newChannel = newBuffer11->getStaticBroadcastChannel(); subject = newBuffer11->getStaticSubject();
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -247,7 +246,7 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t ...@@ -247,7 +246,7 @@ void VertexArray11::updateVertexAttribStorage(const gl::Context *context, size_t
} }
} }
mOnArrayBufferDataDirty[attribIndex].bind(newChannel); mOnArrayBufferDataDirty[attribIndex].bind(subject);
mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get()); mCurrentArrayBuffers[attribIndex].set(context, binding.getBuffer().get());
} }
} }
...@@ -348,9 +347,11 @@ const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() co ...@@ -348,9 +347,11 @@ const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() co
return mTranslatedAttribs; return mTranslatedAttribs;
} }
void VertexArray11::signal(size_t channelID, const gl::Context *context) void VertexArray11::onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message)
{ {
if (channelID == mAttributeStorageTypes.size()) if (index == mAttributeStorageTypes.size())
{ {
mCachedIndexInfoValid = false; mCachedIndexInfoValid = false;
mLastElementType = GL_NONE; mLastElementType = GL_NONE;
...@@ -358,10 +359,10 @@ void VertexArray11::signal(size_t channelID, const gl::Context *context) ...@@ -358,10 +359,10 @@ void VertexArray11::signal(size_t channelID, const gl::Context *context)
} }
else else
{ {
ASSERT(mAttributeStorageTypes[channelID] != VertexStorageType::CURRENT_VALUE); ASSERT(mAttributeStorageTypes[index] != VertexStorageType::CURRENT_VALUE);
// This can change a buffer's storage, we'll need to re-check. // This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(channelID); mAttribsToUpdate.set(index);
// Changing the vertex attribute state can affect the vertex shader. // Changing the vertex attribute state can affect the vertex shader.
Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer(); Renderer11 *renderer = GetImplAs<Context11>(context)->getRenderer();
......
...@@ -19,7 +19,7 @@ namespace rx ...@@ -19,7 +19,7 @@ namespace rx
{ {
class Renderer11; class Renderer11;
class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver class VertexArray11 : public VertexArrayImpl, public angle::ObserverInterface
{ {
public: public:
VertexArray11(const gl::VertexArrayState &data); VertexArray11(const gl::VertexArrayState &data);
...@@ -38,8 +38,10 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver ...@@ -38,8 +38,10 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
const std::vector<TranslatedAttribute> &getTranslatedAttribs() const; const std::vector<TranslatedAttribute> &getTranslatedAttribs() const;
// SignalReceiver implementation // Observer implementation
void signal(size_t channelID, const gl::Context *context) override; void onSubjectStateChange(const gl::Context *context,
angle::SubjectIndex index,
angle::SubjectMessage message) override;
Serial getCurrentStateSerial() const { return mCurrentStateSerial; } Serial getCurrentStateSerial() const { return mCurrentStateSerial; }
...@@ -78,8 +80,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver ...@@ -78,8 +80,8 @@ class VertexArray11 : public VertexArrayImpl, public OnBufferDataDirtyReceiver
std::vector<gl::BindingPointer<gl::Buffer>> mCurrentArrayBuffers; std::vector<gl::BindingPointer<gl::Buffer>> mCurrentArrayBuffers;
gl::BindingPointer<gl::Buffer> mCurrentElementArrayBuffer; gl::BindingPointer<gl::Buffer> mCurrentElementArrayBuffer;
std::vector<OnBufferDataDirtyBinding> mOnArrayBufferDataDirty; std::vector<angle::ObserverBinding> mOnArrayBufferDataDirty;
OnBufferDataDirtyBinding mOnElementArrayBufferDataDirty; angle::ObserverBinding mOnElementArrayBufferDataDirty;
Serial mCurrentStateSerial; Serial mCurrentStateSerial;
......
...@@ -424,16 +424,6 @@ IndexStorageType ClassifyIndexStorage(const gl::State &glState, ...@@ -424,16 +424,6 @@ IndexStorageType ClassifyIndexStorage(const gl::State &glState,
unsigned int offset, unsigned int offset,
bool *needsTranslation); bool *needsTranslation);
// Used for state change notifications between buffers and vertex arrays.
using OnBufferDataDirtyBinding = angle::ChannelBinding<size_t, const gl::Context *>;
using OnBufferDataDirtyChannel = angle::BroadcastChannel<size_t, const gl::Context *>;
using OnBufferDataDirtyReceiver = angle::SignalReceiver<size_t, const gl::Context *>;
// Used for state change notifications between RenderTarget11 and Framebuffer11.
using OnRenderTargetDirtyBinding = angle::ChannelBinding<size_t, const gl::Context *>;
using OnRenderTargetDirtyChannel = angle::BroadcastChannel<size_t, const gl::Context *>;
using OnRenderTargetDirtyReceiver = angle::SignalReceiver<size_t, const gl::Context *>;
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ #endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
//
// Copyright 2018 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.
//
// signal_utils:
// 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/
#include "libANGLE/signal_utils.h"
#include "common/debug.h"
namespace angle
{
// Observer implementation.
ObserverInterface::~ObserverInterface() = default;
// Subject implementation.
Subject::Subject()
{
}
Subject::~Subject()
{
resetObservers();
}
bool Subject::hasObservers() const
{
return !mObservers.empty();
}
void Subject::addObserver(ObserverBinding *observer)
{
ASSERT(std::find(mObservers.begin(), mObservers.end(), observer) == mObservers.end());
mObservers.push_back(observer);
}
void Subject::removeObserver(ObserverBinding *observer)
{
auto iter = std::find(mObservers.begin(), mObservers.end(), observer);
ASSERT(iter != mObservers.end());
mObservers.erase(iter);
}
void Subject::onStateChange(const gl::Context *context, SubjectMessage message) const
{
if (mObservers.empty())
return;
for (const angle::ObserverBinding *receiver : mObservers)
{
receiver->onStateChange(context, message);
}
}
void Subject::resetObservers()
{
for (angle::ObserverBinding *observer : mObservers)
{
observer->onSubjectReset();
}
mObservers.clear();
}
// ObserverBinding implementation.
ObserverBinding::ObserverBinding(ObserverInterface *observer, SubjectIndex index)
: mSubject(nullptr), mObserver(observer), mIndex(index)
{
ASSERT(observer);
}
ObserverBinding::~ObserverBinding()
{
reset();
}
ObserverBinding::ObserverBinding(const ObserverBinding &other) = default;
ObserverBinding &ObserverBinding::operator=(const ObserverBinding &other) = default;
void ObserverBinding::bind(Subject *subject)
{
ASSERT(mObserver);
if (mSubject)
{
mSubject->removeObserver(this);
}
mSubject = subject;
if (mSubject)
{
mSubject->addObserver(this);
}
}
void ObserverBinding::reset()
{
bind(nullptr);
}
void ObserverBinding::onStateChange(const gl::Context *context, SubjectMessage message) const
{
mObserver->onSubjectStateChange(context, mIndex, message);
}
void ObserverBinding::onSubjectReset()
{
mSubject = nullptr;
}
} // namespace angle
...@@ -4,184 +4,84 @@ ...@@ -4,184 +4,84 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// signal_utils: // signal_utils:
// Helper classes for tracking dependent state changes between objects. // Implements the Observer pattern for sending state change notifications
// These changes are signaled to the dependent class via channels. // from Subject objects to dependent Observer objects.
//
// See design document: // See design document:
// https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/ // https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/
#ifndef LIBANGLE_SIGNAL_UTILS_H_ #ifndef LIBANGLE_SIGNAL_UTILS_H_
#define LIBANGLE_SIGNAL_UTILS_H_ #define LIBANGLE_SIGNAL_UTILS_H_
#include <set>
#include "common/angleutils.h" #include "common/angleutils.h"
#include "common/debug.h"
namespace angle namespace gl
{ {
class Context;
} // namespace gl
// Interface that the depending class inherits from. namespace angle
template <typename ChannelID = uint32_t, typename... MessageT>
class SignalReceiver
{ {
public:
virtual ~SignalReceiver() = default;
virtual void signal(ChannelID channelID, MessageT... message) = 0;
};
template <typename ChannelID, typename... MessageT> using SubjectIndex = size_t;
class ChannelBinding;
// The host class owns the channel. It uses the channel to fire signals to the receiver. enum class SubjectMessage
template <typename ChannelID = uint32_t, typename... MessageT>
class BroadcastChannel final : NonCopyable
{ {
public: STATE_CHANGE,
BroadcastChannel();
~BroadcastChannel();
void signal(MessageT... message) const;
void reset();
bool empty() const;
private:
// Only the ChannelBinding class should add or remove receivers.
friend class ChannelBinding<ChannelID, MessageT...>;
void addReceiver(ChannelBinding<ChannelID, MessageT...> *receiver);
void removeReceiver(ChannelBinding<ChannelID, MessageT...> *receiver);
std::vector<ChannelBinding<ChannelID, MessageT...> *> mReceivers;
}; };
template <typename ChannelID, typename... MessageT> // The observing class inherits from this interface class.
BroadcastChannel<ChannelID, MessageT...>::BroadcastChannel() class ObserverInterface
{ {
} public:
virtual ~ObserverInterface();
template <typename ChannelID, typename... MessageT> virtual void onSubjectStateChange(const gl::Context *context,
BroadcastChannel<ChannelID, MessageT...>::~BroadcastChannel() SubjectIndex index,
{ SubjectMessage message) = 0;
reset(); };
}
template <typename ChannelID, typename... MessageT> class ObserverBinding;
void BroadcastChannel<ChannelID, MessageT...>::addReceiver(
ChannelBinding<ChannelID, MessageT...> *receiver)
{
ASSERT(std::find(mReceivers.begin(), mReceivers.end(), receiver) == mReceivers.end());
mReceivers.push_back(receiver);
}
template <typename ChannelID, typename... MessageT> // Maintains a list of observer bindings. Sends update messages to the observer.
void BroadcastChannel<ChannelID, MessageT...>::removeReceiver( class Subject : NonCopyable
ChannelBinding<ChannelID, MessageT...> *receiver)
{ {
auto iter = std::find(mReceivers.begin(), mReceivers.end(), receiver); public:
ASSERT(iter != mReceivers.end()); Subject();
mReceivers.erase(iter); virtual ~Subject();
}
template <typename ChannelID, typename... MessageT> void onStateChange(const gl::Context *context, SubjectMessage message) const;
void BroadcastChannel<ChannelID, MessageT...>::signal(MessageT... message) const bool hasObservers() const;
{ void resetObservers();
if (mReceivers.empty())
return;
for (const auto *receiver : mReceivers) private:
{ // Only the ObserverBinding class should add or remove observers.
receiver->signal(message...); friend class ObserverBinding;
} void addObserver(ObserverBinding *observer);
} void removeObserver(ObserverBinding *observer);
template <typename ChannelID, typename... MessageT> std::vector<ObserverBinding *> mObservers;
void BroadcastChannel<ChannelID, MessageT...>::reset() };
{
for (auto receiver : mReceivers)
{
receiver->onChannelClosed();
}
mReceivers.clear();
}
template <typename ChannelID, typename... MessageT>
bool BroadcastChannel<ChannelID, MessageT...>::empty() const
{
return mReceivers.empty();
}
// The dependent class keeps bindings to the host's BroadcastChannel. // Keeps a binding between a Subject and Observer, with a specific subject index.
template <typename ChannelID = uint32_t, typename... MessageT> class ObserverBinding final
class ChannelBinding final
{ {
public: public:
ChannelBinding(SignalReceiver<ChannelID, MessageT...> *receiver, ChannelID channelID); ObserverBinding(ObserverInterface *observer, SubjectIndex index);
~ChannelBinding(); ~ObserverBinding();
ChannelBinding(const ChannelBinding &other) = default; ObserverBinding(const ObserverBinding &other);
ChannelBinding &operator=(const ChannelBinding &other) = default; ObserverBinding &operator=(const ObserverBinding &other);
void bind(BroadcastChannel<ChannelID, MessageT...> *channel); void bind(Subject *subject);
void reset(); void reset();
void signal(MessageT... message) const; void onStateChange(const gl::Context *context, SubjectMessage message) const;
void onChannelClosed(); void onSubjectReset();
private: private:
BroadcastChannel<ChannelID, MessageT...> *mChannel; Subject *mSubject;
SignalReceiver<ChannelID, MessageT...> *mReceiver; ObserverInterface *mObserver;
ChannelID mChannelID; SubjectIndex mIndex;
}; };
template <typename ChannelID, typename... MessageT>
ChannelBinding<ChannelID, MessageT...>::ChannelBinding(
SignalReceiver<ChannelID, MessageT...> *receiver,
ChannelID channelID)
: mChannel(nullptr), mReceiver(receiver), mChannelID(channelID)
{
ASSERT(receiver);
}
template <typename ChannelID, typename... MessageT>
ChannelBinding<ChannelID, MessageT...>::~ChannelBinding()
{
reset();
}
template <typename ChannelID, typename... MessageT>
void ChannelBinding<ChannelID, MessageT...>::bind(BroadcastChannel<ChannelID, MessageT...> *channel)
{
ASSERT(mReceiver);
if (mChannel)
{
mChannel->removeReceiver(this);
}
mChannel = channel;
if (mChannel)
{
mChannel->addReceiver(this);
}
}
template <typename ChannelID, typename... MessageT>
void ChannelBinding<ChannelID, MessageT...>::reset()
{
bind(nullptr);
}
template <typename ChannelID, typename... MessageT>
void ChannelBinding<ChannelID, MessageT...>::signal(MessageT... message) const
{
mReceiver->signal(mChannelID, message...);
}
template <typename ChannelID, typename... MessageT>
void ChannelBinding<ChannelID, MessageT...>::onChannelClosed()
{
mChannel = nullptr;
}
} // namespace angle } // namespace angle
#endif // LIBANGLE_SIGNAL_UTILS_H_ #endif // LIBANGLE_SIGNAL_UTILS_H_
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// signal_utils_unittest: // signal_utils_unittest:
// Unit tests for signals and related utils. // Unit tests for Observers and related classes.
#include <gtest/gtest.h> #include <gtest/gtest.h>
...@@ -16,23 +16,28 @@ using namespace testing; ...@@ -16,23 +16,28 @@ using namespace testing;
namespace namespace
{ {
struct SignalThing : public SignalReceiver<> struct ObserverClass : public ObserverInterface
{ {
void signal(uint32_t channelID) override { wasSignaled = true; } void onSubjectStateChange(const gl::Context *context,
bool wasSignaled = false; SubjectIndex index,
SubjectMessage message) override
{
wasNotified = true;
}
bool wasNotified = false;
}; };
// Test that broadcast signals work. // Test that Observer/Subject state change notifications work.
TEST(SignalTest, BroadcastSignals) TEST(ObserverTest, BasicUsage)
{ {
BroadcastChannel<> channel; Subject subject;
SignalThing thing; ObserverClass observer;
ChannelBinding<> binding(&thing, 0u); ObserverBinding binding(&observer, 0u);
binding.bind(&channel); binding.bind(&subject);
ASSERT_FALSE(thing.wasSignaled); ASSERT_FALSE(observer.wasNotified);
channel.signal(); subject.onStateChange(nullptr, SubjectMessage::STATE_CHANGE);
ASSERT_TRUE(thing.wasSignaled); ASSERT_TRUE(observer.wasNotified);
} }
} // anonymous namespace } // anonymous namespace
...@@ -284,6 +284,7 @@ ...@@ -284,6 +284,7 @@
'libANGLE/renderer/load_functions_table_autogen.cpp', 'libANGLE/renderer/load_functions_table_autogen.cpp',
'libANGLE/renderer/renderer_utils.cpp', 'libANGLE/renderer/renderer_utils.cpp',
'libANGLE/renderer/renderer_utils.h', 'libANGLE/renderer/renderer_utils.h',
'libANGLE/signal_utils.cpp',
'libANGLE/signal_utils.h', 'libANGLE/signal_utils.h',
'libANGLE/validationEGL.cpp', 'libANGLE/validationEGL.cpp',
'libANGLE/validationEGL.h', 'libANGLE/validationEGL.h',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment