• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/renderer/gpu/compositor_software_output_device.h"
6 
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"
16 
17 namespace {
18 
19 const size_t kInvalidIndex = static_cast<size_t>(-1);
20 
21 }  // namespace
22 
23 namespace content {
24 
Buffer(unsigned id,scoped_ptr<cc::SharedBitmap> bitmap)25 CompositorSoftwareOutputDevice::Buffer::Buffer(
26     unsigned id,
27     scoped_ptr<cc::SharedBitmap> bitmap)
28     : id_(id), shared_bitmap_(bitmap.Pass()), free_(true), parent_(NULL) {}
29 
~Buffer()30 CompositorSoftwareOutputDevice::Buffer::~Buffer() {
31 }
32 
SetParent(Buffer * parent,const gfx::Rect & damage)33 void CompositorSoftwareOutputDevice::Buffer::SetParent(
34     Buffer* parent, const gfx::Rect& damage) {
35   parent_ = parent;
36   damage_ = damage;
37 }
38 
FindDamageDifferenceFrom(Buffer * buffer,SkRegion * result) const39 bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom(
40     Buffer* buffer, SkRegion* result) const {
41   if (!buffer)
42     return false;
43 
44   if (buffer == this) {
45     *result = SkRegion();
46     return true;
47   }
48 
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;
56     }
57     current = current->parent_;
58   }
59 
60   return false;
61 }
62 
CompositorSoftwareOutputDevice()63 CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice()
64     : current_index_(kInvalidIndex),
65       next_buffer_id_(1),
66       shared_bitmap_manager_(
67           RenderThreadImpl::current()->shared_bitmap_manager()) {
68   DetachFromThread();
69 }
70 
~CompositorSoftwareOutputDevice()71 CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() {
72   DCHECK(CalledOnValidThread());
73 }
74 
GetNextId()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;
81 }
82 
83 CompositorSoftwareOutputDevice::Buffer*
CreateBuffer()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());
89 }
90 
FindFreeBuffer(size_t hint)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;
96   }
97 
98   buffers_.push_back(CreateBuffer());
99   return buffers_.size() - 1;
100 }
101 
Resize(const gfx::Size & viewport_pixel_size,float scale_factor)102 void CompositorSoftwareOutputDevice::Resize(
103     const gfx::Size& viewport_pixel_size,
104     float scale_factor) {
105   DCHECK(CalledOnValidThread());
106 
107   scale_factor_ = scale_factor;
108 
109   if (viewport_pixel_size_ == viewport_pixel_size)
110     return;
111 
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;
117     }
118   }
119 
120   buffers_.clear();
121   current_index_ = kInvalidIndex;
122   viewport_pixel_size_ = viewport_pixel_size;
123 }
124 
DiscardBackbuffer()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;
131     }
132   }
133   buffers_.clear();
134   current_index_ = kInvalidIndex;
135 }
136 
EnsureBackbuffer()137 void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
138 }
139 
BeginPaint(const gfx::Rect & damage_rect)140 SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(
141     const gfx::Rect& damage_rect) {
142   DCHECK(CalledOnValidThread());
143 
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);
151 
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   SkBitmap bitmap;
156   bitmap.installPixels(info, current->memory(), info.minRowBytes());
157   canvas_ = skia::AdoptRef(new SkCanvas(bitmap));
158 
159   if (!previous) {
160     DCHECK(damage_rect == gfx::Rect(viewport_pixel_size_));
161   } else {
162     // Find the smallest damage region that needs
163     // to be copied from the |previous| buffer.
164     SkRegion region;
165     bool found =
166         current->FindDamageDifferenceFrom(previous, &region) ||
167         previous->FindDamageDifferenceFrom(current, &region);
168     if (!found)
169       region = SkRegion(RectToSkIRect(gfx::Rect(viewport_pixel_size_)));
170     region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op);
171 
172     // Copy over the damage region.
173     if (!region.isEmpty()) {
174       SkImageInfo info = SkImageInfo::MakeN32Premul(
175           viewport_pixel_size_.width(), viewport_pixel_size_.height());
176       SkBitmap back_bitmap;
177       back_bitmap.installPixels(info, previous->memory(), info.minRowBytes());
178 
179       for (SkRegion::Iterator it(region); !it.done(); it.next()) {
180         const SkIRect& src_rect = it.rect();
181         SkRect dst_rect = SkRect::Make(src_rect);
182         canvas_->drawBitmapRect(back_bitmap, &src_rect, dst_rect, NULL);
183       }
184     }
185   }
186 
187   // Make |current| child of |previous| and orphan all of |current|'s children.
188   current->SetParent(previous, damage_rect);
189   for (size_t i = 0; i < buffers_.size(); ++i) {
190     Buffer* buffer = buffers_[i];
191     if (buffer->parent() == current)
192       buffer->SetParent(NULL, gfx::Rect(viewport_pixel_size_));
193   }
194   damage_rect_ = damage_rect;
195 
196   return canvas_.get();
197 }
198 
EndPaint(cc::SoftwareFrameData * frame_data)199 void CompositorSoftwareOutputDevice::EndPaint(
200     cc::SoftwareFrameData* frame_data) {
201   DCHECK(CalledOnValidThread());
202   DCHECK(frame_data);
203 
204   Buffer* buffer = buffers_[current_index_];
205   frame_data->id = buffer->id();
206   frame_data->size = viewport_pixel_size_;
207   frame_data->damage_rect = damage_rect_;
208   frame_data->bitmap_id = buffer->shared_bitmap_id();
209 }
210 
ReclaimSoftwareFrame(unsigned id)211 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
212   DCHECK(CalledOnValidThread());
213 
214   if (!id)
215     return;
216 
217   // The reclaimed buffer id might not be among the currently
218   // active buffers if we got a resize event in the mean time.
219   ScopedVector<Buffer>::iterator it =
220       std::find_if(buffers_.begin(), buffers_.end(), CompareById(id));
221   if (it != buffers_.end()) {
222     DCHECK(!(*it)->free());
223     (*it)->SetFree(true);
224     return;
225   } else {
226     it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(),
227                       CompareById(id));
228     DCHECK(it != awaiting_ack_.end());
229     awaiting_ack_.erase(it);
230   }
231 }
232 
233 }  // namespace content
234