Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / gpu / compositor_software_output_device.cc
blob93155cc9ceeabfff34a1730f15c3e74c097b9c94
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/child/child_shared_bitmap_manager.h"
10 #include "content/renderer/render_process.h"
11 #include "content/renderer/render_thread_impl.h"
12 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "third_party/skia/include/core/SkPixelRef.h"
14 #include "third_party/skia/include/core/SkRegion.h"
15 #include "ui/gfx/skia_util.h"
17 namespace {
19 const size_t kInvalidIndex = static_cast<size_t>(-1);
21 } // namespace
23 namespace content {
25 CompositorSoftwareOutputDevice::Buffer::Buffer(
26 unsigned id,
27 scoped_ptr<cc::SharedBitmap> bitmap)
28 : id_(id), shared_bitmap_(bitmap.Pass()), free_(true), parent_(NULL) {}
30 CompositorSoftwareOutputDevice::Buffer::~Buffer() {
33 void CompositorSoftwareOutputDevice::Buffer::SetParent(
34 Buffer* parent, const gfx::Rect& damage) {
35 parent_ = parent;
36 damage_ = damage;
39 bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom(
40 Buffer* buffer, SkRegion* result) const {
41 if (!buffer)
42 return false;
44 if (buffer == this) {
45 *result = SkRegion();
46 return true;
49 SkRegion damage;
50 const Buffer* current = this;
51 while (current->parent_) {
52 damage.op(RectToSkIRect(current->damage_), SkRegion::kUnion_Op);
53 if (current->parent_ == buffer) {
54 *result = damage;
55 return true;
57 current = current->parent_;
60 return false;
63 CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice()
64 : current_index_(kInvalidIndex),
65 next_buffer_id_(1),
66 shared_bitmap_manager_(
67 RenderThreadImpl::current()->shared_bitmap_manager()) {
68 DetachFromThread();
71 CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() {
72 DCHECK(CalledOnValidThread());
75 unsigned CompositorSoftwareOutputDevice::GetNextId() {
76 unsigned id = next_buffer_id_++;
77 // Zero is reserved to label invalid frame id.
78 if (id == 0)
79 id = next_buffer_id_++;
80 return id;
83 CompositorSoftwareOutputDevice::Buffer*
84 CompositorSoftwareOutputDevice::CreateBuffer() {
85 scoped_ptr<cc::SharedBitmap> shared_bitmap =
86 shared_bitmap_manager_->AllocateSharedBitmap(viewport_pixel_size_);
87 CHECK(shared_bitmap);
88 return new Buffer(GetNextId(), shared_bitmap.Pass());
91 size_t CompositorSoftwareOutputDevice::FindFreeBuffer(size_t hint) {
92 for (size_t i = 0; i < buffers_.size(); ++i) {
93 size_t index = (hint + i) % buffers_.size();
94 if (buffers_[index]->free())
95 return index;
98 buffers_.push_back(CreateBuffer());
99 return buffers_.size() - 1;
102 void CompositorSoftwareOutputDevice::Resize(
103 const gfx::Size& viewport_pixel_size,
104 float scale_factor) {
105 DCHECK(CalledOnValidThread());
107 scale_factor_ = scale_factor;
109 if (viewport_pixel_size_ == viewport_pixel_size)
110 return;
112 // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
113 for (size_t i = 0; i < buffers_.size(); ++i) {
114 if (!buffers_[i]->free()) {
115 awaiting_ack_.push_back(buffers_[i]);
116 buffers_[i] = NULL;
120 buffers_.clear();
121 current_index_ = kInvalidIndex;
122 viewport_pixel_size_ = viewport_pixel_size;
125 void CompositorSoftwareOutputDevice::DiscardBackbuffer() {
126 // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
127 for (size_t i = 0; i < buffers_.size(); ++i) {
128 if (!buffers_[i]->free()) {
129 awaiting_ack_.push_back(buffers_[i]);
130 buffers_[i] = NULL;
133 buffers_.clear();
134 current_index_ = kInvalidIndex;
137 void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
140 SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(
141 const gfx::Rect& damage_rect) {
142 DCHECK(CalledOnValidThread());
144 Buffer* previous = NULL;
145 if (current_index_ != kInvalidIndex)
146 previous = buffers_[current_index_];
147 current_index_ = FindFreeBuffer(current_index_ + 1);
148 Buffer* current = buffers_[current_index_];
149 DCHECK(current->free());
150 current->SetFree(false);
152 // Set up a canvas for the current front buffer.
153 SkImageInfo info = SkImageInfo::MakeN32Premul(viewport_pixel_size_.width(),
154 viewport_pixel_size_.height());
155 surface_ = skia::AdoptRef(SkSurface::NewRasterDirect(info, current->memory(),
156 info.minRowBytes()));
158 if (!previous) {
159 DCHECK(damage_rect == gfx::Rect(viewport_pixel_size_));
160 } else {
161 // Find the smallest damage region that needs
162 // to be copied from the |previous| buffer.
163 SkRegion region;
164 bool found =
165 current->FindDamageDifferenceFrom(previous, &region) ||
166 previous->FindDamageDifferenceFrom(current, &region);
167 if (!found)
168 region = SkRegion(RectToSkIRect(gfx::Rect(viewport_pixel_size_)));
169 region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op);
171 // Copy over the damage region.
172 if (!region.isEmpty()) {
173 SkImageInfo info = SkImageInfo::MakeN32Premul(
174 viewport_pixel_size_.width(), viewport_pixel_size_.height());
175 SkBitmap back_bitmap;
176 back_bitmap.installPixels(info, previous->memory(), info.minRowBytes());
178 for (SkRegion::Iterator it(region); !it.done(); it.next()) {
179 const SkIRect& src_rect = it.rect();
180 SkRect dst_rect = SkRect::Make(src_rect);
181 surface_->getCanvas()->drawBitmapRect(back_bitmap, &src_rect, dst_rect);
186 // Make |current| child of |previous| and orphan all of |current|'s children.
187 current->SetParent(previous, damage_rect);
188 for (size_t i = 0; i < buffers_.size(); ++i) {
189 Buffer* buffer = buffers_[i];
190 if (buffer->parent() == current)
191 buffer->SetParent(NULL, gfx::Rect(viewport_pixel_size_));
193 damage_rect_ = damage_rect;
195 return surface_->getCanvas();
198 void CompositorSoftwareOutputDevice::EndPaint(
199 cc::SoftwareFrameData* frame_data) {
200 DCHECK(CalledOnValidThread());
201 DCHECK(frame_data);
203 Buffer* buffer = buffers_[current_index_];
204 frame_data->id = buffer->id();
205 frame_data->size = viewport_pixel_size_;
206 frame_data->damage_rect = damage_rect_;
207 frame_data->bitmap_id = buffer->shared_bitmap_id();
210 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
211 DCHECK(CalledOnValidThread());
213 if (!id)
214 return;
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);
223 return;
224 } else {
225 it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(),
226 CompareById(id));
227 DCHECK(it != awaiting_ack_.end());
228 awaiting_ack_.erase(it);
232 } // namespace content