Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / gpu / compositor_software_output_device.cc
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/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"
15
16 namespace content {
17
18 CompositorSoftwareOutputDevice::Buffer::Buffer(
19     unsigned id, scoped_ptr<base::SharedMemory> mem)
20     : id_(id),
21       mem_(mem.Pass()),
22       free_(true),
23       parent_(NULL) {
24 }
25
26 CompositorSoftwareOutputDevice::Buffer::~Buffer() {
27 }
28
29 void CompositorSoftwareOutputDevice::Buffer::SetParent(
30     Buffer* parent, const gfx::Rect& damage) {
31   parent_ = parent;
32   damage_ = damage;
33 }
34
35 bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom(
36     Buffer* buffer, SkRegion* result) const {
37   if (!buffer)
38     return false;
39
40   if (buffer == this) {
41     *result = SkRegion();
42     return true;
43   }
44
45   SkRegion damage;
46   const Buffer* current = this;
47   while (current->parent_) {
48     damage.op(RectToSkIRect(current->damage_), SkRegion::kUnion_Op);
49     if (current->parent_ == buffer) {
50       *result = damage;
51       return true;
52     }
53     current = current->parent_;
54   }
55
56   return false;
57 }
58
59 CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice()
60     : current_index_(-1),
61       next_buffer_id_(1),
62       render_thread_(RenderThread::Get()) {
63   DetachFromThread();
64 }
65
66 CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() {
67   DCHECK(CalledOnValidThread());
68 }
69
70 unsigned CompositorSoftwareOutputDevice::GetNextId() {
71   unsigned id = next_buffer_id_++;
72   // Zero is reserved to label invalid frame id.
73   if (id == 0)
74     id = next_buffer_id_++;
75   return id;
76 }
77
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();
83   CHECK(mem);
84   bool success = mem->Map(size);
85   CHECK(success);
86   return new Buffer(GetNextId(), mem.Pass());
87 }
88
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())
93       return index;
94   }
95
96   buffers_.push_back(CreateBuffer());
97   return buffers_.size() - 1;
98 }
99
100 void CompositorSoftwareOutputDevice::Resize(const gfx::Size& viewport_size) {
101   DCHECK(CalledOnValidThread());
102
103   if (viewport_size_ == viewport_size)
104     return;
105
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]);
110       buffers_[i] = NULL;
111     }
112   }
113
114   buffers_.clear();
115   current_index_ = -1;
116   viewport_size_ = viewport_size;
117 }
118
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]);
124       buffers_[i] = NULL;
125     }
126   }
127   buffers_.clear();
128   current_index_ = -1;
129 }
130
131 void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
132 }
133
134 SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(
135     const gfx::Rect& damage_rect) {
136   DCHECK(CalledOnValidThread());
137
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);
145
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()));
153
154   if (!previous) {
155     DCHECK(damage_rect == gfx::Rect(viewport_size_));
156   } else {
157     // Find the smallest damage region that needs
158     // to be copied from the |previous| buffer.
159     SkRegion region;
160     bool found =
161         current->FindDamageDifferenceFrom(previous, &region) ||
162         previous->FindDamageDifferenceFrom(current, &region);
163     if (!found)
164       region = SkRegion(RectToSkIRect(gfx::Rect(viewport_size_)));
165     region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op);
166
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());
174
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);
179       }
180     }
181   }
182
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_));
189   }
190   damage_rect_ = damage_rect;
191
192   return canvas_.get();
193 }
194
195 void CompositorSoftwareOutputDevice::EndPaint(
196     cc::SoftwareFrameData* frame_data) {
197   DCHECK(CalledOnValidThread());
198   DCHECK(frame_data);
199
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();
205
206   CHECK_LE(static_cast<size_t>(frame_data->size.GetArea()) * 4,
207            buffer->shared_memory()->mapped_size());
208 }
209
210 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
211   DCHECK(CalledOnValidThread());
212
213   if (!id)
214     return;
215
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);
229   }
230 }
231
232 }  // namespace content