| Index: content/browser/compositor/software_output_device_mac.mm
|
| diff --git a/content/browser/compositor/software_output_device_mac.mm b/content/browser/compositor/software_output_device_mac.mm
|
| index 5dacbae755c5eaa97a69fb4544135f1a4da80bf2..9f0f7e46a1f53fe56601f7f268439ccfd4e62704 100644
|
| --- a/content/browser/compositor/software_output_device_mac.mm
|
| +++ b/content/browser/compositor/software_output_device_mac.mm
|
| @@ -2,26 +2,156 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#import <Cocoa/Cocoa.h>
|
| -
|
| #include "content/browser/compositor/software_output_device_mac.h"
|
|
|
| +#import <Cocoa/Cocoa.h>
|
| +
|
| +#include "base/mac/foundation_util.h"
|
| +#include "third_party/skia/include/core/SkCanvas.h"
|
| #include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
|
| #include "ui/compositor/compositor.h"
|
| +#include "ui/gfx/skia_util.h"
|
|
|
| namespace content {
|
|
|
| SoftwareOutputDeviceMac::SoftwareOutputDeviceMac(ui::Compositor* compositor)
|
| - : compositor_(compositor) {
|
| -}
|
| + : compositor_(compositor), scale_factor_(1), current_index_(0) {}
|
|
|
| SoftwareOutputDeviceMac::~SoftwareOutputDeviceMac() {
|
| }
|
|
|
| +void SoftwareOutputDeviceMac::Resize(const gfx::Size& pixel_size,
|
| + float scale_factor) {
|
| + if (pixel_size_ == pixel_size && scale_factor_ == scale_factor)
|
| + return;
|
| +
|
| + pixel_size_ = pixel_size;
|
| + scale_factor_ = scale_factor;
|
| +
|
| + DiscardBackbuffer();
|
| +}
|
| +
|
| +void SoftwareOutputDeviceMac::CopyPreviousBufferDamage(
|
| + const SkRegion& new_damage_region) {
|
| + TRACE_EVENT0("browser", "CopyPreviousBufferDamage");
|
| +
|
| + // The region to copy is the region drawn last frame, minus the region that
|
| + // is drawn this frame.
|
| + SkRegion copy_region = previous_buffer_damage_region_;
|
| + bool copy_region_nonempty =
|
| + copy_region.op(new_damage_region, SkRegion::kDifference_Op);
|
| + previous_buffer_damage_region_ = new_damage_region;
|
| +
|
| + if (!copy_region_nonempty)
|
| + return;
|
| +
|
| + IOSurfaceRef previous_io_surface = io_surfaces_[!current_index_].get();
|
| +
|
| + {
|
| + TRACE_EVENT0("browser", "IOSurfaceLock");
|
| + IOReturn io_result = IOSurfaceLock(
|
| + previous_io_surface, kIOSurfaceLockReadOnly | kIOSurfaceLockAvoidSync,
|
| + nullptr);
|
| + if (io_result) {
|
| + DLOG(ERROR) << "Failed to lock previous IOSurface " << io_result;
|
| + return;
|
| + }
|
| + }
|
| +
|
| + uint8_t* pixels =
|
| + static_cast<uint8_t*>(IOSurfaceGetBaseAddress(previous_io_surface));
|
| + size_t stride = IOSurfaceGetBytesPerRow(previous_io_surface);
|
| + size_t bytes_per_element = 4;
|
| + for (SkRegion::Iterator it(copy_region); !it.done(); it.next()) {
|
| + const SkIRect& rect = it.rect();
|
| + canvas_->writePixels(
|
| + SkImageInfo::MakeN32Premul(rect.width(), rect.height()),
|
| + pixels + bytes_per_element * rect.x() + stride * rect.y(), stride,
|
| + rect.x(), rect.y());
|
| + }
|
| +
|
| + {
|
| + TRACE_EVENT0("browser", "IOSurfaceUnlock");
|
| + IOReturn io_result = IOSurfaceUnlock(
|
| + previous_io_surface, kIOSurfaceLockReadOnly | kIOSurfaceLockAvoidSync,
|
| + nullptr);
|
| + if (io_result)
|
| + DLOG(ERROR) << "Failed to unlock previous IOSurface " << io_result;
|
| + }
|
| +}
|
| +
|
| +bool SoftwareOutputDeviceMac::EnsureBuffersExist() {
|
| + for (int i = 0; i < 2; ++i) {
|
| + if (!io_surfaces_[i]) {
|
| + TRACE_EVENT0("browser", "IOSurfaceCreate");
|
| + unsigned pixel_format = 'BGRA';
|
| + unsigned bytes_per_element = 4;
|
| + NSDictionary* options = @{
|
| + static_cast<id>(kIOSurfaceWidth) : @(pixel_size_.width()),
|
| + static_cast<id>(kIOSurfaceHeight) : @(pixel_size_.height()),
|
| + static_cast<id>(kIOSurfacePixelFormat) : @(pixel_format),
|
| + static_cast<id>(kIOSurfaceBytesPerElement) : @(bytes_per_element),
|
| + };
|
| + io_surfaces_[i].reset(IOSurfaceCreate(base::mac::NSToCFCast(options)));
|
| + }
|
| + if (!io_surfaces_[i]) {
|
| + DLOG(ERROR) << "Failed to allocate IOSurface";
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +SkCanvas* SoftwareOutputDeviceMac::BeginPaint(
|
| + const gfx::Rect& new_damage_rect) {
|
| + if (!EnsureBuffersExist())
|
| + return nullptr;
|
| +
|
| + {
|
| + TRACE_EVENT0("browser", "IOSurfaceLock");
|
| + IOReturn io_result = IOSurfaceLock(io_surfaces_[current_index_],
|
| + kIOSurfaceLockAvoidSync, nullptr);
|
| + if (io_result) {
|
| + DLOG(ERROR) << "Failed to lock IOSurface " << io_result;
|
| + return nullptr;
|
| + }
|
| + }
|
| +
|
| + SkPMColor* pixels = static_cast<SkPMColor*>(
|
| + IOSurfaceGetBaseAddress(io_surfaces_[current_index_]));
|
| + size_t stride = IOSurfaceGetBytesPerRow(io_surfaces_[current_index_]);
|
| +
|
| + canvas_ = skia::AdoptRef(SkCanvas::NewRasterDirectN32(
|
| + pixel_size_.width(), pixel_size_.height(), pixels, stride));
|
| +
|
| + CopyPreviousBufferDamage(SkRegion(gfx::RectToSkIRect(new_damage_rect)));
|
| +
|
| + return canvas_.get();
|
| +}
|
| +
|
| void SoftwareOutputDeviceMac::EndPaint() {
|
| SoftwareOutputDevice::EndPaint();
|
| - ui::AcceleratedWidgetMacGotSoftwareFrame(
|
| - compositor_->widget(), scale_factor_, surface_->getCanvas());
|
| + {
|
| + TRACE_EVENT0("browser", "IOSurfaceUnlock");
|
| + IOReturn io_result = IOSurfaceUnlock(io_surfaces_[current_index_],
|
| + kIOSurfaceLockAvoidSync, nullptr);
|
| + if (io_result)
|
| + DLOG(ERROR) << "Failed to unlock IOSurface " << io_result;
|
| + }
|
| +
|
| + canvas_ = nullptr;
|
| + ui::AcceleratedWidgetMacGotIOSurfaceFrame(compositor_->widget(),
|
| + io_surfaces_[current_index_],
|
| + pixel_size_, scale_factor_, false);
|
| +
|
| + current_index_ = !current_index_;
|
| }
|
|
|
| +void SoftwareOutputDeviceMac::DiscardBackbuffer() {
|
| + for (int i = 0; i < 2; ++i)
|
| + io_surfaces_[i].reset();
|
| +}
|
| +
|
| +void SoftwareOutputDeviceMac::EnsureBackbuffer() {}
|
| +
|
| } // namespace content
|
|
|