Chromium Code Reviews| Index: content/browser/renderer_host/software_framebuffer.cc |
| diff --git a/content/browser/renderer_host/software_framebuffer.cc b/content/browser/renderer_host/software_framebuffer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3101da74b49ef79880bac16d4801cfbff331a0a2 |
| --- /dev/null |
| +++ b/content/browser/renderer_host/software_framebuffer.cc |
| @@ -0,0 +1,188 @@ |
| +// Copyright (c) 2013 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 "software_framebuffer.h" |
| + |
| +#include "cc/output/compositor_frame_ack.h" |
| +#include "content/browser/renderer_host/dip_util.h" |
| +#include "content/browser/renderer_host/frame_memory_manager.h" |
| +#include "content/public/browser/render_process_host.h" |
| + |
| +namespace content { |
| + |
| +class MemoryHolder : public base::RefCounted<MemoryHolder> { |
| + public: |
| + MemoryHolder(scoped_ptr<base::SharedMemory> shared_memory, |
| + gfx::Size frame_size, |
| + float frame_scale_factor, |
| + base::Callback<void()> callback) |
| + : shared_memory_(shared_memory.Pass()), |
| + frame_size_(frame_size), |
| + frame_scale_factor_(frame_scale_factor), |
| + callback_(callback) {} |
| + |
| + void GetMailbox(cc::TextureMailbox* mailbox, |
| + scoped_ptr<cc::SingleReleaseCallback>* release_callback) { |
| + *mailbox = cc::TextureMailbox(shared_memory_.get(), frame_size_); |
| + *release_callback = cc::SingleReleaseCallback::Create( |
| + base::Bind(ReleaseMailbox, make_scoped_refptr(this))); |
| + } |
| + const gfx::Size& GetSizeInPixels() const { return frame_size_; } |
| + float GetScaleFactor() const { return frame_scale_factor_; } |
| + const void* GetPixels() const { return shared_memory_->memory(); } |
| + |
| + private: |
| + friend class base::RefCounted<MemoryHolder>; |
| + ~MemoryHolder() { callback_.Run(); } |
| + |
| + static void ReleaseMailbox(scoped_refptr<MemoryHolder> holder, |
| + unsigned sync_point, |
| + bool lost_resource) {} |
| + |
| + scoped_ptr<base::SharedMemory> shared_memory_; |
| + gfx::Size frame_size_; |
| + float frame_scale_factor_; |
| + base::Callback<void()> callback_; |
| +}; |
| + |
| +SoftwareFramebuffer::SoftwareFramebuffer( |
| + SoftwareFramebufferClient* client, |
| + RenderWidgetHostImpl* render_widget_host_impl) |
| + : client_(client), render_widget_host_impl_(render_widget_host_impl) {} |
| + |
| +SoftwareFramebuffer::~SoftwareFramebuffer() { |
| + client_ = NULL; |
| + render_widget_host_impl_ = NULL; |
| + DiscardCurrentFrame(); |
| +} |
| + |
| +void SoftwareFramebuffer::WasShown() { |
| + if (framebuffer_holder_) |
| + FrameMemoryManager::GetInstance()->SetFrameVisibility(this, true); |
| +} |
| + |
| +void SoftwareFramebuffer::WasHidden() { |
| + if (framebuffer_holder_) |
| + FrameMemoryManager::GetInstance()->SetFrameVisibility(this, false); |
| +} |
| + |
| +void SoftwareFramebuffer::DiscardCurrentFrame() { |
| + FrameMemoryManager::GetInstance()->RemoveFrame(this); |
| + framebuffer_holder_ = NULL; |
| +} |
| + |
| +void SoftwareFramebuffer::GetCurrentFrameMailbox( |
| + cc::TextureMailbox* mailbox, |
| + scoped_ptr<cc::SingleReleaseCallback>* release_callback) const { |
| + DCHECK(framebuffer_holder_); |
| + return framebuffer_holder_->GetMailbox(mailbox, |
| + release_callback); |
| +} |
| + |
| +gfx::Size SoftwareFramebuffer::GetCurrentFrameSizeInPixels() const { |
| + DCHECK(framebuffer_holder_); |
| + return framebuffer_holder_->GetSizeInPixels(); |
| +} |
| + |
| +gfx::Size SoftwareFramebuffer::GetCurrentFrameSizeInDIP() const { |
| + DCHECK(framebuffer_holder_); |
| + return ConvertSizeToDIP(framebuffer_holder_->GetScaleFactor(), |
| + framebuffer_holder_->GetSizeInPixels()); |
| +} |
| + |
| +const void* SoftwareFramebuffer::GetCurrentFramePixels() const { |
| + DCHECK(framebuffer_holder_); |
| + return framebuffer_holder_->GetPixels(); |
| +} |
| + |
| +void SoftwareFramebuffer::SwapToNewFrame( |
| + uint32 output_surface_id, |
| + const cc::SoftwareFrameData* frame_data, |
| + float frame_scale_factor) { |
| + const gfx::Size& frame_size = frame_data->size; |
| + const size_t size_in_bytes = 4 * frame_size.GetArea(); |
| + |
| +#ifdef OS_WIN |
| + scoped_ptr<base::SharedMemory> shared_memory( |
| + new base::SharedMemory(frame_data->handle, true, |
| + render_widget_host_impl_->GetProcess()->GetHandle())); |
| +#else |
| + scoped_ptr<base::SharedMemory> shared_memory( |
| + new base::SharedMemory(frame_data->handle, true)); |
| +#endif |
| + |
| + if (!shared_memory->Map(size_in_bytes)) { |
| + render_widget_host_impl_->GetProcess()->ReceivedBadMessage(); |
| + framebuffer_holder_ = NULL; |
| + return; |
| + } |
| + |
| + scoped_refptr<MemoryHolder> holder(new MemoryHolder( |
| + shared_memory.Pass(), |
| + frame_size, |
| + frame_scale_factor, |
| + base::Bind(&SoftwareFramebuffer::ReleaseSoftwareFrame, |
| + AsWeakPtr(), |
| + output_surface_id, |
| + frame_data->id))); |
| + framebuffer_holder_.swap(holder); |
| + |
| + FrameMemoryManager::GetInstance()->AddFrame( |
| + this, !render_widget_host_impl_->is_hidden()); |
| +} |
| + |
| +void SoftwareFramebuffer::SendSoftwareFrameAck(uint32 output_surface_id) { |
| + unsigned software_frame_id = 0; |
| + if (!released_software_frames_.empty()) { |
| + unsigned released_output_surface_id = |
| + released_software_frames_.back().output_surface_id; |
| + if (released_output_surface_id == output_surface_id) { |
| + software_frame_id = released_software_frames_.back().frame_id; |
| + released_software_frames_.pop_back(); |
| + } |
| + } |
| + |
| + cc::CompositorFrameAck ack; |
| + ack.last_software_frame_id = software_frame_id; |
| + if (render_widget_host_impl_) { |
| + RenderWidgetHostImpl::SendSwapCompositorFrameAck( |
|
piman
2013/10/08 02:58:38
I would really prefer if the message sending logic
ccameron
2013/10/22 07:15:55
I did essentially this in the new version. The cal
|
| + render_widget_host_impl_->GetRoutingID(), output_surface_id, |
| + render_widget_host_impl_->GetProcess()->GetID(), ack); |
| + } |
| + SendReclaimSoftwareFrames(); |
| +} |
| + |
| +void SoftwareFramebuffer::SendReclaimSoftwareFrames() { |
| + while (!released_software_frames_.empty()) { |
| + cc::CompositorFrameAck ack; |
| + ack.last_software_frame_id = released_software_frames_.back().frame_id; |
| + if (render_widget_host_impl_) { |
| + RenderWidgetHostImpl::SendReclaimCompositorResources( |
| + render_widget_host_impl_->GetRoutingID(), |
| + released_software_frames_.back().output_surface_id, |
| + render_widget_host_impl_->GetProcess()->GetID(), |
| + ack); |
| + } |
| + released_software_frames_.pop_back(); |
| + } |
| +} |
| + |
| +void SoftwareFramebuffer::ReleaseSoftwareFrame( |
| + uint32 output_surface_id, |
| + unsigned software_frame_id) { |
| + SendReclaimSoftwareFrames(); |
| + released_software_frames_.push_back( |
| + ReleasedFrameInfo(output_surface_id, software_frame_id)); |
| +} |
| + |
| +void SoftwareFramebuffer::ReleaseCurrentFrame() { |
| + DCHECK(framebuffer_holder_); |
| + |
| + DiscardCurrentFrame(); |
| + |
| + if (client_) |
| + client_->CurrentSoftwareFrameWasDiscarded(); |
| +} |
| + |
| +} // namespace content |