summaryrefslogtreecommitdiff
path: root/common/hwc/VariableModeMgr.cpp (plain)
blob: da4017d77e7aeae0e8330186b18b48256eee8c06
1/*
2 * Copyright (c) 2018 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
9
10#include "VariableModeMgr.h"
11
12#include <HwcConfig.h>
13#include <MesonLog.h>
14#include <systemcontrol.h>
15#include <hardware/hwcomposer2.h>
16
17#include <string>
18
19#define DEFUALT_DPI (160)
20#define DEFAULT_REFRESH_RATE_60 (60.0f)
21#define DEFAULT_REFRESH_RATE_50 (50.0f)
22
23#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
24
25/* used for init default configs */
26static const drm_mode_info_t mode_info[] = {
27 { /* VMODE_720P */
28 .name = "720p60hz",
29 .dpiX = DEFUALT_DPI,
30 .dpiY = DEFUALT_DPI,
31 .pixelW = 1280,
32 .pixelH = 720,
33 .refreshRate = DEFAULT_REFRESH_RATE_60,
34 },
35 { /* VMODE_1080P */
36 .name = "1080p60hz",
37 .dpiX = DEFUALT_DPI,
38 .dpiY = DEFUALT_DPI,
39 .pixelW = 1920,
40 .pixelH = 1080,
41 .refreshRate = DEFAULT_REFRESH_RATE_60,
42 },
43 { /* VMODE_720P_50hz */
44 .name = "720p50hz",
45 .dpiX = DEFUALT_DPI,
46 .dpiY = DEFUALT_DPI,
47 .pixelW = 1280,
48 .pixelH = 720,
49 .refreshRate = DEFAULT_REFRESH_RATE_50,
50 },
51 { /* VMODE_1080P_50HZ */
52 .name = "1080p50hz",
53 .dpiX = DEFUALT_DPI,
54 .dpiY = DEFUALT_DPI,
55 .pixelW = 1920,
56 .pixelH = 1080,
57 .refreshRate = DEFAULT_REFRESH_RATE_50,
58 },
59 { /* DefaultMode */
60 .name = "DefaultMode",
61 .dpiX = DEFUALT_DPI,
62 .dpiY = DEFUALT_DPI,
63 .pixelW = 1920,
64 .pixelH = 1080,
65 .refreshRate = DEFAULT_REFRESH_RATE_60,
66 },
67};
68
69VariableModeMgr::VariableModeMgr()
70 : mIsInit(true) {
71}
72
73VariableModeMgr::~VariableModeMgr() {
74
75}
76
77hwc_modes_policy_t VariableModeMgr::getPolicyType() {
78 return FULL_ACTIVE_POLICY;
79}
80
81const char * VariableModeMgr::getName() {
82 return "VariableMode";
83}
84
85void VariableModeMgr::setFramebufferSize(uint32_t w, uint32_t h) {
86 mFbWidth = w;
87 mFbHeight = h;
88}
89
90void VariableModeMgr::setDisplayResources(
91 std::shared_ptr<HwDisplayCrtc> & crtc,
92 std::shared_ptr<HwDisplayConnector> & connector) {
93 mConnector = connector;
94 mCrtc = crtc;
95
96 /*
97 * Only when it is first boot will come here,
98 * initialize a default display mode according to the given FB size,
99 * and will return this default mode to SF before it calls setActiveConfig().
100 */
101 if (mIsInit) {
102 mIsInit = false;
103 reset();
104 initDefaultDispResources();
105 }
106
107 update();
108}
109
110int32_t VariableModeMgr::initDefaultDispResources() {
111 mDefaultMode =
112 findMatchedMode(mFbWidth, mFbHeight, DEFAULT_REFRESH_RATE_60);
113 mHwcActiveModes.emplace(mHwcActiveModes.size(), mDefaultMode);
114 updateHwcActiveConfig(mDefaultMode.name);
115 MESON_LOGV("initDefaultDispResources (%s)", mDefaultMode.name);
116 return 0;
117}
118
119int32_t VariableModeMgr::update() {
120 MESON_LOG_FUN_ENTER();
121 bool useFakeMode = false;
122
123 if (mConnector->isConnected()) {
124 updateHwcDispConfigs();
125 drm_mode_info_t dispmode;
126 if (getDisplayMode(dispmode) == 0) {
127 updateHwcActiveConfig(dispmode.name);
128 } else {
129 useFakeMode = true;
130 MESON_LOGD("Get invalid display mode.");
131 }
132 } else
133 useFakeMode = true;
134
135 if (useFakeMode)
136 updateHwcActiveConfig(mDefaultMode.name);
137
138 MESON_LOG_FUN_LEAVE();
139 return 0;
140}
141
142int32_t VariableModeMgr::getDisplayMode(drm_mode_info_t & mode) {
143 return mCrtc->getMode(mode);
144}
145
146int32_t VariableModeMgr::getDisplayConfigs(
147 uint32_t * outNumConfigs, uint32_t * outConfigs) {
148 *outNumConfigs = mHwcActiveModes.size();
149
150 if (outConfigs) {
151 updateSfDispConfigs();
152 std::map<uint32_t, drm_mode_info_t>::iterator it =
153 mSfActiveModes.begin();
154 for (uint32_t index = 0; it != mSfActiveModes.end(); ++it, ++index) {
155 outConfigs[index] = it->first;
156 MESON_LOGV("outConfig[%d]: %d.", index, outConfigs[index]);
157 }
158 }
159 return HWC2_ERROR_NONE;
160}
161
162int32_t VariableModeMgr::updateHwcDispConfigs() {
163 std::map<uint32_t, drm_mode_info_t> activeModes;
164 mHwcActiveModes.clear();
165
166 mConnector->getModes(activeModes);
167 for (auto it = activeModes.begin(); it != activeModes.end(); ++it) {
168 // skip default / fake active mode as we add it to the end
169 if (!strncmp(mDefaultMode.name, it->second.name, DRM_DISPLAY_MODE_LEN)
170 && mDefaultMode.refreshRate == it->second.refreshRate) {
171 mDefaultModeSupport = true;
172 mDefaultMode.dpiX = it->second.dpiX;
173 mDefaultMode.dpiY = it->second.dpiY;
174 } else {
175 MESON_LOGV("[%s]: Hwc modes %d.", __func__, mHwcActiveModes.size());
176 mHwcActiveModes.emplace(mHwcActiveModes.size(), it->second);
177 }
178 }
179
180 // Add default mode as last, unconditionally in all cases. This is to ensure
181 // availability of 1080p mode always.
182 MESON_LOGV("[%s]: Hwc modes %d.", __func__, mHwcActiveModes.size());
183 mHwcActiveModes.emplace(mHwcActiveModes.size(), mDefaultMode);
184 return HWC2_ERROR_NONE;
185}
186
187int32_t VariableModeMgr::updateSfDispConfigs() {
188 // clear display modes
189 mSfActiveModes.clear();
190
191 mSfActiveModes = mHwcActiveModes;
192
193 // Set active config id used by SF.
194 mSfActiveConfigId = mHwcActiveConfigId;
195
196 return HWC2_ERROR_NONE;
197}
198
199int32_t VariableModeMgr::getDisplayAttribute(
200 uint32_t config, int32_t attribute, int32_t * outValue, int32_t caller) {
201 MESON_LOGV("getDisplayAttribute: config %d, fakeConfig %d,"
202 "HwcActiveConfig %d, SfActiveConfig %d, mExtModeSet %d, caller (%s)",
203 config, mFakeConfigId, mHwcActiveConfigId, mSfActiveConfigId, mExtModeSet,
204 caller == CALL_FROM_SF ? "SF" : "HWC");
205
206 std::map<uint32_t, drm_mode_info_t>::iterator it;
207 if (CALL_FROM_SF == caller) {
208 it = mSfActiveModes.find(config);
209 } else if (CALL_FROM_HWC == caller) {
210 it = mHwcActiveModes.find(config);
211 }
212
213 if (it != mHwcActiveModes.end() || it != mSfActiveModes.end()) {
214 drm_mode_info_t curMode = it->second;
215
216 switch (attribute) {
217 case HWC2_ATTRIBUTE_WIDTH:
218 *outValue = curMode.pixelW;
219 break;
220 case HWC2_ATTRIBUTE_HEIGHT:
221 *outValue = curMode.pixelH;
222 break;
223 case HWC2_ATTRIBUTE_VSYNC_PERIOD:
224 #ifdef HWC_HEADLESS
225 *outValue = 1e9 / (HWC_HEADLESS_REFRESHRATE);
226 #else
227 *outValue = 1e9 / curMode.refreshRate;
228 #endif
229 break;
230 case HWC2_ATTRIBUTE_DPI_X:
231 *outValue = curMode.dpiX * 1000.0f;
232 break;
233 case HWC2_ATTRIBUTE_DPI_Y:
234 *outValue = curMode.dpiY * 1000.0f;
235 break;
236 default:
237 MESON_LOGE("Unkown display attribute(%d)", attribute);
238 break;
239 }
240
241 return HWC2_ERROR_NONE;
242 } else {
243 MESON_LOGE("[%s]: no support display config: %d", __func__, config);
244 return HWC2_ERROR_UNSUPPORTED;
245 }
246}
247
248int32_t VariableModeMgr::updateHwcActiveConfig(
249 const char * activeMode) {
250 mActiveConfigStr = activeMode;
251
252 for (auto it = mHwcActiveModes.begin(); it != mHwcActiveModes.end(); ++it) {
253 if (strncmp(activeMode, it->second.name, DRM_DISPLAY_MODE_LEN) == 0) {
254 mHwcActiveConfigId = it->first;
255 mFakeConfigId = mHwcActiveModes.size()-1;
256 MESON_LOGD("updateActiveConfig to (%s, %d)", activeMode, mHwcActiveConfigId);
257 return HWC2_ERROR_NONE;
258 }
259 }
260
261 // If we reach here we are trying to set an unsupported mode. This can happen as
262 // SystemControl does not guarantee to keep the EDID mode list and the active
263 // mode id synchronised. We therefore handle the case where the active mode is
264 // not supported by ensuring something sane is set instead.
265 // NOTE: this is only really a workaround - HWC should instead guarantee that
266 // the display mode list and active mode reported to SF are kept in sync with
267 // hot plug events.
268 mHwcActiveConfigId = mHwcActiveModes.size()-1;
269 mFakeConfigId = mHwcActiveConfigId;
270 MESON_LOGD("updateActiveConfig something error to (%s, %d)", activeMode, mHwcActiveConfigId);
271
272 return HWC2_ERROR_NONE;
273}
274
275int32_t VariableModeMgr::getActiveConfig(
276 uint32_t * outConfig, int32_t caller) {
277 if (CALL_FROM_SF == caller) {
278 *outConfig = mExtModeSet ? mSfActiveConfigId : mFakeConfigId;
279 } else if (CALL_FROM_HWC == caller) {
280 *outConfig = mExtModeSet ? mHwcActiveConfigId : mFakeConfigId;
281 }
282 MESON_LOGV("[%s]: ret %d, Sf id %d, Hwc id %d, fake id %d, mExtModeSet %d, caller (%s)",
283 __func__ ,*outConfig, mSfActiveConfigId, mHwcActiveConfigId, mFakeConfigId,
284 mExtModeSet, caller == CALL_FROM_SF ? "SF" : "HWC");
285 return HWC2_ERROR_NONE;
286}
287
288int32_t VariableModeMgr::setActiveConfig(
289 uint32_t config) {
290 std::map<uint32_t, drm_mode_info_t>::iterator it =
291 mSfActiveModes.find(config);
292 if (it != mSfActiveModes.end()) {
293 drm_mode_info_t cfg = it->second;
294
295 // update real active config.
296 updateHwcActiveConfig(cfg.name);
297
298 // since SF is asking to set the mode, we should update mSFActiveConfigId
299 // as well here so that when SF calls getActiveConfig, we return correct
300 // mode. Without it, mSFActiveConfigId is getting updated only when
301 // updateSfDispConfigs is called by getDisplayConfigs. But getDisplayConfigs
302 // does not get called when user manually selects a mode and mSFActiveConfigId
303 // stays stale.
304 mSfActiveConfigId = mHwcActiveConfigId;
305
306 // It is possible that default mode is not supported by the sink
307 // and it was only advertised to the FWK to force 1080p UI.
308 // Trap this case and do nothing. FWK will keep thinking
309 // 1080p is supported and set.
310 if (!mDefaultModeSupport
311 && strncmp(cfg.name, mDefaultMode.name, DRM_DISPLAY_MODE_LEN) == 0) {
312 MESON_LOGD("setActiveConfig default mode not supported");
313 return HWC2_ERROR_NONE;
314 }
315
316 mCrtc->setMode(cfg);
317 mExtModeSet = true;
318 MESON_LOGD("setActiveConfig %d, mExtModeSet %d",
319 config, mExtModeSet);
320 return HWC2_ERROR_NONE;
321 } else {
322 MESON_LOGE("set invalild active config (%d)", config);
323 return HWC2_ERROR_NOT_VALIDATED;
324 }
325}
326
327void VariableModeMgr::reset() {
328 mHwcActiveModes.clear();
329 mSfActiveModes.clear();
330 mDefaultModeSupport = false;
331 mSfActiveConfigId = mHwcActiveConfigId = mFakeConfigId = -1;
332 mExtModeSet = false;
333}
334
335const drm_mode_info_t VariableModeMgr::findMatchedMode(
336 uint32_t width, uint32_t height, float refreshrate) {
337 uint32_t i = 0;
338 uint32_t size = ARRAY_SIZE(mode_info);
339 for (i = 0; i < size; i++) {
340 if (mode_info[i].pixelW == width &&
341 mode_info[i].pixelH == height &&
342 mode_info[i].refreshRate == refreshrate) {
343 return mode_info[i];
344 }
345 }
346 return mode_info[size-1];
347}
348
349void VariableModeMgr::dump(String8 & dumpstr) {
350 dumpstr.appendFormat("VariableModeMgr: %s\n", mActiveConfigStr.c_str());
351 dumpstr.append("---------------------------------------------------------"
352 "-------------------------\n");
353 dumpstr.append("| CONFIG | VSYNC_PERIOD | WIDTH | HEIGHT |"
354 " DPI_X | DPI_Y |\n");
355 dumpstr.append("+------------+------------------+-----------+------------+"
356 "-----------+-----------+\n");
357 std::map<uint32_t, drm_mode_info_t>::iterator it =
358 mHwcActiveModes.begin();
359 for (; it != mHwcActiveModes.end(); ++it) {
360 int mode = it->first;
361 drm_mode_info_t config = it->second;
362 dumpstr.appendFormat("%s %2d | %.3f | %5d | %5d |"
363 " %3d | %3d \n",
364 (mode == (int)mHwcActiveConfigId) ? "* " : " ",
365 mode,
366 config.refreshRate,
367 config.pixelW,
368 config.pixelH,
369 config.dpiX,
370 config.dpiY);
371 }
372 dumpstr.append("---------------------------------------------------------"
373 "-------------------------\n");
374}
375
376