1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.display.mode;
18 
19 import android.view.SurfaceControl;
20 
21 final class Vote {
22     // DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest
23     // priority vote, it's overridden by all other considerations. It acts to set a default
24     // frame rate for a device.
25     static final int PRIORITY_DEFAULT_RENDER_FRAME_RATE = 0;
26 
27     // PRIORITY_FLICKER_REFRESH_RATE votes for a single refresh rate like [60,60], [90,90] or
28     // null. It is used to set a preferred refresh rate value in case the higher priority votes
29     // result is a range.
30     static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
31 
32     // High-brightness-mode may need a specific range of refresh-rates to function properly.
33     static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
34 
35     // SETTING_MIN_RENDER_FRAME_RATE is used to propose a lower bound of the render frame rate.
36     // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
37     static final int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
38 
39     // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
40     // frame rate in certain cases, mostly to preserve power.
41     // @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
42     // @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
43     // It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
44     static final int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 4;
45 
46     // We split the app request into different priorities in case we can satisfy one desire
47     // without the other.
48 
49     // Application can specify preferred refresh rate with below attrs.
50     // @see android.view.WindowManager.LayoutParams#preferredRefreshRate
51     // @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
52     //
53     // When the app specifies a LayoutParams#preferredDisplayModeId, in addition to the
54     // refresh rate, it also chooses a preferred size (resolution) as part of the selected
55     // mode id. The app preference is then translated to APP_REQUEST_BASE_MODE_REFRESH_RATE and
56     // optionally to APP_REQUEST_SIZE as well, if a mode id was selected.
57     // The system also forces some apps like denylisted app to run at a lower refresh rate.
58     // @see android.R.array#config_highRefreshRateBlacklist
59     //
60     // When summarizing the votes and filtering the allowed display modes, these votes determine
61     // which mode id should be the base mode id to be sent to SurfaceFlinger:
62     // - APP_REQUEST_BASE_MODE_REFRESH_RATE is used to validate the vote summary. If a summary
63     //   includes a base mode refresh rate, but it is not in the refresh rate range, then the
64     //   summary is considered invalid so we could drop a lower priority vote and try again.
65     // - APP_REQUEST_SIZE is used to filter out display modes of a different size.
66     //
67     // The preferred refresh rate is set on the main surface of the app outside of
68     // DisplayModeDirector.
69     // @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
70     static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
71     static final int PRIORITY_APP_REQUEST_SIZE = 6;
72 
73     // SETTING_PEAK_RENDER_FRAME_RATE has a high priority and will restrict the bounds of the
74     // rest of low priority voters. It votes [0, max(PEAK, MIN)]
75     static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 7;
76 
77     // To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh
78     // rate to max value (same as for PRIORITY_UDFPS) on lock screen
79     static final int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 8;
80 
81     // For concurrent displays we want to limit refresh rate on all displays
82     static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 9;
83 
84     // LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
85     // Settings.Global.LOW_POWER_MODE is on.
86     static final int PRIORITY_LOW_POWER_MODE = 10;
87 
88     // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
89     // higher priority voters' result is a range, it will fix the rate to a single choice.
90     // It's used to avoid refresh rate switches in certain conditions which may result in the
91     // user seeing the display flickering when the switches occur.
92     static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 11;
93 
94     // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
95     static final int PRIORITY_SKIN_TEMPERATURE = 12;
96 
97     // The proximity sensor needs the refresh rate to be locked in order to function, so this is
98     // set to a high priority.
99     static final int PRIORITY_PROXIMITY = 13;
100 
101     // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
102     // to function, so this needs to be the highest priority of all votes.
103     static final int PRIORITY_UDFPS = 14;
104 
105     // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
106     // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
107 
108     static final int MIN_PRIORITY = PRIORITY_DEFAULT_RENDER_FRAME_RATE;
109     static final int MAX_PRIORITY = PRIORITY_UDFPS;
110 
111     // The cutoff for the app request refresh rate range. Votes with priorities lower than this
112     // value will not be considered when constructing the app request refresh rate range.
113     static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
114             PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE;
115 
116     /**
117      * A value signifying an invalid width or height in a vote.
118      */
119     static final int INVALID_SIZE = -1;
120 
121     /**
122      * The requested width of the display in pixels, or INVALID_SIZE;
123      */
124     public final int width;
125     /**
126      * The requested height of the display in pixels, or INVALID_SIZE;
127      */
128     public final int height;
129     /**
130      * Information about the refresh rate frame rate ranges DM would like to set the display to.
131      */
132     public final SurfaceControl.RefreshRateRanges refreshRateRanges;
133 
134     /**
135      * Whether refresh rate switching should be disabled (i.e. the refresh rate range is
136      * a single value).
137      */
138     public final boolean disableRefreshRateSwitching;
139 
140     /**
141      * The preferred refresh rate selected by the app. It is used to validate that the summary
142      * refresh rate ranges include this value, and are not restricted by a lower priority vote.
143      */
144     public final float appRequestBaseModeRefreshRate;
145 
forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate)146     static Vote forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate) {
147         return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate, 0,
148                 Float.POSITIVE_INFINITY,
149                 minRefreshRate == maxRefreshRate, 0f);
150     }
151 
forRenderFrameRates(float minFrameRate, float maxFrameRate)152     static Vote forRenderFrameRates(float minFrameRate, float maxFrameRate) {
153         return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, minFrameRate,
154                 maxFrameRate,
155                 false, 0f);
156     }
157 
forSize(int width, int height)158     static Vote forSize(int width, int height) {
159         return new Vote(width, height, 0, Float.POSITIVE_INFINITY, 0, Float.POSITIVE_INFINITY,
160                 false,
161                 0f);
162     }
163 
forDisableRefreshRateSwitching()164     static Vote forDisableRefreshRateSwitching() {
165         return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
166                 Float.POSITIVE_INFINITY, true,
167                 0f);
168     }
169 
forBaseModeRefreshRate(float baseModeRefreshRate)170     static Vote forBaseModeRefreshRate(float baseModeRefreshRate) {
171         return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
172                 Float.POSITIVE_INFINITY, false,
173                 baseModeRefreshRate);
174     }
175 
Vote(int width, int height, float minPhysicalRefreshRate, float maxPhysicalRefreshRate, float minRenderFrameRate, float maxRenderFrameRate, boolean disableRefreshRateSwitching, float baseModeRefreshRate)176     private Vote(int width, int height,
177             float minPhysicalRefreshRate,
178             float maxPhysicalRefreshRate,
179             float minRenderFrameRate,
180             float maxRenderFrameRate,
181             boolean disableRefreshRateSwitching,
182             float baseModeRefreshRate) {
183         this.width = width;
184         this.height = height;
185         this.refreshRateRanges = new SurfaceControl.RefreshRateRanges(
186                 new SurfaceControl.RefreshRateRange(minPhysicalRefreshRate, maxPhysicalRefreshRate),
187                 new SurfaceControl.RefreshRateRange(minRenderFrameRate, maxRenderFrameRate));
188         this.disableRefreshRateSwitching = disableRefreshRateSwitching;
189         this.appRequestBaseModeRefreshRate = baseModeRefreshRate;
190     }
191 
priorityToString(int priority)192     static String priorityToString(int priority) {
193         switch (priority) {
194             case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
195                 return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
196             case PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE:
197                 return "PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE";
198             case PRIORITY_APP_REQUEST_SIZE:
199                 return "PRIORITY_APP_REQUEST_SIZE";
200             case PRIORITY_DEFAULT_RENDER_FRAME_RATE:
201                 return "PRIORITY_DEFAULT_REFRESH_RATE";
202             case PRIORITY_FLICKER_REFRESH_RATE:
203                 return "PRIORITY_FLICKER_REFRESH_RATE";
204             case PRIORITY_FLICKER_REFRESH_RATE_SWITCH:
205                 return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH";
206             case PRIORITY_HIGH_BRIGHTNESS_MODE:
207                 return "PRIORITY_HIGH_BRIGHTNESS_MODE";
208             case PRIORITY_PROXIMITY:
209                 return "PRIORITY_PROXIMITY";
210             case PRIORITY_LOW_POWER_MODE:
211                 return "PRIORITY_LOW_POWER_MODE";
212             case PRIORITY_SKIN_TEMPERATURE:
213                 return "PRIORITY_SKIN_TEMPERATURE";
214             case PRIORITY_UDFPS:
215                 return "PRIORITY_UDFPS";
216             case PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE:
217                 return "PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE";
218             case PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE:
219                 return "PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE";
220             case PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE:
221                 return "PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE";
222             case PRIORITY_LAYOUT_LIMITED_FRAME_RATE:
223                 return "PRIORITY_LAYOUT_LIMITED_FRAME_RATE";
224             default:
225                 return Integer.toString(priority);
226         }
227     }
228 
229     @Override
toString()230     public String toString() {
231         return "Vote: {"
232                 + "width: " + width + ", height: " + height
233                 + ", refreshRateRanges: " + refreshRateRanges
234                 + ", disableRefreshRateSwitching: " + disableRefreshRateSwitching
235                 + ", appRequestBaseModeRefreshRate: "  + appRequestBaseModeRefreshRate + "}";
236     }
237 }
238