diff options
author | jbauman <jbauman@chromium.org> | 2015-05-12 16:02:10 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-12 23:03:30 +0000 |
commit | 8fe39ccf33d9f1a2d785c4deebce4cc7afad7d1e (patch) | |
tree | b541b3a22089b7f5b4ff417c5a5692eed1e7bd63 | |
parent | b71e399156a93a2ea675c77f1cb98c84dac813eb (diff) | |
download | chromium_src-8fe39ccf33d9f1a2d785c4deebce4cc7afad7d1e.zip chromium_src-8fe39ccf33d9f1a2d785c4deebce4cc7afad7d1e.tar.gz chromium_src-8fe39ccf33d9f1a2d785c4deebce4cc7afad7d1e.tar.bz2 |
Share backing canvases between browser compositors.
The software compositor's canvas is only used between BeginPaint and EndPaint. Those happen consecutively for a compositor, so we can share a single buffer to back multiple canvases, one per compositor. This cuts down on memory used to that necessary to contain just the largest window of the process.
Review URL: https://codereview.chromium.org/1132133004
Cr-Commit-Position: refs/heads/master@{#329525}
4 files changed, 142 insertions, 27 deletions
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index 151ba00..4abccc1 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc @@ -108,6 +108,9 @@ GpuProcessTransportFactory::GpuProcessTransportFactory() raster_thread_.reset(new RasterThread(task_graph_runner_.get())); raster_thread_->Start(); } +#if defined(OS_WIN) + software_backing_.reset(new OutputDeviceBacking); +#endif } GpuProcessTransportFactory::~GpuProcessTransportFactory() { @@ -130,11 +133,12 @@ GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() { return CreateContextCommon(gpu_channel_host, 0); } -scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice( +scoped_ptr<cc::SoftwareOutputDevice> +GpuProcessTransportFactory::CreateSoftwareOutputDevice( ui::Compositor* compositor) { #if defined(OS_WIN) - return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin( - compositor)); + return scoped_ptr<cc::SoftwareOutputDevice>( + new SoftwareOutputDeviceWin(software_backing_.get(), compositor)); #elif defined(USE_OZONE) return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceOzone( compositor)); diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h index 54f02ef..171c030 100644 --- a/content/browser/compositor/gpu_process_transport_factory.h +++ b/content/browser/compositor/gpu_process_transport_factory.h @@ -22,6 +22,7 @@ class Thread; } namespace cc { +class SoftwareOutputDevice; class SurfaceManager; } @@ -29,6 +30,7 @@ namespace content { class BrowserCompositorOutputSurface; class CompositorSwapClient; class ContextProviderCommandBuffer; +class OutputDeviceBacking; class ReflectorImpl; class WebGraphicsContext3DCommandBufferImpl; @@ -78,6 +80,8 @@ class GpuProcessTransportFactory struct PerCompositorData; PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor); + scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice( + ui::Compositor* compositor); void EstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor, bool create_gpu_output_surface, int num_attempts); @@ -98,6 +102,10 @@ class GpuProcessTransportFactory scoped_ptr<cc::TaskGraphRunner> task_graph_runner_; scoped_ptr<base::SimpleThread> raster_thread_; +#if defined(OS_WIN) + scoped_ptr<OutputDeviceBacking> software_backing_; +#endif + // The contents of this map and its methods may only be used on the compositor // thread. IDMap<BrowserCompositorOutputSurface> output_surface_map_; diff --git a/content/browser/compositor/software_output_device_win.cc b/content/browser/compositor/software_output_device_win.cc index 7c6ca0c..bb22e90 100644 --- a/content/browser/compositor/software_output_device_win.cc +++ b/content/browser/compositor/software_output_device_win.cc @@ -4,33 +4,97 @@ #include "content/browser/compositor/software_output_device_win.h" +#include "base/memory/shared_memory.h" #include "content/public/browser/browser_thread.h" +#include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkDevice.h" #include "ui/compositor/compositor.h" -#include "ui/gfx/canvas.h" #include "ui/gfx/gdi_util.h" #include "ui/gfx/skia_util.h" namespace content { -SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(ui::Compositor* compositor) +OutputDeviceBacking::OutputDeviceBacking() : created_byte_size_(0) { +} + +OutputDeviceBacking::~OutputDeviceBacking() { + DCHECK(devices_.empty()); +} + +void OutputDeviceBacking::Resized() { + size_t new_size = GetMaxByteSize(); + if (new_size == created_byte_size_) + return; + for (SoftwareOutputDeviceWin* device : devices_) { + device->ReleaseContents(); + } + backing_.reset(); + created_byte_size_ = 0; +} + +void OutputDeviceBacking::RegisterOutputDevice( + SoftwareOutputDeviceWin* device) { + devices_.push_back(device); +} + +void OutputDeviceBacking::UnregisterOutputDevice( + SoftwareOutputDeviceWin* device) { + auto it = std::find(devices_.begin(), devices_.end(), device); + DCHECK(it != devices_.end()); + devices_.erase(it); + Resized(); +} + +base::SharedMemory* OutputDeviceBacking::GetSharedMemory() { + if (backing_) + return backing_.get(); + created_byte_size_ = GetMaxByteSize(); + + backing_.reset(new base::SharedMemory); + CHECK(backing_->CreateAnonymous(created_byte_size_)); + return backing_.get(); +} + +size_t OutputDeviceBacking::GetMaxByteSize() { + size_t max_size = 0; + for (const SoftwareOutputDeviceWin* device : devices_) { + max_size = std::max( + max_size, + static_cast<size_t>(device->viewport_pixel_size().GetArea() * 4)); + } + return max_size; +} + +SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(OutputDeviceBacking* backing, + ui::Compositor* compositor) : hwnd_(compositor->widget()), - is_hwnd_composited_(false) { - // TODO(skaslev) Remove this when crbug.com/180702 is fixed. + is_hwnd_composited_(false), + backing_(backing), + in_paint_(false) { DCHECK_CURRENTLY_ON(BrowserThread::UI); LONG style = GetWindowLong(hwnd_, GWL_EXSTYLE); is_hwnd_composited_ = !!(style & WS_EX_COMPOSITED); + // Layered windows must be completely updated every time, so they can't + // share contents with other windows. + if (is_hwnd_composited_) + backing_ = nullptr; + if (backing_) + backing_->RegisterOutputDevice(this); } SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(!in_paint_); + if (backing_) + backing_->UnregisterOutputDevice(this); } void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size, float scale_factor) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(!in_paint_); scale_factor_ = scale_factor; @@ -38,29 +102,35 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size, return; viewport_pixel_size_ = viewport_pixel_size; - contents_.reset(new gfx::Canvas(viewport_pixel_size, 1.0f, true)); - memset(&bitmap_info_, 0, sizeof(bitmap_info_)); - gfx::CreateBitmapHeader(viewport_pixel_size_.width(), - viewport_pixel_size_.height(), - &bitmap_info_.bmiHeader); + if (backing_) + backing_->Resized(); + contents_.clear(); } SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(contents_); + DCHECK(!in_paint_); + if (!contents_) { + HANDLE shared_section = NULL; + if (backing_) + shared_section = backing_->GetSharedMemory()->handle(); + contents_ = skia::AdoptRef(skia::CreatePlatformCanvas( + viewport_pixel_size_.width(), viewport_pixel_size_.height(), true, + shared_section, skia::CRASH_ON_FAILURE)); + } damage_rect_ = damage_rect; - return contents_ ? contents_->sk_canvas() : NULL; + in_paint_ = true; + return contents_.get(); } void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(contents_); DCHECK(frame_data); + DCHECK(in_paint_); - if (!contents_) - return; - + in_paint_ = false; SoftwareOutputDevice::EndPaint(frame_data); gfx::Rect rect = damage_rect_; @@ -68,8 +138,6 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) { if (rect.IsEmpty()) return; - SkCanvas* canvas = contents_->sk_canvas(); - DCHECK(canvas); if (is_hwnd_composited_) { RECT wr; GetWindowRect(hwnd_, &wr); @@ -83,16 +151,23 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) { style |= WS_EX_LAYERED; SetWindowLong(hwnd_, GWL_EXSTYLE, style); - HDC dib_dc = skia::BeginPlatformPaint(canvas); + HDC dib_dc = skia::BeginPlatformPaint(contents_.get()); ::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero, RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); - skia::EndPlatformPaint(canvas); + skia::EndPlatformPaint(contents_.get()); } else { HDC hdc = ::GetDC(hwnd_); RECT src_rect = rect.ToRECT(); - skia::DrawToNativeContext(canvas, hdc, rect.x(), rect.y(), &src_rect); + skia::DrawToNativeContext(contents_.get(), hdc, rect.x(), rect.y(), + &src_rect); ::ReleaseDC(hwnd_, hdc); } } +void SoftwareOutputDeviceWin::ReleaseContents() { + DCHECK(!contents_ || contents_->unique()); + DCHECK(!in_paint_); + contents_.clear(); +} + } // namespace content diff --git a/content/browser/compositor/software_output_device_win.h b/content/browser/compositor/software_output_device_win.h index 7063f20..8b7fc16 100644 --- a/content/browser/compositor/software_output_device_win.h +++ b/content/browser/compositor/software_output_device_win.h @@ -5,13 +5,15 @@ #ifndef CONTENT_BROWSER_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_WIN_H_ #define CONTENT_BROWSER_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_WIN_H_ +#include <vector> + #include "base/memory/scoped_ptr.h" #include "cc/output/software_output_device.h" #include <windows.h> -namespace gfx { -class Canvas; +namespace base { +class SharedMemory; } namespace ui { @@ -19,10 +21,32 @@ class Compositor; } namespace content { +class SoftwareOutputDeviceWin; + +class OutputDeviceBacking { + public: + OutputDeviceBacking(); + ~OutputDeviceBacking(); + + void Resized(); + void RegisterOutputDevice(SoftwareOutputDeviceWin* device); + void UnregisterOutputDevice(SoftwareOutputDeviceWin* device); + base::SharedMemory* GetSharedMemory(); + + private: + size_t GetMaxByteSize(); + + std::vector<SoftwareOutputDeviceWin*> devices_; + scoped_ptr<base::SharedMemory> backing_; + size_t created_byte_size_; + + DISALLOW_COPY_AND_ASSIGN(OutputDeviceBacking); +}; class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice { public: - explicit SoftwareOutputDeviceWin(ui::Compositor* compositor); + SoftwareOutputDeviceWin(OutputDeviceBacking* backing, + ui::Compositor* compositor); ~SoftwareOutputDeviceWin() override; void Resize(const gfx::Size& viewport_pixel_size, @@ -30,11 +54,15 @@ class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice { SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; void EndPaint(cc::SoftwareFrameData* frame_data) override; + gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; } + void ReleaseContents(); + private: HWND hwnd_; - BITMAPINFO bitmap_info_; - scoped_ptr<gfx::Canvas> contents_; + skia::RefPtr<SkCanvas> contents_; bool is_hwnd_composited_; + OutputDeviceBacking* backing_; + bool in_paint_; DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWin); }; |