1 /* 2 * Copyright (c) 2014-2017, 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 42 int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, 43 HWCCallbacks *callbacks, qService::QService *qservice, 44 HWCDisplay **hwc_display) { 45 return Create(core_intf, buffer_allocator, callbacks, 0, 0, qservice, false, hwc_display); 46 } 47 48 int HWCDisplayExternal::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator, 49 HWCCallbacks *callbacks, 50 uint32_t primary_width, uint32_t primary_height, 51 qService::QService *qservice, bool use_primary_res, 52 HWCDisplay **hwc_display) { 53 uint32_t external_width = 0; 54 uint32_t external_height = 0; 55 DisplayError error = kErrorNone; 56 57 HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, buffer_allocator, callbacks, 58 qservice); 59 int status = hwc_display_external->Init(); 60 if (status) { 61 delete hwc_display_external; 62 return status; 63 } 64 65 error = hwc_display_external->GetMixerResolution(&external_width, &external_height); 66 if (error != kErrorNone) { 67 Destroy(hwc_display_external); 68 return -EINVAL; 69 } 70 71 if (primary_width && primary_height) { 72 // use_primary_res means HWCDisplayExternal should directly set framebuffer resolution to the 73 // provided primary_width and primary_height 74 if (use_primary_res) { 75 external_width = primary_width; 76 external_height = primary_height; 77 } else { 78 int downscale_enabled = 0; 79 HWCDebugHandler::Get()->GetProperty("sdm.debug.downscale_external", &downscale_enabled); 80 if (downscale_enabled) { 81 GetDownscaleResolution(primary_width, primary_height, &external_width, &external_height); 82 } 83 } 84 } 85 86 status = hwc_display_external->SetFrameBufferResolution(external_width, external_height); 87 if (status) { 88 Destroy(hwc_display_external); 89 return status; 90 } 91 92 *hwc_display = hwc_display_external; 93 94 return status; 95 } 96 97 void HWCDisplayExternal::Destroy(HWCDisplay *hwc_display) { 98 hwc_display->Deinit(); 99 delete hwc_display; 100 } 101 102 HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, 103 HWCBufferAllocator *buffer_allocator, 104 HWCCallbacks *callbacks, 105 qService::QService *qservice) 106 : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice, 107 DISPLAY_CLASS_EXTERNAL, buffer_allocator) { 108 } 109 110 HWC2::Error HWCDisplayExternal::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) { 111 auto status = HWC2::Error::None; 112 113 if (secure_display_active_) { 114 MarkLayersForGPUBypass(); 115 return status; 116 } 117 118 BuildLayerStack(); 119 120 if (layer_set_.empty()) { 121 flush_ = true; 122 return status; 123 } 124 125 status = PrepareLayerStack(out_num_types, out_num_requests); 126 return status; 127 } 128 129 HWC2::Error HWCDisplayExternal::Present(int32_t *out_retire_fence) { 130 auto status = HWC2::Error::None; 131 132 if (!secure_display_active_) { 133 status = HWCDisplay::CommitLayerStack(); 134 if (status == HWC2::Error::None) { 135 status = HWCDisplay::PostCommitLayerStack(out_retire_fence); 136 } 137 } 138 CloseAcquireFds(); 139 return status; 140 } 141 142 void HWCDisplayExternal::ApplyScanAdjustment(hwc_rect_t *display_frame) { 143 if ((underscan_width_ <= 0) || (underscan_height_ <= 0)) { 144 return; 145 } 146 147 float width_ratio = FLOAT(underscan_width_) / 100.0f; 148 float height_ratio = FLOAT(underscan_height_) / 100.0f; 149 150 uint32_t mixer_width = 0; 151 uint32_t mixer_height = 0; 152 GetMixerResolution(&mixer_width, &mixer_height); 153 154 if (mixer_width == 0 || mixer_height == 0) { 155 DLOGV("Invalid mixer dimensions (%d, %d)", mixer_width, mixer_height); 156 return; 157 } 158 159 uint32_t new_mixer_width = UINT32(mixer_width * FLOAT(1.0f - width_ratio)); 160 uint32_t new_mixer_height = UINT32(mixer_height * FLOAT(1.0f - height_ratio)); 161 162 int x_offset = INT((FLOAT(mixer_width) * width_ratio) / 2.0f); 163 int y_offset = INT((FLOAT(mixer_height) * height_ratio) / 2.0f); 164 165 display_frame->left = (display_frame->left * INT32(new_mixer_width) / INT32(mixer_width)) 166 + x_offset; 167 display_frame->top = (display_frame->top * INT32(new_mixer_height) / INT32(mixer_height)) + 168 y_offset; 169 display_frame->right = ((display_frame->right * INT32(new_mixer_width)) / INT32(mixer_width)) + 170 x_offset; 171 display_frame->bottom = ((display_frame->bottom * INT32(new_mixer_height)) / INT32(mixer_height)) 172 + y_offset; 173 } 174 175 void HWCDisplayExternal::SetSecureDisplay(bool secure_display_active) { 176 if (secure_display_active_ != secure_display_active) { 177 secure_display_active_ = secure_display_active; 178 179 if (secure_display_active_) { 180 DisplayError error = display_intf_->Flush(); 181 validated_.reset(); 182 if (error != kErrorNone) { 183 DLOGE("Flush failed. Error = %d", error); 184 } 185 } 186 } 187 return; 188 } 189 190 static void AdjustSourceResolution(uint32_t dst_width, uint32_t dst_height, uint32_t *src_width, 191 uint32_t *src_height) { 192 *src_height = (dst_width * (*src_height)) / (*src_width); 193 *src_width = dst_width; 194 } 195 196 void HWCDisplayExternal::GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height, 197 uint32_t *non_primary_width, 198 uint32_t *non_primary_height) { 199 uint32_t primary_area = primary_width * primary_height; 200 uint32_t non_primary_area = (*non_primary_width) * (*non_primary_height); 201 202 if (primary_area > non_primary_area) { 203 if (primary_height > primary_width) { 204 std::swap(primary_height, primary_width); 205 } 206 AdjustSourceResolution(primary_width, primary_height, non_primary_width, non_primary_height); 207 } 208 } 209 210 int HWCDisplayExternal::SetState(bool connected) { 211 DisplayError error = kErrorNone; 212 DisplayState state = kStateOff; 213 DisplayConfigVariableInfo fb_config = {}; 214 215 if (connected) { 216 if (display_null_.IsActive()) { 217 error = core_intf_->CreateDisplay(type_, this, &display_intf_); 218 if (error != kErrorNone) { 219 DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p", 220 error, type_, this, &display_intf_); 221 return -EINVAL; 222 } 223 224 // Restore HDMI attributes when display is reconnected. 225 // This is to ensure that surfaceflinger & sdm are in sync. 226 display_null_.GetFrameBufferConfig(&fb_config); 227 int status = SetFrameBufferResolution(fb_config.x_pixels, fb_config.y_pixels); 228 if (status) { 229 DLOGW("Set frame buffer config failed. Error = %d", error); 230 return -1; 231 } 232 233 display_null_.GetDisplayState(&state); 234 display_intf_->SetDisplayState(state); 235 validated_.reset(); 236 237 SetVsyncEnabled(HWC2::Vsync::Enable); 238 239 display_null_.SetActive(false); 240 DLOGI("Display is connected successfully."); 241 } else { 242 DLOGI("Display is already connected."); 243 } 244 } else { 245 if (!display_null_.IsActive()) { 246 // Preserve required attributes of HDMI display that surfaceflinger sees. 247 // Restore HDMI attributes when display is reconnected. 248 display_intf_->GetDisplayState(&state); 249 display_null_.SetDisplayState(state); 250 251 error = display_intf_->GetFrameBufferConfig(&fb_config); 252 if (error != kErrorNone) { 253 DLOGW("Get frame buffer config failed. Error = %d", error); 254 return -1; 255 } 256 display_null_.SetFrameBufferConfig(fb_config); 257 258 SetVsyncEnabled(HWC2::Vsync::Disable); 259 core_intf_->DestroyDisplay(display_intf_); 260 display_intf_ = &display_null_; 261 262 display_null_.SetActive(true); 263 DLOGI("Display is disconnected successfully."); 264 } else { 265 DLOGI("Display is already disconnected."); 266 } 267 } 268 269 return 0; 270 } 271 272 void HWCDisplayExternal::GetUnderScanConfig() { 273 if (!display_intf_->IsUnderscanSupported()) { 274 // Read user defined underscan width and height 275 HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &underscan_width_); 276 HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &underscan_height_); 277 } 278 } 279 280 } // namespace sdm 281