Edit

kc3-lang/angle/src/libANGLE/signal_utils.h

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2017-09-20 13:20:30
    Hash : ea84f6ff
    Message : Pass Context to Framebuffer11 dirty callback. This allows us to call StateManager11::invalidateRenderTarget from the Framebuffer11::signal function, which will then trigger state refresh on the next draw call. This requires passing Context through a few more Renderbuffer methods, and reorganizing the RenderTarget signalling so that it doesn't signal dirty in the destructor. Instead they are signaled as they are destroyed in the containing classes. BUG=angleproject:2151 Change-Id: I4cf575e4a01b48275ff78d75bc55b2d1fced591d Reviewed-on: https://chromium-review.googlesource.com/673139 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Frank Henigman <fjhenigman@chromium.org>

  • src/libANGLE/signal_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.
    //   See design document:
    //   https://docs.google.com/document/d/15Edfotqg6_l1skTEL8ADQudF_oIdNa7i8Po43k6jMd4/
    
    #ifndef LIBANGLE_SIGNAL_UTILS_H_
    #define LIBANGLE_SIGNAL_UTILS_H_
    
    #include <set>
    
    #include "common/angleutils.h"
    #include "common/debug.h"
    
    namespace angle
    {
    
    // Interface that the depending class inherits from.
    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>
    class ChannelBinding;
    
    // The host class owns the channel. It uses the channel to fire signals to the receiver.
    template <typename ChannelID = uint32_t, typename... MessageT>
    class BroadcastChannel final : NonCopyable
    {
      public:
        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>
    BroadcastChannel<ChannelID, MessageT...>::BroadcastChannel()
    {
    }
    
    template <typename ChannelID, typename... MessageT>
    BroadcastChannel<ChannelID, MessageT...>::~BroadcastChannel()
    {
        reset();
    }
    
    template <typename ChannelID, typename... MessageT>
    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>
    void BroadcastChannel<ChannelID, MessageT...>::removeReceiver(
        ChannelBinding<ChannelID, MessageT...> *receiver)
    {
        auto iter = std::find(mReceivers.begin(), mReceivers.end(), receiver);
        ASSERT(iter != mReceivers.end());
        mReceivers.erase(iter);
    }
    
    template <typename ChannelID, typename... MessageT>
    void BroadcastChannel<ChannelID, MessageT...>::signal(MessageT... message) const
    {
        if (mReceivers.empty())
            return;
    
        for (const auto *receiver : mReceivers)
        {
            receiver->signal(message...);
        }
    }
    
    template <typename ChannelID, typename... MessageT>
    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.
    template <typename ChannelID = uint32_t, typename... MessageT>
    class ChannelBinding final
    {
      public:
        ChannelBinding(SignalReceiver<ChannelID, MessageT...> *receiver, ChannelID channelID);
        ~ChannelBinding();
        ChannelBinding(const ChannelBinding &other) = default;
        ChannelBinding &operator=(const ChannelBinding &other) = default;
    
        void bind(BroadcastChannel<ChannelID, MessageT...> *channel);
        void reset();
        void signal(MessageT... message) const;
        void onChannelClosed();
    
      private:
        BroadcastChannel<ChannelID, MessageT...> *mChannel;
        SignalReceiver<ChannelID, MessageT...> *mReceiver;
        ChannelID mChannelID;
    };
    
    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
    
    #endif  // LIBANGLE_SIGNAL_UTILS_H_