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 #ifndef UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_ 6 #define UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 #include <xf86drmMode.h> 11 #include <vector> 12 13 #include "base/basictypes.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_vector.h" 16 #include "base/memory/weak_ptr.h" 17 #include "ui/ozone/platform/dri/dri_wrapper.h" 18 19 namespace gfx { 20 class Point; 21 } 22 23 namespace ui { 24 25 class CrtcState; 26 class ScanoutBuffer; 27 28 struct OverlayPlane { 29 // Simpler constructor for the primary plane. 30 explicit OverlayPlane(scoped_refptr<ScanoutBuffer> buffer); 31 32 OverlayPlane(scoped_refptr<ScanoutBuffer> buffer, 33 int z_order, 34 gfx::OverlayTransform plane_transform, 35 const gfx::Rect& display_bounds, 36 const gfx::RectF& crop_rect); 37 38 ~OverlayPlane(); 39 40 scoped_refptr<ScanoutBuffer> buffer; 41 int z_order; 42 gfx::OverlayTransform plane_transform; 43 gfx::Rect display_bounds; 44 gfx::RectF crop_rect; 45 int overlay_plane; 46 }; 47 48 typedef std::vector<OverlayPlane> OverlayPlaneList; 49 50 // The HDCOz will handle modesettings and scannout operations for hardware 51 // devices. 52 // 53 // In the DRM world there are 3 components that need to be paired up to be able 54 // to display an image to the monitor: CRTC (cathode ray tube controller), 55 // encoder and connector. The CRTC determines which framebuffer to read, when 56 // to scanout and where to scanout. Encoders converts the stream from the CRTC 57 // to the appropriate format for the connector. The connector is the physical 58 // connection that monitors connect to. 59 // 60 // There is no 1:1:1 pairing for these components. It is possible for an encoder 61 // to be compatible to multiple CRTCs and each connector can be used with 62 // multiple encoders. In addition, it is possible to use one CRTC with multiple 63 // connectors such that we can display the same image on multiple monitors. 64 // 65 // For example, the following configuration shows 2 different screens being 66 // initialized separately. 67 // ------------- ------------- 68 // | Connector | | Connector | 69 // | HDMI | | VGA | 70 // ------------- ------------- 71 // ^ ^ 72 // | | 73 // ------------- ------------- 74 // | Encoder1 | | Encoder2 | 75 // ------------- ------------- 76 // ^ ^ 77 // | | 78 // ------------- ------------- 79 // | CRTC1 | | CRTC2 | 80 // ------------- ------------- 81 // 82 // In the following configuration 2 different screens are associated with the 83 // same CRTC, so on scanout the same framebuffer will be displayed on both 84 // monitors. 85 // ------------- ------------- 86 // | Connector | | Connector | 87 // | HDMI | | VGA | 88 // ------------- ------------- 89 // ^ ^ 90 // | | 91 // ------------- ------------- 92 // | Encoder1 | | Encoder2 | 93 // ------------- ------------- 94 // ^ ^ 95 // | | 96 // ---------------------- 97 // | CRTC1 | 98 // ---------------------- 99 // 100 // Note that it is possible to have more connectors than CRTCs which means that 101 // only a subset of connectors can be active independently, showing different 102 // framebuffers. Though, in this case, it would be possible to have all 103 // connectors active if some use the same CRTC to mirror the display. 104 class HardwareDisplayController 105 : public base::SupportsWeakPtr<HardwareDisplayController> { 106 public: 107 HardwareDisplayController(DriWrapper* drm, 108 scoped_ptr<CrtcState> state); 109 110 ~HardwareDisplayController(); 111 112 // Performs the initial CRTC configuration. If successful, it will display the 113 // framebuffer for |primary| with |mode|. 114 bool Modeset(const OverlayPlane& primary, 115 drmModeModeInfo mode); 116 117 // Reconfigures the CRTC with the current surface and mode. 118 bool Enable(); 119 120 // Disables the CRTC. 121 void Disable(); 122 123 void QueueOverlayPlane(const OverlayPlane& plane); 124 125 // Schedules the |overlays|' framebuffers to be displayed on the next vsync 126 // event. The event will be posted on the graphics card file descriptor |fd_| 127 // and it can be read and processed by |drmHandleEvent|. That function can 128 // define the callback for the page flip event. A generic data argument will 129 // be presented to the callback. We use that argument to pass in the HDCO 130 // object the event belongs to. 131 // 132 // Between this call and the callback, the framebuffers used in this call 133 // should not be modified in any way as it would cause screen tearing if the 134 // hardware performed the flip. Note that the frontbuffer should also not 135 // be modified as it could still be displayed. 136 // 137 // Note that this function does not block. Also, this function should not be 138 // called again before the page flip occurrs. 139 // 140 // Returns true if the page flip was successfully registered, false otherwise. 141 bool SchedulePageFlip(); 142 143 // TODO(dnicoara) This should be on the MessageLoop when Ozone can have 144 // BeginFrame can be triggered explicitly by Ozone. 145 void WaitForPageFlipEvent(); 146 147 // Called when the page flip event occurred. The event is provided by the 148 // kernel when a VBlank event finished. This allows the controller to 149 // update internal state and propagate the update to the surface. 150 // The tuple (seconds, useconds) represents the event timestamp. |seconds| 151 // represents the number of seconds while |useconds| represents the 152 // microseconds (< 1 second) in the timestamp. 153 void OnPageFlipEvent(unsigned int frame, 154 unsigned int seconds, 155 unsigned int useconds); 156 157 // Set the hardware cursor to show the contents of |surface|. 158 bool SetCursor(scoped_refptr<ScanoutBuffer> buffer); 159 160 bool UnsetCursor(); 161 162 // Moves the hardware cursor to |location|. 163 bool MoveCursor(const gfx::Point& location); 164 165 void AddCrtc(scoped_ptr<CrtcState> state); 166 scoped_ptr<CrtcState> RemoveCrtc(uint32_t crtc); 167 bool HasCrtc(uint32_t crtc) const; 168 bool IsMirrored() const; 169 bool IsDisabled() const; 170 gfx::Size GetModeSize() const; 171 172 gfx::Point origin() const { return origin_; } 173 void set_origin(const gfx::Point& origin) { origin_ = origin; } 174 175 const drmModeModeInfo& get_mode() const { return mode_; }; 176 uint64_t get_time_of_last_flip() const { 177 return time_of_last_flip_; 178 }; 179 180 private: 181 bool ModesetCrtc(const scoped_refptr<ScanoutBuffer>& buffer, 182 drmModeModeInfo mode, 183 CrtcState* state); 184 185 bool SchedulePageFlipOnCrtc(const OverlayPlaneList& overlays, 186 CrtcState* state); 187 188 // Buffers need to be declared first so that they are destroyed last. Needed 189 // since the controllers may reference the buffers. 190 OverlayPlaneList current_planes_; 191 OverlayPlaneList pending_planes_; 192 scoped_refptr<ScanoutBuffer> cursor_buffer_; 193 194 // Object containing the connection to the graphics device and wraps the API 195 // calls to control it. 196 DriWrapper* drm_; 197 198 // Stores the CRTC configuration. This is used to identify monitors and 199 // configure them. 200 ScopedVector<CrtcState> crtc_states_; 201 gfx::Point origin_; 202 drmModeModeInfo mode_; 203 bool is_disabled_; 204 uint64_t time_of_last_flip_; 205 206 // Keeps track of the number of page flips scheduled but not yet serviced (in 207 // mirror mode each CRTC schedules its own page flip event). This value is 208 // changed as follows: 209 // 1) incremented when a successful SchedulePageFlipOnController() occurrs, 210 // 2) decremented when the page flip callback is triggered, 211 // 3) reset to 0 when a drmModeSetCrtc is called (via the DriWrapper). 212 uint32_t pending_page_flips_; 213 214 DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController); 215 }; 216 217 } // namespace ui 218 219 #endif // UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_ 220