From f6a5261539900d7fb66c05623e091fad88c8b905 Mon Sep 17 00:00:00 2001 From: "dnicoara@chromium.org" Date: Wed, 23 Oct 2013 19:19:54 +0000 Subject: SoftwareOutputDevice implementation using an OZONE software renderer as the backend. SOD's expectation is that Ozone provides a SkCanvas as the accelerated widget. BUG= Review URL: https://codereview.chromium.org/23862004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230488 0039d316-1c4b-4281-b951-d872f2087c98 --- .../browser/aura/gpu_process_transport_factory.cc | 5 + .../browser/aura/software_output_device_ozone.cc | 69 ++++++++ .../browser/aura/software_output_device_ozone.h | 36 ++++ .../aura/software_output_device_ozone_unittest.cc | 189 +++++++++++++++++++++ content/content_browser.gypi | 2 + content/content_tests.gypi | 1 + 6 files changed, 302 insertions(+) create mode 100644 content/browser/aura/software_output_device_ozone.cc create mode 100644 content/browser/aura/software_output_device_ozone.h create mode 100644 content/browser/aura/software_output_device_ozone_unittest.cc (limited to 'content') diff --git a/content/browser/aura/gpu_process_transport_factory.cc b/content/browser/aura/gpu_process_transport_factory.cc index 64ba33d..12bfd8c 100644 --- a/content/browser/aura/gpu_process_transport_factory.cc +++ b/content/browser/aura/gpu_process_transport_factory.cc @@ -36,6 +36,8 @@ #if defined(OS_WIN) #include "content/browser/aura/software_output_device_win.h" #include "ui/surface/accelerated_surface_win.h" +#elif defined(USE_OZONE) +#include "content/browser/aura/software_output_device_ozone.h" #elif defined(USE_X11) #include "content/browser/aura/software_output_device_x11.h" #endif @@ -205,6 +207,9 @@ scoped_ptr CreateSoftwareOutputDevice( #if defined(OS_WIN) return scoped_ptr(new SoftwareOutputDeviceWin( compositor)); +#elif defined(USE_OZONE) + return scoped_ptr(new SoftwareOutputDeviceOzone( + compositor)); #elif defined(USE_X11) return scoped_ptr(new SoftwareOutputDeviceX11( compositor)); diff --git a/content/browser/aura/software_output_device_ozone.cc b/content/browser/aura/software_output_device_ozone.cc new file mode 100644 index 0000000..c704fed --- /dev/null +++ b/content/browser/aura/software_output_device_ozone.cc @@ -0,0 +1,69 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/aura/software_output_device_ozone.h" +#include "third_party/skia/include/core/SkBitmapDevice.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "ui/compositor/compositor.h" +#include "ui/gfx/ozone/surface_factory_ozone.h" +#include "ui/gfx/skia_util.h" + +namespace content { + +SoftwareOutputDeviceOzone::SoftwareOutputDeviceOzone( + ui::Compositor* compositor) : compositor_(compositor) { + if (gfx::SurfaceFactoryOzone::GetInstance()->InitializeHardware() != + gfx::SurfaceFactoryOzone::INITIALIZED) + LOG(FATAL) << "Failed to initialize hardware in OZONE"; +} + +SoftwareOutputDeviceOzone::~SoftwareOutputDeviceOzone() { +} + +void SoftwareOutputDeviceOzone::Resize(gfx::Size viewport_size) { + if (viewport_size_ == viewport_size) + return; + + viewport_size_ = viewport_size; + gfx::Rect bounds(viewport_size_); + + gfx::SurfaceFactoryOzone* factory = gfx::SurfaceFactoryOzone::GetInstance(); + factory->AttemptToResizeAcceleratedWidget(compositor_->widget(), + bounds); + gfx::AcceleratedWidget realized_widget = factory->RealizeAcceleratedWidget( + compositor_->widget()); + + if (realized_widget == gfx::kNullAcceleratedWidget) + LOG(FATAL) << "Failed to get a realized AcceleratedWidget"; + + canvas_ = skia::SharePtr(factory->GetCanvasForWidget(realized_widget)); + device_ = skia::SharePtr(canvas_->getDevice()); +} + +SkCanvas* SoftwareOutputDeviceOzone::BeginPaint(gfx::Rect damage_rect) { + DCHECK(gfx::Rect(viewport_size_).Contains(damage_rect)); + + canvas_->clipRect(gfx::RectToSkRect(damage_rect), SkRegion::kReplace_Op); + // Save the current state so we can restore once we're done drawing. This is + // saved after the clip since we want to keep the clip information after we're + // done drawing such that OZONE knows what was updated. + canvas_->save(); + + return SoftwareOutputDevice::BeginPaint(damage_rect); +} + +void SoftwareOutputDeviceOzone::EndPaint(cc::SoftwareFrameData* frame_data) { + SoftwareOutputDevice::EndPaint(frame_data); + + canvas_->restore(); + + if (damage_rect_.IsEmpty()) + return; + + bool scheduled = gfx::SurfaceFactoryOzone::GetInstance()->SchedulePageFlip( + compositor_->widget()); + DCHECK(scheduled) << "Failed to schedule pageflip"; +} + +} // namespace content diff --git a/content/browser/aura/software_output_device_ozone.h b/content/browser/aura/software_output_device_ozone.h new file mode 100644 index 0000000..cee91f8 --- /dev/null +++ b/content/browser/aura/software_output_device_ozone.h @@ -0,0 +1,36 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_OZONE_H_ +#define CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_OZONE_H_ + +#include "cc/output/software_output_device.h" + +namespace ui { +class Compositor; +} + +namespace content { + +// Ozone implementation which relies on software rendering. Ozone will present +// an accelerated widget as a SkCanvas. SoftwareOutputDevice will then use the +// Ozone provided canvas to draw. +class SoftwareOutputDeviceOzone : public cc::SoftwareOutputDevice { + public: + explicit SoftwareOutputDeviceOzone(ui::Compositor* compositor); + virtual ~SoftwareOutputDeviceOzone(); + + virtual void Resize(gfx::Size viewport_size) OVERRIDE; + virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE; + virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE; + + private: + ui::Compositor* compositor_; + + DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzone); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_DEVICE_OZONE_H_ diff --git a/content/browser/aura/software_output_device_ozone_unittest.cc b/content/browser/aura/software_output_device_ozone_unittest.cc new file mode 100644 index 0000000..552116e --- /dev/null +++ b/content/browser/aura/software_output_device_ozone_unittest.cc @@ -0,0 +1,189 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "cc/output/software_frame_data.h" +#include "content/browser/aura/software_output_device_ozone.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmapDevice.h" +#include "ui/compositor/compositor.h" +#include "ui/gfx/ozone/surface_factory_ozone.h" +#include "ui/gfx/size.h" +#include "ui/gfx/skia_util.h" +#include "ui/gl/gl_implementation.h" + +namespace { + +class MockSurfaceFactoryOzone : public gfx::SurfaceFactoryOzone { + public: + MockSurfaceFactoryOzone() {} + virtual ~MockSurfaceFactoryOzone() {} + + virtual HardwareState InitializeHardware() OVERRIDE { + return SurfaceFactoryOzone::INITIALIZED; + } + + virtual void ShutdownHardware() OVERRIDE {} + virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE { return 1; } + virtual gfx::AcceleratedWidget RealizeAcceleratedWidget( + gfx::AcceleratedWidget w) OVERRIDE { return w; } + virtual bool LoadEGLGLES2Bindings() OVERRIDE { return false; } + virtual bool AttemptToResizeAcceleratedWidget( + gfx::AcceleratedWidget w, const gfx::Rect& bounds) OVERRIDE { + device_ = skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config, + bounds.width(), + bounds.height(), + true)); + canvas_ = skia::AdoptRef(new SkCanvas(device_.get())); + return true; + } + virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w) OVERRIDE { + return canvas_.get(); + } + virtual gfx::VSyncProvider* GetVSyncProvider( + gfx::AcceleratedWidget w) OVERRIDE { + return NULL; + } + private: + skia::RefPtr device_; + skia::RefPtr canvas_; + + DISALLOW_COPY_AND_ASSIGN(MockSurfaceFactoryOzone); +}; + +} // namespace + +class SoftwareOutputDeviceOzoneTest : public testing::Test { + public: + SoftwareOutputDeviceOzoneTest(); + virtual ~SoftwareOutputDeviceOzoneTest(); + + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; + + protected: + scoped_ptr output_device_; + + private: + scoped_ptr compositor_; + scoped_ptr message_loop_; + scoped_ptr surface_factory_; + + DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceOzoneTest); +}; + +SoftwareOutputDeviceOzoneTest::SoftwareOutputDeviceOzoneTest() { + CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL)); + message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI)); +} + +SoftwareOutputDeviceOzoneTest::~SoftwareOutputDeviceOzoneTest() { +} + +void SoftwareOutputDeviceOzoneTest::SetUp() { + ui::Compositor::InitializeContextFactoryForTests(false); + ui::Compositor::Initialize(); + + surface_factory_.reset(new MockSurfaceFactoryOzone()); + gfx::SurfaceFactoryOzone::SetInstance(surface_factory_.get()); + + const gfx::Size size(500, 400); + compositor_.reset(new ui::Compositor(gfx::SurfaceFactoryOzone::GetInstance() + ->GetAcceleratedWidget())); + compositor_->SetScaleAndSize(1.0f, size); + + output_device_.reset(new content::SoftwareOutputDeviceOzone( + compositor_.get())); + output_device_->Resize(size); +} + +void SoftwareOutputDeviceOzoneTest::TearDown() { + output_device_.reset(); + compositor_.reset(); + surface_factory_.reset(); + ui::Compositor::Terminate(); +} + +TEST_F(SoftwareOutputDeviceOzoneTest, CheckClipAfterBeginPaint) { + gfx::Rect damage(10, 10, 100, 100); + SkCanvas* canvas = output_device_->BeginPaint(damage); + + SkIRect sk_bounds; + canvas->getClipDeviceBounds(&sk_bounds); + + EXPECT_EQ(damage.ToString(), gfx::SkIRectToRect(sk_bounds).ToString()); +} + +TEST_F(SoftwareOutputDeviceOzoneTest, CheckClipAfterSecondBeginPaint) { + gfx::Rect damage(10, 10, 100, 100); + SkCanvas* canvas = output_device_->BeginPaint(damage); + + cc::SoftwareFrameData frame; + output_device_->EndPaint(&frame); + + damage = gfx::Rect(100, 100, 100, 100); + canvas = output_device_->BeginPaint(damage); + SkIRect sk_bounds; + canvas->getClipDeviceBounds(&sk_bounds); + + EXPECT_EQ(damage.ToString(), gfx::SkIRectToRect(sk_bounds).ToString()); +} + +TEST_F(SoftwareOutputDeviceOzoneTest, CheckCorrectResizeBehavior) { + gfx::Rect damage(0, 0, 100, 100); + gfx::Size size(200, 100); + // Reduce size. + output_device_->Resize(size); + + SkCanvas* canvas = output_device_->BeginPaint(damage); + gfx::Size canvas_size(canvas->getDeviceSize().width(), + canvas->getDeviceSize().height()); + EXPECT_EQ(size.ToString(), canvas_size.ToString()); + + size.SetSize(1000, 500); + // Increase size. + output_device_->Resize(size); + + canvas = output_device_->BeginPaint(damage); + canvas_size.SetSize(canvas->getDeviceSize().width(), + canvas->getDeviceSize().height()); + EXPECT_EQ(size.ToString(), canvas_size.ToString()); + +} + +TEST_F(SoftwareOutputDeviceOzoneTest, CheckCopyToBitmap) { + const gfx::Rect area(6, 4); + output_device_->Resize(area.size()); + SkCanvas* canvas = output_device_->BeginPaint(area); + + // Clear the background to black. + canvas->drawColor(SK_ColorBLACK); + + cc::SoftwareFrameData frame; + output_device_->EndPaint(&frame); + + // Draw a white rectangle. + gfx::Rect damage(area.width() / 2, area.height() / 2); + canvas = output_device_->BeginPaint(damage); + + canvas->drawColor(SK_ColorWHITE); + + output_device_->EndPaint(&frame); + + SkBitmap bitmap; + output_device_->CopyToBitmap(area, &bitmap); + + SkAutoLockPixels pixel_lock(bitmap); + // Check that the copied bitmap contains the same pixel values as what we + // painted. + for (int i = 0; i < area.height(); ++i) { + for (int j = 0; j < area.width(); ++j) { + if (j < damage.width() && i < damage.height()) + EXPECT_EQ(SK_ColorWHITE, bitmap.getColor(j, i)); + else + EXPECT_EQ(SK_ColorBLACK, bitmap.getColor(j, i)); + } + } +} diff --git a/content/content_browser.gypi b/content/content_browser.gypi index a1bf021..a064be2 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -308,6 +308,8 @@ 'browser/aura/resize_lock.h', 'browser/aura/software_browser_compositor_output_surface.cc', 'browser/aura/software_browser_compositor_output_surface.h', + 'browser/aura/software_output_device_ozone.cc', + 'browser/aura/software_output_device_ozone.h', 'browser/aura/software_output_device_win.cc', 'browser/aura/software_output_device_win.h', 'browser/aura/software_output_device_x11.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 69c7f1c..45d5b50 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -325,6 +325,7 @@ 'browser/accessibility/browser_accessibility_manager_unittest.cc', 'browser/accessibility/browser_accessibility_win_unittest.cc', 'browser/appcache/chrome_appcache_service_unittest.cc', + 'browser/aura/software_output_device_ozone_unittest.cc', 'browser/browser_thread_unittest.cc', 'browser/browser_url_handler_impl_unittest.cc', 'browser/byte_stream_unittest.cc', -- cgit v1.1