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/weak_ptr.h" 16 #include "ui/ozone/ozone_export.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 ScanoutSurface; 26 27 // The HDCOz will handle modesettings and scannout operations for hardware 28 // devices. 29 // 30 // In the DRM world there are 3 components that need to be paired up to be able 31 // to display an image to the monitor: CRTC (cathode ray tube controller), 32 // encoder and connector. The CRTC determines which framebuffer to read, when 33 // to scanout and where to scanout. Encoders converts the stream from the CRTC 34 // to the appropriate format for the connector. The connector is the physical 35 // connection that monitors connect to. 36 // 37 // There is no 1:1:1 pairing for these components. It is possible for an encoder 38 // to be compatible to multiple CRTCs and each connector can be used with 39 // multiple encoders. In addition, it is possible to use one CRTC with multiple 40 // connectors such that we can display the same image on multiple monitors. 41 // 42 // For example, the following configuration shows 2 different screens being 43 // initialized separately. 44 // ------------- ------------- 45 // | Connector | | Connector | 46 // | HDMI | | VGA | 47 // ------------- ------------- 48 // ^ ^ 49 // | | 50 // ------------- ------------- 51 // | Encoder1 | | Encoder2 | 52 // ------------- ------------- 53 // ^ ^ 54 // | | 55 // ------------- ------------- 56 // | CRTC1 | | CRTC2 | 57 // ------------- ------------- 58 // 59 // In the following configuration 2 different screens are associated with the 60 // same CRTC, so on scanout the same framebuffer will be displayed on both 61 // monitors. 62 // ------------- ------------- 63 // | Connector | | Connector | 64 // | HDMI | | VGA | 65 // ------------- ------------- 66 // ^ ^ 67 // | | 68 // ------------- ------------- 69 // | Encoder1 | | Encoder2 | 70 // ------------- ------------- 71 // ^ ^ 72 // | | 73 // ---------------------- 74 // | CRTC1 | 75 // ---------------------- 76 // 77 // Note that it is possible to have more connectors than CRTCs which means that 78 // only a subset of connectors can be active independently, showing different 79 // framebuffers. Though, in this case, it would be possible to have all 80 // connectors active if some use the same CRTC to mirror the display. 81 // 82 // TODO(dnicoara) Need to have a way to detect events (such as monitor 83 // connected or disconnected). 84 class OZONE_EXPORT HardwareDisplayController 85 : public base::SupportsWeakPtr<HardwareDisplayController> { 86 public: 87 HardwareDisplayController(DriWrapper* drm, 88 uint32_t connector_id, 89 uint32_t crtc_id); 90 91 ~HardwareDisplayController(); 92 93 // Associate the HDCO with a surface implementation and initialize it. 94 bool BindSurfaceToController(scoped_ptr<ScanoutSurface> surface, 95 drmModeModeInfo mode); 96 97 void UnbindSurfaceFromController(); 98 99 // Reconfigures the CRTC with the current surface and mode. 100 bool Enable(); 101 102 // Disables the CRTC. 103 void Disable(); 104 105 // Schedules the |surface_|'s framebuffer to be displayed on the next vsync 106 // event. The event will be posted on the graphics card file descriptor |fd_| 107 // and it can be read and processed by |drmHandleEvent|. That function can 108 // define the callback for the page flip event. A generic data argument will 109 // be presented to the callback. We use that argument to pass in the HDCO 110 // object the event belongs to. 111 // 112 // Between this call and the callback, the framebuffer used in this call 113 // should not be modified in any way as it would cause screen tearing if the 114 // hardware performed the flip. Note that the frontbuffer should also not 115 // be modified as it could still be displayed. 116 // 117 // Note that this function does not block. Also, this function should not be 118 // called again before the page flip occurrs. 119 // 120 // Returns true if the page flip was successfully registered, false otherwise. 121 bool SchedulePageFlip(); 122 123 // TODO(dnicoara) This should be on the MessageLoop when Ozone can have 124 // BeginFrame can be triggered explicitly by Ozone. 125 void WaitForPageFlipEvent(); 126 127 // Called when the page flip event occurred. The event is provided by the 128 // kernel when a VBlank event finished. This allows the controller to 129 // update internal state and propagate the update to the surface. 130 // The tuple (seconds, useconds) represents the event timestamp. |seconds| 131 // represents the number of seconds while |useconds| represents the 132 // microseconds (< 1 second) in the timestamp. 133 void OnPageFlipEvent(unsigned int frame, 134 unsigned int seconds, 135 unsigned int useconds); 136 137 // Set the hardware cursor to show the contents of |surface|. 138 bool SetCursor(ScanoutSurface* surface); 139 140 bool UnsetCursor(); 141 142 // Moves the hardware cursor to |location|. 143 bool MoveCursor(const gfx::Point& location); 144 145 const drmModeModeInfo& get_mode() const { return mode_; }; 146 uint32_t connector_id() const { return connector_id_; } 147 uint32_t crtc_id() const { return crtc_id_; } 148 ScanoutSurface* surface() const { 149 return surface_.get(); 150 }; 151 152 uint64_t get_time_of_last_flip() const { 153 return time_of_last_flip_; 154 }; 155 156 private: 157 // Object containing the connection to the graphics device and wraps the API 158 // calls to control it. 159 DriWrapper* drm_; 160 161 // TODO(dnicoara) Need to allow a CRTC to have multiple connectors. 162 uint32_t connector_id_; 163 164 uint32_t crtc_id_; 165 166 // TODO(dnicoara) Need to store all the modes. 167 drmModeModeInfo mode_; 168 169 scoped_ptr<ScanoutSurface> surface_; 170 171 uint64_t time_of_last_flip_; 172 173 // Keeps track of the CRTC state. If a surface has been bound, then the value 174 // is set to false. Otherwise it is true. 175 bool is_disabled_; 176 177 DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController); 178 }; 179 180 } // namespace ui 181 182 #endif // UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_CONTROLLER_H_ 183