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.
5 #include "content/renderer/gpu/compositor_software_output_device.h"
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"
19 const size_t kInvalidIndex
= static_cast<size_t>(-1);
25 CompositorSoftwareOutputDevice::Buffer::Buffer(
27 scoped_ptr
<cc::SharedBitmap
> bitmap
)
28 : id_(id
), shared_bitmap_(bitmap
.Pass()), free_(true), parent_(NULL
) {}
30 CompositorSoftwareOutputDevice::Buffer::~Buffer() {
33 void CompositorSoftwareOutputDevice::Buffer::SetParent(
34 Buffer
* parent
, const gfx::Rect
& damage
) {
39 bool CompositorSoftwareOutputDevice::Buffer::FindDamageDifferenceFrom(
40 Buffer
* buffer
, SkRegion
* result
) const {
50 const Buffer
* current
= this;
51 while (current
->parent_
) {
52 damage
.op(RectToSkIRect(current
->damage_
), SkRegion::kUnion_Op
);
53 if (current
->parent_
== buffer
) {
57 current
= current
->parent_
;
63 CompositorSoftwareOutputDevice::CompositorSoftwareOutputDevice()
64 : current_index_(kInvalidIndex
),
66 shared_bitmap_manager_(
67 RenderThreadImpl::current()->shared_bitmap_manager()) {
71 CompositorSoftwareOutputDevice::~CompositorSoftwareOutputDevice() {
72 DCHECK(CalledOnValidThread());
75 unsigned CompositorSoftwareOutputDevice::GetNextId() {
76 unsigned id
= next_buffer_id_
++;
77 // Zero is reserved to label invalid frame id.
79 id
= next_buffer_id_
++;
83 CompositorSoftwareOutputDevice::Buffer
*
84 CompositorSoftwareOutputDevice::CreateBuffer() {
85 scoped_ptr
<cc::SharedBitmap
> shared_bitmap
=
86 shared_bitmap_manager_
->AllocateSharedBitmap(viewport_pixel_size_
);
88 return new Buffer(GetNextId(), shared_bitmap
.Pass());
91 size_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())
98 buffers_
.push_back(CreateBuffer());
99 return buffers_
.size() - 1;
102 void CompositorSoftwareOutputDevice::Resize(
103 const gfx::Size
& viewport_pixel_size
,
104 float scale_factor
) {
105 DCHECK(CalledOnValidThread());
107 scale_factor_
= scale_factor
;
109 if (viewport_pixel_size_
== viewport_pixel_size
)
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
]);
121 current_index_
= kInvalidIndex
;
122 viewport_pixel_size_
= viewport_pixel_size
;
125 void 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
]);
134 current_index_
= kInvalidIndex
;
137 void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
140 SkCanvas
* CompositorSoftwareOutputDevice::BeginPaint(
141 const gfx::Rect
& damage_rect
) {
142 DCHECK(CalledOnValidThread());
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);
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 surface_
= skia::AdoptRef(SkSurface::NewRasterDirect(info
, current
->memory(),
156 info
.minRowBytes()));
159 DCHECK(damage_rect
== gfx::Rect(viewport_pixel_size_
));
161 // Find the smallest damage region that needs
162 // to be copied from the |previous| buffer.
165 current
->FindDamageDifferenceFrom(previous
, ®ion
) ||
166 previous
->FindDamageDifferenceFrom(current
, ®ion
);
168 region
= SkRegion(RectToSkIRect(gfx::Rect(viewport_pixel_size_
)));
169 region
.op(RectToSkIRect(damage_rect
), SkRegion::kDifference_Op
);
171 // Copy over the damage region.
172 if (!region
.isEmpty()) {
173 SkImageInfo info
= SkImageInfo::MakeN32Premul(
174 viewport_pixel_size_
.width(), viewport_pixel_size_
.height());
175 SkBitmap back_bitmap
;
176 back_bitmap
.installPixels(info
, previous
->memory(), info
.minRowBytes());
178 for (SkRegion::Iterator
it(region
); !it
.done(); it
.next()) {
179 const SkIRect
& src_rect
= it
.rect();
180 SkRect dst_rect
= SkRect::Make(src_rect
);
181 surface_
->getCanvas()->drawBitmapRect(back_bitmap
, &src_rect
, dst_rect
);
186 // Make |current| child of |previous| and orphan all of |current|'s children.
187 current
->SetParent(previous
, damage_rect
);
188 for (size_t i
= 0; i
< buffers_
.size(); ++i
) {
189 Buffer
* buffer
= buffers_
[i
];
190 if (buffer
->parent() == current
)
191 buffer
->SetParent(NULL
, gfx::Rect(viewport_pixel_size_
));
193 damage_rect_
= damage_rect
;
195 return surface_
->getCanvas();
198 void CompositorSoftwareOutputDevice::EndPaint(
199 cc::SoftwareFrameData
* frame_data
) {
200 DCHECK(CalledOnValidThread());
203 Buffer
* buffer
= buffers_
[current_index_
];
204 frame_data
->id
= buffer
->id();
205 frame_data
->size
= viewport_pixel_size_
;
206 frame_data
->damage_rect
= damage_rect_
;
207 frame_data
->bitmap_id
= buffer
->shared_bitmap_id();
210 void CompositorSoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id
) {
211 DCHECK(CalledOnValidThread());
216 // The reclaimed buffer id might not be among the currently
217 // active buffers if we got a resize event in the mean time.
218 ScopedVector
<Buffer
>::iterator it
=
219 std::find_if(buffers_
.begin(), buffers_
.end(), CompareById(id
));
220 if (it
!= buffers_
.end()) {
221 DCHECK(!(*it
)->free());
222 (*it
)->SetFree(true);
225 it
= std::find_if(awaiting_ack_
.begin(), awaiting_ack_
.end(),
227 DCHECK(it
!= awaiting_ack_
.end());
228 awaiting_ack_
.erase(it
);
232 } // namespace content