1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_DISPLAY_MANAGER_CONFIGURE_DISPLAYS_TASK_H_
#define UI_DISPLAY_MANAGER_CONFIGURE_DISPLAYS_TASK_H_
#include <stddef.h>
#include <queue>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/display/manager/display_manager_export.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/native_display_observer.h"
#include "ui/gfx/geometry/point.h"
namespace display {
class DisplayMode;
class DisplaySnapshot;
class NativeDisplayDelegate;
struct DisplayConfigurationParams;
struct DISPLAY_MANAGER_EXPORT DisplayConfigureRequest {
DisplayConfigureRequest(DisplaySnapshot* display,
const DisplayMode* mode,
const gfx::Point& origin,
bool enable_vrr);
DisplayConfigureRequest(DisplaySnapshot* display,
const DisplayMode* mode,
const gfx::Point& origin);
DisplayConfigureRequest(const DisplayConfigureRequest& other);
~DisplayConfigureRequest();
raw_ptr<DisplaySnapshot> display;
std::unique_ptr<const DisplayMode> mode;
gfx::Point origin;
bool enable_vrr;
};
using RequestAndStatusList = std::pair<const DisplayConfigureRequest*, bool>;
// ConfigureDisplaysTask is in charge of applying the display configuration as
// requested by Ash. If the original request fails, the task will attempt to
// modify the request by downgrading the resolution of one or more of the
// displays and try again until it either succeeds a modeset or exhaust all
// available options.
//
// Displays are bandwidth constrained in 2 ways: (1) system memory bandwidth
// (ie: scanning pixels from memory), and (2) link bandwidth (ie: scanning
// pixels from the SoC to the display). Naturally all displays share (1),
// however with DisplayPort Multi-stream Transport (DP MST), displays may also
// share (2). The introduction of MST support drastically increases the
// likelihood of modeset failures due to (2) since multiple displays will all be
// sharing the same physical connection.
//
// If we're constrained by (1), reducing the resolution of any display will
// relieve pressure. However if we're constrained by (2), only those displays on
// the saturated link can relieve pressure.
//
// Note that the |enable_vrr| property is not modified in the event of a
// downgrade, as it does not affect bandwidth and changing its value would not
// cause a failing request to succeed.
class DISPLAY_MANAGER_EXPORT ConfigureDisplaysTask
: public NativeDisplayObserver {
public:
// Note: the enum values below match those of the ConfigureDisplaysTaskStatus
// histogram enum and should never change, or else it will make historical
// data of the affected metrics difficult to process.
enum Status {
// At least one of the displays failed to apply any mode it supports.
ERROR = 0,
// The requested configuration was applied.
SUCCESS = 1,
// At least one of the displays failed to apply the requested
// configuration, but it managed to fall back to another mode.
PARTIAL_SUCCESS = 2,
kMaxValue = PARTIAL_SUCCESS
};
using ResponseCallback = base::OnceCallback<void(Status)>;
ConfigureDisplaysTask(
NativeDisplayDelegate* delegate,
const std::vector<DisplayConfigureRequest>& requests,
ResponseCallback callback,
ConfigurationType configuration_type = kConfigurationTypeFull);
ConfigureDisplaysTask(const ConfigureDisplaysTask&) = delete;
ConfigureDisplaysTask& operator=(const ConfigureDisplaysTask&) = delete;
~ConfigureDisplaysTask() override;
// Starts the configuration task.
void Run();
// display::NativeDisplayObserver:
void OnConfigurationChanged() override;
void OnDisplaySnapshotsInvalidated() override;
private:
struct RequestToOriginalMode {
RequestToOriginalMode(DisplayConfigureRequest* request,
const DisplayMode* original_mode);
RequestToOriginalMode(const RequestToOriginalMode& other);
~RequestToOriginalMode();
raw_ptr<DisplayConfigureRequest> request;
const std::unique_ptr<const DisplayMode> original_mode;
};
using PartitionedRequestsQueue =
std::queue<std::vector<RequestToOriginalMode>>;
// Deals with the aftermath of the initial configuration, which attempts to
// configure all displays together.
// Upon failure, partitions the original request from Ash into smaller
// requests where the displays are grouped by the physical connector they
// connect to and initiates the retry sequence.
void OnFirstAttemptConfigured(
const std::vector<DisplayConfigurationParams>& request_results,
bool config_success);
// Deals with the aftermath of a configuration retry, which attempts to
// configure a subset of the displays grouped together by the physical
// connector they connect to.
// Upon success, initiates the retry sequence on the next group of displays.
// Otherwise, downgrades the display with the largest bandwidth requirement
// and tries again.
// If any of the display groups entirely fail to modeset (i.e. exhaust all
// available modes during retry), the configuration will fail as a whole, but
// will continue to try to modeset the remaining display groups.
void OnRetryConfigured(
const std::vector<DisplayConfigurationParams>& request_results,
bool config_success);
// Finalizes the configuration after a modeset attempt was made (as opposed to
// test-modeset).
void OnConfigured(
const std::vector<DisplayConfigurationParams>& request_results,
bool config_success);
// Partition |requests_| by their base connector id (i.e. the physical
// connector the displays are connected to) and populate the result in
// |pending_display_group_requests_|. We assume the order of requests
// submitted by Ash is important, so the partitioning is done in order.
void PartitionRequests();
// Downgrade the request with the highest bandwidth requirement AND
// alternative modes in |requests_| (excluding internal displays and disable
// requests). Return false if no request was downgraded.
bool DowngradeDisplayRequestGroup();
raw_ptr<NativeDisplayDelegate> delegate_; // Not owned.
// Holds the next configuration request to attempt modeset.
std::vector<DisplayConfigureRequest> requests_;
// Whether this request should be seamless or not (i.e. should a full modeset
// be permitted or not).
const ConfigurationType configuration_type_;
// A queue of display requests grouped by their
// |requests_[index]->display->base_connector_id()|. These request groups are
// used to downgrade displays' modes stored in |requests_| when the original
// request fails to modeset and a the fallback logic is triggered.
PartitionedRequestsQueue pending_display_group_requests_;
// The last configuration parameter request list that passed modeset test
// during retry, which will be used for modeset once we are done testing.
std::vector<display::DisplayConfigurationParams>
last_successful_config_parameters_;
// The final requests and their configuration status for UMA.
std::vector<RequestAndStatusList> final_requests_status_;
// When the task finishes executing it runs the callback to notify that the
// task is done and the task status.
ResponseCallback callback_;
Status task_status_;
base::WeakPtrFactory<ConfigureDisplaysTask> weak_ptr_factory_{this};
};
} // namespace display
#endif // UI_DISPLAY_MANAGER_CONFIGURE_DISPLAYS_TASK_H_
|