Chromium Code Reviews| Index: content/renderer/gpu/frame_swap_message_queue.cc |
| diff --git a/content/renderer/gpu/frame_swap_message_queue.cc b/content/renderer/gpu/frame_swap_message_queue.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c103e4bc87f6911dd6f91cce31698b8673c1812d |
| --- /dev/null |
| +++ b/content/renderer/gpu/frame_swap_message_queue.cc |
| @@ -0,0 +1,222 @@ |
| +// 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 <limits> |
| + |
| +#include "base/containers/hash_tables.h" |
| +#include "base/logging.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<IPC::Message> msg, |
| + bool insert_unique, |
| + bool* is_first) = 0; |
| + virtual void DrainMessages(int source_frame_number, |
| + ScopedVector<IPC::Message>* messages) = 0; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(FrameSwapMessageSubQueue); |
| +}; |
| + |
| +namespace { |
| + |
| +class SendMessageScopeImpl : public FrameSwapMessageQueue::SendMessageScope { |
| + public: |
| + SendMessageScopeImpl(base::Lock* lock) : auto_lock_(*lock) {} |
| + virtual ~SendMessageScopeImpl() OVERRIDE {} |
| + |
| + private: |
| + base::AutoLock auto_lock_; |
| +}; |
| + |
| +class VisualStateQueue : public FrameSwapMessageSubQueue { |
| + public: |
| + VisualStateQueue() {} |
| + |
| + virtual ~VisualStateQueue() { |
| + for (VisualStateQueueMap::iterator i = queue_.begin(); i != queue_.end(); |
| + i++) { |
| + STLDeleteElements(&i->second); |
| + } |
| + } |
| + |
| + virtual bool Empty() const { return queue_.empty(); } |
| + |
| + virtual void QueueMessage(int source_frame_number, |
| + scoped_ptr<IPC::Message> msg, |
| + bool insert_unique, |
| + bool* is_first) { |
| + DCHECK(!insert_unique); |
| + if (is_first) |
| + *is_first = (queue_.count(source_frame_number) == 0); |
| + |
| + queue_[source_frame_number].push_back(msg.release()); |
| + } |
| + |
| + virtual void DrainMessages(int source_frame_number, |
| + ScopedVector<IPC::Message>* messages) { |
| + VisualStateQueueMap::iterator end = queue_.upper_bound(source_frame_number); |
| + for (VisualStateQueueMap::iterator i = queue_.begin(); i != end; i++) { |
| + DCHECK(i->first <= source_frame_number); |
| + messages->insert(messages->end(), i->second.begin(), i->second.end()); |
| + i->second.clear(); |
| + } |
| + queue_.erase(queue_.begin(), end); |
| + } |
| + |
| + private: |
| + typedef std::map<int, std::vector<IPC::Message*> > VisualStateQueueMap; |
| + VisualStateQueueMap queue_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(VisualStateQueue); |
| +}; |
| + |
| +class SwapQueue : public FrameSwapMessageSubQueue { |
| + public: |
| + SwapQueue() {} |
| + virtual bool Empty() const { return queue_.empty(); } |
| + |
| + virtual void QueueMessage(int source_frame_number, |
| + scoped_ptr<IPC::Message> msg, |
| + bool insert_unique, |
| + bool* is_first) { |
| + if (insert_unique) |
|
piman
2014/06/25 21:20:32
I don't think we need the complexity for the UNIQU
mkosiba (inactive)
2014/06/26 12:36:47
Done.
|
| + unique_types_.insert(msg->type()); |
| + if (is_first) |
| + *is_first = Empty(); |
| + queue_.push_back(msg.release()); |
| + } |
| + |
| + virtual void DrainMessages(int source_frame_number, |
| + ScopedVector<IPC::Message>* messages) { |
| + base::hash_set<uint32> types_seen; |
| + size_t initial_messages_size = messages->size(); |
| + for (ScopedVector<IPC::Message>::reverse_iterator i = queue_.rbegin(); |
| + i != queue_.rend(); |
| + ++i) { |
| + if (!unique_types_.count((*i)->type()) || |
| + types_seen.insert((*i)->type()).second) { |
| + messages->push_back(*i); |
| + } else { |
| + delete *i; |
| + } |
| + } |
| + queue_.weak_clear(); |
| + std::reverse(messages->begin() + initial_messages_size, messages->end()); |
| + } |
| + |
| + private: |
| + base::hash_set<uint32> unique_types_; |
| + ScopedVector<IPC::Message> 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: |
| + case MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP_UNIQUE: |
| + 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<IPC::Message> msg, |
| + bool* is_first) { |
| + base::AutoLock lock(lock_); |
| + bool insert_unique = policy == MESSAGE_DELIVERY_POLICY_WITH_NEXT_SWAP_UNIQUE; |
| + GetSubQueue(policy) |
| + ->QueueMessage(source_frame_number, msg.Pass(), insert_unique, is_first); |
| +} |
| + |
| +void FrameSwapMessageQueue::DidSwap(int source_frame_number) { |
| + base::AutoLock lock(lock_); |
| + |
| + visual_state_queue_->DrainMessages(source_frame_number, |
| + &next_drain_messages_); |
| +} |
| + |
| +void FrameSwapMessageQueue::DidNotSwap(int source_frame_number, |
| + cc::SwapPromise::DidNotSwapReason reason, |
| + ScopedVector<IPC::Message>* 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); |
| + // fallthrough |
| + case cc::SwapPromise::COMMIT_FAILS: |
| + visual_state_queue_->DrainMessages(source_frame_number, messages); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +void FrameSwapMessageQueue::DrainMessages( |
| + ScopedVector<IPC::Message>* messages) { |
| + lock_.AssertAcquired(); |
| + |
| + swap_queue_->DrainMessages(0, messages); |
| + messages->insert(messages->end(), |
| + next_drain_messages_.begin(), |
| + next_drain_messages_.end()); |
| + next_drain_messages_.weak_clear(); |
| +} |
| + |
| +scoped_ptr<FrameSwapMessageQueue::SendMessageScope> |
| +FrameSwapMessageQueue::AcquireSendMessageScope() { |
| + return make_scoped_ptr(new SendMessageScopeImpl(&lock_)) |
| + .PassAs<SendMessageScope>(); |
| +} |
| + |
| +// static |
| +void FrameSwapMessageQueue::TransferMessages(ScopedVector<IPC::Message>& source, |
| + vector<IPC::Message>* dest) { |
| + for (vector<IPC::Message*>::iterator i = source.begin(); i != source.end(); |
| + ++i) { |
| + IPC::Message* m(*i); |
| + dest->push_back(*m); |
| + delete m; |
| + } |
| + source.weak_clear(); |
| +} |
| + |
| +} // namespace content |