Commit 8fe39ccf authored by jbauman's avatar jbauman Committed by Commit bot

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}
parent b71e3991
...@@ -108,6 +108,9 @@ GpuProcessTransportFactory::GpuProcessTransportFactory() ...@@ -108,6 +108,9 @@ GpuProcessTransportFactory::GpuProcessTransportFactory()
raster_thread_.reset(new RasterThread(task_graph_runner_.get())); raster_thread_.reset(new RasterThread(task_graph_runner_.get()));
raster_thread_->Start(); raster_thread_->Start();
} }
#if defined(OS_WIN)
software_backing_.reset(new OutputDeviceBacking);
#endif
} }
GpuProcessTransportFactory::~GpuProcessTransportFactory() { GpuProcessTransportFactory::~GpuProcessTransportFactory() {
...@@ -130,11 +133,12 @@ GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() { ...@@ -130,11 +133,12 @@ GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
return CreateContextCommon(gpu_channel_host, 0); return CreateContextCommon(gpu_channel_host, 0);
} }
scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice( scoped_ptr<cc::SoftwareOutputDevice>
GpuProcessTransportFactory::CreateSoftwareOutputDevice(
ui::Compositor* compositor) { ui::Compositor* compositor) {
#if defined(OS_WIN) #if defined(OS_WIN)
return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin( return scoped_ptr<cc::SoftwareOutputDevice>(
compositor)); new SoftwareOutputDeviceWin(software_backing_.get(), compositor));
#elif defined(USE_OZONE) #elif defined(USE_OZONE)
return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceOzone( return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceOzone(
compositor)); compositor));
......
...@@ -22,6 +22,7 @@ class Thread; ...@@ -22,6 +22,7 @@ class Thread;
} }
namespace cc { namespace cc {
class SoftwareOutputDevice;
class SurfaceManager; class SurfaceManager;
} }
...@@ -29,6 +30,7 @@ namespace content { ...@@ -29,6 +30,7 @@ namespace content {
class BrowserCompositorOutputSurface; class BrowserCompositorOutputSurface;
class CompositorSwapClient; class CompositorSwapClient;
class ContextProviderCommandBuffer; class ContextProviderCommandBuffer;
class OutputDeviceBacking;
class ReflectorImpl; class ReflectorImpl;
class WebGraphicsContext3DCommandBufferImpl; class WebGraphicsContext3DCommandBufferImpl;
...@@ -78,6 +80,8 @@ class GpuProcessTransportFactory ...@@ -78,6 +80,8 @@ class GpuProcessTransportFactory
struct PerCompositorData; struct PerCompositorData;
PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor); PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor);
scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
ui::Compositor* compositor);
void EstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor, void EstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor,
bool create_gpu_output_surface, bool create_gpu_output_surface,
int num_attempts); int num_attempts);
...@@ -98,6 +102,10 @@ class GpuProcessTransportFactory ...@@ -98,6 +102,10 @@ class GpuProcessTransportFactory
scoped_ptr<cc::TaskGraphRunner> task_graph_runner_; scoped_ptr<cc::TaskGraphRunner> task_graph_runner_;
scoped_ptr<base::SimpleThread> raster_thread_; 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 // The contents of this map and its methods may only be used on the compositor
// thread. // thread.
IDMap<BrowserCompositorOutputSurface> output_surface_map_; IDMap<BrowserCompositorOutputSurface> output_surface_map_;
......
...@@ -4,33 +4,97 @@ ...@@ -4,33 +4,97 @@
#include "content/browser/compositor/software_output_device_win.h" #include "content/browser/compositor/software_output_device_win.h"
#include "base/memory/shared_memory.h"
#include "content/public/browser/browser_thread.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/SkBitmap.h"
#include "third_party/skia/include/core/SkDevice.h" #include "third_party/skia/include/core/SkDevice.h"
#include "ui/compositor/compositor.h" #include "ui/compositor/compositor.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/gdi_util.h" #include "ui/gfx/gdi_util.h"
#include "ui/gfx/skia_util.h" #include "ui/gfx/skia_util.h"
namespace content { 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()), : hwnd_(compositor->widget()),
is_hwnd_composited_(false) { is_hwnd_composited_(false),
// TODO(skaslev) Remove this when crbug.com/180702 is fixed. backing_(backing),
in_paint_(false) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
LONG style = GetWindowLong(hwnd_, GWL_EXSTYLE); LONG style = GetWindowLong(hwnd_, GWL_EXSTYLE);
is_hwnd_composited_ = !!(style & WS_EX_COMPOSITED); 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() { SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!in_paint_);
if (backing_)
backing_->UnregisterOutputDevice(this);
} }
void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size, void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
float scale_factor) { float scale_factor) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!in_paint_);
scale_factor_ = scale_factor; scale_factor_ = scale_factor;
...@@ -38,29 +102,35 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size, ...@@ -38,29 +102,35 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
return; return;
viewport_pixel_size_ = viewport_pixel_size; viewport_pixel_size_ = viewport_pixel_size;
contents_.reset(new gfx::Canvas(viewport_pixel_size, 1.0f, true)); if (backing_)
memset(&bitmap_info_, 0, sizeof(bitmap_info_)); backing_->Resized();
gfx::CreateBitmapHeader(viewport_pixel_size_.width(), contents_.clear();
viewport_pixel_size_.height(),
&bitmap_info_.bmiHeader);
} }
SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) { SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); 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; damage_rect_ = damage_rect;
return contents_ ? contents_->sk_canvas() : NULL; in_paint_ = true;
return contents_.get();
} }
void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) { void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(contents_); DCHECK(contents_);
DCHECK(frame_data); DCHECK(frame_data);
DCHECK(in_paint_);
if (!contents_) in_paint_ = false;
return;
SoftwareOutputDevice::EndPaint(frame_data); SoftwareOutputDevice::EndPaint(frame_data);
gfx::Rect rect = damage_rect_; gfx::Rect rect = damage_rect_;
...@@ -68,8 +138,6 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) { ...@@ -68,8 +138,6 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) {
if (rect.IsEmpty()) if (rect.IsEmpty())
return; return;
SkCanvas* canvas = contents_->sk_canvas();
DCHECK(canvas);
if (is_hwnd_composited_) { if (is_hwnd_composited_) {
RECT wr; RECT wr;
GetWindowRect(hwnd_, &wr); GetWindowRect(hwnd_, &wr);
...@@ -83,16 +151,23 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) { ...@@ -83,16 +151,23 @@ void SoftwareOutputDeviceWin::EndPaint(cc::SoftwareFrameData* frame_data) {
style |= WS_EX_LAYERED; style |= WS_EX_LAYERED;
SetWindowLong(hwnd_, GWL_EXSTYLE, style); 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, ::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero,
RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
skia::EndPlatformPaint(canvas); skia::EndPlatformPaint(contents_.get());
} else { } else {
HDC hdc = ::GetDC(hwnd_); HDC hdc = ::GetDC(hwnd_);
RECT src_rect = rect.ToRECT(); 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); ::ReleaseDC(hwnd_, hdc);
} }
} }
void SoftwareOutputDeviceWin::ReleaseContents() {
DCHECK(!contents_ || contents_->unique());
DCHECK(!in_paint_);
contents_.clear();
}
} // namespace content } // namespace content
...@@ -5,13 +5,15 @@ ...@@ -5,13 +5,15 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_WIN_H_ #ifndef CONTENT_BROWSER_COMPOSITOR_SOFTWARE_OUTPUT_DEVICE_WIN_H_
#define 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 "base/memory/scoped_ptr.h"
#include "cc/output/software_output_device.h" #include "cc/output/software_output_device.h"
#include <windows.h> #include <windows.h>
namespace gfx { namespace base {
class Canvas; class SharedMemory;
} }
namespace ui { namespace ui {
...@@ -19,10 +21,32 @@ class Compositor; ...@@ -19,10 +21,32 @@ class Compositor;
} }
namespace content { 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 { class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice {
public: public:
explicit SoftwareOutputDeviceWin(ui::Compositor* compositor); SoftwareOutputDeviceWin(OutputDeviceBacking* backing,
ui::Compositor* compositor);
~SoftwareOutputDeviceWin() override; ~SoftwareOutputDeviceWin() override;
void Resize(const gfx::Size& viewport_pixel_size, void Resize(const gfx::Size& viewport_pixel_size,
...@@ -30,11 +54,15 @@ class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice { ...@@ -30,11 +54,15 @@ class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice {
SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
void EndPaint(cc::SoftwareFrameData* frame_data) override; void EndPaint(cc::SoftwareFrameData* frame_data) override;
gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; }
void ReleaseContents();
private: private:
HWND hwnd_; HWND hwnd_;
BITMAPINFO bitmap_info_; skia::RefPtr<SkCanvas> contents_;
scoped_ptr<gfx::Canvas> contents_;
bool is_hwnd_composited_; bool is_hwnd_composited_;
OutputDeviceBacking* backing_;
bool in_paint_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWin); DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWin);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment