// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/renderer/gpu/frame_swap_message_queue.h" #include #include #include #include "base/containers/hash_tables.h" #include "base/logging.h" #include "base/macros.h" #include "base/stl_util.h" #include "ipc/ipc_message.h" using std::vector; namespace content { class FrameSwapMessageSubQueue { public: FrameSwapMessageSubQueue() {} virtual ~FrameSwapMessageSubQueue() {} virtual bool Empty() const = 0; virtual void QueueMessage(int source_frame_number, scoped_ptr msg, bool* is_first) = 0; virtual void DrainMessages( int source_frame_number, std::vector>* messages) = 0; private: DISALLOW_COPY_AND_ASSIGN(FrameSwapMessageSubQueue); }; namespace { // Queue specific to MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE. class SendMessageScopeImpl : public FrameSwapMessageQueue::SendMessageScope { public: SendMessageScopeImpl(base::Lock* lock) : auto_lock_(*lock) {} ~SendMessageScopeImpl() override {} private: base::AutoLock auto_lock_; }; class VisualStateQueue : public FrameSwapMessageSubQueue { public: VisualStateQueue() {} ~VisualStateQueue() override { for (VisualStateQueueMap::iterator i = queue_.begin(); i != queue_.end(); i++) { STLDeleteElements(&i->second); } } bool Empty() const override { return queue_.empty(); } void QueueMessage(int source_frame_number, scoped_ptr msg, bool* is_first) override { if (is_first) *is_first = (queue_.count(source_frame_number) == 0); queue_[source_frame_number].push_back(msg.release()); } void DrainMessages(int source_frame_number, std::vector>* messages) override { auto end = queue_.upper_bound(source_frame_number); for (auto i = queue_.begin(); i != end; i++) { DCHECK(i->first <= source_frame_number); for (IPC::Message* msg : i->second) { messages->push_back(make_scoped_ptr(msg)); } i->second.clear(); } queue_.erase(queue_.begin(), end); } private: typedef std::map > VisualStateQueueMap; VisualStateQueueMap queue_; DISALLOW_COPY_AND_ASSIGN(VisualStateQueue); }; // Queue specific to MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP. class SwapQueue : public FrameSwapMessageSubQueue { public: SwapQueue() {} bool Empty() const override { return queue_.empty(); } void QueueMessage(int source_frame_number, scoped_ptr msg, bool* is_first) override { if (is_first) *is_first = Empty(); queue_.push_back(std::move(msg)); } void DrainMessages(int source_frame_number, std::vector>* messages) override { std::move(queue_.begin(), queue_.end(), std::back_inserter(*messages)); queue_.clear(); } private: std::vector> queue_; DISALLOW_COPY_AND_ASSIGN(SwapQueue); }; } // namespace FrameSwapMessageQueue::FrameSwapMessageQueue() : visual_state_queue_(new VisualStateQueue()), swap_queue_(new SwapQueue()) { } FrameSwapMessageQueue::~FrameSwapMessageQueue() { } bool FrameSwapMessageQueue::Empty() const { base::AutoLock lock(lock_); return next_drain_messages_.empty() && visual_state_queue_->Empty() && swap_queue_->Empty(); } FrameSwapMessageSubQueue* FrameSwapMessageQueue::GetSubQueue( MessageDeliveryPolicy policy) { switch (policy) { case MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP: return swap_queue_.get(); break; case MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE: return visual_state_queue_.get(); break; } NOTREACHED(); return NULL; } void FrameSwapMessageQueue::QueueMessageForFrame(MessageDeliveryPolicy policy, int source_frame_number, scoped_ptr msg, bool* is_first) { base::AutoLock lock(lock_); GetSubQueue(policy) ->QueueMessage(source_frame_number, std::move(msg), is_first); } void FrameSwapMessageQueue::DidActivate(int source_frame_number) { base::AutoLock lock(lock_); visual_state_queue_->DrainMessages(source_frame_number, &next_drain_messages_); } void FrameSwapMessageQueue::DidSwap(int source_frame_number) { base::AutoLock lock(lock_); swap_queue_->DrainMessages(0, &next_drain_messages_); } void FrameSwapMessageQueue::DidNotSwap( int source_frame_number, cc::SwapPromise::DidNotSwapReason reason, std::vector>* messages) { base::AutoLock lock(lock_); switch (reason) { case cc::SwapPromise::SWAP_FAILS: case cc::SwapPromise::COMMIT_NO_UPDATE: swap_queue_->DrainMessages(source_frame_number, messages); visual_state_queue_->DrainMessages(source_frame_number, messages); break; case cc::SwapPromise::COMMIT_FAILS: case cc::SwapPromise::ACTIVATION_FAILS: // Do not queue any responses here. If ACTIVATION_FAILS or // COMMIT_FAILS the renderer is shutting down, which will result // in the RenderFrameHostImpl destructor firing the remaining // response callbacks itself. break; } } void FrameSwapMessageQueue::DrainMessages( std::vector>* messages) { lock_.AssertAcquired(); std::move(next_drain_messages_.begin(), next_drain_messages_.end(), std::back_inserter(*messages)); next_drain_messages_.clear(); } scoped_ptr FrameSwapMessageQueue::AcquireSendMessageScope() { return make_scoped_ptr(new SendMessageScopeImpl(&lock_)); } // static void FrameSwapMessageQueue::TransferMessages( std::vector>* source, vector* dest) { for (const auto& msg : *source) { dest->push_back(*msg.get()); } source->clear(); } } // namespace content