| OLD | NEW |
| (Empty) |
| 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 | |
| 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 | |
| 30 CompositorSoftwareOutputDevice::Buffer::~Buffer() { | |
| 31 } | |
| 32 | |
| 33 void CompositorSoftwareOutputDevice::Buffer::SetParent( | |
| 34 Buffer* parent, const gfx::Rect& damage) { | |
| 35 parent_ = parent; | |
| 36 damage_ = damage; | |
| 37 } | |
| 38 | |
| 39 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 | |
| 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 | |
| 71 CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() { | |
| 72 DCHECK(CalledOnValidThread()); | |
| 73 } | |
| 74 | |
| 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* | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 137 void CompositorSoftwareOutputDevice::EnsureBackbuffer() { | |
| 138 } | |
| 139 | |
| 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 surface_ = skia::AdoptRef(SkSurface::NewRasterDirect(info, current->memory(), | |
| 156 info.minRowBytes())); | |
| 157 | |
| 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, ®ion) || | |
| 166 previous->FindDamageDifferenceFrom(current, ®ion); | |
| 167 if (!found) | |
| 168 region = SkRegion(RectToSkIRect(gfx::Rect(viewport_pixel_size_))); | |
| 169 region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op); | |
| 170 | |
| 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()); | |
| 177 | |
| 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); | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 | |
| 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_)); | |
| 192 } | |
| 193 damage_rect_ = damage_rect; | |
| 194 | |
| 195 return surface_->getCanvas(); | |
| 196 } | |
| 197 | |
| 198 void CompositorSoftwareOutputDevice::EndPaint( | |
| 199 cc::SoftwareFrameData* frame_data) { | |
| 200 DCHECK(CalledOnValidThread()); | |
| 201 DCHECK(frame_data); | |
| 202 | |
| 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(); | |
| 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 | |
| OLD | NEW |