1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/gpu/compositor_software_output_device.h"
7 #include "base/logging.h"
8 #include "cc/output/software_frame_data.h"
9 #include "content/renderer/render_process.h"
10 #include "third_party/skia/include/core/SkBitmapDevice.h"
11 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "third_party/skia/include/core/SkPixelRef.h"
13 #include "third_party/skia/include/core/SkRegion.h"
14 #include "ui/gfx/skia_util.h"
18 CompositorSoftwareOutputDevice::Buffer::Buffer(
19 unsigned id, scoped_ptr<base::SharedMemory> mem)
26 CompositorSoftwareOutputDevice::Buffer::~Buffer() {
29 void CompositorSoftwareOutputDevice::Buffer::SetParent(
30 Buffer* parent, const gfx::Rect& damage) {
35 bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom(
36 Buffer* buffer, SkRegion* result) const {
46 const Buffer* current = this;
47 while (current->parent_) {
48 damage.op(RectToSkIRect(current->damage_), SkRegion::kUnion_Op);
49 if (current->parent_ == buffer) {
53 current = current->parent_;
59 CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice()
62 render_thread_(RenderThread::Get()) {
66 CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() {
67 DCHECK(CalledOnValidThread());
70 unsigned CompositorSoftwareOutputDevice::GetNextId() {
71 unsigned id = next_buffer_id_++;
72 // Zero is reserved to label invalid frame id.
74 id = next_buffer_id_++;
78 CompositorSoftwareOutputDevice::Buffer*
79 CompositorSoftwareOutputDevice::CreateBuffer() {
80 const size_t size = 4 * viewport_size_.GetArea();
81 scoped_ptr<base::SharedMemory> mem =
82 render_thread_->HostAllocateSharedMemoryBuffer(size).Pass();
84 bool success = mem->Map(size);
86 return new Buffer(GetNextId(), mem.Pass());
89 size_t CompositorSoftwareOutputDevice::FindFreeBuffer(size_t hint) {
90 for (size_t i = 0; i < buffers_.size(); ++i) {
91 size_t index = (hint + i) % buffers_.size();
92 if (buffers_[index]->free())
96 buffers_.push_back(CreateBuffer());
97 return buffers_.size() - 1;
100 void CompositorSoftwareOutputDevice::Resize(const gfx::Size& viewport_size) {
101 DCHECK(CalledOnValidThread());
103 if (viewport_size_ == viewport_size)
106 // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
107 for (size_t i = 0; i < buffers_.size(); ++i) {
108 if (!buffers_[i]->free()) {
109 awaiting_ack_.push_back(buffers_[i]);
116 viewport_size_ = viewport_size;
119 void CompositorSoftwareOutputDevice::DiscardBackbuffer() {
120 // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
121 for (size_t i = 0; i < buffers_.size(); ++i) {
122 if (!buffers_[i]->free()) {
123 awaiting_ack_.push_back(buffers_[i]);
131 void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
134 SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(
135 const gfx::Rect& damage_rect) {
136 DCHECK(CalledOnValidThread());
138 Buffer* previous = NULL;
139 if (current_index_ != size_t(-1))
140 previous = buffers_[current_index_];
141 current_index_ = FindFreeBuffer(current_index_ + 1);
142 Buffer* current = buffers_[current_index_];
143 DCHECK(current->free());
144 current->SetFree(false);
146 // Set up a canvas for the current front buffer.
147 bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
148 viewport_size_.width(),
149 viewport_size_.height());
150 bitmap_.setPixels(current->memory());
151 device_ = skia::AdoptRef(new SkBitmapDevice(bitmap_));
152 canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
155 DCHECK(damage_rect == gfx::Rect(viewport_size_));
157 // Find the smallest damage region that needs
158 // to be copied from the |previous| buffer.
161 current->FindDamageDifferenceFrom(previous, ®ion) ||
162 previous->FindDamageDifferenceFrom(current, ®ion);
164 region = SkRegion(RectToSkIRect(gfx::Rect(viewport_size_)));
165 region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op);
167 // Copy over the damage region.
168 if (!region.isEmpty()) {
169 SkBitmap back_bitmap;
170 back_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
171 viewport_size_.width(),
172 viewport_size_.height());
173 back_bitmap.setPixels(previous->memory());
175 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
176 const SkIRect& src_rect = it.rect();
177 SkRect dst_rect = SkRect::Make(src_rect);
178 canvas_->drawBitmapRect(back_bitmap, &src_rect, dst_rect, NULL);
183 // Make |current| child of |previous| and orphan all of |current|'s children.
184 current->SetParent(previous, damage_rect);
185 for (size_t i = 0; i < buffers_.size(); ++i) {
186 Buffer* buffer = buffers_[i];
187 if (buffer->parent() == current)
188 buffer->SetParent(NULL, gfx::Rect(viewport_size_));
190 damage_rect_ = damage_rect;
192 return canvas_.get();
195 void CompositorSoftwareOutputDevice::EndPaint(
196 cc::SoftwareFrameData* frame_data) {
197 DCHECK(CalledOnValidThread());
200 Buffer* buffer = buffers_[current_index_];
201 frame_data->id = buffer->id();
202 frame_data->size = viewport_size_;
203 frame_data->damage_rect = damage_rect_;
204 frame_data->handle = buffer->handle();
206 CHECK_LE(static_cast<size_t>(frame_data->size.GetArea()) * 4,
207 buffer->shared_memory()->mapped_size());
210 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
211 DCHECK(CalledOnValidThread());
216 // The reclaimed buffer id might not be among the currently
217 // active buffers if we got a resize event in the mean time.
218 ScopedVector<Buffer>::iterator it =
219 std::find_if(buffers_.begin(), buffers_.end(), CompareById(id));
220 if (it != buffers_.end()) {
221 DCHECK(!(*it)->free());
222 (*it)->SetFree(true);
225 it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(),
227 DCHECK(it != awaiting_ack_.end());
228 awaiting_ack_.erase(it);
232 } // namespace content