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