summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/render_process.cc
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-20 02:00:04 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-20 02:00:04 +0000
commite68e62fa169c45bd779bfe890aa4fcdaa24d267d (patch)
treeefdb18adec880e7f780d8cde4e12893d3a20234f /chrome/renderer/render_process.cc
parent7fe07d0726bad485fa40150aa9f7cecb1318217e (diff)
downloadchromium_src-e68e62fa169c45bd779bfe890aa4fcdaa24d267d.zip
chromium_src-e68e62fa169c45bd779bfe890aa4fcdaa24d267d.tar.gz
chromium_src-e68e62fa169c45bd779bfe890aa4fcdaa24d267d.tar.bz2
Bitmap transport
This patch reworks bitmap transport on all platforms. Linux and Mac are switched from serialising bitmaps over the IPC channel to using shared memory. All platforms gain a shared memory mapping cache on the host side. The concept of a TransportDIB (device independent bitmap) is added to encapsulate most of the platform specifics. On Linux, we use SysV shared memory. This is because X shared pixmaps, which predate POSIX SHM, can only use SysV. By using SysV between renderer and browser, we open up the possibility to map the shared memory directly from the renderer to the X server. On Mac, we use POSIX shared memory. However, since this needs filesystem access and the Mac renderer is sandboxed from the filesystem, we add two new messages from renderer -> browser: The first, AllocTransportDIB, synchronously creates a transport DIB in the browser and passes a handle back to the renderer. The second, FreeTransportDIB, asynchronously, notifies the browser that it may close its handle to the shared memory region. On Mac, the shared memory regions are identified by their inode numbers on the wire. This means that the browser must keep handles open to all the allocated shared memory regions (since an inode number is insufficient to map the region). The alternative design is that the renderer passes the file descriptor with each paint operation. Since passing file descriptors is special case in the code, I felt that it would be best to minimise their use. Creating and freeing transport DIBs are relatively rare operations relative to paints and scrolls. On Windows, most of the code remains the same, except that Windows now uses the mapping cache added in this patch. This allows the browser to maintain a shared memory mapping for a transport DIB over several paints. Previously it mapped and unmapped for every operation, causing lots of TLB and VM churn. Review URL: http://codereview.chromium.org/21485 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10071 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/render_process.cc')
-rw-r--r--chrome/renderer/render_process.cc163
1 files changed, 107 insertions, 56 deletions
diff --git a/chrome/renderer/render_process.cc b/chrome/renderer/render_process.cc
index 853693b..198f854f 100644
--- a/chrome/renderer/render_process.cc
+++ b/chrome/renderer/render_process.cc
@@ -25,6 +25,7 @@
#include "chrome/common/ipc_channel.h"
#include "chrome/common/ipc_message_utils.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/transport_dib.h"
#include "chrome/renderer/render_view.h"
#include "webkit/glue/webkit_glue.h"
@@ -36,7 +37,10 @@ bool RenderProcess::load_plugins_in_process_ = false;
RenderProcess::RenderProcess(const std::wstring& channel_name)
: render_thread_(channel_name),
- ALLOW_THIS_IN_INITIALIZER_LIST(clearer_factory_(this)) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_(
+ base::TimeDelta::FromSeconds(5),
+ this, &RenderProcess::ClearTransportDIBCache)),
+ sequence_number_(0) {
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i)
shared_mem_cache_[i] = NULL;
}
@@ -48,7 +52,7 @@ RenderProcess::~RenderProcess() {
// This race condition causes a crash when the renderer process is shutting
// down.
render_thread_.Stop();
- ClearSharedMemCache();
+ ClearTransportDIBCache();
}
// static
@@ -124,97 +128,144 @@ bool RenderProcess::ShouldLoadPluginsInProcess() {
return load_plugins_in_process_;
}
-// static
-base::SharedMemory* RenderProcess::AllocSharedMemory(size_t size) {
- self()->clearer_factory_.RevokeAll();
-
- base::SharedMemory* mem = self()->GetSharedMemFromCache(size);
- if (mem)
- return mem;
+// -----------------------------------------------------------------------------
+// Platform specific code for dealing with bitmap transport...
- // Round-up size to allocation granularity
- size_t allocation_granularity = base::SysInfo::VMAllocationGranularity();
- size = size / allocation_granularity + 1;
- size = size * allocation_granularity;
+// -----------------------------------------------------------------------------
+// Create a platform canvas object which renders into the given transport
+// memory.
+// -----------------------------------------------------------------------------
+static skia::PlatformCanvas* CanvasFromTransportDIB(
+ TransportDIB* dib, const gfx::Rect& rect) {
+#if defined(OS_WIN)
+ return new skia::PlatformCanvas(rect.width(), rect.height(), true,
+ dib->handle());
+#elif defined(OS_LINUX) || defined(OS_MACOSX)
+ return new skia::PlatformCanvas(rect.width(), rect.height(), true,
+ reinterpret_cast<uint8_t*>(dib->memory()));
+#endif
+}
- mem = new base::SharedMemory();
- if (!mem)
+TransportDIB* RenderProcess::CreateTransportDIB(size_t size) {
+#if defined(OS_WIN) || defined(OS_LINUX)
+ // Windows and Linux create transport DIBs inside the renderer
+ return TransportDIB::Create(size, sequence_number_++);
+#elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX)
+ // Mac creates transport DIBs in the browser, so we need to do a sync IPC to
+ // get one.
+ IPC::Maybe<TransportDIB::Handle> mhandle;
+ IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &mhandle);
+ if (!render_thread_.Send(msg))
return NULL;
- if (!mem->Create(L"", false, true, size)) {
- delete mem;
+ if (!mhandle.valid)
return NULL;
+ return TransportDIB::Map(mhandle.value);
+#endif // defined(OS_MACOSX)
+}
+
+void RenderProcess::FreeTransportDIB(TransportDIB* dib) {
+ if (!dib)
+ return;
+
+#if defined(OS_MACOSX)
+ // On Mac we need to tell the browser that it can drop a reference to the
+ // shared memory.
+ IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id());
+ render_thread_.Send(msg);
+#endif
+
+ delete dib;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// static
+skia::PlatformCanvas* RenderProcess::GetDrawingCanvas(
+ TransportDIB** memory, const gfx::Rect& rect) {
+ const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width());
+ const size_t size = stride * rect.height();
+
+ if (!self()->GetTransportDIBFromCache(memory, size)) {
+ *memory = self()->CreateTransportDIB(size);
+ if (!*memory)
+ return false;
}
- return mem;
+ return CanvasFromTransportDIB(*memory, rect);
}
// static
-void RenderProcess::FreeSharedMemory(base::SharedMemory* mem) {
+void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) {
if (self()->PutSharedMemInCache(mem)) {
- self()->ScheduleCacheClearer();
+ self()->shared_mem_cache_cleaner_.Reset();
return;
}
- DeleteSharedMem(mem);
-}
-// static
-void RenderProcess::DeleteSharedMem(base::SharedMemory* mem) {
- delete mem;
+ self()->FreeTransportDIB(mem);
}
-base::SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) {
+bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem,
+ size_t size) {
// look for a cached object that is suitable for the requested size.
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
- base::SharedMemory* mem = shared_mem_cache_[i];
- if (mem && mem->max_size() >= size) {
+ if (shared_mem_cache_[i] &&
+ size <= shared_mem_cache_[i]->size()) {
+ *mem = shared_mem_cache_[i];
shared_mem_cache_[i] = NULL;
- return mem;
+ return true;
}
}
- return NULL;
+
+ return false;
}
-bool RenderProcess::PutSharedMemInCache(base::SharedMemory* mem) {
+int RenderProcess::FindFreeCacheSlot(size_t size) {
// simple algorithm:
// - look for an empty slot to store mem, or
- // - if full, then replace any existing cache entry that is smaller than the
- // given shared memory object.
+ // - if full, then replace smallest entry which is smaller than |size|
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
- if (!shared_mem_cache_[i]) {
- shared_mem_cache_[i] = mem;
- return true;
- }
+ if (shared_mem_cache_[i] == NULL)
+ return i;
}
- for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
- base::SharedMemory* cached_mem = shared_mem_cache_[i];
- if (cached_mem->max_size() < mem->max_size()) {
- shared_mem_cache_[i] = mem;
- DeleteSharedMem(cached_mem);
- return true;
+
+ size_t smallest_size = size;
+ int smallest_index = -1;
+
+ for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) {
+ const size_t entry_size = shared_mem_cache_[i]->size();
+ if (entry_size < smallest_size) {
+ smallest_size = entry_size;
+ smallest_index = i;
}
}
- return false;
+
+ if (smallest_index != -1) {
+ FreeTransportDIB(shared_mem_cache_[smallest_index]);
+ shared_mem_cache_[smallest_index] = NULL;
+ }
+
+ return smallest_index;
}
-void RenderProcess::ClearSharedMemCache() {
+bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) {
+ const int slot = FindFreeCacheSlot(mem->size());
+ if (slot == -1)
+ return false;
+
+ shared_mem_cache_[slot] = mem;
+ return true;
+}
+
+void RenderProcess::ClearTransportDIBCache() {
for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
if (shared_mem_cache_[i]) {
- DeleteSharedMem(shared_mem_cache_[i]);
+ FreeTransportDIB(shared_mem_cache_[i]);
shared_mem_cache_[i] = NULL;
}
}
}
-void RenderProcess::ScheduleCacheClearer() {
- // If we already have a deferred clearer, then revoke it so we effectively
- // delay cache clearing until idle for our desired interval.
- clearer_factory_.RevokeAll();
-
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache),
- 5000 /* 5 seconds */);
-}
-
void RenderProcess::Cleanup() {
// TODO(port)
// Try and limit what we pull in for our non-Win unit test bundle