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/SkBitmapDevice.h" 13 #include "third_party/skia/include/core/SkCanvas.h" 14 #include "third_party/skia/include/core/SkPixelRef.h" 15 #include "third_party/skia/include/core/SkRegion.h" 16 #include "ui/gfx/skia_util.h" 17 18 namespace content { 19 20 CompositorSoftwareOutputDevice::Buffer::Buffer( 21 unsigned id, 22 scoped_ptr<cc::SharedBitmap> bitmap) 23 : id_(id), shared_bitmap_(bitmap.Pass()), free_(true), parent_(NULL) {} 24 25 CompositorSoftwareOutputDevice::Buffer::~Buffer() { 26 } 27 28 void CompositorSoftwareOutputDevice::Buffer::SetParent( 29 Buffer* parent, const gfx::Rect& damage) { 30 parent_ = parent; 31 damage_ = damage; 32 } 33 34 bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom( 35 Buffer* buffer, SkRegion* result) const { 36 if (!buffer) 37 return false; 38 39 if (buffer == this) { 40 *result = SkRegion(); 41 return true; 42 } 43 44 SkRegion damage; 45 const Buffer* current = this; 46 while (current->parent_) { 47 damage.op(RectToSkIRect(current->damage_), SkRegion::kUnion_Op); 48 if (current->parent_ == buffer) { 49 *result = damage; 50 return true; 51 } 52 current = current->parent_; 53 } 54 55 return false; 56 } 57 58 CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice() 59 : current_index_(-1), 60 next_buffer_id_(1), 61 shared_bitmap_manager_( 62 RenderThreadImpl::current()->shared_bitmap_manager()) { 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 scoped_ptr<cc::SharedBitmap> shared_bitmap = 81 shared_bitmap_manager_->AllocateSharedBitmap(viewport_pixel_size_); 82 CHECK(shared_bitmap); 83 return new Buffer(GetNextId(), shared_bitmap.Pass()); 84 } 85 86 size_t CompositorSoftwareOutputDevice::FindFreeBuffer(size_t hint) { 87 for (size_t i = 0; i < buffers_.size(); ++i) { 88 size_t index = (hint + i) % buffers_.size(); 89 if (buffers_[index]->free()) 90 return index; 91 } 92 93 buffers_.push_back(CreateBuffer()); 94 return buffers_.size() - 1; 95 } 96 97 void CompositorSoftwareOutputDevice::Resize( 98 const gfx::Size& viewport_pixel_size, 99 float scale_factor) { 100 DCHECK(CalledOnValidThread()); 101 102 scale_factor_ = scale_factor; 103 104 if (viewport_pixel_size_ == viewport_pixel_size) 105 return; 106 107 // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged. 108 for (size_t i = 0; i < buffers_.size(); ++i) { 109 if (!buffers_[i]->free()) { 110 awaiting_ack_.push_back(buffers_[i]); 111 buffers_[i] = NULL; 112 } 113 } 114 115 buffers_.clear(); 116 current_index_ = -1; 117 viewport_pixel_size_ = viewport_pixel_size; 118 } 119 120 void CompositorSoftwareOutputDevice::DiscardBackbuffer() { 121 // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged. 122 for (size_t i = 0; i < buffers_.size(); ++i) { 123 if (!buffers_[i]->free()) { 124 awaiting_ack_.push_back(buffers_[i]); 125 buffers_[i] = NULL; 126 } 127 } 128 buffers_.clear(); 129 current_index_ = -1; 130 } 131 132 void CompositorSoftwareOutputDevice::EnsureBackbuffer() { 133 } 134 135 SkCanvas* CompositorSoftwareOutputDevice::BeginPaint( 136 const gfx::Rect& damage_rect) { 137 DCHECK(CalledOnValidThread()); 138 139 Buffer* previous = NULL; 140 if (current_index_ != size_t(-1)) 141 previous = buffers_[current_index_]; 142 current_index_ = FindFreeBuffer(current_index_ + 1); 143 Buffer* current = buffers_[current_index_]; 144 DCHECK(current->free()); 145 current->SetFree(false); 146 147 // Set up a canvas for the current front buffer. 148 SkImageInfo info = SkImageInfo::MakeN32Premul(viewport_pixel_size_.width(), 149 viewport_pixel_size_.height()); 150 SkBitmap bitmap; 151 bitmap.installPixels(info, current->memory(), info.minRowBytes()); 152 canvas_ = skia::AdoptRef(new SkCanvas(bitmap)); 153 154 if (!previous) { 155 DCHECK(damage_rect == gfx::Rect(viewport_pixel_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, ®ion) || 162 previous->FindDamageDifferenceFrom(current, ®ion); 163 if (!found) 164 region = SkRegion(RectToSkIRect(gfx::Rect(viewport_pixel_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_pixel_size_.width(), 172 viewport_pixel_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_pixel_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_pixel_size_; 203 frame_data->damage_rect = damage_rect_; 204 frame_data->bitmap_id = buffer->shared_bitmap_id(); 205 } 206 207 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) { 208 DCHECK(CalledOnValidThread()); 209 210 if (!id) 211 return; 212 213 // The reclaimed buffer id might not be among the currently 214 // active buffers if we got a resize event in the mean time. 215 ScopedVector<Buffer>::iterator it = 216 std::find_if(buffers_.begin(), buffers_.end(), CompareById(id)); 217 if (it != buffers_.end()) { 218 DCHECK(!(*it)->free()); 219 (*it)->SetFree(true); 220 return; 221 } else { 222 it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(), 223 CompareById(id)); 224 DCHECK(it != awaiting_ack_.end()); 225 awaiting_ack_.erase(it); 226 } 227 } 228 229 } // namespace content 230