compositor_software_output_device.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/SkCanvas.h" 11#include "third_party/skia/include/core/SkDevice.h" 12#include "third_party/skia/include/core/SkPixelRef.h" 13#include "ui/gfx/skia_util.h" 14#include "ui/surface/transport_dib.h" 15 16namespace content { 17 18CompositorSoftwareOutputDevice::DIB::DIB(size_t size) { 19 RenderProcess* render_process = RenderProcess::current(); 20 dib_ = render_process->CreateTransportDIB(size); 21 CHECK(dib_); 22 bool success = dib_->Map(); 23 CHECK(success); 24} 25 26CompositorSoftwareOutputDevice::DIB::~DIB() { 27 RenderProcess* render_process = RenderProcess::current(); 28 render_process->FreeTransportDIB(dib_); 29} 30 31CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice() 32 : front_buffer_(-1), 33 num_free_buffers_(0) { 34 DetachFromThread(); 35} 36 37CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() { 38 DCHECK(CalledOnValidThread()); 39} 40 41CompositorSoftwareOutputDevice::DIB* 42CompositorSoftwareOutputDevice::CreateDIB() { 43 const size_t size = 4 * viewport_size_.GetArea(); 44 return new DIB(size); 45} 46 47void CompositorSoftwareOutputDevice::Resize(gfx::Size viewport_size) { 48 DCHECK(CalledOnValidThread()); 49 50 if (viewport_size_ == viewport_size) 51 return; 52 53 // Keep non-ACKed dibs open. 54 int first_non_free = front_buffer_ + num_free_buffers_ + 1; 55 int num_non_free = dibs_.size() - num_free_buffers_; 56 for (int i = 0; i < num_non_free; ++i) { 57 int index = (first_non_free + i) % dibs_.size(); 58 awaiting_ack_.push_back(dibs_[index]); 59 dibs_[index] = NULL; 60 } 61 62 dibs_.clear(); 63 front_buffer_ = -1; 64 num_free_buffers_ = 0; 65 viewport_size_ = viewport_size; 66} 67 68SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(gfx::Rect damage_rect) { 69 DCHECK(CalledOnValidThread()); 70 71 gfx::Rect last_damage_rect = damage_rect_; 72 damage_rect_ = damage_rect; 73 74 int last_buffer = front_buffer_; 75 if (num_free_buffers_ == 0) { 76 dibs_.insert(dibs_.begin() + (front_buffer_ + 1), CreateDIB()); 77 last_damage_rect = gfx::Rect(viewport_size_); 78 } else { 79 --num_free_buffers_; 80 } 81 front_buffer_ = (front_buffer_ + 1) % dibs_.size(); 82 83 TransportDIB* front_dib = dibs_[front_buffer_]->dib(); 84 DCHECK(front_dib); 85 DCHECK(front_dib->memory()); 86 87 // Set up a canvas for the current front buffer. 88 bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 89 viewport_size_.width(), 90 viewport_size_.height()); 91 bitmap_.setPixels(front_dib->memory()); 92 device_ = skia::AdoptRef(new SkDevice(bitmap_)); 93 canvas_ = skia::AdoptRef(new SkCanvas(device_.get())); 94 95 // Copy over previous damage. 96 if (last_buffer != -1) { 97 TransportDIB* last_dib = dibs_[last_buffer]->dib(); 98 SkBitmap back_bitmap; 99 back_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100 viewport_size_.width(), 101 viewport_size_.height()); 102 back_bitmap.setPixels(last_dib->memory()); 103 104 SkRegion region(RectToSkIRect(last_damage_rect)); 105 region.op(RectToSkIRect(damage_rect), SkRegion::kDifference_Op); 106 for (SkRegion::Iterator it(region); !it.done(); it.next()) { 107 const SkIRect& src_rect = it.rect(); 108 SkRect dst_rect = SkRect::Make(src_rect); 109 canvas_->drawBitmapRect(back_bitmap, &src_rect, dst_rect, NULL); 110 } 111 } 112 113 return canvas_.get(); 114} 115 116void CompositorSoftwareOutputDevice::EndPaint( 117 cc::SoftwareFrameData* frame_data) { 118 DCHECK(CalledOnValidThread()); 119 120 if (frame_data) { 121 frame_data->size = viewport_size_; 122 frame_data->damage_rect = damage_rect_; 123 frame_data->dib_id = dibs_[front_buffer_]->dib()->id(); 124 } 125} 126 127void CompositorSoftwareOutputDevice::ReclaimDIB(const TransportDIB::Id& id) { 128 DCHECK(CalledOnValidThread()); 129 130 if (!TransportDIB::is_valid_id(id)) 131 return; 132 133 // The reclaimed dib id might not be among the currently 134 // active dibs if we got a resize event in the mean time. 135 ScopedVector<DIB>::iterator it = 136 std::find_if(dibs_.begin(), dibs_.end(), CompareById(id)); 137 if (it != dibs_.end()) { 138 ++num_free_buffers_; 139 DCHECK_LE(static_cast<size_t>(num_free_buffers_), dibs_.size()); 140 return; 141 } else { 142 it = std::find_if(awaiting_ack_.begin(), awaiting_ack_.end(), 143 CompareById(id)); 144 DCHECK(it != awaiting_ack_.end()); 145 awaiting_ack_.erase(it); 146 } 147} 148 149} // namespace content 150