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 17namespace { 18 19const size_t kInvalidIndex = static_cast<size_t>(-1); 20 21} // namespace 22 23namespace content { 24 25CompositorSoftwareOutputDevice::Buffer::Buffer( 26 unsigned id, 27 scoped_ptr<cc::SharedBitmap> bitmap) 28 : id_(id), shared_bitmap_(bitmap.Pass()), free_(true), parent_(NULL) {} 29 30CompositorSoftwareOutputDevice::Buffer::~Buffer() { 31} 32 33void CompositorSoftwareOutputDevice::Buffer::SetParent( 34 Buffer* parent, const gfx::Rect& damage) { 35 parent_ = parent; 36 damage_ = damage; 37} 38 39bool 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 63CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice() 64 : current_index_(kInvalidIndex), 65 next_buffer_id_(1), 66 shared_bitmap_manager_( 67 RenderThreadImpl::current()->shared_bitmap_manager()) { 68 DetachFromThread(); 69} 70 71CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() { 72 DCHECK(CalledOnValidThread()); 73} 74 75unsigned 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 83CompositorSoftwareOutputDevice::Buffer* 84CompositorSoftwareOutputDevice::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 91size_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 102void 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 125void 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 137void CompositorSoftwareOutputDevice::EnsureBackbuffer() { 138} 139 140SkCanvas* 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, ®ion) || 167 previous->FindDamageDifferenceFrom(current, ®ion); 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 199void 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 211void 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