Commit e02a6834 by Jamie Madill Committed by Commit Bot

Refactor how we signal dependent state changes.

Dependent state changes happen when the user calls TexImage on a Texture attached to a Framebuffer. The Framebuffer should be told 'hey, you should know about this'. Other objects also have dependent relationships, like VertexArrays and Buffers. This refactoring uses a binding pointer design, similar to the type 'RefCountObject'. This design fixes the need for manual decoupling when one or the other is destroyed. The pointers are cleaned up in destructors, and do no-ops when either the source or dest is missing. Also move these new classes to a location where they are accessible to the GL layer; they will be important for framebuffer completeness. BUG=angleproject:1388 Change-Id: I92610acb85dae6f9c009b8f071e121fde53782ae Reviewed-on: https://chromium-review.googlesource.com/348953Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent d2b50a0b
......@@ -118,7 +118,9 @@ class Buffer11::BufferStorage : angle::NonCopyable
class Buffer11::NativeStorage : public Buffer11::BufferStorage
{
public:
NativeStorage(Renderer11 *renderer, BufferUsage usage, const NotificationSet *onStorageChanged);
NativeStorage(Renderer11 *renderer,
BufferUsage usage,
const angle::BroadcastChannel *onStorageChanged);
~NativeStorage() override;
bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; }
......@@ -143,7 +145,7 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage
unsigned int bufferSize);
ID3D11Buffer *mNativeStorage;
const NotificationSet *mOnStorageChanged;
const angle::BroadcastChannel *mOnStorageChanged;
};
// A emulated indexed buffer storage represents an underlying D3D11 buffer for data
......@@ -666,7 +668,7 @@ Buffer11::BufferStorage *Buffer11::allocateStorage(BufferUsage usage)
case BUFFER_USAGE_EMULATED_INDEXED_VERTEX:
return new EmulatedIndexedStorage(mRenderer);
case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK:
return new NativeStorage(mRenderer, usage, &mDirectBufferDirtyCallbacks);
return new NativeStorage(mRenderer, usage, &mDirectBroadcastChannel);
default:
return new NativeStorage(mRenderer, usage, nullptr);
}
......@@ -822,7 +824,7 @@ void Buffer11::initializeStaticData()
BufferD3D::initializeStaticData();
// Notify when static data changes.
mStaticBufferDirtyCallbacks.signal();
mStaticBroadcastChannel.signal();
}
void Buffer11::invalidateStaticData()
......@@ -830,27 +832,17 @@ void Buffer11::invalidateStaticData()
BufferD3D::invalidateStaticData();
// Notify when static data changes.
mStaticBufferDirtyCallbacks.signal();
mStaticBroadcastChannel.signal();
}
void Buffer11::addStaticBufferDirtyCallback(const NotificationCallback *callback)
angle::BroadcastChannel *Buffer11::getStaticBroadcastChannel()
{
mStaticBufferDirtyCallbacks.add(callback);
return &mStaticBroadcastChannel;
}
void Buffer11::removeStaticBufferDirtyCallback(const NotificationCallback *callback)
angle::BroadcastChannel *Buffer11::getDirectBroadcastChannel()
{
mStaticBufferDirtyCallbacks.remove(callback);
}
void Buffer11::addDirectBufferDirtyCallback(const NotificationCallback *callback)
{
mDirectBufferDirtyCallbacks.add(callback);
}
void Buffer11::removeDirectBufferDirtyCallback(const NotificationCallback *callback)
{
mDirectBufferDirtyCallbacks.remove(callback);
return &mDirectBroadcastChannel;
}
Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage)
......@@ -874,7 +866,7 @@ gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, s
Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer,
BufferUsage usage,
const NotificationSet *onStorageChanged)
const angle::BroadcastChannel *onStorageChanged)
: BufferStorage(renderer, usage), mNativeStorage(nullptr), mOnStorageChanged(onStorageChanged)
{
}
......
......@@ -13,7 +13,7 @@
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/signal_utils.h"
namespace gl
{
......@@ -79,14 +79,11 @@ class Buffer11 : public BufferD3D
gl::Error unmap(GLboolean *result) override;
gl::Error markTransformFeedbackUsage() override;
// We use two set of dirty callbacks for two events. Static buffers are marked dirty whenever
// the data is changed, because they must be re-translated. Direct buffers only need to be
// 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
// updated when the underlying ID3D11Buffer pointer changes - hopefully far less often.
void addStaticBufferDirtyCallback(const NotificationCallback *callback);
void removeStaticBufferDirtyCallback(const NotificationCallback *callback);
void addDirectBufferDirtyCallback(const NotificationCallback *callback);
void removeDirectBufferDirtyCallback(const NotificationCallback *callback);
angle::BroadcastChannel *getStaticBroadcastChannel();
angle::BroadcastChannel *getDirectBroadcastChannel();
private:
class BufferStorage;
......@@ -139,8 +136,8 @@ class Buffer11 : public BufferD3D
unsigned int mReadUsageCount;
unsigned int mSystemMemoryDeallocThreshold;
NotificationSet mStaticBufferDirtyCallbacks;
NotificationSet mDirectBufferDirtyCallbacks;
angle::BroadcastChannel mStaticBroadcastChannel;
angle::BroadcastChannel mDirectBroadcastChannel;
};
} // namespace rx
......
......@@ -22,6 +22,8 @@
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Texture.h"
using namespace angle;
namespace rx
{
......@@ -56,7 +58,7 @@ gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachme
void UpdateCachedRenderTarget(const gl::FramebufferAttachment *attachment,
RenderTarget11 *&cachedRenderTarget,
const NotificationCallback &callbackFunc)
ChannelBinding *channelBinding)
{
RenderTarget11 *newRenderTarget = nullptr;
if (attachment)
......@@ -65,54 +67,30 @@ void UpdateCachedRenderTarget(const gl::FramebufferAttachment *attachment,
}
if (newRenderTarget != cachedRenderTarget)
{
if (cachedRenderTarget)
{
cachedRenderTarget->removeDirtyCallback(&callbackFunc);
}
if (newRenderTarget)
{
newRenderTarget->addDirtyCallback(&callbackFunc);
}
auto channel = (newRenderTarget ? newRenderTarget->getBroadcastChannel() : nullptr);
channelBinding->bind(channel);
cachedRenderTarget = newRenderTarget;
}
}
} // anonymous namespace
Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer)
: FramebufferD3D(data, renderer), mRenderer(renderer), mCachedDepthStencilRenderTarget(nullptr)
: FramebufferD3D(data, renderer),
mRenderer(renderer),
mCachedDepthStencilRenderTarget(nullptr),
mDepthStencilRenderTargetDirty(this, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
{
ASSERT(mRenderer != nullptr);
mCachedColorRenderTargets.fill(nullptr);
for (size_t colorIndex = 0; colorIndex < data.getColorAttachments().size(); ++colorIndex)
{
auto callback = [this, colorIndex]()
{
this->markColorRenderTargetDirty(colorIndex);
};
mColorRenderTargetsDirty.push_back(callback);
mColorRenderTargetsDirty.push_back(
ChannelBinding(this, static_cast<SignalToken>(colorIndex)));
}
mDepthStencilRenderTargetDirty = [this]()
{
this->markDepthStencilRenderTargetDirty();
};
}
Framebuffer11::~Framebuffer11()
{
for (size_t colorIndex = 0; colorIndex < mCachedColorRenderTargets.size(); ++colorIndex)
{
auto *colorRenderTarget = mCachedColorRenderTargets[colorIndex];
if (colorRenderTarget)
{
colorRenderTarget->removeDirtyCallback(&mColorRenderTargetsDirty[colorIndex]);
}
}
if (mCachedDepthStencilRenderTarget)
{
mCachedDepthStencilRenderTarget->removeDirtyCallback(&mDepthStencilRenderTargetDirty);
}
}
gl::Error Framebuffer11::invalidateSwizzles() const
......@@ -488,13 +466,13 @@ void Framebuffer11::updateColorRenderTarget(size_t colorIndex)
{
UpdateCachedRenderTarget(mState.getColorAttachment(colorIndex),
mCachedColorRenderTargets[colorIndex],
mColorRenderTargetsDirty[colorIndex]);
&mColorRenderTargetsDirty[colorIndex]);
}
void Framebuffer11::updateDepthStencilRenderTarget()
{
UpdateCachedRenderTarget(mState.getDepthOrStencilAttachment(), mCachedDepthStencilRenderTarget,
mDepthStencilRenderTargetDirty);
&mDepthStencilRenderTargetDirty);
}
void Framebuffer11::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
......@@ -504,7 +482,7 @@ void Framebuffer11::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits;
mInternalDirtyBits.reset();
for (auto dirtyBit : angle::IterateBitSet(mergedDirtyBits))
for (auto dirtyBit : IterateBitSet(mergedDirtyBits))
{
switch (dirtyBit)
{
......@@ -533,17 +511,19 @@ void Framebuffer11::syncState(const gl::Framebuffer::DirtyBits &dirtyBits)
FramebufferD3D::syncState(dirtyBits);
}
void Framebuffer11::markColorRenderTargetDirty(size_t colorIndex)
{
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex);
mCachedColorRenderTargets[colorIndex] = nullptr;
}
void Framebuffer11::markDepthStencilRenderTargetDirty()
void Framebuffer11::signal(SignalToken token)
{
// Stencil is redundant in this case.
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT);
mCachedDepthStencilRenderTarget = nullptr;
if (token == gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS)
{
// Stencil is redundant in this case.
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT);
mCachedDepthStencilRenderTarget = nullptr;
}
else
{
mInternalDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + token);
mCachedColorRenderTargets[token] = nullptr;
}
}
bool Framebuffer11::hasAnyInternalDirtyBit() const
......
......@@ -11,12 +11,13 @@
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/signal_utils.h"
namespace rx
{
class Renderer11;
class Framebuffer11 : public FramebufferD3D
class Framebuffer11 : public FramebufferD3D, public angle::SignalReceiver
{
public:
Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer);
......@@ -40,13 +41,12 @@ class Framebuffer11 : public FramebufferD3D
return mCachedDepthStencilRenderTarget;
}
void markColorRenderTargetDirty(size_t colorIndex);
void markDepthStencilRenderTargetDirty();
bool hasAnyInternalDirtyBit() const;
// TODO(jmadill): make this non-const
void syncInternalState() const;
void signal(angle::SignalToken token) override;
private:
gl::Error clearImpl(ContextImpl *context, const ClearParameters &clearParams) override;
......@@ -77,8 +77,8 @@ class Framebuffer11 : public FramebufferD3D
RenderTargetArray mCachedColorRenderTargets;
RenderTarget11 *mCachedDepthStencilRenderTarget;
std::vector<NotificationCallback> mColorRenderTargetsDirty;
NotificationCallback mDepthStencilRenderTargetDirty;
std::vector<angle::ChannelBinding> mColorRenderTargetsDirty;
angle::ChannelBinding mDepthStencilRenderTargetDirty;
gl::Framebuffer::DirtyBits mInternalDirtyBits;
};
......
......@@ -187,22 +187,12 @@ RenderTarget11::~RenderTarget11()
signalDirty();
}
void RenderTarget11::addDirtyCallback(const NotificationCallback *callback)
{
mDirtyCallbacks.add(callback);
}
void RenderTarget11::removeDirtyCallback(const NotificationCallback *callback)
{
mDirtyCallbacks.remove(callback);
}
void RenderTarget11::signalDirty()
{
mDirtyCallbacks.signal();
mBroadcastChannel.signal();
// Clear the signal list. We can't do this in the callback because it mutates the iterator.
mDirtyCallbacks.clear();
// Clear the list. We can't do this in the receiver because it would mutate during iteration.
mBroadcastChannel.reset();
}
TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv,
......
......@@ -11,9 +11,9 @@
#define LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_
#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/signal_utils.h"
namespace rx
{
......@@ -34,14 +34,13 @@ class RenderTarget11 : public RenderTargetD3D
virtual unsigned int getSubresourceIndex() const = 0;
void addDirtyCallback(const NotificationCallback *callback);
void removeDirtyCallback(const NotificationCallback *callback);
void signalDirty() override;
angle::BroadcastChannel *getBroadcastChannel() { return &mBroadcastChannel; }
d3d11::ANGLEFormat getANGLEFormat() const { return mANGLEFormat; }
protected:
NotificationSet mDirtyCallbacks;
angle::BroadcastChannel mBroadcastChannel;
d3d11::ANGLEFormat mANGLEFormat;
};
......@@ -132,6 +131,6 @@ class SurfaceRenderTarget11 : public RenderTarget11
bool mDepth;
};
}
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_
......@@ -12,6 +12,8 @@
#include "common/BitSetIterator.h"
#include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
using namespace angle;
namespace rx
{
......@@ -45,11 +47,7 @@ VertexArray11::VertexArray11(const gl::VertexArrayState &data)
{
for (size_t attribIndex = 0; attribIndex < mCurrentBuffers.size(); ++attribIndex)
{
auto callback = [this, attribIndex]()
{
this->markBufferDataDirty(attribIndex);
};
mOnBufferDataDirty.push_back(callback);
mOnBufferDataDirty.push_back(ChannelBinding(this, static_cast<SignalToken>(attribIndex)));
}
}
......@@ -59,7 +57,6 @@ VertexArray11::~VertexArray11()
{
if (mCurrentBuffers[attribIndex].get())
{
unlinkBuffer(attribIndex, mAttributeStorageTypes[attribIndex]);
mCurrentBuffers[attribIndex].set(nullptr);
}
}
......@@ -116,22 +113,23 @@ void VertexArray11::updateVertexAttribStorage(size_t attribIndex)
{
// Note that for static callbacks, promotion to a static buffer from a dynamic buffer means
// we need to tag dynamic buffers with static callbacks.
if (oldBuffer11 != nullptr)
{
unlinkBuffer(attribIndex, oldStorageType);
}
BroadcastChannel *newChannel = nullptr;
if (newBuffer11 != nullptr)
{
if (newStorageType == VertexStorageType::DIRECT)
{
newBuffer11->addDirectBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
else if (newStorageType == VertexStorageType::STATIC ||
newStorageType == VertexStorageType::DYNAMIC)
switch (newStorageType)
{
newBuffer11->addStaticBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
case VertexStorageType::DIRECT:
newChannel = newBuffer11->getDirectBroadcastChannel();
break;
case VertexStorageType::STATIC:
case VertexStorageType::DYNAMIC:
newChannel = newBuffer11->getStaticBroadcastChannel();
break;
default:
break;
}
}
mOnBufferDataDirty[attribIndex].bind(newChannel);
mCurrentBuffers[attribIndex] = attrib.buffer;
}
}
......@@ -230,12 +228,12 @@ const std::vector<TranslatedAttribute> &VertexArray11::getTranslatedAttribs() co
return mTranslatedAttribs;
}
void VertexArray11::markBufferDataDirty(size_t attribIndex)
void VertexArray11::signal(SignalToken token)
{
ASSERT(mAttributeStorageTypes[attribIndex] != VertexStorageType::CURRENT_VALUE);
ASSERT(mAttributeStorageTypes[token] != VertexStorageType::CURRENT_VALUE);
// This can change a buffer's storage, we'll need to re-check.
mAttribsToUpdate.set(attribIndex);
mAttribsToUpdate.set(token);
}
void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::State &state, GLsizei count)
......@@ -248,18 +246,4 @@ void VertexArray11::clearDirtyAndPromoteDynamicAttribs(const gl::State &state, G
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
VertexDataManager::PromoteDynamicAttribs(mTranslatedAttribs, activeDynamicAttribs, count);
}
void VertexArray11::unlinkBuffer(size_t attribIndex, VertexStorageType storageType)
{
Buffer11 *buffer = GetImplAs<Buffer11>(mCurrentBuffers[attribIndex].get());
if (storageType == VertexStorageType::DIRECT)
{
buffer->removeDirectBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
else if (storageType == VertexStorageType::STATIC || storageType == VertexStorageType::DYNAMIC)
{
buffer->removeStaticBufferDirtyCallback(&mOnBufferDataDirty[attribIndex]);
}
}
} // namespace rx
......@@ -11,12 +11,13 @@
#include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/signal_utils.h"
namespace rx
{
class Renderer11;
class VertexArray11 : public VertexArrayImpl
class VertexArray11 : public VertexArrayImpl, public angle::SignalReceiver
{
public:
VertexArray11(const gl::VertexArrayState &data);
......@@ -32,10 +33,11 @@ class VertexArray11 : public VertexArrayImpl
const std::vector<TranslatedAttribute> &getTranslatedAttribs() const;
// SignalReceiver implementation
void signal(angle::SignalToken token) override;
private:
void updateVertexAttribStorage(size_t attribIndex);
void markBufferDataDirty(size_t attribIndex);
void unlinkBuffer(size_t attribIndex, VertexStorageType storageType);
std::vector<VertexStorageType> mAttributeStorageTypes;
std::vector<TranslatedAttribute> mTranslatedAttribs;
......@@ -52,7 +54,7 @@ class VertexArray11 : public VertexArrayImpl
// We need to keep a safe pointer to the Buffer so we can attach the correct dirty callbacks.
std::vector<BindingPointer<gl::Buffer>> mCurrentBuffers;
std::vector<NotificationCallback> mOnBufferDataDirty;
std::vector<angle::ChannelBinding> mOnBufferDataDirty;
};
} // namespace rx
......
......@@ -1724,40 +1724,4 @@ bool UsePresentPathFast(const Renderer11 *renderer,
renderer->presentPathFastEnabled());
}
NotificationSet::NotificationSet()
{
}
NotificationSet::~NotificationSet()
{
}
void NotificationSet::add(const NotificationCallback *callback)
{
ASSERT(mCallbacks.count(callback) == 0);
mCallbacks.insert(callback);
}
void NotificationSet::remove(const NotificationCallback *callback)
{
ASSERT(mCallbacks.count(callback) == 1);
mCallbacks.erase(callback);
}
void NotificationSet::signal() const
{
if (mCallbacks.empty())
return;
for (const auto *callback : mCallbacks)
{
(*callback)();
}
}
void NotificationSet::clear()
{
mCallbacks.clear();
}
} // namespace rx
......@@ -404,23 +404,6 @@ gl::ErrorOrResult<TextureHelper11> CreateStagingTexture(GLenum textureType,
bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
using NotificationCallback = std::function<void()>;
class NotificationSet final : angle::NonCopyable
{
public:
NotificationSet();
~NotificationSet();
void add(const NotificationCallback *callback);
void remove(const NotificationCallback *callback);
void signal() const;
void clear();
private:
std::set<const NotificationCallback *> mCallbacks;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
//
// 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.
//
// signal_utils:
// Helper classes for tracking dependent state changes between objects.
// These changes are signaled to the dependent class via channels.
#include "libANGLE/signal_utils.h"
#include "common/debug.h"
namespace angle
{
BroadcastChannel::BroadcastChannel()
{
}
BroadcastChannel::~BroadcastChannel()
{
reset();
}
void BroadcastChannel::addReceiver(ChannelBinding *receiver)
{
ASSERT(mReceivers.count(receiver) == 0);
mReceivers.insert(receiver);
}
void BroadcastChannel::removeReceiver(ChannelBinding *receiver)
{
ASSERT(mReceivers.count(receiver) == 1);
mReceivers.erase(receiver);
}
void BroadcastChannel::signal() const
{
if (mReceivers.empty())
return;
for (const auto *receiver : mReceivers)
{
receiver->signal();
}
}
void BroadcastChannel::reset()
{
for (auto receiver : mReceivers)
{
receiver->onChannelClosed();
}
mReceivers.clear();
}
ChannelBinding::ChannelBinding(SignalReceiver *receiver, SignalToken token)
: mChannel(nullptr), mReceiver(receiver), mToken(token)
{
ASSERT(receiver);
}
ChannelBinding::~ChannelBinding()
{
reset();
}
void ChannelBinding::bind(BroadcastChannel *channel)
{
ASSERT(mReceiver);
if (mChannel)
{
mChannel->removeReceiver(this);
}
mChannel = channel;
if (mChannel)
{
mChannel->addReceiver(this);
}
}
void ChannelBinding::reset()
{
bind(nullptr);
}
void ChannelBinding::signal() const
{
mReceiver->signal(mToken);
}
void ChannelBinding::onChannelClosed()
{
mChannel = nullptr;
}
} // namespace angle
//
// 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.
//
// signal_utils:
// Helper classes for tracking dependent state changes between objects.
// These changes are signaled to the dependent class via channels.
#ifndef LIBANGLE_SIGNAL_UTILS_H_
#define LIBANGLE_SIGNAL_UTILS_H_
#include <set>
#include "common/angleutils.h"
namespace angle
{
// Message token passed to the receiver;
using SignalToken = uint32_t;
// Interface that the depending class inherits from.
class SignalReceiver
{
public:
virtual void signal(SignalToken token) = 0;
};
class ChannelBinding;
// The host class owns the channel. It uses the channel to fire signals to the receiver.
class BroadcastChannel final : NonCopyable
{
public:
BroadcastChannel();
~BroadcastChannel();
void signal() const;
void reset();
private:
// Only the ChannelBinding class should add or remove receivers.
friend class ChannelBinding;
void addReceiver(ChannelBinding *receiver);
void removeReceiver(ChannelBinding *receiver);
std::set<ChannelBinding *> mReceivers;
};
// The dependent class keeps bindings to the host's BroadcastChannel.
class ChannelBinding final
{
public:
ChannelBinding(SignalReceiver *receiver, SignalToken token);
~ChannelBinding();
ChannelBinding(const ChannelBinding &other) = default;
ChannelBinding &operator=(const ChannelBinding &other) = default;
void bind(BroadcastChannel *channel);
void reset();
void signal() const;
void onChannelClosed();
private:
BroadcastChannel *mChannel;
SignalReceiver *mReceiver;
SignalToken mToken;
};
} // namespace angle
#endif // LIBANGLE_SIGNAL_UTILS_H_
//
// Copyright (c) 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.
//
// signal_utils_unittest:
// Unit tests for signals and related utils.
#include <gtest/gtest.h>
#include "libANGLE/signal_utils.h"
using namespace angle;
using namespace testing;
namespace
{
struct SignalThing : public SignalReceiver
{
void signal(SignalToken token) override { wasSignaled = true; }
bool wasSignaled = false;
};
// Test that broadcast signals work.
TEST(SignalTest, BroadcastSignals)
{
BroadcastChannel channel;
SignalThing thing;
ChannelBinding binding(&thing, 0u);
binding.bind(&channel);
ASSERT_FALSE(thing.wasSignaled);
channel.signal();
ASSERT_TRUE(thing.wasSignaled);
}
} // anonymous namespace
......@@ -172,6 +172,8 @@
'libANGLE/renderer/imageformats.h',
'libANGLE/renderer/renderer_utils.cpp',
'libANGLE/renderer/renderer_utils.h',
'libANGLE/signal_utils.cpp',
'libANGLE/signal_utils.h',
'libANGLE/validationEGL.cpp',
'libANGLE/validationEGL.h',
'libANGLE/validationES.cpp',
......
......@@ -30,7 +30,6 @@
'<(angle_path)/src/libANGLE/ResourceManager_unittest.cpp',
'<(angle_path)/src/libANGLE/Surface_unittest.cpp',
'<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp',
'<(angle_path)/src/libANGLE/validationES_unittest.cpp',
'<(angle_path)/src/libANGLE/renderer/BufferImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/FramebufferImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/ProgramImpl_mock.h',
......@@ -38,6 +37,8 @@
'<(angle_path)/src/libANGLE/renderer/ImageImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/TextureImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/TransformFeedbackImpl_mock.h',
'<(angle_path)/src/libANGLE/signal_utils_unittest.cpp',
'<(angle_path)/src/libANGLE/validationES_unittest.cpp',
'<(angle_path)/src/tests/angle_unittests_utils.h',
'<(angle_path)/src/tests/compiler_tests/API_test.cpp',
'<(angle_path)/src/tests/compiler_tests/BuiltInFunctionEmulator_test.cpp',
......
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