diff options
author | jbauman@chromium.org <jbauman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-14 21:50:36 +0000 |
---|---|---|
committer | jbauman@chromium.org <jbauman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-14 21:50:36 +0000 |
commit | 142b19f13984918a79842905ddfee6efed72e56d (patch) | |
tree | 7efe121e525119596cbe23fdc6b12120b43c6ae5 | |
parent | 6b4c88b9d8dc0dbcca025bd768dd62dce09d362a (diff) | |
download | chromium_src-142b19f13984918a79842905ddfee6efed72e56d.zip chromium_src-142b19f13984918a79842905ddfee6efed72e56d.tar.gz chromium_src-142b19f13984918a79842905ddfee6efed72e56d.tar.bz2 |
Revert 257161 "Revert 256955 "Add shared bitmap managers for bro..."
Turns out the child process was mapping the memory twice, so fixed that.
> Revert 256955 "Add shared bitmap managers for browser and render..."
>
> Seems to be causing renderer crashes and possibly out-of-memory issues.
>
> > Add shared bitmap managers for browser and renderer processes.
> >
> > The shared bitmap managers will allow software tiles to be allocated in shared memory, so delegated rendering could be used with them.
> >
> > BUG=327220
> > R=danakj@chromium.org, jschuh@chromium.org, piman@chromium.org
> >
> > Review URL: https://codereview.chromium.org/148243013
>
> TBR=jbauman@chromium.org
>
> Review URL: https://codereview.chromium.org/197703004
TBR=jbauman@chromium.org
Review URL: https://codereview.chromium.org/200913002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257216 0039d316-1c4b-4281-b951-d872f2087c98
21 files changed, 668 insertions, 7 deletions
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc index 66cd53c..b189386 100644 --- a/cc/output/delegating_renderer.cc +++ b/cc/output/delegating_renderer.cc @@ -162,8 +162,8 @@ void DelegatingRenderer::SetVisible(bool visible) { // We loop visibility to the GPU process, since that's what manages memory. // That will allow it to feed us with memory allocations that we can act // upon. - DCHECK(context_provider); - context_provider->ContextSupport()->SetSurfaceVisible(visible); + if (context_provider) + context_provider->ContextSupport()->SetSurfaceVisible(visible); } void DelegatingRenderer::SendManagedMemoryStats(size_t bytes_visible, diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index ed1d0da..2fee3d2 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc @@ -1949,7 +1949,8 @@ void ResourceProvider::BeginSetPixels(ResourceId id) { DCHECK(resource->pixel_buffer); DCHECK_EQ(RGBA_8888, resource->format); - std::swap(resource->pixels, resource->pixel_buffer); + memcpy( + resource->pixels, resource->pixel_buffer, 4 * resource->size.GetArea()); delete[] resource->pixel_buffer; resource->pixel_buffer = NULL; } diff --git a/cc/resources/shared_bitmap.cc b/cc/resources/shared_bitmap.cc index 3a6fc35..3b94d45 100644 --- a/cc/resources/shared_bitmap.cc +++ b/cc/resources/shared_bitmap.cc @@ -4,6 +4,9 @@ #include "cc/resources/shared_bitmap.h" +#include "base/numerics/safe_math.h" +#include "base/rand_util.h" + namespace cc { SharedBitmap::SharedBitmap( @@ -14,4 +17,26 @@ SharedBitmap::SharedBitmap( SharedBitmap::~SharedBitmap() { free_callback_.Run(this); } +// static +bool SharedBitmap::GetSizeInBytes(const gfx::Size& size, + size_t* size_in_bytes) { + if (size.width() <= 0 || size.height() <= 0) + return false; + base::CheckedNumeric<int> s = size.width(); + s *= size.height(); + s *= 4; + if (!s.IsValid()) + return false; + *size_in_bytes = s.ValueOrDie(); + return true; +} + +// static +SharedBitmapId SharedBitmap::GenerateId() { + SharedBitmapId id; + // Needs cryptographically-secure random numbers. + base::RandBytes(id.name, sizeof(id.name)); + return id; +} + } // namespace cc diff --git a/cc/resources/shared_bitmap.h b/cc/resources/shared_bitmap.h index 9575068..d62ffcc 100644 --- a/cc/resources/shared_bitmap.h +++ b/cc/resources/shared_bitmap.h @@ -10,6 +10,7 @@ #include "base/memory/shared_memory.h" #include "cc/base/cc_export.h" #include "gpu/command_buffer/common/mailbox.h" +#include "ui/gfx/size.h" namespace base { class SharedMemory; } @@ -38,6 +39,11 @@ class CC_EXPORT SharedBitmap { SharedBitmapId id() { return id_; } + // Returns true if the size is valid and false otherwise. + static bool GetSizeInBytes(const gfx::Size& size, size_t* size_in_bytes); + + static SharedBitmapId GenerateId(); + private: base::SharedMemory* memory_; SharedBitmapId id_; diff --git a/content/browser/compositor/image_transport_factory.cc b/content/browser/compositor/image_transport_factory.cc index c0b739d..70ffc9c 100644 --- a/content/browser/compositor/image_transport_factory.cc +++ b/content/browser/compositor/image_transport_factory.cc @@ -7,6 +7,7 @@ #include "base/command_line.h" #include "content/browser/compositor/gpu_process_transport_factory.h" #include "content/browser/compositor/no_transport_image_transport_factory.h" +#include "content/common/host_shared_bitmap_manager.h" #include "ui/compositor/compositor.h" #include "ui/compositor/compositor_switches.h" #include "ui/gl/gl_implementation.h" @@ -26,6 +27,7 @@ void ImageTransportFactory::Initialize() { return; g_factory = new GpuProcessTransportFactory; ui::ContextFactory::SetInstance(g_factory->AsContextFactory()); + ui::Compositor::SetSharedBitmapManager(HostSharedBitmapManager::current()); } void ImageTransportFactory::InitializeForUnitTests( diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 0aa002b..958b491 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -35,6 +35,7 @@ #include "content/common/desktop_notification_messages.h" #include "content/common/frame_messages.h" #include "content/common/gpu/client/gpu_memory_buffer_impl.h" +#include "content/common/host_shared_bitmap_manager.h" #include "content/common/media/media_param_traits.h" #include "content/common/view_messages.h" #include "content/public/browser/browser_child_process_host.h" @@ -354,6 +355,7 @@ RenderMessageFilter::~RenderMessageFilter() { } void RenderMessageFilter::OnChannelClosing() { + HostSharedBitmapManager::current()->ProcessRemoved(PeerHandle()); #if defined(ENABLE_PLUGINS) for (std::set<OpenChannelToNpapiPluginCallback*>::iterator it = plugin_host_clients_.begin(); it != plugin_host_clients_.end(); ++it) { @@ -430,8 +432,14 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, OnCheckNotificationPermission) IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory, OnAllocateSharedMemory) + IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedBitmap, + OnAllocateSharedBitmap) IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer, OnAllocateGpuMemoryBuffer) + IPC_MESSAGE_HANDLER(ChildProcessHostMsg_AllocatedSharedBitmap, + OnAllocatedSharedBitmap) + IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedSharedBitmap, + OnDeletedSharedBitmap) #if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID) IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB) IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB) @@ -926,6 +934,26 @@ void RenderMessageFilter::OnAllocateSharedMemory( buffer_size, PeerHandle(), handle); } +void RenderMessageFilter::OnAllocateSharedBitmap( + uint32 buffer_size, + const cc::SharedBitmapId& id, + base::SharedMemoryHandle* handle) { + HostSharedBitmapManager::current()->AllocateSharedBitmapForChild( + PeerHandle(), buffer_size, id, handle); +} + +void RenderMessageFilter::OnAllocatedSharedBitmap( + size_t buffer_size, + const base::SharedMemoryHandle& handle, + const cc::SharedBitmapId& id) { + HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap( + buffer_size, handle, PeerHandle(), id); +} + +void RenderMessageFilter::OnDeletedSharedBitmap(const cc::SharedBitmapId& id) { + HostSharedBitmapManager::current()->ChildDeletedSharedBitmap(id); +} + net::CookieStore* RenderMessageFilter::GetCookieStoreForURL( const GURL& url) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index b87b962..a82ed94 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h @@ -19,6 +19,7 @@ #include "base/sequenced_task_runner_helpers.h" #include "base/strings/string16.h" #include "build/build_config.h" +#include "cc/resources/shared_bitmap_manager.h" #include "content/common/pepper_renderer_instance_data.h" #include "content/public/browser/browser_message_filter.h" #include "content/public/common/three_d_api_types.h" @@ -213,6 +214,13 @@ class RenderMessageFilter : public BrowserMessageFilter { // in the renderer on POSIX due to the sandbox. void OnAllocateSharedMemory(uint32 buffer_size, base::SharedMemoryHandle* handle); + void OnAllocateSharedBitmap(uint32 buffer_size, + const cc::SharedBitmapId& id, + base::SharedMemoryHandle* handle); + void OnAllocatedSharedBitmap(size_t buffer_size, + const base::SharedMemoryHandle& handle, + const cc::SharedBitmapId& id); + void OnDeletedSharedBitmap(const cc::SharedBitmapId& id); void OnResolveProxy(const GURL& url, IPC::Message* reply_msg); // Browser side transport DIB allocation diff --git a/content/child/child_shared_bitmap_manager.cc b/content/child/child_shared_bitmap_manager.cc new file mode 100644 index 0000000..7325789 --- /dev/null +++ b/content/child/child_shared_bitmap_manager.cc @@ -0,0 +1,91 @@ +// 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 "content/child/child_shared_bitmap_manager.h" + +#include "content/child/child_thread.h" +#include "content/common/child_process_messages.h" +#include "ui/gfx/size.h" + +namespace content { + +ChildSharedBitmapManager::ChildSharedBitmapManager( + scoped_refptr<ThreadSafeSender> sender) + : sender_(sender) {} + +ChildSharedBitmapManager::~ChildSharedBitmapManager() {} + +scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::AllocateSharedBitmap( + const gfx::Size& size) { + TRACE_EVENT2("renderer", + "ChildSharedBitmapManager::AllocateSharedMemory", + "width", + size.width(), + "height", + size.height()); + size_t memory_size; + if (!cc::SharedBitmap::GetSizeInBytes(size, &memory_size)) + return scoped_ptr<cc::SharedBitmap>(); + cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + scoped_ptr<base::SharedMemory> memory; +#if defined(OS_POSIX) + base::SharedMemoryHandle handle; + sender_->Send(new ChildProcessHostMsg_SyncAllocateSharedBitmap( + memory_size, id, &handle)); + memory = make_scoped_ptr(new base::SharedMemory(handle, false)); + memory->Map(memory_size); +#else + memory.reset(ChildThread::AllocateSharedMemory(memory_size, sender_)); + CHECK(memory); + base::SharedMemoryHandle handle_to_send = memory->handle(); + sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap( + memory_size, handle_to_send, id)); +#endif + // The compositor owning the SharedBitmap will be closed before the + // ChildThread containng this, making the use of base::Unretained safe. + return scoped_ptr<cc::SharedBitmap>(new cc::SharedBitmap( + memory.release(), + id, + base::Bind(&ChildSharedBitmapManager::FreeSharedMemory, + base::Unretained(this)))); +} + +scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::GetSharedBitmapFromId( + const gfx::Size&, + const cc::SharedBitmapId&) { + NOTREACHED(); + return scoped_ptr<cc::SharedBitmap>(); +} + +scoped_ptr<cc::SharedBitmap> ChildSharedBitmapManager::GetBitmapForSharedMemory( + base::SharedMemory* mem) { + cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + base::SharedMemoryHandle handle_to_send = mem->handle(); +#if defined(OS_POSIX) + if (!mem->ShareToProcess(base::GetCurrentProcessHandle(), &handle_to_send)) + return scoped_ptr<cc::SharedBitmap>(); +#endif + sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap( + mem->mapped_size(), handle_to_send, id)); + // The compositor owning the SharedBitmap will be closed before the + // ChildThread containng this, making the use of base::Unretained safe. + return scoped_ptr<cc::SharedBitmap>(new cc::SharedBitmap( + mem, + id, + base::Bind(&ChildSharedBitmapManager::ReleaseSharedBitmap, + base::Unretained(this)))); +} + +void ChildSharedBitmapManager::FreeSharedMemory(cc::SharedBitmap* bitmap) { + TRACE_EVENT0("renderer", "ChildSharedBitmapManager::FreeSharedMemory"); + sender_->Send(new ChildProcessHostMsg_DeletedSharedBitmap(bitmap->id())); + delete bitmap->memory(); +} + +void ChildSharedBitmapManager::ReleaseSharedBitmap(cc::SharedBitmap* handle) { + TRACE_EVENT0("renderer", "ChildSharedBitmapManager::ReleaseSharedBitmap"); + sender_->Send(new ChildProcessHostMsg_DeletedSharedBitmap(handle->id())); +} + +} // namespace content diff --git a/content/child/child_shared_bitmap_manager.h b/content/child/child_shared_bitmap_manager.h new file mode 100644 index 0000000..1e54466 --- /dev/null +++ b/content/child/child_shared_bitmap_manager.h @@ -0,0 +1,40 @@ +// 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. + +#ifndef CONTENT_CHILD_CHILD_SHARED_BITMAP_MANAGER_H_ +#define CONTENT_CHILD_CHILD_SHARED_BITMAP_MANAGER_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "cc/resources/shared_bitmap_manager.h" +#include "content/child/thread_safe_sender.h" + +namespace content { + +class ChildSharedBitmapManager : public cc::SharedBitmapManager { + public: + ChildSharedBitmapManager(scoped_refptr<ThreadSafeSender> sender); + virtual ~ChildSharedBitmapManager(); + + virtual scoped_ptr<cc::SharedBitmap> AllocateSharedBitmap( + const gfx::Size& size) OVERRIDE; + virtual scoped_ptr<cc::SharedBitmap> GetSharedBitmapFromId( + const gfx::Size&, + const cc::SharedBitmapId&) OVERRIDE; + virtual scoped_ptr<cc::SharedBitmap> GetBitmapForSharedMemory( + base::SharedMemory* mem) OVERRIDE; + + private: + void FreeSharedMemory(cc::SharedBitmap* bitmap); + void ReleaseSharedBitmap(cc::SharedBitmap*); + + scoped_refptr<ThreadSafeSender> sender_; + + DISALLOW_COPY_AND_ASSIGN(ChildSharedBitmapManager); +}; + +} // namespace content + +#endif // CONTENT_CHILD_CHILD_SHARED_BITMAP_MANAGER_H_ diff --git a/content/child/child_thread.cc b/content/child/child_thread.cc index 57919e5..3ecdb58 100644 --- a/content/child/child_thread.cc +++ b/content/child/child_thread.cc @@ -27,6 +27,7 @@ #include "content/child/child_histogram_message_filter.h" #include "content/child/child_process.h" #include "content/child/child_resource_message_filter.h" +#include "content/child/child_shared_bitmap_manager.h" #include "content/child/fileapi/file_system_dispatcher.h" #include "content/child/power_monitor_broadcast_source.h" #include "content/child/quota_dispatcher.h" @@ -311,6 +312,9 @@ void ChildThread::Init() { ::HeapProfilerStop, ::GetHeapProfile)); #endif + + shared_bitmap_manager_.reset( + new ChildSharedBitmapManager(thread_safe_sender())); } ChildThread::~ChildThread() { diff --git a/content/child/child_thread.h b/content/child/child_thread.h index 33083bf..233e9c8 100644 --- a/content/child/child_thread.h +++ b/content/child/child_thread.h @@ -38,6 +38,7 @@ class WebFrame; namespace content { class ChildHistogramMessageFilter; class ChildResourceMessageFilter; +class ChildSharedBitmapManager; class FileSystemDispatcher; class ServiceWorkerDispatcher; class ServiceWorkerMessageFilter; @@ -86,6 +87,10 @@ class CONTENT_EXPORT ChildThread : public IPC::Listener, public IPC::Sender { static base::SharedMemory* AllocateSharedMemory(size_t buf_size, IPC::Sender* sender); + ChildSharedBitmapManager* shared_bitmap_manager() const { + return shared_bitmap_manager_.get(); + } + ResourceDispatcher* resource_dispatcher() const { return resource_dispatcher_.get(); } @@ -227,6 +232,8 @@ class CONTENT_EXPORT ChildThread : public IPC::Listener, public IPC::Sender { scoped_refptr<QuotaMessageFilter> quota_message_filter_; + scoped_ptr<ChildSharedBitmapManager> shared_bitmap_manager_; + base::WeakPtrFactory<ChildThread> channel_connected_factory_; // Observes the trace event system. When tracing is enabled, optionally diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h index 5700c48..f220891 100644 --- a/content/common/child_process_messages.h +++ b/content/common/child_process_messages.h @@ -11,6 +11,7 @@ #include "base/memory/shared_memory.h" #include "base/tracked_objects.h" #include "base/values.h" +#include "cc/resources/shared_bitmap_manager.h" #include "content/common/content_export.h" #include "ipc/ipc_message_macros.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -146,6 +147,23 @@ IPC_SYNC_MESSAGE_CONTROL1_1(ChildProcessHostMsg_SyncAllocateSharedMemory, uint32 /* buffer size */, base::SharedMemoryHandle) +// Asks the browser to create a block of shared memory for the child process to +// fill in and pass back to the browser. +IPC_SYNC_MESSAGE_CONTROL2_1(ChildProcessHostMsg_SyncAllocateSharedBitmap, + uint32 /* buffer size */, + cc::SharedBitmapId, + base::SharedMemoryHandle) + +// Informs the browser that the child allocated a shared bitmap. +IPC_MESSAGE_CONTROL3(ChildProcessHostMsg_AllocatedSharedBitmap, + uint32 /* buffer size */, + base::SharedMemoryHandle, + cc::SharedBitmapId) + +// Informs the browser that the child deleted a shared bitmap. +IPC_MESSAGE_CONTROL1(ChildProcessHostMsg_DeletedSharedBitmap, + cc::SharedBitmapId) + #if defined(USE_TCMALLOC) // Reply to ChildProcessMsg_GetTcmallocStats. IPC_MESSAGE_CONTROL1(ChildProcessHostMsg_TcmallocStats, diff --git a/content/common/host_shared_bitmap_manager.cc b/content/common/host_shared_bitmap_manager.cc new file mode 100644 index 0000000..aa0cd81 --- /dev/null +++ b/content/common/host_shared_bitmap_manager.cc @@ -0,0 +1,168 @@ +// 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/common/host_shared_bitmap_manager.h" + +#include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" +#include "content/common/view_messages.h" +#include "ui/gfx/size.h" + +namespace content { + +class BitmapData : public base::RefCountedThreadSafe<BitmapData> { + public: + BitmapData(base::ProcessHandle process_handle, + base::SharedMemoryHandle memory_handle, + size_t buffer_size) + : process_handle(process_handle), + memory_handle(memory_handle), + buffer_size(buffer_size) {} + base::ProcessHandle process_handle; + base::SharedMemoryHandle memory_handle; + scoped_ptr<base::SharedMemory> memory; + size_t buffer_size; + + private: + friend class base::RefCountedThreadSafe<BitmapData>; + ~BitmapData() {} + DISALLOW_COPY_AND_ASSIGN(BitmapData); +}; + +// Holds a reference on the memory to keep it alive. +void FreeSharedMemory(scoped_refptr<BitmapData> data, + cc::SharedBitmap* bitmap) {} + +base::LazyInstance<HostSharedBitmapManager> g_shared_memory_manager = + LAZY_INSTANCE_INITIALIZER; + +HostSharedBitmapManager::HostSharedBitmapManager() {} +HostSharedBitmapManager::~HostSharedBitmapManager() {} + +HostSharedBitmapManager* HostSharedBitmapManager::current() { + return g_shared_memory_manager.Pointer(); +} + +scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::AllocateSharedBitmap( + const gfx::Size& size) { + // Bitmaps allocated in host don't need to be shared to other processes, so + // allocate them with new instead. + return scoped_ptr<cc::SharedBitmap>(); +} + +scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetSharedBitmapFromId( + const gfx::Size& size, + const cc::SharedBitmapId& id) { + base::AutoLock lock(lock_); + BitmapMap::iterator it = handle_map_.find(id); + if (it == handle_map_.end()) + return scoped_ptr<cc::SharedBitmap>(); + + BitmapData* data = it->second.get(); + + size_t bitmap_size; + if (!cc::SharedBitmap::GetSizeInBytes(size, &bitmap_size) || + bitmap_size > data->buffer_size) + return scoped_ptr<cc::SharedBitmap>(); + + if (!data->memory->memory()) { + TRACE_EVENT0("renderer_host", + "HostSharedBitmapManager::GetSharedBitmapFromId"); + if (!data->memory->Map(data->buffer_size)) { + return scoped_ptr<cc::SharedBitmap>(); + } + } + + scoped_ptr<cc::SharedBitmap> bitmap(new cc::SharedBitmap( + data->memory.get(), id, base::Bind(&FreeSharedMemory, it->second))); + + return bitmap.Pass(); +} + +scoped_ptr<cc::SharedBitmap> HostSharedBitmapManager::GetBitmapForSharedMemory( + base::SharedMemory*) { + return scoped_ptr<cc::SharedBitmap>(); +} + +void HostSharedBitmapManager::ChildAllocatedSharedBitmap( + size_t buffer_size, + const base::SharedMemoryHandle& handle, + base::ProcessHandle process_handle, + const cc::SharedBitmapId& id) { + base::AutoLock lock(lock_); + if (handle_map_.find(id) != handle_map_.end()) + return; + scoped_refptr<BitmapData> data( + new BitmapData(process_handle, handle, buffer_size)); + + handle_map_[id] = data; + process_map_[process_handle].insert(id); +#if defined(OS_WIN) + data->memory = make_scoped_ptr( + new base::SharedMemory(data->memory_handle, false, data->process_handle)); +#else + data->memory = + make_scoped_ptr(new base::SharedMemory(data->memory_handle, false)); +#endif +} + +void HostSharedBitmapManager::AllocateSharedBitmapForChild( + base::ProcessHandle process_handle, + size_t buffer_size, + const cc::SharedBitmapId& id, + base::SharedMemoryHandle* shared_memory_handle) { + base::AutoLock lock(lock_); + if (handle_map_.find(id) != handle_map_.end()) { + *shared_memory_handle = base::SharedMemory::NULLHandle(); + return; + } + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); + if (!shared_memory->CreateAndMapAnonymous(buffer_size)) { + LOG(ERROR) << "Cannot create shared memory buffer"; + *shared_memory_handle = base::SharedMemory::NULLHandle(); + return; + } + + scoped_refptr<BitmapData> data( + new BitmapData(process_handle, shared_memory->handle(), buffer_size)); + data->memory = shared_memory.Pass(); + + handle_map_[id] = data; + process_map_[process_handle].insert(id); + if (!data->memory->ShareToProcess(process_handle, shared_memory_handle)) { + LOG(ERROR) << "Cannot share shared memory buffer"; + *shared_memory_handle = base::SharedMemory::NULLHandle(); + return; + } +} + +void HostSharedBitmapManager::ChildDeletedSharedBitmap( + const cc::SharedBitmapId& id) { + base::AutoLock lock(lock_); + BitmapMap::iterator it = handle_map_.find(id); + if (it == handle_map_.end()) + return; + base::hash_set<cc::SharedBitmapId>& res = + process_map_[it->second->process_handle]; + res.erase(id); + handle_map_.erase(it); +} + +void HostSharedBitmapManager::ProcessRemoved( + base::ProcessHandle process_handle) { + base::AutoLock lock(lock_); + ProcessMap::iterator proc_it = process_map_.find(process_handle); + if (proc_it == process_map_.end()) + return; + base::hash_set<cc::SharedBitmapId>& res = proc_it->second; + + for (base::hash_set<cc::SharedBitmapId>::iterator it = res.begin(); + it != res.end(); + ++it) { + handle_map_.erase(*it); + } + process_map_.erase(proc_it); +} + +} // namespace content diff --git a/content/common/host_shared_bitmap_manager.h b/content/common/host_shared_bitmap_manager.h new file mode 100644 index 0000000..439abe6 --- /dev/null +++ b/content/common/host_shared_bitmap_manager.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef CONTENT_COMMON_HOST_SHARED_BITMAP_MANAGER_H_ +#define CONTENT_COMMON_HOST_SHARED_BITMAP_MANAGER_H_ + +#include <map> +#include <set> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/containers/hash_tables.h" +#include "base/hash.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/shared_memory.h" +#include "base/synchronization/lock.h" +#include "cc/resources/shared_bitmap_manager.h" +#include "content/common/content_export.h" + +namespace BASE_HASH_NAMESPACE { +#if defined(COMPILER_GCC) +template <> +struct hash<cc::SharedBitmapId> { + size_t operator()(const cc::SharedBitmapId& id) const { + return base::Hash(reinterpret_cast<const char*>(id.name), sizeof(id.name)); + } +}; +#elif defined(COMPILER_MSVC) +inline std::size_t hash_value(const cc::SharedBitmapId& id) { + return base::Hash(reinterpret_cast<const char*>(id.name), sizeof(id.name)); +} +#endif // COMPILER +} // namespace BASE_HASH_NAMESPACE + +namespace content { +class BitmapData; + +class CONTENT_EXPORT HostSharedBitmapManager : public cc::SharedBitmapManager { + public: + HostSharedBitmapManager(); + virtual ~HostSharedBitmapManager(); + + static HostSharedBitmapManager* current(); + + // cc::SharedBitmapManager implementation. + virtual scoped_ptr<cc::SharedBitmap> AllocateSharedBitmap( + const gfx::Size& size) OVERRIDE; + virtual scoped_ptr<cc::SharedBitmap> GetSharedBitmapFromId( + const gfx::Size& size, + const cc::SharedBitmapId&) OVERRIDE; + virtual scoped_ptr<cc::SharedBitmap> GetBitmapForSharedMemory( + base::SharedMemory*) OVERRIDE; + + void AllocateSharedBitmapForChild( + base::ProcessHandle process_handle, + size_t buffer_size, + const cc::SharedBitmapId& id, + base::SharedMemoryHandle* shared_memory_handle); + void ChildAllocatedSharedBitmap(size_t buffer_size, + const base::SharedMemoryHandle& handle, + base::ProcessHandle process_handle, + const cc::SharedBitmapId& id); + void ChildDeletedSharedBitmap(const cc::SharedBitmapId& id); + void ProcessRemoved(base::ProcessHandle process_handle); + + private: + base::Lock lock_; + + typedef base::hash_map<cc::SharedBitmapId, scoped_refptr<BitmapData> > + BitmapMap; + BitmapMap handle_map_; + + typedef base::hash_map<base::ProcessHandle, + base::hash_set<cc::SharedBitmapId> > ProcessMap; + ProcessMap process_map_; +}; + +} // namespace content + +#endif // CONTENT_COMMON_HOST_SHARED_BITMAP_MANAGER_H_ diff --git a/content/common/host_shared_bitmap_manager_unittest.cc b/content/common/host_shared_bitmap_manager_unittest.cc new file mode 100644 index 0000000..1f7d8dd --- /dev/null +++ b/content/common/host_shared_bitmap_manager_unittest.cc @@ -0,0 +1,160 @@ +// 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 "content/common/host_shared_bitmap_manager.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { +namespace { + +class HostSharedBitmapManagerTest : public testing::Test { + protected: + virtual void SetUp() { manager_.reset(new HostSharedBitmapManager()); } + scoped_ptr<HostSharedBitmapManager> manager_; +}; + +TEST_F(HostSharedBitmapManagerTest, TestCreate) { + gfx::Size bitmap_size(1, 1); + size_t size_in_bytes; + EXPECT_TRUE(cc::SharedBitmap::GetSizeInBytes(bitmap_size, &size_in_bytes)); + scoped_ptr<base::SharedMemory> bitmap(new base::SharedMemory()); + bitmap->CreateAndMapAnonymous(size_in_bytes); + memset(bitmap->memory(), 0xff, size_in_bytes); + cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + + base::SharedMemoryHandle handle; + bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle); + manager_->ChildAllocatedSharedBitmap( + size_in_bytes, handle, base::GetCurrentProcessHandle(), id); + + scoped_ptr<cc::SharedBitmap> large_bitmap; + large_bitmap = manager_->GetSharedBitmapFromId(gfx::Size(1024, 1024), id); + EXPECT_TRUE(large_bitmap.get() == NULL); + + scoped_ptr<cc::SharedBitmap> very_large_bitmap; + very_large_bitmap = + manager_->GetSharedBitmapFromId(gfx::Size(1, (1 << 30) | 1), id); + EXPECT_TRUE(very_large_bitmap.get() == NULL); + + scoped_ptr<cc::SharedBitmap> negative_size_bitmap; + negative_size_bitmap = + manager_->GetSharedBitmapFromId(gfx::Size(-1, 1024), id); + EXPECT_TRUE(negative_size_bitmap.get() == NULL); + + cc::SharedBitmapId id2 = cc::SharedBitmap::GenerateId(); + scoped_ptr<cc::SharedBitmap> invalid_bitmap; + invalid_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id2); + EXPECT_TRUE(invalid_bitmap.get() == NULL); + + scoped_ptr<cc::SharedBitmap> shared_bitmap; + shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id); + ASSERT_TRUE(shared_bitmap.get() != NULL); + EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), 4), 0); + + scoped_ptr<cc::SharedBitmap> large_bitmap2; + large_bitmap2 = manager_->GetSharedBitmapFromId(gfx::Size(1024, 1024), id); + EXPECT_TRUE(large_bitmap2.get() == NULL); + + scoped_ptr<cc::SharedBitmap> shared_bitmap2; + shared_bitmap2 = manager_->GetSharedBitmapFromId(bitmap_size, id); + EXPECT_TRUE(shared_bitmap2->pixels() == shared_bitmap->pixels()); + shared_bitmap2.reset(); + EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), + 0); + + manager_->ChildDeletedSharedBitmap(id); + + memset(bitmap->memory(), 0, size_in_bytes); + + EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), + 0); + bitmap.reset(); + shared_bitmap.reset(); +} + +TEST_F(HostSharedBitmapManagerTest, TestCreateForChild) { + gfx::Size bitmap_size(1, 1); + size_t size_in_bytes; + EXPECT_TRUE(cc::SharedBitmap::GetSizeInBytes(bitmap_size, &size_in_bytes)); + cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + base::SharedMemoryHandle handle; + manager_->AllocateSharedBitmapForChild( + base::GetCurrentProcessHandle(), size_in_bytes, id, &handle); + + EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle)); + scoped_ptr<base::SharedMemory> bitmap(new base::SharedMemory(handle, false)); + EXPECT_TRUE(bitmap->Map(size_in_bytes)); + memset(bitmap->memory(), 0xff, size_in_bytes); + + scoped_ptr<cc::SharedBitmap> shared_bitmap; + shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id); + EXPECT_TRUE(shared_bitmap); + EXPECT_TRUE( + memcmp(bitmap->memory(), shared_bitmap->pixels(), size_in_bytes) == 0); +} + +TEST_F(HostSharedBitmapManagerTest, RemoveProcess) { + gfx::Size bitmap_size(1, 1); + size_t size_in_bytes; + EXPECT_TRUE(cc::SharedBitmap::GetSizeInBytes(bitmap_size, &size_in_bytes)); + scoped_ptr<base::SharedMemory> bitmap(new base::SharedMemory()); + bitmap->CreateAndMapAnonymous(size_in_bytes); + memset(bitmap->memory(), 0xff, size_in_bytes); + cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + + base::SharedMemoryHandle handle; + bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle); + manager_->ChildAllocatedSharedBitmap( + size_in_bytes, handle, base::GetCurrentProcessHandle(), id); + + manager_->ProcessRemoved(base::kNullProcessHandle); + + scoped_ptr<cc::SharedBitmap> shared_bitmap; + shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id); + ASSERT_TRUE(shared_bitmap.get() != NULL); + + manager_->ProcessRemoved(base::GetCurrentProcessHandle()); + + scoped_ptr<cc::SharedBitmap> shared_bitmap2; + shared_bitmap2 = manager_->GetSharedBitmapFromId(bitmap_size, id); + EXPECT_TRUE(shared_bitmap2.get() == NULL); + EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), + 0); + + shared_bitmap.reset(); + + // Should no-op. + manager_->ChildDeletedSharedBitmap(id); +} + +TEST_F(HostSharedBitmapManagerTest, AddDuplicate) { + gfx::Size bitmap_size(1, 1); + size_t size_in_bytes; + EXPECT_TRUE(cc::SharedBitmap::GetSizeInBytes(bitmap_size, &size_in_bytes)); + scoped_ptr<base::SharedMemory> bitmap(new base::SharedMemory()); + bitmap->CreateAndMapAnonymous(size_in_bytes); + memset(bitmap->memory(), 0xff, size_in_bytes); + cc::SharedBitmapId id = cc::SharedBitmap::GenerateId(); + + base::SharedMemoryHandle handle; + bitmap->ShareToProcess(base::GetCurrentProcessHandle(), &handle); + manager_->ChildAllocatedSharedBitmap( + size_in_bytes, handle, base::GetCurrentProcessHandle(), id); + + scoped_ptr<base::SharedMemory> bitmap2(new base::SharedMemory()); + bitmap2->CreateAndMapAnonymous(size_in_bytes); + memset(bitmap2->memory(), 0x00, size_in_bytes); + + manager_->ChildAllocatedSharedBitmap( + size_in_bytes, bitmap2->handle(), base::GetCurrentProcessHandle(), id); + + scoped_ptr<cc::SharedBitmap> shared_bitmap; + shared_bitmap = manager_->GetSharedBitmapFromId(bitmap_size, id); + ASSERT_TRUE(shared_bitmap.get() != NULL); + EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), + 0); +} + +} // namespace +} // namespace content diff --git a/content/content_child.gypi b/content/content_child.gypi index 8e4abc1..cdd7e79 100644 --- a/content/content_child.gypi +++ b/content/content_child.gypi @@ -41,6 +41,8 @@ 'child/child_process.h', 'child/child_resource_message_filter.cc', 'child/child_resource_message_filter.h', + 'child/child_shared_bitmap_manager.cc', + 'child/child_shared_bitmap_manager.h', 'child/child_thread.cc', 'child/child_thread.h', 'child/content_child_helpers.cc', diff --git a/content/content_common.gypi b/content/content_common.gypi index ca814f0..8e46bb5 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -257,6 +257,8 @@ 'common/gpu/texture_image_transport_surface.h', 'common/handle_enumerator_win.cc', 'common/handle_enumerator_win.h', + 'common/host_shared_bitmap_manager.cc', + 'common/host_shared_bitmap_manager.h', 'common/image_messages.h', 'common/indexed_db/indexed_db_constants.h', 'common/indexed_db/indexed_db_key.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 95ca3bb..d1154bf 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -523,6 +523,7 @@ 'common/common_param_traits_unittest.cc', 'common/dom_storage/dom_storage_map_unittest.cc', 'common/gpu/gpu_memory_manager_unittest.cc', + 'common/host_shared_bitmap_manager_unittest.cc', 'common/indexed_db/indexed_db_key_unittest.cc', 'common/input/input_param_traits_unittest.cc', 'common/input/web_input_event_traits_unittest.cc', diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 8f88197..5f1910d 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc @@ -24,6 +24,7 @@ #include "cc/debug/micro_benchmark.h" #include "cc/layers/layer.h" #include "cc/trees/layer_tree_host.h" +#include "content/child/child_shared_bitmap_manager.h" #include "content/common/content_switches_internal.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/public/common/content_switches.h" @@ -395,10 +396,13 @@ void RenderWidgetCompositor::Initialize(cc::LayerTreeSettings settings) { RenderThreadImpl::current()->compositor_message_loop_proxy(); if (compositor_message_loop_proxy.get()) { layer_tree_host_ = cc::LayerTreeHost::CreateThreaded( - this, NULL, settings, compositor_message_loop_proxy); + this, + ChildThread::current()->shared_bitmap_manager(), + settings, + compositor_message_loop_proxy); } else { layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded( - this, this, NULL, settings); + this, this, ChildThread::current()->shared_bitmap_manager(), settings); } DCHECK(layer_tree_host_); } diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index e31bcfd..76b4413 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc @@ -45,6 +45,7 @@ enum SwapType { bool g_compositor_initialized = false; base::Thread* g_compositor_thread = NULL; +cc::SharedBitmapManager* g_shared_bitmap_manager; ui::ContextFactory* g_context_factory = NULL; @@ -249,9 +250,13 @@ Compositor::Compositor(gfx::AcceleratedWidget widget) base::TimeTicks before_create = base::TimeTicks::Now(); if (!!g_compositor_thread) { host_ = cc::LayerTreeHost::CreateThreaded( - this, NULL, settings, g_compositor_thread->message_loop_proxy()); + this, + g_shared_bitmap_manager, + settings, + g_compositor_thread->message_loop_proxy()); } else { - host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings); + host_ = cc::LayerTreeHost::CreateSingleThreaded( + this, this, g_shared_bitmap_manager, settings); } UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor", base::TimeTicks::Now() - before_create); @@ -320,6 +325,11 @@ void Compositor::Terminate() { g_compositor_initialized = false; } +// static +void Compositor::SetSharedBitmapManager(cc::SharedBitmapManager* manager) { + g_shared_bitmap_manager = manager; +} + void Compositor::ScheduleDraw() { if (g_compositor_thread) { host_->Composite(gfx::FrameTime::Now()); diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 21c582e..f91a294 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h @@ -33,6 +33,7 @@ class ContextProvider; class Layer; class LayerTreeDebugState; class LayerTreeHost; +class SharedBitmapManager; } namespace gfx { @@ -177,6 +178,7 @@ class COMPOSITOR_EXPORT Compositor static bool WasInitializedWithThread(); static scoped_refptr<base::MessageLoopProxy> GetCompositorMessageLoop(); static void Terminate(); + static void SetSharedBitmapManager(cc::SharedBitmapManager* manager); // Schedules a redraw of the layer tree associated with this compositor. void ScheduleDraw(); |