Home | History | Annotate | Download | only in gpu
      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, &region) ||
    162         previous->FindDamageDifferenceFrom(current, &region);
    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