1 // Copyright 2014 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 "ui/ozone/platform/dri/dri_surface_factory.h"
9 #include "base/debug/trace_event.h"
10 #include "base/message_loop/message_loop.h"
11 #include "third_party/skia/include/core/SkBitmap.h"
12 #include "third_party/skia/include/core/SkDevice.h"
13 #include "third_party/skia/include/core/SkSurface.h"
14 #include "ui/gfx/native_widget_types.h"
15 #include "ui/ozone/platform/dri/dri_surface.h"
16 #include "ui/ozone/platform/dri/dri_util.h"
17 #include "ui/ozone/platform/dri/dri_vsync_provider.h"
18 #include "ui/ozone/platform/dri/dri_wrapper.h"
19 #include "ui/ozone/platform/dri/hardware_display_controller.h"
20 #include "ui/ozone/platform/dri/screen_manager.h"
21 #include "ui/ozone/public/surface_ozone_canvas.h"
27 // TODO(dnicoara) Read the cursor plane size from the hardware.
28 const gfx::Size
kCursorSize(64, 64);
30 void UpdateCursorImage(DriSurface
* cursor
, const SkBitmap
& image
) {
32 image
.getBounds(&damage
);
34 // Clear to transparent in case |image| is smaller than the canvas.
35 SkCanvas
* canvas
= cursor
->GetDrawableForWidget();
36 canvas
->clear(SK_ColorTRANSPARENT
);
40 0, 0, canvas
->getDeviceSize().width(), canvas
->getDeviceSize().height());
41 canvas
->clipRect(clip
, SkRegion::kReplace_Op
);
42 canvas
->drawBitmapRectToRect(image
, &damage
, damage
);
45 class DriSurfaceAdapter
: public ui::SurfaceOzoneCanvas
{
47 DriSurfaceAdapter(const base::WeakPtr
<HardwareDisplayController
>& controller
);
48 virtual ~DriSurfaceAdapter();
50 // SurfaceOzoneCanvas:
51 virtual skia::RefPtr
<SkCanvas
> GetCanvas() OVERRIDE
;
52 virtual void ResizeCanvas(const gfx::Size
& viewport_size
) OVERRIDE
;
53 virtual void PresentCanvas(const gfx::Rect
& damage
) OVERRIDE
;
54 virtual scoped_ptr
<gfx::VSyncProvider
> CreateVSyncProvider() OVERRIDE
;
57 void UpdateNativeSurface(const gfx::Rect
& damage
);
59 skia::RefPtr
<SkSurface
> surface_
;
60 gfx::Rect last_damage_
;
61 base::WeakPtr
<HardwareDisplayController
> controller_
;
63 DISALLOW_COPY_AND_ASSIGN(DriSurfaceAdapter
);
66 DriSurfaceAdapter::DriSurfaceAdapter(
67 const base::WeakPtr
<HardwareDisplayController
>& controller
)
68 : controller_(controller
) {
71 DriSurfaceAdapter::~DriSurfaceAdapter() {
74 skia::RefPtr
<SkCanvas
> DriSurfaceAdapter::GetCanvas() {
75 return skia::SharePtr(surface_
->getCanvas());
78 void DriSurfaceAdapter::ResizeCanvas(const gfx::Size
& viewport_size
) {
79 SkImageInfo info
= SkImageInfo::MakeN32(
80 viewport_size
.width(), viewport_size
.height(), kOpaque_SkAlphaType
);
81 surface_
= skia::AdoptRef(SkSurface::NewRaster(info
));
84 void DriSurfaceAdapter::PresentCanvas(const gfx::Rect
& damage
) {
85 CHECK(base::MessageLoopForUI::IsCurrent());
89 UpdateNativeSurface(damage
);
90 controller_
->SchedulePageFlip();
91 controller_
->WaitForPageFlipEvent();
94 scoped_ptr
<gfx::VSyncProvider
> DriSurfaceAdapter::CreateVSyncProvider() {
95 return scoped_ptr
<gfx::VSyncProvider
>(new DriVSyncProvider(controller_
));
98 void DriSurfaceAdapter::UpdateNativeSurface(const gfx::Rect
& damage
) {
99 SkCanvas
* canvas
= static_cast<DriSurface
*>(controller_
->surface())
100 ->GetDrawableForWidget();
102 // The DriSurface is double buffered, so the current back buffer is
103 // missing the previous update. Expand damage region.
104 SkRect real_damage
= RectToSkRect(UnionRects(damage
, last_damage_
));
106 // Copy damage region.
107 skia::RefPtr
<SkImage
> image
= skia::AdoptRef(surface_
->newImageSnapshot());
108 image
->draw(canvas
, &real_damage
, real_damage
, NULL
);
110 last_damage_
= damage
;
116 const gfx::AcceleratedWidget
DriSurfaceFactory::kDefaultWidgetHandle
= 1;
118 DriSurfaceFactory::DriSurfaceFactory(DriWrapper
* drm
,
119 ScreenManager
* screen_manager
)
121 screen_manager_(screen_manager
),
122 state_(UNINITIALIZED
),
123 allocated_widgets_(0) {
126 DriSurfaceFactory::~DriSurfaceFactory() {
127 if (state_
== INITIALIZED
)
131 ui::SurfaceFactoryOzone::HardwareState
DriSurfaceFactory::InitializeHardware() {
132 if (state_
!= UNINITIALIZED
)
135 if (drm_
->get_fd() < 0) {
136 LOG(ERROR
) << "Failed to create DRI connection";
141 cursor_surface_
.reset(CreateSurface(kCursorSize
));
142 if (!cursor_surface_
->Initialize()) {
143 LOG(ERROR
) << "Failed to initialize cursor surface";
148 state_
= INITIALIZED
;
152 void DriSurfaceFactory::ShutdownHardware() {
153 CHECK(state_
== INITIALIZED
);
154 state_
= UNINITIALIZED
;
157 gfx::AcceleratedWidget
DriSurfaceFactory::GetAcceleratedWidget() {
158 CHECK(state_
!= FAILED
);
160 // We're not using 0 since other code assumes that a 0 AcceleratedWidget is an
162 return ++allocated_widgets_
;
165 scoped_ptr
<ui::SurfaceOzoneCanvas
> DriSurfaceFactory::CreateCanvasForWidget(
166 gfx::AcceleratedWidget w
) {
167 CHECK(state_
== INITIALIZED
);
168 // Initial cursor set.
171 return scoped_ptr
<ui::SurfaceOzoneCanvas
>(
172 new DriSurfaceAdapter(screen_manager_
->GetDisplayController(w
)));
175 bool DriSurfaceFactory::LoadEGLGLES2Bindings(
176 AddGLLibraryCallback add_gl_library
,
177 SetGLGetProcAddressProcCallback set_gl_get_proc_address
) {
181 gfx::Size
DriSurfaceFactory::GetWidgetSize(gfx::AcceleratedWidget w
) {
182 base::WeakPtr
<HardwareDisplayController
> controller
=
183 screen_manager_
->GetDisplayController(w
);
185 return gfx::Size(controller
->get_mode().hdisplay
,
186 controller
->get_mode().vdisplay
);
188 return gfx::Size(0, 0);
191 void DriSurfaceFactory::SetHardwareCursor(gfx::AcceleratedWidget window
,
192 const SkBitmap
& image
,
193 const gfx::Point
& location
) {
194 cursor_bitmap_
= image
;
195 cursor_location_
= location
;
197 if (state_
!= INITIALIZED
)
203 void DriSurfaceFactory::MoveHardwareCursor(gfx::AcceleratedWidget window
,
204 const gfx::Point
& location
) {
205 cursor_location_
= location
;
207 if (state_
!= INITIALIZED
)
210 base::WeakPtr
<HardwareDisplayController
> controller
=
211 screen_manager_
->GetDisplayController(window
);
213 controller
->MoveCursor(location
);
216 ////////////////////////////////////////////////////////////////////////////////
217 // DriSurfaceFactory private
219 DriSurface
* DriSurfaceFactory::CreateSurface(const gfx::Size
& size
) {
220 return new DriSurface(drm_
, size
);
223 void DriSurfaceFactory::ResetCursor(gfx::AcceleratedWidget w
) {
224 base::WeakPtr
<HardwareDisplayController
> controller
=
225 screen_manager_
->GetDisplayController(w
);
227 if (!cursor_bitmap_
.empty()) {
228 // Draw new cursor into backbuffer.
229 UpdateCursorImage(cursor_surface_
.get(), cursor_bitmap_
);
231 // Reset location & buffer.
233 controller
->MoveCursor(cursor_location_
);
234 controller
->SetCursor(cursor_surface_
.get());
239 controller
->UnsetCursor();