Home | History | Annotate | Download | only in display
      1 // Copyright (c) 2012 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 CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
      6 #define CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
      7 
      8 #include <map>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/event_types.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/observer_list.h"
     17 #include "base/timer/timer.h"
     18 #include "chromeos/chromeos_export.h"
     19 #include "third_party/cros_system_api/dbus/service_constants.h"
     20 
     21 // Forward declarations for Xlib and Xrandr.
     22 // This is so unused X definitions don't pollute the namespace.
     23 typedef unsigned long XID;
     24 typedef XID RROutput;
     25 typedef XID RRCrtc;
     26 typedef XID RRMode;
     27 
     28 namespace chromeos {
     29 
     30 // Used to describe the state of a multi-display configuration.
     31 enum OutputState {
     32   STATE_INVALID,
     33   STATE_HEADLESS,
     34   STATE_SINGLE,
     35   STATE_DUAL_MIRROR,
     36   STATE_DUAL_EXTENDED,
     37 };
     38 
     39 // Video output types.
     40 enum OutputType {
     41   OUTPUT_TYPE_NONE = 0,
     42   OUTPUT_TYPE_UNKNOWN = 1 << 0,
     43   OUTPUT_TYPE_INTERNAL = 1 << 1,
     44   OUTPUT_TYPE_VGA = 1 << 2,
     45   OUTPUT_TYPE_HDMI = 1 << 3,
     46   OUTPUT_TYPE_DVI = 1 << 4,
     47   OUTPUT_TYPE_DISPLAYPORT = 1 << 5,
     48   OUTPUT_TYPE_NETWORK = 1 << 6,
     49 };
     50 
     51 // Content protection methods applied on video output.
     52 enum OutputProtectionMethod {
     53   OUTPUT_PROTECTION_METHOD_NONE = 0,
     54   OUTPUT_PROTECTION_METHOD_HDCP = 1 << 0,
     55 };
     56 
     57 // HDCP protection state.
     58 enum HDCPState {
     59   HDCP_STATE_UNDESIRED,
     60   HDCP_STATE_DESIRED,
     61   HDCP_STATE_ENABLED
     62 };
     63 
     64 // This class interacts directly with the underlying Xrandr API to manipulate
     65 // CTRCs and Outputs.
     66 class CHROMEOS_EXPORT OutputConfigurator
     67     : public base::MessageLoop::Dispatcher,
     68       public base::MessagePumpObserver {
     69  public:
     70   typedef uint64_t OutputProtectionClientId;
     71   static const OutputProtectionClientId kInvalidClientId = 0;
     72 
     73   struct ModeInfo {
     74     ModeInfo();
     75     ModeInfo(int width, int height, bool interlaced, float refresh_rate);
     76 
     77     int width;
     78     int height;
     79     bool interlaced;
     80     float refresh_rate;
     81   };
     82 
     83   typedef std::map<RRMode, ModeInfo> ModeInfoMap;
     84 
     85   struct CoordinateTransformation {
     86     // Initialized to the identity transformation.
     87     CoordinateTransformation();
     88 
     89     float x_scale;
     90     float x_offset;
     91     float y_scale;
     92     float y_offset;
     93   };
     94 
     95   // Information about an output's current state.
     96   struct OutputSnapshot {
     97     OutputSnapshot();
     98     ~OutputSnapshot();
     99 
    100     RROutput output;
    101 
    102     // CRTC that should be used for this output. Not necessarily the CRTC
    103     // that XRandR reports is currently being used.
    104     RRCrtc crtc;
    105 
    106     // Mode currently being used by the output.
    107     RRMode current_mode;
    108 
    109     // "Best" mode supported by the output.
    110     RRMode native_mode;
    111 
    112     // Mode used when displaying the same desktop on multiple outputs.
    113     RRMode mirror_mode;
    114 
    115     // User-selected mode for the output.
    116     RRMode selected_mode;
    117 
    118     // Output's origin on the framebuffer.
    119     int x;
    120     int y;
    121 
    122     // Output's physical dimensions.
    123     uint64 width_mm;
    124     uint64 height_mm;
    125 
    126     // TODO(kcwu): Remove this. Check type == OUTPUT_TYPE_INTERNAL instead.
    127     bool is_internal;
    128     bool is_aspect_preserving_scaling;
    129 
    130     // The type of output.
    131     OutputType type;
    132 
    133     // Map from mode IDs to details about the corresponding modes.
    134     ModeInfoMap mode_infos;
    135 
    136     // XInput device ID or 0 if this output isn't a touchscreen.
    137     int touch_device_id;
    138 
    139     CoordinateTransformation transform;
    140 
    141     // Display id for this output.
    142     int64 display_id;
    143 
    144     bool has_display_id;
    145 
    146     // This output's index in the array returned by XRandR. Stable even as
    147     // outputs are connected or disconnected.
    148     int index;
    149   };
    150 
    151   class Observer {
    152    public:
    153     virtual ~Observer() {}
    154 
    155     // Called after the display mode has been changed. |output| contains the
    156     // just-applied configuration. Note that the X server is no longer grabbed
    157     // when this method is called, so the actual configuration could've changed
    158     // already.
    159     virtual void OnDisplayModeChanged(
    160         const std::vector<OutputSnapshot>& outputs) {}
    161 
    162     // Called after a display mode change attempt failed. |failed_new_state| is
    163     // the new state which the system failed to enter.
    164     virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) {}
    165   };
    166 
    167   // Interface for classes that make decisions about which output state
    168   // should be used.
    169   class StateController {
    170    public:
    171     virtual ~StateController() {}
    172 
    173     // Called when displays are detected.
    174     virtual OutputState GetStateForDisplayIds(
    175         const std::vector<int64>& display_ids) const = 0;
    176 
    177     // Queries the resolution (|width|x|height|) in pixels
    178     // to select output mode for the given display id.
    179     virtual bool GetResolutionForDisplayId(int64 display_id,
    180                                            int* width,
    181                                            int* height) const = 0;
    182   };
    183 
    184   // Interface for classes that implement software based mirroring.
    185   class SoftwareMirroringController {
    186    public:
    187     virtual ~SoftwareMirroringController() {}
    188 
    189     // Called when the hardware mirroring failed.
    190     virtual void SetSoftwareMirroring(bool enabled) = 0;
    191   };
    192 
    193   // Interface for classes that perform actions on behalf of OutputController.
    194   class Delegate {
    195    public:
    196     virtual ~Delegate() {}
    197 
    198     // Initializes the XRandR extension, saving the base event ID to
    199     // |event_base|.
    200     virtual void InitXRandRExtension(int* event_base) = 0;
    201 
    202     // Tells XRandR to update its configuration in response to |event|, an
    203     // RRScreenChangeNotify event.
    204     virtual void UpdateXRandRConfiguration(const base::NativeEvent& event) = 0;
    205 
    206     // Grabs the X server and refreshes XRandR-related resources.  While
    207     // the server is grabbed, other clients are blocked.  Must be balanced
    208     // by a call to UngrabServer().
    209     virtual void GrabServer() = 0;
    210 
    211     // Ungrabs the server and frees XRandR-related resources.
    212     virtual void UngrabServer() = 0;
    213 
    214     // Flushes all pending requests and waits for replies.
    215     virtual void SyncWithServer() = 0;
    216 
    217     // Sets the window's background color to |color_argb|.
    218     virtual void SetBackgroundColor(uint32 color_argb) = 0;
    219 
    220     // Enables DPMS and forces it to the "on" state.
    221     virtual void ForceDPMSOn() = 0;
    222 
    223     // Returns information about the current outputs. This method may block for
    224     // 60 milliseconds or more. The returned outputs are not fully initialized;
    225     // the rest of the work happens in
    226     // OutputConfigurator::UpdateCachedOutputs().
    227     virtual std::vector<OutputSnapshot> GetOutputs() = 0;
    228 
    229     // Adds |mode| to |output|.
    230     virtual void AddOutputMode(RROutput output, RRMode mode) = 0;
    231 
    232     // Calls XRRSetCrtcConfig() with the given options but some of our default
    233     // output count and rotation arguments. Returns true on success.
    234     virtual bool ConfigureCrtc(RRCrtc crtc,
    235                                RRMode mode,
    236                                RROutput output,
    237                                int x,
    238                                int y) = 0;
    239 
    240     // Called to set the frame buffer (underlying XRR "screen") size.  Has
    241     // a side-effect of disabling all CRTCs.
    242     virtual void CreateFrameBuffer(
    243         int width,
    244         int height,
    245         const std::vector<OutputConfigurator::OutputSnapshot>& outputs) = 0;
    246 
    247     // Configures XInput's Coordinate Transformation Matrix property.
    248     // |touch_device_id| the ID of the touchscreen device to configure.
    249     // |ctm| contains the desired transformation parameters.  The offsets
    250     // in it should be normalized so that 1 corresponds to the X or Y axis
    251     // size for the corresponding offset.
    252     virtual void ConfigureCTM(int touch_device_id,
    253                               const CoordinateTransformation& ctm) = 0;
    254 
    255     // Sends a D-Bus message to the power manager telling it that the
    256     // machine is or is not projecting.
    257     virtual void SendProjectingStateToPowerManager(bool projecting) = 0;
    258 
    259     // Gets HDCP state of output.
    260     virtual bool GetHDCPState(RROutput id, HDCPState* state) = 0;
    261 
    262     // Sets HDCP state of output.
    263     virtual bool SetHDCPState(RROutput id, HDCPState state) = 0;
    264   };
    265 
    266   // Helper class used by tests.
    267   class TestApi {
    268    public:
    269     TestApi(OutputConfigurator* configurator, int xrandr_event_base)
    270         : configurator_(configurator),
    271           xrandr_event_base_(xrandr_event_base) {}
    272     ~TestApi() {}
    273 
    274     const std::vector<OutputSnapshot>& cached_outputs() const {
    275       return configurator_->cached_outputs_;
    276     }
    277 
    278     // Dispatches an RRScreenChangeNotify event to |configurator_|.
    279     void SendScreenChangeEvent();
    280 
    281     // Dispatches an RRNotify_OutputChange event to |configurator_|.
    282     void SendOutputChangeEvent(RROutput output,
    283                                RRCrtc crtc,
    284                                RRMode mode,
    285                                bool connected);
    286 
    287     // If |configure_timer_| is started, stops the timer, runs
    288     // ConfigureOutputs(), and returns true; returns false otherwise.
    289     bool TriggerConfigureTimeout();
    290 
    291    private:
    292     OutputConfigurator* configurator_;  // not owned
    293 
    294     int xrandr_event_base_;
    295 
    296     DISALLOW_COPY_AND_ASSIGN(TestApi);
    297   };
    298 
    299   // Flags that can be passed to SetDisplayPower().
    300   static const int kSetDisplayPowerNoFlags                     = 0;
    301   // Configure displays even if the passed-in state matches |power_state_|.
    302   static const int kSetDisplayPowerForceProbe                  = 1 << 0;
    303   // Do not change the state if multiple displays are connected or if the
    304   // only connected display is external.
    305   static const int kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
    306 
    307   // Gap between screens so cursor at bottom of active display doesn't
    308   // partially appear on top of inactive display. Higher numbers guard
    309   // against larger cursors, but also waste more memory.
    310   // For simplicity, this is hard-coded to avoid the complexity of always
    311   // determining the DPI of the screen and rationalizing which screen we
    312   // need to use for the DPI calculation.
    313   // See crbug.com/130188 for initial discussion.
    314   static const int kVerticalGap = 60;
    315 
    316   // Returns a pointer to the ModeInfo struct in |output| corresponding to
    317   // |mode|, or NULL if the struct isn't present.
    318   static const ModeInfo* GetModeInfo(const OutputSnapshot& output,
    319                                      RRMode mode);
    320 
    321   // Returns the mode within |output| that matches the given size with highest
    322   // refresh rate. Returns None if no matching output was found.
    323   static RRMode FindOutputModeMatchingSize(const OutputSnapshot& output,
    324                                            int width,
    325                                            int height);
    326 
    327   OutputConfigurator();
    328   virtual ~OutputConfigurator();
    329 
    330   OutputState output_state() const { return output_state_; }
    331   DisplayPowerState power_state() const { return power_state_; }
    332 
    333   void set_state_controller(StateController* controller) {
    334     state_controller_ = controller;
    335   }
    336   void set_mirroring_controller(SoftwareMirroringController* controller) {
    337     mirroring_controller_ = controller;
    338   }
    339 
    340   // Replaces |delegate_| with |delegate| and sets |configure_display_| to
    341   // true.  Should be called before Init().
    342   void SetDelegateForTesting(scoped_ptr<Delegate> delegate);
    343 
    344   // Sets the initial value of |power_state_|.  Must be called before Start().
    345   void SetInitialDisplayPower(DisplayPowerState power_state);
    346 
    347   // Initialization, must be called right after constructor.
    348   // |is_panel_fitting_enabled| indicates hardware panel fitting support.
    349   void Init(bool is_panel_fitting_enabled);
    350 
    351   // Does initial configuration of displays during startup.
    352   // If |background_color_argb| is non zero and there are multiple displays,
    353   // OutputConfigurator sets the background color of X's RootWindow to this
    354   // color.
    355   void Start(uint32 background_color_argb);
    356 
    357   // Stop handling display configuration events/requests.
    358   void Stop();
    359 
    360   // Called when powerd notifies us that some set of displays should be turned
    361   // on or off.  This requires enabling or disabling the CRTC associated with
    362   // the display(s) in question so that the low power state is engaged.
    363   // |flags| contains bitwise-or-ed kSetDisplayPower* values.
    364   bool SetDisplayPower(DisplayPowerState power_state, int flags);
    365 
    366   // Force switching the display mode to |new_state|. Returns false if
    367   // switching failed (possibly because |new_state| is invalid for the
    368   // current set of connected outputs).
    369   bool SetDisplayMode(OutputState new_state);
    370 
    371   // Called when an RRNotify event is received.  The implementation is
    372   // interested in the cases of RRNotify events which correspond to output
    373   // add/remove events.  Note that Output add/remove events are sent in response
    374   // to our own reconfiguration operations so spurious events are common.
    375   // Spurious events will have no effect.
    376   virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
    377 
    378   // Overridden from base::MessagePumpObserver:
    379   virtual base::EventStatus WillProcessEvent(
    380       const base::NativeEvent& event) OVERRIDE;
    381   virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
    382 
    383   void AddObserver(Observer* observer);
    384   void RemoveObserver(Observer* observer);
    385 
    386   // Sets all the displays into pre-suspend mode; usually this means
    387   // configure them for their resume state. This allows faster resume on
    388   // machines where display configuration is slow.
    389   void SuspendDisplays();
    390 
    391   // Reprobes displays to handle changes made while the system was
    392   // suspended.
    393   void ResumeDisplays();
    394 
    395   const std::map<int, float>& GetMirroredDisplayAreaRatioMap() {
    396     return mirrored_display_area_ratio_map_;
    397   }
    398 
    399   // Configure outputs with |kConfigureDelayMs| delay,
    400   // so that time-consuming ConfigureOutputs() won't be called multiple times.
    401   void ScheduleConfigureOutputs();
    402 
    403   // Registers a client for output protection and requests a client id. Returns
    404   // 0 if requesting failed.
    405   OutputProtectionClientId RegisterOutputProtectionClient();
    406 
    407   // Unregisters the client.
    408   void UnregisterOutputProtectionClient(OutputProtectionClientId client_id);
    409 
    410   // Queries link status and protection status.
    411   // |link_mask| is the type of connected output links, which is a bitmask of
    412   // OutputType values. |protection_mask| is the desired protection methods,
    413   // which is a bitmask of the OutputProtectionMethod values.
    414   // Returns true on success.
    415   bool QueryOutputProtectionStatus(
    416       OutputProtectionClientId client_id,
    417       int64 display_id,
    418       uint32_t* link_mask,
    419       uint32_t* protection_mask);
    420 
    421   // Requests the desired protection methods.
    422   // |protection_mask| is the desired protection methods, which is a bitmask
    423   // of the OutputProtectionMethod values.
    424   // Returns true when the protection request has been made.
    425   bool EnableOutputProtection(
    426       OutputProtectionClientId client_id,
    427       int64 display_id,
    428       uint32_t desired_protection_mask);
    429 
    430  private:
    431   // Mapping a display_id to a protection request bitmask.
    432   typedef std::map<int64, uint32_t> DisplayProtections;
    433   // Mapping a client to its protection request.
    434   typedef std::map<OutputProtectionClientId,
    435                    DisplayProtections> ProtectionRequests;
    436 
    437   // Updates |cached_outputs_| to contain currently-connected outputs. Calls
    438   // |delegate_->GetOutputs()| and then does additional work, like finding the
    439   // mirror mode and setting user-preferred modes. Note that the server must be
    440   // grabbed via |delegate_->GrabServer()| first.
    441   void UpdateCachedOutputs();
    442 
    443   // Helper method for UpdateCachedOutputs() that initializes the passed-in
    444   // outputs' |mirror_mode| fields by looking for a mode in |internal_output|
    445   // and |external_output| having the same resolution. Returns false if a shared
    446   // mode wasn't found or created.
    447   //
    448   // |try_panel_fitting| allows creating a panel-fitting mode for
    449   // |internal_output| instead of only searching for a matching mode (note that
    450   // it may lead to a crash if |internal_info| is not capable of panel fitting).
    451   //
    452   // |preserve_aspect| limits the search/creation only to the modes having the
    453   // native aspect ratio of |external_output|.
    454   bool FindMirrorMode(OutputSnapshot* internal_output,
    455                       OutputSnapshot* external_output,
    456                       bool try_panel_fitting,
    457                       bool preserve_aspect);
    458 
    459   // Configures outputs.
    460   void ConfigureOutputs();
    461 
    462   // Notifies observers about an attempted state change.
    463   void NotifyObservers(bool success, OutputState attempted_state);
    464 
    465   // Switches to the state specified in |output_state| and |power_state|.
    466   // If the hardware mirroring failed and |mirroring_controller_| is set,
    467   // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()|
    468   // to enable software based mirroring.
    469   // On success, updates |output_state_|, |power_state_|, and |cached_outputs_|
    470   // and returns true.
    471   bool EnterStateOrFallBackToSoftwareMirroring(
    472       OutputState output_state,
    473       DisplayPowerState power_state);
    474 
    475   // Switches to the state specified in |output_state| and |power_state|.
    476   // On success, updates |output_state_|, |power_state_|, and
    477   // |cached_outputs_| and returns true.
    478   bool EnterState(OutputState output_state, DisplayPowerState power_state);
    479 
    480   // Returns the output state that should be used with |cached_outputs_| while
    481   // in |power_state|.
    482   OutputState ChooseOutputState(DisplayPowerState power_state) const;
    483 
    484   // Computes the relevant transformation for mirror mode.
    485   // |output| is the output on which mirror mode is being applied.
    486   // Returns the transformation or identity if computations fail.
    487   CoordinateTransformation GetMirrorModeCTM(
    488       const OutputConfigurator::OutputSnapshot& output);
    489 
    490   // Computes the relevant transformation for extended mode.
    491   // |output| is the output on which extended mode is being applied.
    492   // |width| and |height| are the width and height of the combined framebuffer.
    493   // Returns the transformation or identity if computations fail.
    494   CoordinateTransformation GetExtendedModeCTM(
    495       const OutputConfigurator::OutputSnapshot& output,
    496       int framebuffer_width,
    497       int frame_buffer_height);
    498 
    499   // Returns the ratio between mirrored mode area and native mode area:
    500   // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
    501   float GetMirroredDisplayAreaRatio(
    502       const OutputConfigurator::OutputSnapshot& output);
    503 
    504   // Applies output protections according to requests.
    505   bool ApplyProtections(const DisplayProtections& requests);
    506 
    507   StateController* state_controller_;
    508   SoftwareMirroringController* mirroring_controller_;
    509   scoped_ptr<Delegate> delegate_;
    510 
    511   // Used to enable modes which rely on panel fitting.
    512   bool is_panel_fitting_enabled_;
    513 
    514   // Key of the map is the touch display's id, and the value of the map is the
    515   // touch display's area ratio in mirror mode defined as :
    516   // mirror_mode_area / native_mode_area.
    517   // This is used for scaling touch event's radius when the touch display is in
    518   // mirror mode :
    519   // new_touch_radius = sqrt(area_ratio) * old_touch_radius
    520   std::map<int, float> mirrored_display_area_ratio_map_;
    521 
    522   // This is detected by the constructor to determine whether or not we should
    523   // be enabled.  If we aren't running on ChromeOS, we can't assume that the
    524   // Xrandr X11 extension is supported.
    525   // If this flag is set to false, any attempts to change the output
    526   // configuration to immediately fail without changing the state.
    527   bool configure_display_;
    528 
    529   // The base of the event numbers used to represent XRandr events used in
    530   // decoding events regarding output add/remove.
    531   int xrandr_event_base_;
    532 
    533   // The current display state.
    534   OutputState output_state_;
    535 
    536   // The current power state.
    537   DisplayPowerState power_state_;
    538 
    539   // Most-recently-used output configuration. Note that the actual
    540   // configuration changes asynchronously.
    541   std::vector<OutputSnapshot> cached_outputs_;
    542 
    543   ObserverList<Observer> observers_;
    544 
    545   // The timer to delay configuring outputs. See also the comments in
    546   // Dispatch().
    547   scoped_ptr<base::OneShotTimer<OutputConfigurator> > configure_timer_;
    548 
    549   // Id for next output protection client.
    550   OutputProtectionClientId next_output_protection_client_id_;
    551 
    552   // Output protection requests of each client.
    553   ProtectionRequests client_protection_requests_;
    554 
    555   DISALLOW_COPY_AND_ASSIGN(OutputConfigurator);
    556 };
    557 
    558 typedef std::vector<OutputConfigurator::OutputSnapshot> OutputSnapshotList;
    559 
    560 }  // namespace chromeos
    561 
    562 #endif  // CHROMEOS_DISPLAY_OUTPUT_CONFIGURATOR_H_
    563