summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/frame_memory_manager.cc66
-rw-r--r--content/browser/renderer_host/frame_memory_manager.h44
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc132
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h16
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.h16
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.mm114
-rw-r--r--content/browser/renderer_host/software_frame_manager.cc243
-rw-r--r--content/browser/renderer_host/software_frame_manager.h105
-rw-r--r--content/browser/renderer_host/software_frame_manager_unittest.cc255
-rw-r--r--content/content_browser.gypi4
-rw-r--r--content/content_tests.gypi1
11 files changed, 765 insertions, 231 deletions
diff --git a/content/browser/renderer_host/frame_memory_manager.cc b/content/browser/renderer_host/frame_memory_manager.cc
deleted file mode 100644
index 708bddf..0000000
--- a/content/browser/renderer_host/frame_memory_manager.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 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 "content/browser/renderer_host/frame_memory_manager.h"
-
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/sys_info.h"
-
-namespace content {
-
-namespace {
-
-size_t MaxNumberOfSavedFrames() {
- return std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256));
-}
-
-} // namespace
-
-FrameMemoryManager* FrameMemoryManager::GetInstance() {
- return Singleton<FrameMemoryManager>::get();
-}
-
-void FrameMemoryManager::AddFrame(FrameContainer* frame, bool visible) {
- RemoveFrame(frame);
- if (visible)
- visible_frames_.insert(frame);
- else
- hidden_frames_.push_front(frame);
- CullHiddenFrames();
-}
-
-void FrameMemoryManager::RemoveFrame(FrameContainer* frame) {
- visible_frames_.erase(frame);
- hidden_frames_.remove(frame);
-}
-
-void FrameMemoryManager::SetFrameVisibility(FrameContainer* frame,
- bool visible) {
- if (visible) {
- hidden_frames_.remove(frame);
- visible_frames_.insert(frame);
- } else {
- visible_frames_.erase(frame);
- hidden_frames_.push_front(frame);
- CullHiddenFrames();
- }
-}
-
-FrameMemoryManager::FrameMemoryManager() {}
-
-FrameMemoryManager::~FrameMemoryManager() {}
-
-void FrameMemoryManager::CullHiddenFrames() {
- while (!hidden_frames_.empty() &&
- hidden_frames_.size() + visible_frames_.size() >
- MaxNumberOfSavedFrames()) {
- size_t old_size = hidden_frames_.size();
- // Should remove self from list.
- hidden_frames_.back()->ReleaseCurrentFrame();
- DCHECK_EQ(hidden_frames_.size() + 1, old_size);
- }
-}
-
-} // namespace content
diff --git a/content/browser/renderer_host/frame_memory_manager.h b/content/browser/renderer_host/frame_memory_manager.h
deleted file mode 100644
index ce3fc25..0000000
--- a/content/browser/renderer_host/frame_memory_manager.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 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.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_FRAME_MEMORY_MANAGER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_FRAME_MEMORY_MANAGER_H_
-
-#include <list>
-#include <set>
-
-#include "base/basictypes.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace content {
-
-class FrameContainer {
- public:
- virtual void ReleaseCurrentFrame() = 0;
-};
-
-class FrameMemoryManager {
- public:
- static FrameMemoryManager* GetInstance();
-
- void AddFrame(FrameContainer*, bool visible);
- void RemoveFrame(FrameContainer*);
- void SetFrameVisibility(FrameContainer*, bool visible);
-
- private:
- FrameMemoryManager();
- ~FrameMemoryManager();
- void CullHiddenFrames();
- friend struct DefaultSingletonTraits<FrameMemoryManager>;
-
- std::set<FrameContainer*> visible_frames_;
- std::list<FrameContainer*> hidden_frames_;
-
- DISALLOW_COPY_AND_ASSIGN(FrameMemoryManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_FRAME_MEMORY_MANAGER_H_
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 4d616bb..fab01ac 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -93,35 +93,6 @@ using WebKit::WebTouchEvent;
namespace content {
-void ReleaseMailbox(scoped_refptr<MemoryHolder> holder,
- unsigned sync_point,
- bool lost_resource) {}
-
-class MemoryHolder : public base::RefCounted<MemoryHolder> {
- public:
- MemoryHolder(scoped_ptr<base::SharedMemory> shared_memory,
- gfx::Size frame_size,
- base::Callback<void()> callback)
- : shared_memory_(shared_memory.Pass()),
- frame_size_(frame_size),
- 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)));
- }
-
- private:
- friend class base::RefCounted<MemoryHolder>;
- ~MemoryHolder() { callback_.Run(); }
-
- scoped_ptr<base::SharedMemory> shared_memory_;
- gfx::Size frame_size_;
- base::Callback<void()> callback_;
-};
-
namespace {
void MailboxReleaseCallback(scoped_ptr<base::SharedMemory> shared_memory,
@@ -603,7 +574,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
can_lock_compositor_(YES),
cursor_visibility_state_in_renderer_(UNKNOWN),
paint_observer_(NULL),
- touch_editing_client_(NULL) {
+ touch_editing_client_(NULL),
+ weak_ptr_factory_(this) {
host_->SetView(this);
window_observer_.reset(new WindowObserver(this));
aura::client::SetTooltipText(window_, &tooltip_);
@@ -614,6 +586,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
#if defined(OS_WIN)
transient_observer_.reset(new TransientWindowObserver(this));
#endif
+ software_frame_manager_.reset(new SoftwareFrameManager(
+ weak_ptr_factory_.GetWeakPtr()));
}
////////////////////////////////////////////////////////////////////////////////
@@ -698,8 +672,7 @@ void RenderWidgetHostViewAura::WasShown() {
if (!host_->is_hidden())
return;
host_->WasShown();
- if (framebuffer_holder_)
- FrameMemoryManager::GetInstance()->SetFrameVisibility(this, true);
+ software_frame_manager_->SetVisibility(true);
aura::RootWindow* root = window_->GetRootWindow();
if (root) {
@@ -727,9 +700,7 @@ void RenderWidgetHostViewAura::WasHidden() {
if (!host_ || host_->is_hidden())
return;
host_->WasHidden();
- if (framebuffer_holder_)
- FrameMemoryManager::GetInstance()->SetFrameVisibility(this, false);
-
+ software_frame_manager_->SetVisibility(false);
released_front_lock_ = NULL;
#if defined(OS_WIN)
@@ -1288,12 +1259,12 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() {
current_frame_size_ = ConvertSizeToDIP(
current_surface_->device_scale_factor(), current_surface_->size());
CheckResizeLock();
- framebuffer_holder_ = NULL;
- FrameMemoryManager::GetInstance()->RemoveFrame(this);
- } else if (is_compositing_active && framebuffer_holder_) {
+ software_frame_manager_->DiscardCurrentFrame();
+ } else if (is_compositing_active &&
+ software_frame_manager_->HasCurrentFrame()) {
cc::TextureMailbox mailbox;
scoped_ptr<cc::SingleReleaseCallback> callback;
- framebuffer_holder_->GetMailbox(&mailbox, &callback);
+ software_frame_manager_->GetCurrentFrameMailbox(&mailbox, &callback);
window_->layer()->SetTextureMailbox(mailbox,
callback.Pass(),
last_swapped_surface_scale_factor_);
@@ -1304,8 +1275,7 @@ void RenderWidgetHostViewAura::UpdateExternalTexture() {
window_->layer()->SetShowPaintedContent();
resize_lock_.reset();
host_->WasResized();
- framebuffer_holder_ = NULL;
- FrameMemoryManager::GetInstance()->RemoveFrame(this);
+ software_frame_manager_->DiscardCurrentFrame();
}
}
@@ -1440,8 +1410,7 @@ void RenderWidgetHostViewAura::SwapDelegatedFrame(
gfx::Rect damage_rect_in_dip =
ConvertRectToDIP(frame_device_scale_factor, damage_rect);
- framebuffer_holder_ = NULL;
- FrameMemoryManager::GetInstance()->RemoveFrame(this);
+ software_frame_manager_->DiscardCurrentFrame();
if (ShouldSkipFrame(frame_size_in_dip)) {
cc::CompositorFrameAck ack;
@@ -1575,38 +1544,14 @@ void RenderWidgetHostViewAura::SwapSoftwareFrame(
return;
}
- 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,
- host_->GetProcess()->GetHandle()));
-#else
- scoped_ptr<base::SharedMemory> shared_memory(
- new base::SharedMemory(frame_data->handle, true));
-#endif
-
-#ifdef OS_WIN
- if (!shared_memory->Map(0)) {
- DLOG(ERROR) << "Unable to map renderer memory.";
- RecordAction(UserMetricsAction("BadMessageTerminate_RWHVA1"));
- host_->GetProcess()->ReceivedBadMessage();
- return;
- }
-
- if (shared_memory->mapped_size() < size_in_bytes) {
- DLOG(ERROR) << "Shared memory too small for given rectangle";
- RecordAction(UserMetricsAction("BadMessageTerminate_RWHVA2"));
+ if (!software_frame_manager_->SwapToNewFrame(
+ output_surface_id,
+ frame_data.get(),
+ frame_device_scale_factor,
+ host_->GetProcess()->GetHandle())) {
host_->GetProcess()->ReceivedBadMessage();
return;
}
-#else
- if (!shared_memory->Map(size_in_bytes)) {
- DLOG(ERROR) << "Unable to map renderer memory.";
- RecordAction(UserMetricsAction("BadMessageTerminate_RWHVA1"));
- host_->GetProcess()->ReceivedBadMessage();
- return;
- }
-#endif
if (last_swapped_surface_size_ != frame_size) {
DLOG_IF(ERROR, damage_rect != gfx::Rect(frame_size))
@@ -1615,17 +1560,9 @@ void RenderWidgetHostViewAura::SwapSoftwareFrame(
last_swapped_surface_size_ = frame_size;
last_swapped_surface_scale_factor_ = frame_device_scale_factor;
- scoped_refptr<MemoryHolder> holder(new MemoryHolder(
- shared_memory.Pass(),
- frame_size,
- base::Bind(&RenderWidgetHostViewAura::ReleaseSoftwareFrame,
- AsWeakPtr(),
- output_surface_id,
- frame_data->id)));
- framebuffer_holder_.swap(holder);
cc::TextureMailbox mailbox;
scoped_ptr<cc::SingleReleaseCallback> callback;
- framebuffer_holder_->GetMailbox(&mailbox, &callback);
+ software_frame_manager_->GetCurrentFrameMailbox(&mailbox, &callback);
DCHECK(mailbox.IsSharedMemory());
current_frame_size_ = frame_size_in_dip;
@@ -1648,7 +1585,8 @@ void RenderWidgetHostViewAura::SwapSoftwareFrame(
if (paint_observer_)
paint_observer_->OnUpdateCompositorContent();
DidReceiveFrameFromRenderer();
- FrameMemoryManager::GetInstance()->AddFrame(this, !host_->is_hidden());
+
+ software_frame_manager_->SwapToNewFrameComplete(!host_->is_hidden());
}
void RenderWidgetHostViewAura::SendSoftwareFrameAck(uint32 output_surface_id) {
@@ -1756,8 +1694,7 @@ void RenderWidgetHostViewAura::BuffersSwapped(
const BufferPresentedCallback& ack_callback) {
scoped_refptr<ui::Texture> previous_texture(current_surface_);
const gfx::Rect surface_rect = gfx::Rect(surface_size);
- framebuffer_holder_ = NULL;
- FrameMemoryManager::GetInstance()->RemoveFrame(this);
+ software_frame_manager_->DiscardCurrentFrame();
if (!SwapBuffersPrepare(surface_rect,
surface_scale_factor,
@@ -3070,16 +3007,21 @@ void RenderWidgetHostViewAura::OnRootWindowHostMoved(
UpdateScreenInfo(window_);
}
-void RenderWidgetHostViewAura::ReleaseCurrentFrame() {
- if (framebuffer_holder_.get() && !current_surface_.get()) {
- framebuffer_holder_ = NULL;
- ui::Compositor* compositor = GetCompositor();
- if (compositor) {
- AddOnCommitCallbackAndDisableLocks(base::Bind(
- &RenderWidgetHostViewAura::SendReclaimSoftwareFrames, AsWeakPtr()));
- }
- UpdateExternalTexture();
+////////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewAura, SoftwareFrameManagerClient implementation:
+
+void RenderWidgetHostViewAura::SoftwareFrameWasFreed(
+ uint32 output_surface_id, unsigned frame_id) {
+ ReleaseSoftwareFrame(output_surface_id, frame_id);
+}
+
+void RenderWidgetHostViewAura::ReleaseReferencesToSoftwareFrame() {
+ ui::Compositor* compositor = GetCompositor();
+ if (compositor) {
+ AddOnCommitCallbackAndDisableLocks(base::Bind(
+ &RenderWidgetHostViewAura::SendReclaimSoftwareFrames, AsWeakPtr()));
}
+ UpdateExternalTexture();
}
////////////////////////////////////////////////////////////////////////////////
@@ -3253,10 +3195,6 @@ RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
// Aura root window and we don't have a way to get an input method object
// associated with the window, but just in case.
DetachFromInputMethod();
- FrameMemoryManager::GetInstance()->RemoveFrame(this);
- // The destruction of the holder may call back into the RWHVA, so do it
- // early.
- framebuffer_holder_ = NULL;
if (resource_collection_.get())
resource_collection_->SetClient(NULL);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 77b5db4..f333eed 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -20,8 +20,8 @@
#include "cc/resources/texture_mailbox.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/aura/image_transport_factory.h"
-#include "content/browser/renderer_host/frame_memory_manager.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/renderer_host/software_frame_manager.h"
#include "content/common/content_export.h"
#include "content/common/gpu/client/gl_helper.h"
#include "third_party/skia/include/core/SkRegion.h"
@@ -59,7 +59,6 @@ class Texture;
}
namespace content {
-class MemoryHolder;
class RenderWidgetHostImpl;
class RenderWidgetHostView;
class ResizeLock;
@@ -78,7 +77,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
public aura::client::CursorClientObserver,
public ImageTransportFactoryObserver,
public BrowserAccessibilityDelegate,
- public FrameContainer,
+ public SoftwareFrameManagerClient,
public base::SupportsWeakPtr<RenderWidgetHostViewAura>,
public cc::DelegatedFrameResourceCollectionClient {
public:
@@ -332,8 +331,10 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
virtual void OnRootWindowHostMoved(const aura::RootWindow* root,
const gfx::Point& new_origin) OVERRIDE;
- // FrameContainer implementation:
- virtual void ReleaseCurrentFrame() OVERRIDE;
+ // SoftwareFrameManagerClient implementation:
+ virtual void SoftwareFrameWasFreed(
+ uint32 output_surface_id, unsigned frame_id) OVERRIDE;
+ virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE;
bool CanCopyToBitmap() const;
@@ -613,8 +614,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// The current frontbuffer texture.
scoped_refptr<ui::Texture> current_surface_;
- // This holds the current software framebuffer.
- scoped_refptr<MemoryHolder> framebuffer_holder_;
+ // This holds the current software framebuffer, if any.
+ scoped_ptr<SoftwareFrameManager> software_frame_manager_;
// With delegated renderer, this is the last output surface, used to
// disambiguate resources with the same id coming from different output
@@ -754,6 +755,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
};
scoped_ptr<ReleasedFrameInfo> released_software_frame_;
+ base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAura);
};
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 6a9caaa..da16bc2 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -18,6 +18,7 @@
#include "base/time/time.h"
#include "content/browser/accessibility/browser_accessibility_delegate_mac.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/renderer_host/software_frame_manager.h"
#include "content/common/edit_command.h"
#import "content/public/browser/render_widget_host_view_mac_base.h"
#include "ipc/ipc_sender.h"
@@ -196,7 +197,8 @@ class RenderWidgetHostImpl;
//
// RenderWidgetHostView class hierarchy described in render_widget_host_view.h.
class RenderWidgetHostViewMac : public RenderWidgetHostViewBase,
- public IPC::Sender {
+ public IPC::Sender,
+ public SoftwareFrameManagerClient {
public:
virtual ~RenderWidgetHostViewMac();
@@ -283,6 +285,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostViewBase,
virtual void BeginFrameSubscription(
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE;
virtual void EndFrameSubscription() OVERRIDE;
+ virtual void OnSwapCompositorFrame(
+ uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
virtual void OnAcceleratedCompositingStateChange() OVERRIDE;
virtual void OnAccessibilityEvents(
const std::vector<AccessibilityHostMsg_EventParams>& params
@@ -316,6 +320,11 @@ class RenderWidgetHostViewMac : public RenderWidgetHostViewBase,
// IPC::Sender implementation.
virtual bool Send(IPC::Message* message) OVERRIDE;
+ // SoftwareFrameManagerClient implementation:
+ virtual void SoftwareFrameWasFreed(
+ uint32 output_surface_id, unsigned frame_id) OVERRIDE;
+ virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE;
+
// Forwards the mouse event to the renderer.
void ForwardMouseEvent(const WebKit::WebMouseEvent& event);
@@ -412,6 +421,9 @@ class RenderWidgetHostViewMac : public RenderWidgetHostViewBase,
scoped_ptr<CompositingIOSurfaceMac> compositing_iosurface_;
scoped_refptr<CompositingIOSurfaceContext> compositing_iosurface_context_;
+ // This holds the current software compositing framebuffer, if any.
+ scoped_ptr<SoftwareFrameManager> software_frame_manager_;
+
// Whether to allow overlapping views.
bool allow_overlapping_views_;
@@ -552,6 +564,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostViewBase,
// Subscriber that listens to frame presentation events.
scoped_ptr<RenderWidgetHostViewFrameSubscriber> frame_subscriber_;
+ base::WeakPtrFactory<RenderWidgetHostViewMac>
+ software_frame_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac);
};
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 02c66aa..d632390 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -46,6 +46,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/native_web_keyboard_event.h"
#import "content/public/browser/render_widget_host_view_mac_delegate.h"
+#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -426,7 +427,10 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
weak_factory_(this),
fullscreen_parent_host_view_(NULL),
pending_swap_buffers_acks_weak_factory_(this),
- next_swap_ack_time_(base::Time::Now()) {
+ next_swap_ack_time_(base::Time::Now()),
+ software_frame_weak_ptr_factory_(this) {
+ software_frame_manager_.reset(new SoftwareFrameManager(
+ software_frame_weak_ptr_factory_.GetWeakPtr()));
// |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
// goes away. Since we autorelease it, our caller must put
// |GetNativeView()| into the view hierarchy right after calling us.
@@ -732,6 +736,7 @@ void RenderWidgetHostViewMac::WasShown() {
if (web_contents_switch_paint_time_.is_null())
web_contents_switch_paint_time_ = base::TimeTicks::Now();
render_widget_host_->WasShown();
+ software_frame_manager_->SetVisibility(true);
// We're messing with the window, so do this to ensure no flashes.
if (!use_core_animation_)
@@ -751,6 +756,7 @@ void RenderWidgetHostViewMac::WasHidden() {
// If we have a renderer, then inform it that we are being hidden so it can
// reduce its resource utilization.
render_widget_host_->WasHidden();
+ software_frame_manager_->SetVisibility(false);
// There can be a transparent flash as this view is removed and the next is
// added, because of OSX windowing races between displaying the contents of
@@ -1650,17 +1656,50 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceRelease() {
bool RenderWidgetHostViewMac::HasAcceleratedSurface(
const gfx::Size& desired_size) {
- return last_frame_was_accelerated_ &&
- compositing_iosurface_ &&
- compositing_iosurface_->HasIOSurface() &&
- (desired_size.IsEmpty() ||
- compositing_iosurface_->dip_io_surface_size() == desired_size);
+ if (last_frame_was_accelerated_) {
+ return compositing_iosurface_ &&
+ compositing_iosurface_->HasIOSurface() &&
+ (desired_size.IsEmpty() ||
+ compositing_iosurface_->dip_io_surface_size() == desired_size);
+ } else {
+ return (software_frame_manager_->HasCurrentFrame() &&
+ (desired_size.IsEmpty() ||
+ software_frame_manager_->GetCurrentFrameSizeInDIP() ==
+ desired_size));
+ }
+ return false;
}
void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() {
AckPendingSwapBuffers();
}
+void RenderWidgetHostViewMac::OnSwapCompositorFrame(
+ uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) {
+ // Only software compositor frames are accepted.
+ if (!frame->software_frame_data) {
+ DLOG(ERROR) << "Received unexpected frame type.";
+ RecordAction(UserMetricsAction(
+ "BadMessageTerminate_UnexpectedFrameType"));
+ render_widget_host_->GetProcess()->ReceivedBadMessage();
+ return;
+ }
+
+ GotSoftwareFrame();
+ if (!software_frame_manager_->SwapToNewFrame(
+ output_surface_id,
+ frame->software_frame_data.get(),
+ frame->metadata.device_scale_factor,
+ render_widget_host_->GetProcess()->GetHandle())) {
+ render_widget_host_->GetProcess()->ReceivedBadMessage();
+ return;
+ }
+ software_frame_manager_->SwapToNewFrameComplete(
+ !render_widget_host_->is_hidden());
+
+ [cocoa_view_ setNeedsDisplay:YES];
+}
+
void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() {
}
@@ -1741,6 +1780,19 @@ bool RenderWidgetHostViewMac::Send(IPC::Message* message) {
return false;
}
+void RenderWidgetHostViewMac::SoftwareFrameWasFreed(
+ uint32 output_surface_id, unsigned frame_id) {
+ cc::CompositorFrameAck ack;
+ ack.last_software_frame_id = frame_id;
+ RenderWidgetHostImpl::SendReclaimCompositorResources(
+ render_widget_host_->GetRoutingID(),
+ output_surface_id,
+ render_widget_host_->GetProcess()->GetID(),
+ ack);
+}
+
+void RenderWidgetHostViewMac::ReleaseReferencesToSoftwareFrame() {
+}
void RenderWidgetHostViewMac::ShutdownHost() {
weak_factory_.InvalidateWeakPtrs();
@@ -1764,6 +1816,7 @@ void RenderWidgetHostViewMac::GotAcceleratedFrame() {
// Delete software backingstore.
BackingStoreManager::RemoveBackingStore(render_widget_host_);
+ software_frame_manager_->DiscardCurrentFrame();
}
}
@@ -2718,29 +2771,62 @@ void RenderWidgetHostViewMac::FrameSwapped() {
- (void)drawBackingStore:(BackingStoreMac*)backingStore
dirtyRect:(CGRect)dirtyRect
inContext:(CGContextRef)context {
- if (backingStore) {
+ content::SoftwareFrameManager* software_frame_manager =
+ renderWidgetHostView_->software_frame_manager_.get();
+ // There should never be both a legacy software and software composited
+ // frame.
+ DCHECK(!backingStore || !software_frame_manager->HasCurrentFrame());
+
+ if (backingStore || software_frame_manager->HasCurrentFrame()) {
// Note: All coordinates are in view units, not pixels.
- gfx::Rect bitmapRect(0, 0,
- backingStore->size().width(),
- backingStore->size().height());
+ gfx::Rect bitmapRect(
+ software_frame_manager->HasCurrentFrame() ?
+ software_frame_manager->GetCurrentFrameSizeInDIP() :
+ backingStore->size());
// Specify the proper y offset to ensure that the view is rooted to the
// upper left corner. This can be negative, if the window was resized
// smaller and the renderer hasn't yet repainted.
- int yOffset = NSHeight([self bounds]) - backingStore->size().height();
+ int yOffset = NSHeight([self bounds]) - bitmapRect.height();
NSRect nsDirtyRect = NSRectFromCGRect(dirtyRect);
const gfx::Rect damagedRect([self flipNSRectToRect:nsDirtyRect]);
gfx::Rect paintRect = gfx::IntersectRects(bitmapRect, damagedRect);
if (!paintRect.IsEmpty()) {
- // if we have a CGLayer, draw that into the window
- if (backingStore->cg_layer()) {
+ if (software_frame_manager->HasCurrentFrame()) {
+ // If a software compositor framebuffer is present, draw using that.
+ gfx::Size sizeInPixels =
+ software_frame_manager->GetCurrentFrameSizeInPixels();
+ base::ScopedCFTypeRef<CGDataProviderRef> dataProvider(
+ CGDataProviderCreateWithData(
+ NULL,
+ software_frame_manager->GetCurrentFramePixels(),
+ 4 * sizeInPixels.width() * sizeInPixels.height(),
+ NULL));
+ base::ScopedCFTypeRef<CGImageRef> image(
+ CGImageCreate(
+ sizeInPixels.width(),
+ sizeInPixels.height(),
+ 8,
+ 32,
+ 4 * sizeInPixels.width(),
+ base::mac::GetSystemColorSpace(),
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
+ dataProvider,
+ NULL,
+ false,
+ kCGRenderingIntentDefault));
+ CGRect imageRect = bitmapRect.ToCGRect();
+ imageRect.origin.y = yOffset;
+ CGContextDrawImage(context, imageRect, image);
+ } else if (backingStore->cg_layer()) {
+ // If we have a CGLayer, draw that into the window
// TODO: add clipping to dirtyRect if it improves drawing performance.
CGContextDrawLayerAtPoint(context, CGPointMake(0.0, yOffset),
backingStore->cg_layer());
} else {
- // if we haven't created a layer yet, draw the cached bitmap into
+ // If we haven't created a layer yet, draw the cached bitmap into
// the window. The CGLayer will be created the next time the renderer
// paints.
base::ScopedCFTypeRef<CGImageRef> image(
diff --git a/content/browser/renderer_host/software_frame_manager.cc b/content/browser/renderer_host/software_frame_manager.cc
new file mode 100644
index 0000000..ac6fc3c
--- /dev/null
+++ b/content/browser/renderer_host/software_frame_manager.cc
@@ -0,0 +1,243 @@
+// Copyright 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 "content/browser/renderer_host/software_frame_manager.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/sys_info.h"
+#include "content/browser/renderer_host/dip_util.h"
+#include "content/public/browser/user_metrics.h"
+
+namespace {
+
+void ReleaseMailbox(scoped_refptr<content::SoftwareFrame> frame,
+ unsigned sync_point,
+ bool lost_resource) {}
+
+} // namespace
+
+namespace content {
+
+////////////////////////////////////////////////////////////////////////////////
+// SoftwareFrame
+
+class CONTENT_EXPORT SoftwareFrame : public base::RefCounted<SoftwareFrame> {
+ private:
+ friend class base::RefCounted<SoftwareFrame>;
+ friend class SoftwareFrameManager;
+
+ SoftwareFrame(
+ base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client,
+ uint32 output_surface_id,
+ unsigned frame_id,
+ gfx::Size frame_size_dip,
+ gfx::Size frame_size_pixels,
+ scoped_ptr<base::SharedMemory> shared_memory);
+ ~SoftwareFrame();
+
+ base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client_;
+ const uint32 output_surface_id_;
+ const unsigned frame_id_;
+ const gfx::Size frame_size_dip_;
+ const gfx::Size frame_size_pixels_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareFrame);
+};
+
+SoftwareFrame::SoftwareFrame(
+ base::WeakPtr<SoftwareFrameManagerClient> frame_manager_client,
+ uint32 output_surface_id,
+ unsigned frame_id,
+ gfx::Size frame_size_dip,
+ gfx::Size frame_size_pixels,
+ scoped_ptr<base::SharedMemory> shared_memory)
+ : frame_manager_client_(frame_manager_client),
+ output_surface_id_(output_surface_id),
+ frame_id_(frame_id),
+ frame_size_dip_(frame_size_dip),
+ frame_size_pixels_(frame_size_pixels),
+ shared_memory_(shared_memory.Pass()) {}
+
+SoftwareFrame::~SoftwareFrame() {
+ if (frame_manager_client_) {
+ frame_manager_client_->SoftwareFrameWasFreed(
+ output_surface_id_, frame_id_);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SoftwareFrameManager
+
+SoftwareFrameManager::SoftwareFrameManager(
+ base::WeakPtr<SoftwareFrameManagerClient> client)
+ : client_(client) {}
+
+SoftwareFrameManager::~SoftwareFrameManager() {
+ DiscardCurrentFrame();
+}
+
+bool SoftwareFrameManager::SwapToNewFrame(
+ uint32 output_surface_id,
+ const cc::SoftwareFrameData* frame_data,
+ float frame_device_scale_factor,
+ base::ProcessHandle process_handle) {
+
+#ifdef OS_WIN
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(frame_data->handle, true,
+ process_handle));
+#else
+ scoped_ptr<base::SharedMemory> shared_memory(
+ new base::SharedMemory(frame_data->handle, true));
+#endif
+
+ // The NULL handle is used in testing.
+ if (base::SharedMemory::IsHandleValid(shared_memory->handle())) {
+ const size_t size_in_bytes = 4 * frame_data->size.GetArea();
+#ifdef OS_WIN
+ if (!shared_memory->Map(0)) {
+ DLOG(ERROR) << "Unable to map renderer memory.";
+ RecordAction(UserMetricsAction(
+ "BadMessageTerminate_SharedMemoryManager1"));
+ return false;
+ }
+
+ if (shared_memory->mapped_size() < size_in_bytes) {
+ DLOG(ERROR) << "Shared memory too small for given rectangle";
+ RecordAction(UserMetricsAction(
+ "BadMessageTerminate_SharedMemoryManager2"));
+ return false;
+ }
+#else
+ if (!shared_memory->Map(size_in_bytes)) {
+ DLOG(ERROR) << "Unable to map renderer memory.";
+ RecordAction(UserMetricsAction(
+ "BadMessageTerminate_SharedMemoryManager1"));
+ return false;
+ }
+#endif
+ }
+
+ scoped_refptr<SoftwareFrame> next_frame(new SoftwareFrame(
+ client_,
+ output_surface_id,
+ frame_data->id,
+ ConvertSizeToDIP(frame_device_scale_factor, frame_data->size),
+ frame_data->size,
+ shared_memory.Pass()));
+ current_frame_.swap(next_frame);
+ return true;
+}
+
+bool SoftwareFrameManager::HasCurrentFrame() const {
+ return current_frame_.get() ? true : false;
+}
+
+void SoftwareFrameManager::DiscardCurrentFrame() {
+ if (!HasCurrentFrame())
+ return;
+ current_frame_ = NULL;
+ SoftwareFrameMemoryManager::GetInstance()->RemoveFrame(this);
+}
+
+void SoftwareFrameManager::SwapToNewFrameComplete(bool visible) {
+ DCHECK(HasCurrentFrame());
+ SoftwareFrameMemoryManager::GetInstance()->AddFrame(this, visible);
+}
+
+void SoftwareFrameManager::SetVisibility(bool visible) {
+ if (HasCurrentFrame()) {
+ SoftwareFrameMemoryManager::GetInstance()->SetFrameVisibility(this,
+ visible);
+ }
+}
+
+void SoftwareFrameManager::GetCurrentFrameMailbox(
+ cc::TextureMailbox* mailbox,
+ scoped_ptr<cc::SingleReleaseCallback>* callback) {
+ DCHECK(HasCurrentFrame());
+ *mailbox = cc::TextureMailbox(
+ current_frame_->shared_memory_.get(), current_frame_->frame_size_pixels_);
+ *callback = cc::SingleReleaseCallback::Create(
+ base::Bind(ReleaseMailbox, current_frame_));
+}
+
+const void* SoftwareFrameManager::GetCurrentFramePixels() const {
+ DCHECK(HasCurrentFrame());
+ DCHECK(base::SharedMemory::IsHandleValid(
+ current_frame_->shared_memory_->handle()));
+ return current_frame_->shared_memory_->memory();
+}
+
+gfx::Size SoftwareFrameManager::GetCurrentFrameSizeInPixels() const {
+ DCHECK(HasCurrentFrame());
+ return current_frame_->frame_size_pixels_;
+}
+
+gfx::Size SoftwareFrameManager::GetCurrentFrameSizeInDIP() const {
+ DCHECK(HasCurrentFrame());
+ return current_frame_->frame_size_dip_;
+}
+
+void SoftwareFrameManager::EvictCurrentFrame() {
+ DCHECK(HasCurrentFrame());
+ DiscardCurrentFrame();
+ if (client_)
+ client_->ReleaseReferencesToSoftwareFrame();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SoftwareFrameMemoryManager
+
+SoftwareFrameMemoryManager* SoftwareFrameMemoryManager::GetInstance() {
+ return Singleton<SoftwareFrameMemoryManager>::get();
+}
+
+void SoftwareFrameMemoryManager::AddFrame(SoftwareFrameManager* frame,
+ bool visible) {
+ RemoveFrame(frame);
+ if (visible)
+ visible_frames_.insert(frame);
+ else
+ hidden_frames_.push_front(frame);
+ CullHiddenFrames();
+}
+
+void SoftwareFrameMemoryManager::RemoveFrame(SoftwareFrameManager* frame) {
+ visible_frames_.erase(frame);
+ hidden_frames_.remove(frame);
+}
+
+void SoftwareFrameMemoryManager::SetFrameVisibility(SoftwareFrameManager* frame,
+ bool visible) {
+ if (visible) {
+ hidden_frames_.remove(frame);
+ visible_frames_.insert(frame);
+ } else {
+ visible_frames_.erase(frame);
+ hidden_frames_.push_front(frame);
+ CullHiddenFrames();
+ }
+}
+
+SoftwareFrameMemoryManager::SoftwareFrameMemoryManager()
+ : max_number_of_saved_frames_(
+ std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256))) {}
+
+SoftwareFrameMemoryManager::~SoftwareFrameMemoryManager() {}
+
+void SoftwareFrameMemoryManager::CullHiddenFrames() {
+ while (!hidden_frames_.empty() &&
+ hidden_frames_.size() + visible_frames_.size() >
+ max_number_of_saved_frames()) {
+ size_t old_size = hidden_frames_.size();
+ // Should remove self from list.
+ hidden_frames_.back()->EvictCurrentFrame();
+ DCHECK_EQ(hidden_frames_.size() + 1, old_size);
+ }
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/software_frame_manager.h b/content/browser/renderer_host/software_frame_manager.h
new file mode 100644
index 0000000..d7f186f
--- /dev/null
+++ b/content/browser/renderer_host/software_frame_manager.h
@@ -0,0 +1,105 @@
+// Copyright 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.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
+
+#include <list>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/singleton.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/output/software_frame_data.h"
+#include "cc/resources/single_release_callback.h"
+#include "cc/resources/texture_mailbox.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/size.h"
+
+namespace content {
+class SoftwareFrame;
+class SoftwareFrameMemoryManager;
+
+class CONTENT_EXPORT SoftwareFrameManagerClient {
+ public:
+ // Called when the memory for the current software frame was freed.
+ virtual void SoftwareFrameWasFreed(
+ uint32 output_surface_id, unsigned frame_id) = 0;
+
+ // Called when the SoftwareFrameMemoryManager has requested that the frame
+ // be evicted. Upon receiving this callback, the client should release any
+ // references that it may hold to the current frame, to ensure that its memory
+ // is freed expediently.
+ virtual void ReleaseReferencesToSoftwareFrame() = 0;
+};
+
+class CONTENT_EXPORT SoftwareFrameManager {
+ public:
+ explicit SoftwareFrameManager(
+ base::WeakPtr<SoftwareFrameManagerClient> client);
+ ~SoftwareFrameManager();
+
+ // Swaps to a new frame from shared memory. This frame is guaranteed to
+ // not be evicted until SwapToNewFrameComplete is called.
+ bool SwapToNewFrame(
+ uint32 output_surface_id,
+ const cc::SoftwareFrameData* frame_data,
+ float frame_device_scale_factor,
+ base::ProcessHandle process_handle);
+ void SwapToNewFrameComplete(bool visible);
+ void SetVisibility(bool visible);
+ bool HasCurrentFrame() const;
+ void DiscardCurrentFrame();
+ void GetCurrentFrameMailbox(
+ cc::TextureMailbox* mailbox,
+ scoped_ptr<cc::SingleReleaseCallback>* callback);
+ const void* GetCurrentFramePixels() const;
+ gfx::Size GetCurrentFrameSizeInPixels() const;
+ gfx::Size GetCurrentFrameSizeInDIP() const;
+
+ private:
+ friend class SoftwareFrameMemoryManager;
+
+ // Called by SoftwareFrameMemoryManager to demand that the current frame
+ // be evicted.
+ void EvictCurrentFrame();
+
+ base::WeakPtr<SoftwareFrameManagerClient> client_;
+
+ // This holds the current software framebuffer.
+ scoped_refptr<SoftwareFrame> current_frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManager);
+};
+
+class CONTENT_EXPORT SoftwareFrameMemoryManager {
+ public:
+ static SoftwareFrameMemoryManager* GetInstance();
+
+ void AddFrame(SoftwareFrameManager*, bool visible);
+ void RemoveFrame(SoftwareFrameManager*);
+ void SetFrameVisibility(SoftwareFrameManager*, bool visible);
+
+ size_t max_number_of_saved_frames() const {
+ return max_number_of_saved_frames_;
+ }
+
+ private:
+ SoftwareFrameMemoryManager();
+ ~SoftwareFrameMemoryManager();
+ void CullHiddenFrames();
+ friend struct DefaultSingletonTraits<SoftwareFrameMemoryManager>;
+
+ std::set<SoftwareFrameManager*> visible_frames_;
+ std::list<SoftwareFrameManager*> hidden_frames_;
+ size_t max_number_of_saved_frames_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareFrameMemoryManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_FRAME_MANAGER_H_
diff --git a/content/browser/renderer_host/software_frame_manager_unittest.cc b/content/browser/renderer_host/software_frame_manager_unittest.cc
new file mode 100644
index 0000000..eadbfb6
--- /dev/null
+++ b/content/browser/renderer_host/software_frame_manager_unittest.cc
@@ -0,0 +1,255 @@
+// Copyright 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 "content/browser/renderer_host/software_frame_manager.h"
+
+#include <vector>
+
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class FakeSoftwareFrameManagerClient : public SoftwareFrameManagerClient {
+ public:
+ FakeSoftwareFrameManagerClient()
+ : evicted_count_(0), weak_ptr_factory_(this) {
+ software_frame_manager_.reset(new SoftwareFrameManager(
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ virtual ~FakeSoftwareFrameManagerClient() {}
+ virtual void SoftwareFrameWasFreed(
+ uint32 output_surface_id, unsigned frame_id) OVERRIDE {
+ freed_frames_.push_back(std::make_pair(output_surface_id, frame_id));
+ }
+ virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE {
+ ++evicted_count_;
+ }
+
+ bool SwapToNewFrame(uint32 output_surface, unsigned frame_id) {
+ cc::SoftwareFrameData frame;
+ frame.id = frame_id;
+ frame.size = gfx::Size(1, 1);
+ frame.damage_rect = gfx::Rect(frame.size);
+ frame.handle = base::SharedMemory::NULLHandle();
+ return software_frame_manager_->SwapToNewFrame(
+ output_surface, &frame, 1.0, base::GetCurrentProcessHandle());
+ }
+
+ SoftwareFrameManager* software_frame_manager() {
+ return software_frame_manager_.get();
+ }
+ size_t freed_frame_count() const { return freed_frames_.size(); }
+ size_t evicted_frame_count() const { return evicted_count_; }
+
+ private:
+ std::vector<std::pair<uint32,unsigned> > freed_frames_;
+ size_t evicted_count_;
+
+ scoped_ptr<SoftwareFrameManager> software_frame_manager_;
+ base::WeakPtrFactory<FakeSoftwareFrameManagerClient>
+ weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeSoftwareFrameManagerClient);
+};
+
+class SoftwareFrameManagerTest : public testing::Test {
+ public:
+ SoftwareFrameManagerTest() {}
+ void AllocateClients(size_t num_clients) {
+ for (size_t i = 0; i < num_clients; ++i)
+ clients_.push_back(new FakeSoftwareFrameManagerClient);
+ }
+ void FreeClients() {
+ for (size_t i = 0; i < clients_.size(); ++i)
+ delete clients_[i];
+ clients_.clear();
+ }
+ size_t MaxNumberOfSavedFrames() const {
+ size_t result = SoftwareFrameMemoryManager::GetInstance()->
+ max_number_of_saved_frames();
+ return result;
+ }
+
+ protected:
+ std::vector<FakeSoftwareFrameManagerClient*> clients_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManagerTest);
+};
+
+TEST_F(SoftwareFrameManagerTest, DoNotEvictVisible) {
+ // Create twice as many frames as are allowed.
+ AllocateClients(2 * MaxNumberOfSavedFrames());
+
+ // Swap a visible frame to all clients_. Because they are all visible,
+ // the should not be evicted.
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ bool swap_result = clients_[i]->SwapToNewFrame(
+ static_cast<uint32>(i), 0);
+ clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_TRUE(swap_result);
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+
+ // Swap another frame and make sure the original was freed (but not evicted).
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ bool swap_result = clients_[i]->SwapToNewFrame(
+ static_cast<uint32>(i), 1);
+ clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_TRUE(swap_result);
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(1u, clients_[i]->freed_frame_count());
+ }
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(1u, clients_[i]->freed_frame_count());
+ }
+
+ // Mark the frames as nonvisible and make sure they start getting evicted.
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ clients_[i]->software_frame_manager()->SetVisibility(false);
+ if (clients_.size() - i > MaxNumberOfSavedFrames()) {
+ EXPECT_EQ(1u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(2u, clients_[i]->freed_frame_count());
+ } else {
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(1u, clients_[i]->freed_frame_count());
+ }
+ }
+
+ // Clean up.
+ FreeClients();
+}
+
+TEST_F(SoftwareFrameManagerTest, DoNotEvictDuringSwap) {
+ // Create twice as many frames as are allowed.
+ AllocateClients(2 * MaxNumberOfSavedFrames());
+
+ // Swap a visible frame to all clients_. Because they are all visible,
+ // the should not be evicted.
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+ clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_TRUE(swap_result);
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+
+ // Now create a test non-visible client, and swap a non-visible frame in.
+ scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
+ new FakeSoftwareFrameManagerClient);
+ test_client->software_frame_manager()->SetVisibility(false);
+ {
+ bool swap_result = test_client->SwapToNewFrame(
+ static_cast<uint32>(500), 0);
+ EXPECT_TRUE(swap_result);
+ EXPECT_EQ(0u, test_client->evicted_frame_count());
+ EXPECT_EQ(0u, test_client->freed_frame_count());
+ test_client->software_frame_manager()->SwapToNewFrameComplete(false);
+ EXPECT_EQ(1u, test_client->evicted_frame_count());
+ EXPECT_EQ(1u, test_client->freed_frame_count());
+ }
+
+ // Clean up.
+ FreeClients();
+}
+
+TEST_F(SoftwareFrameManagerTest, Cleanup) {
+ // Create twice as many frames as are allowed.
+ AllocateClients(2 * MaxNumberOfSavedFrames());
+
+ // Swap a visible frame to all clients_. Because they are all visible,
+ // the should not be evicted.
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+ clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_TRUE(swap_result);
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+
+ // Destroy them.
+ FreeClients();
+
+ // Create the maximum number of frames, all non-visible. They should not
+ // be evicted, because the previous frames were cleaned up at destruction.
+ AllocateClients(MaxNumberOfSavedFrames());
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ cc::SoftwareFrameData frame;
+ bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+ clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_TRUE(swap_result);
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
+ EXPECT_EQ(0u, clients_[i]->freed_frame_count());
+ }
+
+ // Clean up.
+ FreeClients();
+}
+
+TEST_F(SoftwareFrameManagerTest, EvictVersusFree) {
+ // Create twice as many frames as are allowed and swap a visible frame to all
+ // clients_. Because they are all visible, the should not be evicted.
+ AllocateClients(2 * MaxNumberOfSavedFrames());
+ for (size_t i = 0; i < clients_.size(); ++i) {
+ clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
+ clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
+ }
+
+ // Create a test client with a frame that is not evicted.
+ scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
+ new FakeSoftwareFrameManagerClient);
+ bool swap_result = test_client->SwapToNewFrame(static_cast<uint32>(500), 0);
+ EXPECT_TRUE(swap_result);
+ test_client->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_EQ(0u, test_client->evicted_frame_count());
+ EXPECT_EQ(0u, test_client->freed_frame_count());
+
+ // Take out a reference on the current frame and make the memory manager
+ // evict it. The frame will not be freed until this reference is released.
+ cc::TextureMailbox mailbox;
+ scoped_ptr<cc::SingleReleaseCallback> callback;
+ test_client->software_frame_manager()->GetCurrentFrameMailbox(
+ &mailbox, &callback);
+ test_client->software_frame_manager()->SetVisibility(false);
+ EXPECT_EQ(1u, test_client->evicted_frame_count());
+ EXPECT_EQ(0u, test_client->freed_frame_count());
+
+ // Swap a few frames. The frames will be freed as they are swapped out.
+ for (size_t frame = 0; frame < 10; ++frame) {
+ bool swap_result = test_client->SwapToNewFrame(
+ static_cast<uint32>(500), 1 + static_cast<int>(frame));
+ EXPECT_TRUE(swap_result);
+ test_client->software_frame_manager()->SwapToNewFrameComplete(true);
+ EXPECT_EQ(frame, test_client->freed_frame_count());
+ EXPECT_EQ(1u, test_client->evicted_frame_count());
+ }
+
+ // The reference to the frame that we didn't free is in the callback
+ // object. It will go away when the callback is destroyed.
+ EXPECT_EQ(9u, test_client->freed_frame_count());
+ EXPECT_EQ(1u, test_client->evicted_frame_count());
+ callback->Run(0, false);
+ callback.reset();
+ EXPECT_EQ(10u, test_client->freed_frame_count());
+ EXPECT_EQ(1u, test_client->evicted_frame_count());
+
+ FreeClients();
+}
+
+} // namespace content
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index aec6539..06cefae 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -789,8 +789,8 @@
'browser/renderer_host/dip_util.h',
'browser/renderer_host/file_utilities_message_filter.cc',
'browser/renderer_host/file_utilities_message_filter.h',
- 'browser/renderer_host/frame_memory_manager.cc',
- 'browser/renderer_host/frame_memory_manager.h',
+ 'browser/renderer_host/software_frame_manager.cc',
+ 'browser/renderer_host/software_frame_manager.h',
'browser/renderer_host/frame_tree.cc',
'browser/renderer_host/frame_tree.h',
'browser/renderer_host/frame_tree_node.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 3ee001c..09673f5 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -442,6 +442,7 @@
'browser/renderer_host/render_widget_host_view_guest_unittest.cc',
'browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm',
'browser/renderer_host/render_widget_host_view_mac_unittest.mm',
+ 'browser/renderer_host/software_frame_manager_unittest.cc',
'browser/renderer_host/synthetic_gesture_controller_unittest.cc',
'browser/renderer_host/text_input_client_mac_unittest.mm',
'browser/renderer_host/web_input_event_aura_unittest.cc',