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.
4
5#include "ui/ozone/platform/dri/ozone_platform_gbm.h"
6
7#include <dlfcn.h>
8#include <gbm.h>
9#include <stdlib.h>
10
11#include "base/at_exit.h"
12#include "base/command_line.h"
13#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
14#include "ui/events/ozone/device/device_manager.h"
15#include "ui/events/ozone/evdev/event_factory_evdev.h"
16#include "ui/ozone/platform/dri/dri_cursor.h"
17#include "ui/ozone/platform/dri/dri_window.h"
18#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
19#include "ui/ozone/platform/dri/dri_window_delegate_proxy.h"
20#include "ui/ozone/platform/dri/dri_window_manager.h"
21#include "ui/ozone/platform/dri/dri_wrapper.h"
22#include "ui/ozone/platform/dri/gbm_buffer.h"
23#include "ui/ozone/platform/dri/gbm_surface.h"
24#include "ui/ozone/platform/dri/gbm_surface_factory.h"
25#include "ui/ozone/platform/dri/gpu_platform_support_gbm.h"
26#include "ui/ozone/platform/dri/gpu_platform_support_host_gbm.h"
27#include "ui/ozone/platform/dri/scanout_buffer.h"
28#include "ui/ozone/platform/dri/screen_manager.h"
29#include "ui/ozone/platform/dri/virtual_terminal_manager.h"
30#include "ui/ozone/public/cursor_factory_ozone.h"
31#include "ui/ozone/public/gpu_platform_support.h"
32#include "ui/ozone/public/gpu_platform_support_host.h"
33#include "ui/ozone/public/ozone_platform.h"
34#include "ui/ozone/public/ozone_switches.h"
35
36#if defined(OS_CHROMEOS)
37#include "ui/ozone/platform/dri/chromeos/display_message_handler.h"
38#include "ui/ozone/platform/dri/chromeos/native_display_delegate_dri.h"
39#include "ui/ozone/platform/dri/chromeos/native_display_delegate_proxy.h"
40#endif
41
42namespace ui {
43
44namespace {
45
46const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
47
48class GbmBufferGenerator : public ScanoutBufferGenerator {
49 public:
50  GbmBufferGenerator(DriWrapper* dri)
51      : dri_(dri),
52        glapi_lib_(dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL)),
53        device_(gbm_create_device(dri_->get_fd())) {
54    if (!device_)
55      LOG(FATAL) << "Unable to initialize gbm for " << kDefaultGraphicsCardPath;
56  }
57  virtual ~GbmBufferGenerator() {
58    gbm_device_destroy(device_);
59    if (glapi_lib_)
60      dlclose(glapi_lib_);
61  }
62
63  gbm_device* device() const { return device_; }
64
65  virtual scoped_refptr<ScanoutBuffer> Create(const gfx::Size& size) OVERRIDE {
66    return GbmBuffer::CreateBuffer(
67        dri_, device_, SurfaceFactoryOzone::RGBA_8888, size, true);
68  }
69
70 protected:
71  DriWrapper* dri_;  // Not owned.
72
73  // HACK: gbm drivers have broken linkage
74  void *glapi_lib_;
75
76  gbm_device* device_;
77
78  DISALLOW_COPY_AND_ASSIGN(GbmBufferGenerator);
79};
80
81class OzonePlatformGbm : public OzonePlatform {
82 public:
83  OzonePlatformGbm(bool use_surfaceless) : use_surfaceless_(use_surfaceless) {
84    base::AtExitManager::RegisterTask(
85        base::Bind(&base::DeletePointer<OzonePlatformGbm>, this));
86  }
87  virtual ~OzonePlatformGbm() {}
88
89  // OzonePlatform:
90  virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() OVERRIDE {
91    return surface_factory_ozone_.get();
92  }
93  virtual CursorFactoryOzone* GetCursorFactoryOzone() OVERRIDE {
94    return cursor_factory_ozone_.get();
95  }
96  virtual GpuPlatformSupport* GetGpuPlatformSupport() OVERRIDE {
97    return gpu_platform_support_.get();
98  }
99  virtual GpuPlatformSupportHost* GetGpuPlatformSupportHost() OVERRIDE {
100    return gpu_platform_support_host_.get();
101  }
102  virtual scoped_ptr<PlatformWindow> CreatePlatformWindow(
103      PlatformWindowDelegate* delegate,
104      const gfx::Rect& bounds) OVERRIDE {
105    scoped_ptr<DriWindow> platform_window(
106        new DriWindow(delegate,
107                      bounds,
108                      scoped_ptr<DriWindowDelegate>(new DriWindowDelegateProxy(
109                          window_manager_->NextAcceleratedWidget(),
110                          gpu_platform_support_host_.get())),
111                      event_factory_ozone_.get(),
112                      ui_window_delegate_manager_.get(),
113                      window_manager_.get()));
114    platform_window->Initialize();
115    return platform_window.PassAs<PlatformWindow>();
116  }
117#if defined(OS_CHROMEOS)
118  virtual scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate()
119      OVERRIDE {
120    return scoped_ptr<NativeDisplayDelegate>(new NativeDisplayDelegateProxy(
121        gpu_platform_support_host_.get(), device_manager_.get()));
122  }
123#endif
124  virtual void InitializeUI() OVERRIDE {
125    vt_manager_.reset(new VirtualTerminalManager());
126    ui_window_delegate_manager_.reset(new DriWindowDelegateManager());
127    // Needed since the browser process creates the accelerated widgets and that
128    // happens through SFO.
129    surface_factory_ozone_.reset(new GbmSurfaceFactory(use_surfaceless_));
130    device_manager_ = CreateDeviceManager();
131    gpu_platform_support_host_.reset(new GpuPlatformSupportHostGbm());
132    cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
133    window_manager_.reset(
134        new DriWindowManager(gpu_platform_support_host_.get()));
135    event_factory_ozone_.reset(new EventFactoryEvdev(window_manager_->cursor(),
136                                                     device_manager_.get()));
137  }
138
139  virtual void InitializeGPU() OVERRIDE {
140    dri_.reset(new DriWrapper(kDefaultGraphicsCardPath));
141    dri_->Initialize();
142    buffer_generator_.reset(new GbmBufferGenerator(dri_.get()));
143    screen_manager_.reset(new ScreenManager(dri_.get(),
144                                            buffer_generator_.get()));
145    gpu_window_delegate_manager_.reset(new DriWindowDelegateManager());
146    if (!surface_factory_ozone_)
147      surface_factory_ozone_.reset(new GbmSurfaceFactory(use_surfaceless_));
148
149    surface_factory_ozone_->InitializeGpu(dri_.get(),
150                                          buffer_generator_->device(),
151                                          screen_manager_.get(),
152                                          gpu_window_delegate_manager_.get());
153    gpu_platform_support_.reset(
154        new GpuPlatformSupportGbm(surface_factory_ozone_.get(),
155                                  gpu_window_delegate_manager_.get(),
156                                  screen_manager_.get()));
157#if defined(OS_CHROMEOS)
158    gpu_platform_support_->AddHandler(scoped_ptr<GpuPlatformSupport>(
159        new DisplayMessageHandler(
160            scoped_ptr<NativeDisplayDelegateDri>(new NativeDisplayDelegateDri(
161                dri_.get(),
162                screen_manager_.get(),
163                NULL)))));
164#endif
165    if (surface_factory_ozone_->InitializeHardware() !=
166        DriSurfaceFactory::INITIALIZED)
167      LOG(FATAL) << "failed to initialize display hardware";
168  }
169
170 private:
171  bool use_surfaceless_;
172  scoped_ptr<VirtualTerminalManager> vt_manager_;
173  scoped_ptr<DriWrapper> dri_;
174  scoped_ptr<GbmBufferGenerator> buffer_generator_;
175  scoped_ptr<ScreenManager> screen_manager_;
176  scoped_ptr<DeviceManager> device_manager_;
177
178  scoped_ptr<GbmSurfaceFactory> surface_factory_ozone_;
179  scoped_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
180  scoped_ptr<EventFactoryEvdev> event_factory_ozone_;
181
182  scoped_ptr<GpuPlatformSupportGbm> gpu_platform_support_;
183  scoped_ptr<GpuPlatformSupportHostGbm> gpu_platform_support_host_;
184
185  scoped_ptr<DriWindowDelegateManager> gpu_window_delegate_manager_;
186  // TODO(dnicoara) Once we have a mock channel for the software path the window
187  // can own the delegates on the browser side. Remove this then.
188  scoped_ptr<DriWindowDelegateManager> ui_window_delegate_manager_;
189
190  // Browser side object only.
191  scoped_ptr<DriWindowManager> window_manager_;
192
193  DISALLOW_COPY_AND_ASSIGN(OzonePlatformGbm);
194};
195
196}  // namespace
197
198OzonePlatform* CreateOzonePlatformGbm() {
199  CommandLine* cmd = CommandLine::ForCurrentProcess();
200  return new OzonePlatformGbm(cmd->HasSwitch(switches::kOzoneUseSurfaceless));
201}
202
203}  // namespace ui
204