1 /*
2 * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <cutils/properties.h>
31 #include <utils/constants.h>
32 #include <utils/debug.h>
33 #include <algorithm>
34
35 #include "hwc_display_external.h"
36 #include "hwc_debugger.h"
37
38 #define __CLASS__ "HWCDisplayExternal"
39
40 namespace sdm {
41
Create(CoreInterface * core_intf,hwc_procs_t const ** hwc_procs,qService::QService * qservice,HWCDisplay ** hwc_display)42 int HWCDisplayExternal::Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs,
43 qService::QService *qservice, HWCDisplay **hwc_display) {
44 return Create(core_intf, hwc_procs, 0, 0, qservice, false, hwc_display);
45 }
46
Create(CoreInterface * core_intf,hwc_procs_t const ** hwc_procs,uint32_t primary_width,uint32_t primary_height,qService::QService * qservice,bool use_primary_res,HWCDisplay ** hwc_display)47 int HWCDisplayExternal::Create(CoreInterface *core_intf, hwc_procs_t const **hwc_procs,
48 uint32_t primary_width, uint32_t primary_height,
49 qService::QService *qservice, bool use_primary_res,
50 HWCDisplay **hwc_display) {
51 uint32_t external_width = 0;
52 uint32_t external_height = 0;
53 int drc_enabled = 0;
54 int drc_reset_fps_enabled = 0;
55 DisplayError error = kErrorNone;
56
57 HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, hwc_procs, qservice);
58 int status = hwc_display_external->Init();
59 if (status) {
60 delete hwc_display_external;
61 return status;
62 }
63
64 error = hwc_display_external->GetMixerResolution(&external_width, &external_height);
65 if (error != kErrorNone) {
66 return -EINVAL;
67 }
68
69 if (primary_width && primary_height) {
70 // use_primary_res means HWCDisplayExternal should directly set framebuffer resolution to the
71 // provided primary_width and primary_height
72 if (use_primary_res) {
73 external_width = primary_width;
74 external_height = primary_height;
75 } else {
76 int downscale_enabled = 0;
77 HWCDebugHandler::Get()->GetProperty("sdm.debug.downscale_external", &downscale_enabled);
78 if (downscale_enabled) {
79 GetDownscaleResolution(primary_width, primary_height, &external_width, &external_height);
80 }
81 }
82 }
83
84 status = hwc_display_external->SetFrameBufferResolution(external_width, external_height);
85 if (status) {
86 Destroy(hwc_display_external);
87 return status;
88 }
89
90 HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_enabled", &(drc_enabled));
91 reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_enabled_ = drc_enabled;
92
93 HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_reset_fps", &(drc_reset_fps_enabled));
94 reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_reset_fps_enabled_ =
95 drc_reset_fps_enabled;
96
97 *hwc_display = hwc_display_external;
98
99 return status;
100 }
101
Destroy(HWCDisplay * hwc_display)102 void HWCDisplayExternal::Destroy(HWCDisplay *hwc_display) {
103 hwc_display->Deinit();
104 delete hwc_display;
105 }
106
HWCDisplayExternal(CoreInterface * core_intf,hwc_procs_t const ** hwc_procs,qService::QService * qservice)107 HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs,
108 qService::QService *qservice)
109 : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice,
110 DISPLAY_CLASS_EXTERNAL) {
111 }
112
Prepare(hwc_display_contents_1_t * content_list)113 int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
114 int status = 0;
115 DisplayError error = kErrorNone;
116
117 if (secure_display_active_) {
118 MarkLayersForGPUBypass(content_list);
119 return status;
120 }
121
122 status = AllocateLayerStack(content_list);
123 if (status) {
124 return status;
125 }
126
127 status = PrePrepareLayerStack(content_list);
128 if (status) {
129 return status;
130 }
131
132 if (content_list->numHwLayers <= 1) {
133 flush_ = true;
134 return 0;
135 }
136
137 bool one_video_updating_layer = SingleVideoLayerUpdating(UINT32(content_list->numHwLayers - 1));
138
139 uint32_t refresh_rate = GetOptimalRefreshRate(one_video_updating_layer);
140 if (current_refresh_rate_ != refresh_rate) {
141 error = display_intf_->SetRefreshRate(refresh_rate);
142 if (error == kErrorNone) {
143 // On success, set current refresh rate to new refresh rate
144 current_refresh_rate_ = refresh_rate;
145 }
146 }
147
148 status = PrepareLayerStack(content_list);
149 if (status) {
150 return status;
151 }
152
153 return 0;
154 }
155
Commit(hwc_display_contents_1_t * content_list)156 int HWCDisplayExternal::Commit(hwc_display_contents_1_t *content_list) {
157 int status = 0;
158
159 if (secure_display_active_) {
160 return status;
161 }
162
163 status = HWCDisplay::CommitLayerStack(content_list);
164 if (status) {
165 return status;
166 }
167
168 status = HWCDisplay::PostCommitLayerStack(content_list);
169 if (status) {
170 return status;
171 }
172
173 return 0;
174 }
175
ApplyScanAdjustment(hwc_rect_t * display_frame)176 void HWCDisplayExternal::ApplyScanAdjustment(hwc_rect_t *display_frame) {
177 if (display_intf_->IsUnderscanSupported()) {
178 return;
179 }
180
181 // Read user defined width and height ratio
182 int width = 0, height = 0;
183 HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &width);
184 float width_ratio = FLOAT(width) / 100.0f;
185 HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &height);
186 float height_ratio = FLOAT(height) / 100.0f;
187
188 if (width_ratio == 0.0f || height_ratio == 0.0f) {
189 return;
190 }
191
192 uint32_t mixer_width = 0;
193 uint32_t mixer_height = 0;
194 GetMixerResolution(&mixer_width, &mixer_height);
195
196 if (mixer_width == 0 || mixer_height == 0) {
197 DLOGV("Invalid mixer dimensions (%d, %d)", mixer_width, mixer_height);
198 return;
199 }
200
201 uint32_t new_mixer_width = UINT32(mixer_width * FLOAT(1.0f - width_ratio));
202 uint32_t new_mixer_height = UINT32(mixer_height * FLOAT(1.0f - height_ratio));
203
204 int x_offset = INT((FLOAT(mixer_width) * width_ratio) / 2.0f);
205 int y_offset = INT((FLOAT(mixer_height) * height_ratio) / 2.0f);
206
207 display_frame->left = (display_frame->left * INT32(new_mixer_width) / INT32(mixer_width))
208 + x_offset;
209 display_frame->top = (display_frame->top * INT32(new_mixer_height) / INT32(mixer_height)) +
210 y_offset;
211 display_frame->right = ((display_frame->right * INT32(new_mixer_width)) / INT32(mixer_width)) +
212 x_offset;
213 display_frame->bottom = ((display_frame->bottom * INT32(new_mixer_height)) / INT32(mixer_height))
214 + y_offset;
215 }
216
SetSecureDisplay(bool secure_display_active,bool force_flush)217 void HWCDisplayExternal::SetSecureDisplay(bool secure_display_active, bool force_flush) {
218 if (secure_display_active_ != secure_display_active) {
219 secure_display_active_ = secure_display_active;
220
221 if (secure_display_active_) {
222 DisplayError error = display_intf_->Flush();
223 if (error != kErrorNone) {
224 DLOGE("Flush failed. Error = %d", error);
225 }
226 }
227 }
228 return;
229 }
230
AdjustSourceResolution(uint32_t dst_width,uint32_t dst_height,uint32_t * src_width,uint32_t * src_height)231 static void AdjustSourceResolution(uint32_t dst_width, uint32_t dst_height, uint32_t *src_width,
232 uint32_t *src_height) {
233 *src_height = (dst_width * (*src_height)) / (*src_width);
234 *src_width = dst_width;
235 }
236
GetDownscaleResolution(uint32_t primary_width,uint32_t primary_height,uint32_t * non_primary_width,uint32_t * non_primary_height)237 void HWCDisplayExternal::GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
238 uint32_t *non_primary_width, uint32_t *non_primary_height) {
239 uint32_t primary_area = primary_width * primary_height;
240 uint32_t non_primary_area = (*non_primary_width) * (*non_primary_height);
241
242 if (primary_area > non_primary_area) {
243 if (primary_height > primary_width) {
244 std::swap(primary_height, primary_width);
245 }
246 AdjustSourceResolution(primary_width, primary_height, non_primary_width, non_primary_height);
247 }
248 }
249
RoundToStandardFPS(float fps)250 uint32_t HWCDisplayExternal::RoundToStandardFPS(float fps) {
251 static const uint32_t standard_fps[] = {23976, 24000, 25000, 29970, 30000, 50000, 59940, 60000};
252 static const uint32_t mapping_fps[] = {59940, 60000, 60000, 59940, 60000, 50000, 59940, 60000};
253 uint32_t frame_rate = (uint32_t)(fps * 1000);
254
255 // process non valid
256 if (frame_rate == 0) {
257 return current_refresh_rate_;
258 }
259
260 int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0]));
261 for (int i = 0; i < count; i++) {
262 // Most likely used for video, the fps for frames should be stable from video side.
263 if (standard_fps[i] > frame_rate) {
264 if (i > 0) {
265 if ((standard_fps[i] - frame_rate) > (frame_rate - standard_fps[i-1])) {
266 return mapping_fps[i-1];
267 } else {
268 return mapping_fps[i];
269 }
270 } else {
271 return mapping_fps[i];
272 }
273 }
274 }
275
276 return standard_fps[count - 1];
277 }
278
PrepareDynamicRefreshRate(Layer * layer)279 void HWCDisplayExternal::PrepareDynamicRefreshRate(Layer *layer) {
280 if (layer->input_buffer.flags.video) {
281 if (layer->frame_rate != 0) {
282 metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
283 } else {
284 metadata_refresh_rate_ = current_refresh_rate_;
285 }
286 layer->frame_rate = current_refresh_rate_;
287 } else if (!layer->frame_rate) {
288 layer->frame_rate = current_refresh_rate_;
289 }
290 }
291
ForceRefreshRate(uint32_t refresh_rate)292 void HWCDisplayExternal::ForceRefreshRate(uint32_t refresh_rate) {
293 if ((refresh_rate && (refresh_rate < min_refresh_rate_ || refresh_rate > max_refresh_rate_)) ||
294 force_refresh_rate_ == refresh_rate) {
295 // Cannot honor force refresh rate, as its beyond the range or new request is same
296 return;
297 }
298
299 force_refresh_rate_ = refresh_rate;
300 }
301
GetOptimalRefreshRate(bool one_updating_layer)302 uint32_t HWCDisplayExternal::GetOptimalRefreshRate(bool one_updating_layer) {
303 if (force_refresh_rate_) {
304 return force_refresh_rate_;
305 } else if (one_updating_layer && drc_enabled_) {
306 return metadata_refresh_rate_;
307 }
308
309 if (drc_reset_fps_enabled_) {
310 DisplayConfigVariableInfo fb_config;
311 display_intf_->GetFrameBufferConfig(&fb_config);
312 return (fb_config.fps * 1000);
313 }
314
315 return current_refresh_rate_;
316 }
317
Perform(uint32_t operation,...)318 int HWCDisplayExternal::Perform(uint32_t operation, ...) {
319 va_list args;
320 va_start(args, operation);
321 int val = va_arg(args, int32_t);
322 va_end(args);
323 switch (operation) {
324 case SET_BINDER_DYN_REFRESH_RATE:
325 ForceRefreshRate(UINT32(val));
326 break;
327 default:
328 DLOGW("Invalid operation %d", operation);
329 return -EINVAL;
330 }
331
332 return 0;
333 }
334
335 } // namespace sdm
336
337