1/* 2 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. 3 * Not a Contribution. 4 * 5 * Copyright 2015 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20#include <cutils/properties.h> 21#include <errno.h> 22#include <math.h> 23#include <sync/sync.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <utils/constants.h> 27#include <utils/debug.h> 28#include <utils/formats.h> 29#include <utils/rect.h> 30#include <qd_utils.h> 31 32#include <algorithm> 33#include <iomanip> 34#include <map> 35#include <sstream> 36#include <string> 37#include <utility> 38#include <vector> 39 40#include "hwc_display.h" 41#include "hwc_debugger.h" 42#include "blit_engine_c2d.h" 43#include "hwc_tonemapper.h" 44 45#ifndef USE_GRALLOC1 46#include <gr.h> 47#endif 48 49#ifdef QTI_BSP 50#include <hardware/display_defs.h> 51#endif 52 53#define __CLASS__ "HWCDisplay" 54 55namespace sdm { 56 57// This weight function is needed because the color primaries are not sorted by gamut size 58static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) { 59 int weight = 10; 60 int lp1 = p1, lp2 = p2; 61 // TODO(user) add weight to other wide gamut primaries 62 if (lp1 == ColorPrimaries_BT2020) { 63 lp1 *= weight; 64 } 65 if (lp1 == ColorPrimaries_BT2020) { 66 lp2 *= weight; 67 } 68 if (lp1 >= lp2) { 69 return p1; 70 } else { 71 return p2; 72 } 73} 74 75HWCColorMode::HWCColorMode(DisplayInterface *display_intf) : display_intf_(display_intf) {} 76 77HWC2::Error HWCColorMode::Init() { 78 PopulateColorModes(); 79 return ApplyDefaultColorMode(); 80} 81 82HWC2::Error HWCColorMode::DeInit() { 83 color_mode_transform_map_.clear(); 84 return HWC2::Error::None; 85} 86 87uint32_t HWCColorMode::GetColorModeCount() { 88 uint32_t count = UINT32(color_mode_transform_map_.size()); 89 DLOGI("Supported color mode count = %d", count); 90 91 return std::max(1U, count); 92} 93 94HWC2::Error HWCColorMode::GetColorModes(uint32_t *out_num_modes, 95 android_color_mode_t *out_modes) { 96 auto it = color_mode_transform_map_.begin(); 97 for (auto i = 0; it != color_mode_transform_map_.end(); it++, i++) { 98 out_modes[i] = it->first; 99 DLOGI("Supports color mode[%d] = %d", i, it->first); 100 } 101 *out_num_modes = UINT32(color_mode_transform_map_.size()); 102 return HWC2::Error::None; 103} 104 105HWC2::Error HWCColorMode::SetColorMode(android_color_mode_t mode) { 106 // first mode in 2D matrix is the mode (identity) 107 if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) { 108 DLOGE("Could not find mode: %d", mode); 109 return HWC2::Error::BadParameter; 110 } 111 auto status = HandleColorModeTransform(mode, current_color_transform_, color_matrix_); 112 if (status != HWC2::Error::None) { 113 DLOGE("failed for mode = %d", mode); 114 } 115 116 return status; 117} 118 119HWC2::Error HWCColorMode::SetColorModeById(int32_t color_mode_id) { 120 DLOGI("Applying mode: %d", color_mode_id); 121 DisplayError error = display_intf_->SetColorModeById(color_mode_id); 122 if (error != kErrorNone) { 123 return HWC2::Error::BadParameter; 124 } 125 return HWC2::Error::None; 126} 127 128HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t hint) { 129 if (!matrix) { 130 return HWC2::Error::BadParameter; 131 } 132 133 double color_matrix[kColorTransformMatrixCount] = {0}; 134 CopyColorTransformMatrix(matrix, color_matrix); 135 136 auto status = HandleColorModeTransform(current_color_mode_, hint, color_matrix); 137 if (status != HWC2::Error::None) { 138 DLOGE("failed for hint = %d", hint); 139 } 140 141 return status; 142} 143 144HWC2::Error HWCColorMode::HandleColorModeTransform(android_color_mode_t mode, 145 android_color_transform_t hint, 146 const double *matrix) { 147 android_color_transform_t transform_hint = hint; 148 std::string color_mode_transform; 149 bool use_matrix = false; 150 if (hint != HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) { 151 // if the mode + transfrom request from HWC matches one mode in SDM, set that 152 if (color_mode_transform.empty()) { 153 transform_hint = HAL_COLOR_TRANSFORM_IDENTITY; 154 use_matrix = true; 155 } else { 156 color_mode_transform = color_mode_transform_map_[mode][hint]; 157 } 158 } else { 159 use_matrix = true; 160 transform_hint = HAL_COLOR_TRANSFORM_IDENTITY; 161 } 162 163 // if the mode count is 1, then only native mode is supported, so just apply matrix w/o 164 // setting mode 165 if (color_mode_transform_map_.size() > 1U) { 166 color_mode_transform = color_mode_transform_map_[mode][transform_hint]; 167 DisplayError error = display_intf_->SetColorMode(color_mode_transform); 168 if (error != kErrorNone) { 169 DLOGE("Failed to set color_mode = %d transform_hint = %d", mode, hint); 170 // failure to force client composition 171 return HWC2::Error::Unsupported; 172 } 173 } 174 175 if (use_matrix) { 176 DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, matrix); 177 if (error != kErrorNone) { 178 DLOGE("Failed to set Color Transform Matrix"); 179 // failure to force client composition 180 return HWC2::Error::Unsupported; 181 } 182 } 183 184 current_color_mode_ = mode; 185 current_color_transform_ = hint; 186 CopyColorTransformMatrix(matrix, color_matrix_); 187 DLOGI("Setting Color Mode = %d Transform Hint = %d Success", mode, hint); 188 189 return HWC2::Error::None; 190} 191 192void HWCColorMode::PopulateColorModes() { 193 uint32_t color_mode_count = 0; 194 // SDM returns modes which is string combination of mode + transform. 195 DisplayError error = display_intf_->GetColorModeCount(&color_mode_count); 196 if (error != kErrorNone || (color_mode_count == 0)) { 197 DLOGW("GetColorModeCount failed, use native color mode"); 198 PopulateTransform(HAL_COLOR_MODE_NATIVE, "native", "identity"); 199 return; 200 } 201 202 DLOGV_IF(kTagQDCM, "Color Modes supported count = %d", color_mode_count); 203 204 const std::string color_transform = "identity"; 205 std::vector<std::string> color_modes(color_mode_count); 206 error = display_intf_->GetColorModes(&color_mode_count, &color_modes); 207 for (uint32_t i = 0; i < color_mode_count; i++) { 208 std::string &mode_string = color_modes.at(i); 209 DLOGV_IF(kTagQDCM, "Color Mode[%d] = %s", i, mode_string.c_str()); 210 AttrVal attr; 211 error = display_intf_->GetColorModeAttr(mode_string, &attr); 212 if (!attr.empty()) { 213 std::string color_gamut, dynamic_range, pic_quality; 214 for (auto &it : attr) { 215 if (it.first.find(kColorGamutAttribute) != std::string::npos) { 216 color_gamut = it.second; 217 } else if (it.first.find(kDynamicRangeAttribute) != std::string::npos) { 218 dynamic_range = it.second; 219 } else if (it.first.find(kPictureQualityAttribute) != std::string::npos) { 220 pic_quality = it.second; 221 } 222 } 223 if (dynamic_range == kHdr) { 224 continue; 225 } 226 if ((color_gamut == kNative) && 227 (pic_quality.empty() || pic_quality == kStandard)) { 228 PopulateTransform(HAL_COLOR_MODE_NATIVE, mode_string, color_transform); 229 } else if ((color_gamut == kSrgb) && 230 (pic_quality.empty() || pic_quality == kStandard)) { 231 PopulateTransform(HAL_COLOR_MODE_SRGB, mode_string, color_transform); 232 } else if ((color_gamut == kDcip3) && 233 (pic_quality.empty() || pic_quality == kStandard)) { 234 PopulateTransform(HAL_COLOR_MODE_DCI_P3, mode_string, color_transform); 235 } else if ((color_gamut == kDisplayP3) && 236 (pic_quality.empty() || pic_quality == kStandard)) { 237 PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, color_transform); 238 } 239 } else { 240 if (mode_string.find("hal_native") != std::string::npos) { 241 PopulateTransform(HAL_COLOR_MODE_NATIVE, mode_string, mode_string); 242 } else if (mode_string.find("hal_srgb") != std::string::npos) { 243 PopulateTransform(HAL_COLOR_MODE_SRGB, mode_string, mode_string); 244 } else if (mode_string.find("hal_adobe") != std::string::npos) { 245 PopulateTransform(HAL_COLOR_MODE_ADOBE_RGB, mode_string, mode_string); 246 } else if (mode_string.find("hal_dci_p3") != std::string::npos) { 247 PopulateTransform(HAL_COLOR_MODE_DCI_P3, mode_string, mode_string); 248 } else if (mode_string.find("hal_display_p3") != std::string::npos) { 249 PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, mode_string); 250 } 251 } 252 } 253} 254 255void HWCColorMode::PopulateTransform(const android_color_mode_t &mode, 256 const std::string &color_mode, 257 const std::string &color_transform) { 258 // TODO(user): Check the substring from QDCM 259 if (color_transform.find("identity") != std::string::npos) { 260 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_IDENTITY] = color_mode; 261 } else if (color_transform.find("arbitrary") != std::string::npos) { 262 // no color mode for arbitrary 263 } else if (color_transform.find("inverse") != std::string::npos) { 264 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_VALUE_INVERSE] = color_mode; 265 } else if (color_transform.find("grayscale") != std::string::npos) { 266 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_GRAYSCALE] = color_mode; 267 } else if (color_transform.find("correct_protonopia") != std::string::npos) { 268 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA] = color_mode; 269 } else if (color_transform.find("correct_deuteranopia") != std::string::npos) { 270 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA] = color_mode; 271 } else if (color_transform.find("correct_tritanopia") != std::string::npos) { 272 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA] = color_mode; 273 } else { 274 color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_IDENTITY] = color_mode; 275 } 276} 277 278HWC2::Error HWCColorMode::ApplyDefaultColorMode() { 279 android_color_mode_t color_mode = HAL_COLOR_MODE_NATIVE; 280 if (color_mode_transform_map_.size() == 1U) { 281 color_mode = color_mode_transform_map_.begin()->first; 282 } else if (color_mode_transform_map_.size() > 1U) { 283 std::string default_color_mode; 284 bool found = false; 285 DisplayError error = display_intf_->GetDefaultColorMode(&default_color_mode); 286 if (error == kErrorNone) { 287 // get the default mode corresponding android_color_mode_t 288 for (auto &it_mode : color_mode_transform_map_) { 289 for (auto &it : it_mode.second) { 290 if (it.second == default_color_mode) { 291 found = true; 292 break; 293 } 294 } 295 if (found) { 296 color_mode = it_mode.first; 297 break; 298 } 299 } 300 } 301 302 // return the first andrid_color_mode_t when we encouter if not found 303 if (!found) { 304 color_mode = color_mode_transform_map_.begin()->first; 305 } 306 } 307 return SetColorMode(color_mode); 308} 309 310void HWCColorMode::Dump(std::ostringstream* os) { 311 *os << "color modes supported: "; 312 for (auto it : color_mode_transform_map_) { 313 *os << it.first <<" "; 314 } 315 *os << "current mode: " << current_color_mode_ << std::endl; 316 *os << "current transform: "; 317 for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) { 318 if (i % 4 == 0) { 319 *os << std::endl; 320 } 321 *os << std::fixed << std::setprecision(2) << std::setw(6) << std::setfill(' ') 322 << color_matrix_[i] << " "; 323 } 324 *os << std::endl; 325} 326 327HWCDisplay::HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks, DisplayType type, 328 hwc2_display_t id, bool needs_blit, qService::QService *qservice, 329 DisplayClass display_class, BufferAllocator *buffer_allocator) 330 : core_intf_(core_intf), 331 callbacks_(callbacks), 332 type_(type), 333 id_(id), 334 needs_blit_(needs_blit), 335 qservice_(qservice), 336 display_class_(display_class) { 337 buffer_allocator_ = static_cast<HWCBufferAllocator *>(buffer_allocator); 338} 339 340int HWCDisplay::Init() { 341 DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_); 342 if (error != kErrorNone) { 343 DLOGE("Display create failed. Error = %d display_type %d event_handler %p disp_intf %p", error, 344 type_, this, &display_intf_); 345 return -EINVAL; 346 } 347 348 HWCDebugHandler::Get()->GetProperty("sys.hwc_disable_hdr", &disable_hdr_handling_); 349 if (disable_hdr_handling_) { 350 DLOGI("HDR Handling disabled"); 351 } 352 353 int property_swap_interval = 1; 354 HWCDebugHandler::Get()->GetProperty("debug.egl.swapinterval", &property_swap_interval); 355 if (property_swap_interval == 0) { 356 swap_interval_zero_ = true; 357 } 358 359 client_target_ = new HWCLayer(id_, buffer_allocator_); 360 361 int blit_enabled = 0; 362 HWCDebugHandler::Get()->GetProperty("persist.hwc.blit.comp", &blit_enabled); 363 if (needs_blit_ && blit_enabled) { 364 // TODO(user): Add blit engine when needed 365 } 366 367 tone_mapper_ = new HWCToneMapper(buffer_allocator_); 368 369 display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_); 370 current_refresh_rate_ = max_refresh_rate_; 371 DLOGI("Display created with id: %d", id_); 372 return 0; 373} 374 375int HWCDisplay::Deinit() { 376 DisplayError error = core_intf_->DestroyDisplay(display_intf_); 377 if (error != kErrorNone) { 378 DLOGE("Display destroy failed. Error = %d", error); 379 return -EINVAL; 380 } 381 382 delete client_target_; 383 384 if (color_mode_) { 385 color_mode_->DeInit(); 386 delete color_mode_; 387 } 388 389 delete tone_mapper_; 390 tone_mapper_ = nullptr; 391 392 return 0; 393} 394 395// LayerStack operations 396HWC2::Error HWCDisplay::CreateLayer(hwc2_layer_t *out_layer_id) { 397 HWCLayer *layer = *layer_set_.emplace(new HWCLayer(id_, buffer_allocator_)); 398 layer_map_.emplace(std::make_pair(layer->GetId(), layer)); 399 *out_layer_id = layer->GetId(); 400 validated_ = false; 401 geometry_changes_ |= GeometryChanges::kAdded; 402 return HWC2::Error::None; 403} 404 405HWCLayer *HWCDisplay::GetHWCLayer(hwc2_layer_t layer_id) { 406 const auto map_layer = layer_map_.find(layer_id); 407 if (map_layer == layer_map_.end()) { 408 DLOGE("[%" PRIu64 "] GetLayer(%" PRIu64 ") failed: no such layer", id_, layer_id); 409 return nullptr; 410 } else { 411 return map_layer->second; 412 } 413} 414 415HWC2::Error HWCDisplay::DestroyLayer(hwc2_layer_t layer_id) { 416 const auto map_layer = layer_map_.find(layer_id); 417 if (map_layer == layer_map_.end()) { 418 DLOGE("[%" PRIu64 "] destroyLayer(%" PRIu64 ") failed: no such layer", id_, layer_id); 419 return HWC2::Error::BadLayer; 420 } 421 const auto layer = map_layer->second; 422 layer_map_.erase(map_layer); 423 const auto z_range = layer_set_.equal_range(layer); 424 for (auto current = z_range.first; current != z_range.second; ++current) { 425 if (*current == layer) { 426 current = layer_set_.erase(current); 427 delete layer; 428 break; 429 } 430 } 431 validated_ = false; 432 433 geometry_changes_ |= GeometryChanges::kRemoved; 434 return HWC2::Error::None; 435} 436 437 438void HWCDisplay::BuildLayerStack() { 439 layer_stack_ = LayerStack(); 440 display_rect_ = LayerRect(); 441 metadata_refresh_rate_ = 0; 442 auto working_primaries = ColorPrimaries_BT709_5; 443 444 // Add one layer for fb target 445 // TODO(user): Add blit target layers 446 for (auto hwc_layer : layer_set_) { 447 // Reset layer data which SDM may change 448 hwc_layer->ResetPerFrameData(); 449 450 Layer *layer = hwc_layer->GetSDMLayer(); 451 layer->flags = {}; // Reset earlier flags 452 if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Client) { 453 layer->flags.skip = true; 454 } else if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::SolidColor) { 455 layer->flags.solid_fill = true; 456 } 457 458#ifdef FEATURE_WIDE_COLOR 459 if (!hwc_layer->SupportedDataspace()) { 460 layer->flags.skip = true; 461 DLOGW_IF(kTagStrategy, "Unsupported dataspace: 0x%x", hwc_layer->GetLayerDataspace()); 462 } 463#endif 464 465 working_primaries = WidestPrimaries(working_primaries, 466 layer->input_buffer.color_metadata.colorPrimaries); 467 468 // set default composition as GPU for SDM 469 layer->composition = kCompositionGPU; 470 471 if (swap_interval_zero_) { 472 if (layer->input_buffer.acquire_fence_fd >= 0) { 473 close(layer->input_buffer.acquire_fence_fd); 474 layer->input_buffer.acquire_fence_fd = -1; 475 } 476 } 477 478 const private_handle_t *handle = 479 reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id); 480 if (handle) { 481#ifdef USE_GRALLOC1 482 if (handle->buffer_type == BUFFER_TYPE_VIDEO) { 483#else 484 if (handle->bufferType == BUFFER_TYPE_VIDEO) { 485#endif 486 layer_stack_.flags.video_present = true; 487 } 488 // TZ Protected Buffer - L1 489 if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { 490 layer_stack_.flags.secure_present = true; 491 } 492 // Gralloc Usage Protected Buffer - L3 - which needs to be treated as Secure & avoid fallback 493 if (handle->flags & private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER) { 494 layer_stack_.flags.secure_present = true; 495 } 496 } 497 498 if (layer->flags.skip) { 499 layer_stack_.flags.skip_present = true; 500 } 501 502 if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Cursor) { 503 // Currently we support only one HWCursor & only at top most z-order 504 if ((*layer_set_.rbegin())->GetId() == hwc_layer->GetId()) { 505 layer->flags.cursor = true; 506 layer_stack_.flags.cursor_present = true; 507 } 508 } 509 510 bool hdr_layer = layer->input_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 && 511 (layer->input_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 || 512 layer->input_buffer.color_metadata.transfer == Transfer_HLG); 513 if (hdr_layer && !disable_hdr_handling_) { 514 // dont honor HDR when its handling is disabled 515 layer->input_buffer.flags.hdr = true; 516 layer_stack_.flags.hdr_present = true; 517 } 518 519 // TODO(user): Move to a getter if this is needed at other places 520 hwc_rect_t scaled_display_frame = {INT(layer->dst_rect.left), INT(layer->dst_rect.top), 521 INT(layer->dst_rect.right), INT(layer->dst_rect.bottom)}; 522 ApplyScanAdjustment(&scaled_display_frame); 523 hwc_layer->SetLayerDisplayFrame(scaled_display_frame); 524 // SDM requires these details even for solid fill 525 if (layer->flags.solid_fill) { 526 LayerBuffer *layer_buffer = &layer->input_buffer; 527 layer_buffer->width = UINT32(layer->dst_rect.right - layer->dst_rect.left); 528 layer_buffer->height = UINT32(layer->dst_rect.bottom - layer->dst_rect.top); 529 layer_buffer->unaligned_width = layer_buffer->width; 530 layer_buffer->unaligned_height = layer_buffer->height; 531 layer_buffer->acquire_fence_fd = -1; 532 layer_buffer->release_fence_fd = -1; 533 layer->src_rect.left = 0; 534 layer->src_rect.top = 0; 535 layer->src_rect.right = layer_buffer->width; 536 layer->src_rect.bottom = layer_buffer->height; 537 } 538 539 if (layer->frame_rate > metadata_refresh_rate_) { 540 metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate); 541 } else { 542 layer->frame_rate = current_refresh_rate_; 543 } 544 display_rect_ = Union(display_rect_, layer->dst_rect); 545 geometry_changes_ |= hwc_layer->GetGeometryChanges(); 546 547 layer->flags.updating = true; 548 if (layer_set_.size() <= kMaxLayerCount) { 549 layer->flags.updating = IsLayerUpdating(layer); 550 } 551 552 layer_stack_.layers.push_back(layer); 553 } 554 555 556#ifdef FEATURE_WIDE_COLOR 557 for (auto hwc_layer : layer_set_) { 558 auto layer = hwc_layer->GetSDMLayer(); 559 if (layer->input_buffer.color_metadata.colorPrimaries != working_primaries && 560 !hwc_layer->SupportLocalConversion(working_primaries)) { 561 layer->flags.skip = true; 562 } 563 if (layer->flags.skip) { 564 layer_stack_.flags.skip_present = true; 565 } 566 } 567#endif 568 569 // TODO(user): Set correctly when SDM supports geometry_changes as bitmask 570 layer_stack_.flags.geometry_changed = UINT32(geometry_changes_ > 0); 571 // Append client target to the layer stack 572 layer_stack_.layers.push_back(client_target_->GetSDMLayer()); 573} 574 575void HWCDisplay::BuildSolidFillStack() { 576 layer_stack_ = LayerStack(); 577 display_rect_ = LayerRect(); 578 579 layer_stack_.layers.push_back(solid_fill_layer_); 580 layer_stack_.flags.geometry_changed = 1U; 581 // Append client target to the layer stack 582 layer_stack_.layers.push_back(client_target_->GetSDMLayer()); 583} 584 585HWC2::Error HWCDisplay::SetLayerZOrder(hwc2_layer_t layer_id, uint32_t z) { 586 const auto map_layer = layer_map_.find(layer_id); 587 if (map_layer == layer_map_.end()) { 588 DLOGE("[%" PRIu64 "] updateLayerZ failed to find layer", id_); 589 return HWC2::Error::BadLayer; 590 } 591 validated_ = false; 592 593 const auto layer = map_layer->second; 594 const auto z_range = layer_set_.equal_range(layer); 595 bool layer_on_display = false; 596 for (auto current = z_range.first; current != z_range.second; ++current) { 597 if (*current == layer) { 598 if ((*current)->GetZ() == z) { 599 // Don't change anything if the Z hasn't changed 600 return HWC2::Error::None; 601 } 602 current = layer_set_.erase(current); 603 layer_on_display = true; 604 break; 605 } 606 } 607 608 if (!layer_on_display) { 609 DLOGE("[%" PRIu64 "] updateLayerZ failed to find layer on display", id_); 610 return HWC2::Error::BadLayer; 611 } 612 613 layer->SetLayerZOrder(z); 614 layer_set_.emplace(layer); 615 return HWC2::Error::None; 616} 617 618HWC2::Error HWCDisplay::SetVsyncEnabled(HWC2::Vsync enabled) { 619 DLOGV("Display ID: %d enabled: %s", id_, to_string(enabled).c_str()); 620 DisplayError error = kErrorNone; 621 622 if (shutdown_pending_ || !callbacks_->VsyncCallbackRegistered()) { 623 return HWC2::Error::None; 624 } 625 626 bool state; 627 if (enabled == HWC2::Vsync::Enable) 628 state = true; 629 else if (enabled == HWC2::Vsync::Disable) 630 state = false; 631 else 632 return HWC2::Error::BadParameter; 633 634 error = display_intf_->SetVSyncState(state); 635 636 if (error != kErrorNone) { 637 if (error == kErrorShutDown) { 638 shutdown_pending_ = true; 639 return HWC2::Error::None; 640 } 641 DLOGE("Failed. enabled = %s, error = %d", to_string(enabled).c_str(), error); 642 return HWC2::Error::BadDisplay; 643 } 644 645 return HWC2::Error::None; 646} 647 648HWC2::Error HWCDisplay::SetPowerMode(HWC2::PowerMode mode) { 649 DLOGV("display = %d, mode = %s", id_, to_string(mode).c_str()); 650 DisplayState state = kStateOff; 651 bool flush_on_error = flush_on_error_; 652 653 if (shutdown_pending_) { 654 return HWC2::Error::None; 655 } 656 657 switch (mode) { 658 case HWC2::PowerMode::Off: 659 // During power off, all of the buffers are released. 660 // Do not flush until a buffer is successfully submitted again. 661 flush_on_error = false; 662 state = kStateOff; 663 if (tone_mapper_) { 664 tone_mapper_->Terminate(); 665 } 666 break; 667 case HWC2::PowerMode::On: 668 state = kStateOn; 669 last_power_mode_ = HWC2::PowerMode::On; 670 break; 671 case HWC2::PowerMode::Doze: 672 state = kStateDoze; 673 last_power_mode_ = HWC2::PowerMode::Doze; 674 break; 675 case HWC2::PowerMode::DozeSuspend: 676 state = kStateDozeSuspend; 677 last_power_mode_ = HWC2::PowerMode::DozeSuspend; 678 break; 679 default: 680 return HWC2::Error::BadParameter; 681 } 682 683 DisplayError error = display_intf_->SetDisplayState(state); 684 if (error == kErrorNone) { 685 flush_on_error_ = flush_on_error; 686 } else { 687 if (error == kErrorShutDown) { 688 shutdown_pending_ = true; 689 return HWC2::Error::None; 690 } 691 DLOGE("Set state failed. Error = %d", error); 692 return HWC2::Error::BadParameter; 693 } 694 695 return HWC2::Error::None; 696} 697 698HWC2::Error HWCDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format, 699 int32_t dataspace) { 700 DisplayConfigVariableInfo variable_config; 701 display_intf_->GetFrameBufferConfig(&variable_config); 702 // TODO(user): Support scaled configurations, other formats and other dataspaces 703 if (format != HAL_PIXEL_FORMAT_RGBA_8888 || dataspace != HAL_DATASPACE_UNKNOWN || 704 width != variable_config.x_pixels || height != variable_config.y_pixels) { 705 return HWC2::Error::Unsupported; 706 } else { 707 return HWC2::Error::None; 708 } 709} 710 711HWC2::Error HWCDisplay::GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes) { 712 if (out_modes) { 713 out_modes[0] = HAL_COLOR_MODE_NATIVE; 714 } 715 *out_num_modes = 1; 716 717 return HWC2::Error::None; 718} 719 720HWC2::Error HWCDisplay::GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs) { 721 // TODO(user): Actually handle multiple configs 722 if (out_configs == nullptr) { 723 *out_num_configs = 1; 724 } else { 725 *out_num_configs = 1; 726 out_configs[0] = 0; 727 } 728 729 return HWC2::Error::None; 730} 731 732HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute, 733 int32_t *out_value) { 734 DisplayConfigVariableInfo variable_config; 735 DisplayError error = display_intf_->GetFrameBufferConfig(&variable_config); 736 if (error != kErrorNone) { 737 DLOGV("Get variable config failed. Error = %d", error); 738 return HWC2::Error::BadDisplay; 739 } 740 741 if (config != 0) { // We only use config[0] - see TODO above 742 return HWC2::Error::BadConfig; 743 } 744 745 switch (attribute) { 746 case HWC2::Attribute::VsyncPeriod: 747 *out_value = INT32(variable_config.vsync_period_ns); 748 break; 749 case HWC2::Attribute::Width: 750 *out_value = INT32(variable_config.x_pixels); 751 break; 752 case HWC2::Attribute::Height: 753 *out_value = INT32(variable_config.y_pixels); 754 break; 755 case HWC2::Attribute::DpiX: 756 *out_value = INT32(variable_config.x_dpi * 1000.0f); 757 break; 758 case HWC2::Attribute::DpiY: 759 *out_value = INT32(variable_config.y_dpi * 1000.0f); 760 break; 761 default: 762 DLOGW("Spurious attribute type = %s", to_string(attribute).c_str()); 763 *out_value = -1; 764 return HWC2::Error::BadConfig; 765 } 766 767 return HWC2::Error::None; 768} 769 770HWC2::Error HWCDisplay::GetDisplayName(uint32_t *out_size, char *out_name) { 771 // TODO(user): Get panel name and EDID name and populate it here 772 if (out_name == nullptr) { 773 *out_size = 32; 774 } else { 775 std::string name; 776 switch (id_) { 777 case HWC_DISPLAY_PRIMARY: 778 name = "Primary Display"; 779 break; 780 case HWC_DISPLAY_EXTERNAL: 781 name = "External Display"; 782 break; 783 case HWC_DISPLAY_VIRTUAL: 784 name = "Virtual Display"; 785 break; 786 default: 787 name = "Unknown"; 788 break; 789 } 790 std::strncpy(out_name, name.c_str(), name.size()); 791 *out_size = UINT32(name.size()); 792 } 793 return HWC2::Error::None; 794} 795 796HWC2::Error HWCDisplay::GetDisplayType(int32_t *out_type) { 797 if (out_type != nullptr) { 798 if (id_ == HWC_DISPLAY_VIRTUAL) { 799 *out_type = HWC2_DISPLAY_TYPE_VIRTUAL; 800 } else { 801 *out_type = HWC2_DISPLAY_TYPE_PHYSICAL; 802 } 803 return HWC2::Error::None; 804 } else { 805 return HWC2::Error::BadParameter; 806 } 807} 808 809// TODO(user): Store configurations and hook them up here 810HWC2::Error HWCDisplay::GetActiveConfig(hwc2_config_t *out_config) { 811 if (out_config != nullptr) { 812 *out_config = 0; 813 return HWC2::Error::None; 814 } else { 815 return HWC2::Error::BadParameter; 816 } 817} 818 819HWC2::Error HWCDisplay::SetClientTarget(buffer_handle_t target, int32_t acquire_fence, 820 int32_t dataspace, hwc_region_t damage) { 821 // TODO(user): SurfaceFlinger gives us a null pointer here when doing full SDE composition 822 // The error is problematic for layer caching as it would overwrite our cached client target. 823 // Reported bug 28569722 to resolve this. 824 // For now, continue to use the last valid buffer reported to us for layer caching. 825 if (target == nullptr) { 826 return HWC2::Error::None; 827 } 828 829 if (acquire_fence == 0) { 830 DLOGE("acquire_fence is zero"); 831 return HWC2::Error::BadParameter; 832 } 833 834 client_target_->SetLayerBuffer(target, acquire_fence); 835 client_target_->SetLayerSurfaceDamage(damage); 836 // Ignoring dataspace for now 837 return HWC2::Error::None; 838} 839 840HWC2::Error HWCDisplay::SetActiveConfig(hwc2_config_t config) { 841 if (config != 0) { 842 return HWC2::Error::BadConfig; 843 } 844 // We have only one config right now - do nothing 845 return HWC2::Error::None; 846} 847 848DisplayError HWCDisplay::SetMixerResolution(uint32_t width, uint32_t height) { 849 return kErrorNotSupported; 850} 851 852void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) { 853 dump_frame_count_ = count; 854 dump_frame_index_ = 0; 855 dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0); 856 857 if (tone_mapper_) { 858 tone_mapper_->SetFrameDumpConfig(count); 859 } 860 861 DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_); 862} 863 864HWC2::PowerMode HWCDisplay::GetLastPowerMode() { 865 return last_power_mode_; 866} 867 868DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) { 869 callbacks_->Vsync(id_, vsync.timestamp); 870 return kErrorNone; 871} 872 873DisplayError HWCDisplay::Refresh() { 874 return kErrorNotSupported; 875} 876 877DisplayError HWCDisplay::CECMessage(char *message) { 878 if (qservice_) { 879 qservice_->onCECMessageReceived(message, 0); 880 } else { 881 DLOGW("Qservice instance not available."); 882 } 883 884 return kErrorNone; 885} 886 887HWC2::Error HWCDisplay::PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests) { 888 layer_changes_.clear(); 889 layer_requests_.clear(); 890 if (shutdown_pending_) { 891 return HWC2::Error::BadDisplay; 892 } 893 894 if (!skip_prepare_) { 895 DisplayError error = display_intf_->Prepare(&layer_stack_); 896 if (error != kErrorNone) { 897 if (error == kErrorShutDown) { 898 shutdown_pending_ = true; 899 } else if (error != kErrorPermission) { 900 DLOGE("Prepare failed. Error = %d", error); 901 // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() 902 // so that previous buffer and fences are released, and override the error. 903 flush_ = true; 904 } 905 return HWC2::Error::BadDisplay; 906 } 907 } else { 908 // Skip is not set 909 MarkLayersForGPUBypass(); 910 skip_prepare_ = false; 911 DLOGI("SecureDisplay %s, Skip Prepare/Commit and Flush", 912 secure_display_active_ ? "Starting" : "Stopping"); 913 flush_ = true; 914 } 915 916 for (auto hwc_layer : layer_set_) { 917 Layer *layer = hwc_layer->GetSDMLayer(); 918 LayerComposition &composition = layer->composition; 919 920 if ((composition == kCompositionSDE) || (composition == kCompositionHybrid) || 921 (composition == kCompositionBlit)) { 922 layer_requests_[hwc_layer->GetId()] = HWC2::LayerRequest::ClearClientTarget; 923 } 924 925 HWC2::Composition requested_composition = hwc_layer->GetClientRequestedCompositionType(); 926 // Set SDM composition to HWC2 type in HWCLayer 927 hwc_layer->SetComposition(composition); 928 HWC2::Composition device_composition = hwc_layer->GetDeviceSelectedCompositionType(); 929 // Update the changes list only if the requested composition is different from SDM comp type 930 // TODO(user): Take Care of other comptypes(BLIT) 931 if (requested_composition != device_composition) { 932 layer_changes_[hwc_layer->GetId()] = device_composition; 933 } 934 } 935 *out_num_types = UINT32(layer_changes_.size()); 936 *out_num_requests = UINT32(layer_requests_.size()); 937 validated_ = true; 938 if (*out_num_types > 0) { 939 return HWC2::Error::HasChanges; 940 } else { 941 return HWC2::Error::None; 942 } 943} 944 945HWC2::Error HWCDisplay::AcceptDisplayChanges() { 946 if (layer_set_.empty()) { 947 return HWC2::Error::None; 948 } 949 950 if (!validated_) { 951 return HWC2::Error::NotValidated; 952 } 953 954 for (const auto& change : layer_changes_) { 955 auto hwc_layer = layer_map_[change.first]; 956 auto composition = change.second; 957 if (hwc_layer != nullptr) { 958 hwc_layer->UpdateClientCompositionType(composition); 959 } else { 960 DLOGW("Invalid layer: %" PRIu64, change.first); 961 } 962 } 963 return HWC2::Error::None; 964} 965 966HWC2::Error HWCDisplay::GetChangedCompositionTypes(uint32_t *out_num_elements, 967 hwc2_layer_t *out_layers, int32_t *out_types) { 968 if (layer_set_.empty()) { 969 return HWC2::Error::None; 970 } 971 972 if (!validated_) { 973 DLOGW("Display is not validated"); 974 return HWC2::Error::NotValidated; 975 } 976 *out_num_elements = UINT32(layer_changes_.size()); 977 if (out_layers != nullptr && out_types != nullptr) { 978 int i = 0; 979 for (auto change : layer_changes_) { 980 out_layers[i] = change.first; 981 out_types[i] = INT32(change.second); 982 i++; 983 } 984 } 985 return HWC2::Error::None; 986} 987 988HWC2::Error HWCDisplay::GetReleaseFences(uint32_t *out_num_elements, hwc2_layer_t *out_layers, 989 int32_t *out_fences) { 990 if (out_layers != nullptr && out_fences != nullptr) { 991 int i = 0; 992 for (auto hwc_layer : layer_set_) { 993 out_layers[i] = hwc_layer->GetId(); 994 out_fences[i] = hwc_layer->PopReleaseFence(); 995 i++; 996 } 997 } 998 *out_num_elements = UINT32(layer_set_.size()); 999 return HWC2::Error::None; 1000} 1001 1002HWC2::Error HWCDisplay::GetDisplayRequests(int32_t *out_display_requests, 1003 uint32_t *out_num_elements, hwc2_layer_t *out_layers, 1004 int32_t *out_layer_requests) { 1005 // No display requests for now 1006 // Use for sharing blit buffers and 1007 // writing wfd buffer directly to output if there is full GPU composition 1008 // and no color conversion needed 1009 if (layer_set_.empty()) { 1010 return HWC2::Error::None; 1011 } 1012 1013 if (!validated_) { 1014 DLOGW("Display is not validated"); 1015 return HWC2::Error::NotValidated; 1016 } 1017 *out_display_requests = 0; 1018 *out_num_elements = UINT32(layer_requests_.size()); 1019 if (out_layers != nullptr && out_layer_requests != nullptr) { 1020 int i = 0; 1021 for (auto &request : layer_requests_) { 1022 out_layers[i] = request.first; 1023 out_layer_requests[i] = INT32(request.second); 1024 i++; 1025 } 1026 } 1027 1028 auto client_target_layer = client_target_->GetSDMLayer(); 1029 if (client_target_layer->request.flags.flip_buffer) { 1030 *out_display_requests = INT32(HWC2::DisplayRequest::FlipClientTarget); 1031 } 1032 1033 return HWC2::Error::None; 1034} 1035 1036HWC2::Error HWCDisplay::GetHdrCapabilities(uint32_t *out_num_types, int32_t *out_types, 1037 float *out_max_luminance, 1038 float *out_max_average_luminance, 1039 float *out_min_luminance) { 1040 DisplayConfigFixedInfo fixed_info = {}; 1041 display_intf_->GetConfig(&fixed_info); 1042 1043 if (!fixed_info.hdr_supported) { 1044 *out_num_types = 0; 1045 DLOGI("HDR is not supported"); 1046 return HWC2::Error::None; 1047 } 1048 1049 if (out_types == nullptr) { 1050 // 1(now) - because we support only HDR10, change when HLG & DOLBY vision are supported 1051 *out_num_types = 1; 1052 } else { 1053 // Only HDR10 supported 1054 *out_types = HAL_HDR_HDR10; 1055 static const float kLuminanceFactor = 10000.0; 1056 // luminance is expressed in the unit of 0.0001 cd/m2, convert it to 1cd/m2. 1057 *out_max_luminance = FLOAT(fixed_info.max_luminance)/kLuminanceFactor; 1058 *out_max_average_luminance = FLOAT(fixed_info.average_luminance)/kLuminanceFactor; 1059 *out_min_luminance = FLOAT(fixed_info.min_luminance)/kLuminanceFactor; 1060 } 1061 1062 return HWC2::Error::None; 1063} 1064 1065 1066HWC2::Error HWCDisplay::CommitLayerStack(void) { 1067 if (shutdown_pending_ || layer_set_.empty()) { 1068 return HWC2::Error::None; 1069 } 1070 1071 if (!validated_) { 1072 DLOGW("Display is not validated"); 1073 return HWC2::Error::NotValidated; 1074 } 1075 1076 DumpInputBuffers(); 1077 1078 if (!flush_) { 1079 DisplayError error = kErrorUndefined; 1080 int status = 0; 1081 if (tone_mapper_) { 1082 if (layer_stack_.flags.hdr_present) { 1083 status = tone_mapper_->HandleToneMap(&layer_stack_); 1084 if (status != 0) { 1085 DLOGE("Error handling HDR in ToneMapper"); 1086 } 1087 } else { 1088 tone_mapper_->Terminate(); 1089 } 1090 } 1091 error = display_intf_->Commit(&layer_stack_); 1092 validated_ = false; 1093 1094 if (error == kErrorNone) { 1095 // A commit is successfully submitted, start flushing on failure now onwards. 1096 flush_on_error_ = true; 1097 } else { 1098 if (error == kErrorShutDown) { 1099 shutdown_pending_ = true; 1100 return HWC2::Error::Unsupported; 1101 } else if (error != kErrorPermission) { 1102 DLOGE("Commit failed. Error = %d", error); 1103 // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() 1104 // so that previous buffer and fences are released, and override the error. 1105 flush_ = true; 1106 } 1107 } 1108 } 1109 1110 return HWC2::Error::None; 1111} 1112 1113HWC2::Error HWCDisplay::PostCommitLayerStack(int32_t *out_retire_fence) { 1114 auto status = HWC2::Error::None; 1115 1116 // Do no call flush on errors, if a successful buffer is never submitted. 1117 if (flush_ && flush_on_error_) { 1118 display_intf_->Flush(); 1119 } 1120 1121 if (tone_mapper_ && tone_mapper_->IsActive()) { 1122 tone_mapper_->PostCommit(&layer_stack_); 1123 } 1124 1125 // TODO(user): No way to set the client target release fence on SF 1126 int32_t &client_target_release_fence = 1127 client_target_->GetSDMLayer()->input_buffer.release_fence_fd; 1128 if (client_target_release_fence >= 0) { 1129 close(client_target_release_fence); 1130 client_target_release_fence = -1; 1131 } 1132 1133 for (auto hwc_layer : layer_set_) { 1134 hwc_layer->ResetGeometryChanges(); 1135 Layer *layer = hwc_layer->GetSDMLayer(); 1136 LayerBuffer *layer_buffer = &layer->input_buffer; 1137 1138 if (!flush_) { 1139 // If swapinterval property is set to 0 or for single buffer layers, do not update f/w 1140 // release fences and discard fences from driver 1141 if (swap_interval_zero_ || layer->flags.single_buffer) { 1142 close(layer_buffer->release_fence_fd); 1143 layer_buffer->release_fence_fd = -1; 1144 } else if (layer->composition != kCompositionGPU) { 1145 hwc_layer->PushReleaseFence(layer_buffer->release_fence_fd); 1146 layer_buffer->release_fence_fd = -1; 1147 } else { 1148 hwc_layer->PushReleaseFence(-1); 1149 } 1150 } 1151 1152 if (layer_buffer->acquire_fence_fd >= 0) { 1153 close(layer_buffer->acquire_fence_fd); 1154 layer_buffer->acquire_fence_fd = -1; 1155 } 1156 } 1157 1158 *out_retire_fence = -1; 1159 if (!flush_) { 1160 // if swapinterval property is set to 0 then close and reset the list retire fence 1161 if (swap_interval_zero_) { 1162 close(layer_stack_.retire_fence_fd); 1163 layer_stack_.retire_fence_fd = -1; 1164 } 1165 *out_retire_fence = layer_stack_.retire_fence_fd; 1166 1167 if (dump_frame_count_) { 1168 dump_frame_count_--; 1169 dump_frame_index_++; 1170 } 1171 } 1172 1173 geometry_changes_ = GeometryChanges::kNone; 1174 flush_ = false; 1175 1176 ClearRequestFlags(); 1177 1178 return status; 1179} 1180 1181void HWCDisplay::SetIdleTimeoutMs(uint32_t timeout_ms) { 1182 return; 1183} 1184 1185DisplayError HWCDisplay::SetMaxMixerStages(uint32_t max_mixer_stages) { 1186 DisplayError error = kErrorNone; 1187 1188 if (display_intf_) { 1189 error = display_intf_->SetMaxMixerStages(max_mixer_stages); 1190 } 1191 1192 return error; 1193} 1194 1195LayerBufferFormat HWCDisplay::GetSDMFormat(const int32_t &source, const int flags) { 1196 LayerBufferFormat format = kFormatInvalid; 1197 if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { 1198 switch (source) { 1199 case HAL_PIXEL_FORMAT_RGBA_8888: 1200 format = kFormatRGBA8888Ubwc; 1201 break; 1202 case HAL_PIXEL_FORMAT_RGBX_8888: 1203 format = kFormatRGBX8888Ubwc; 1204 break; 1205 case HAL_PIXEL_FORMAT_BGR_565: 1206 format = kFormatBGR565Ubwc; 1207 break; 1208 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: 1209 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: 1210 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: 1211 format = kFormatYCbCr420SPVenusUbwc; 1212 break; 1213 case HAL_PIXEL_FORMAT_RGBA_1010102: 1214 format = kFormatRGBA1010102Ubwc; 1215 break; 1216 case HAL_PIXEL_FORMAT_RGBX_1010102: 1217 format = kFormatRGBX1010102Ubwc; 1218 break; 1219 case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: 1220 format = kFormatYCbCr420TP10Ubwc; 1221 break; 1222 case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: 1223 format = kFormatYCbCr420P010Ubwc; 1224 break; 1225 default: 1226 DLOGE("Unsupported format type for UBWC %d", source); 1227 return kFormatInvalid; 1228 } 1229 return format; 1230 } 1231 1232 switch (source) { 1233 case HAL_PIXEL_FORMAT_RGBA_8888: 1234 format = kFormatRGBA8888; 1235 break; 1236 case HAL_PIXEL_FORMAT_RGBA_5551: 1237 format = kFormatRGBA5551; 1238 break; 1239 case HAL_PIXEL_FORMAT_RGBA_4444: 1240 format = kFormatRGBA4444; 1241 break; 1242 case HAL_PIXEL_FORMAT_BGRA_8888: 1243 format = kFormatBGRA8888; 1244 break; 1245 case HAL_PIXEL_FORMAT_RGBX_8888: 1246 format = kFormatRGBX8888; 1247 break; 1248 case HAL_PIXEL_FORMAT_BGRX_8888: 1249 format = kFormatBGRX8888; 1250 break; 1251 case HAL_PIXEL_FORMAT_RGB_888: 1252 format = kFormatRGB888; 1253 break; 1254 case HAL_PIXEL_FORMAT_RGB_565: 1255 format = kFormatRGB565; 1256 break; 1257 case HAL_PIXEL_FORMAT_BGR_565: 1258 format = kFormatBGR565; 1259 break; 1260 case HAL_PIXEL_FORMAT_BGR_888: 1261 format = kFormatBGR888; 1262 break; 1263 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: 1264 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: 1265 format = kFormatYCbCr420SemiPlanarVenus; 1266 break; 1267 case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS: 1268 format = kFormatYCrCb420SemiPlanarVenus; 1269 break; 1270 case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC: 1271 format = kFormatYCbCr420SPVenusUbwc; 1272 break; 1273 case HAL_PIXEL_FORMAT_YV12: 1274 format = kFormatYCrCb420PlanarStride16; 1275 break; 1276 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 1277 format = kFormatYCrCb420SemiPlanar; 1278 break; 1279 case HAL_PIXEL_FORMAT_YCbCr_420_SP: 1280 format = kFormatYCbCr420SemiPlanar; 1281 break; 1282 case HAL_PIXEL_FORMAT_YCbCr_422_SP: 1283 format = kFormatYCbCr422H2V1SemiPlanar; 1284 break; 1285 case HAL_PIXEL_FORMAT_YCbCr_422_I: 1286 format = kFormatYCbCr422H2V1Packed; 1287 break; 1288 case HAL_PIXEL_FORMAT_CbYCrY_422_I: 1289 format = kFormatCbYCrY422H2V1Packed; 1290 break; 1291 case HAL_PIXEL_FORMAT_RGBA_1010102: 1292 format = kFormatRGBA1010102; 1293 break; 1294 case HAL_PIXEL_FORMAT_ARGB_2101010: 1295 format = kFormatARGB2101010; 1296 break; 1297 case HAL_PIXEL_FORMAT_RGBX_1010102: 1298 format = kFormatRGBX1010102; 1299 break; 1300 case HAL_PIXEL_FORMAT_XRGB_2101010: 1301 format = kFormatXRGB2101010; 1302 break; 1303 case HAL_PIXEL_FORMAT_BGRA_1010102: 1304 format = kFormatBGRA1010102; 1305 break; 1306 case HAL_PIXEL_FORMAT_ABGR_2101010: 1307 format = kFormatABGR2101010; 1308 break; 1309 case HAL_PIXEL_FORMAT_BGRX_1010102: 1310 format = kFormatBGRX1010102; 1311 break; 1312 case HAL_PIXEL_FORMAT_XBGR_2101010: 1313 format = kFormatXBGR2101010; 1314 break; 1315 case HAL_PIXEL_FORMAT_YCbCr_420_P010: 1316 format = kFormatYCbCr420P010; 1317 break; 1318 case HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC: 1319 format = kFormatYCbCr420TP10Ubwc; 1320 break; 1321 case HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC: 1322 format = kFormatYCbCr420P010Ubwc; 1323 break; 1324 default: 1325 DLOGW("Unsupported format type = %d", source); 1326 return kFormatInvalid; 1327 } 1328 1329 return format; 1330} 1331 1332void HWCDisplay::DumpInputBuffers() { 1333 char dir_path[PATH_MAX]; 1334 1335 if (!dump_frame_count_ || flush_ || !dump_input_layers_) { 1336 return; 1337 } 1338 1339 snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString()); 1340 1341 if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) { 1342 DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); 1343 return; 1344 } 1345 1346 // if directory exists already, need to explicitly change the permission. 1347 if (errno == EEXIST && chmod(dir_path, 0777) != 0) { 1348 DLOGW("Failed to change permissions on %s directory", dir_path); 1349 return; 1350 } 1351 1352 for (uint32_t i = 0; i < layer_stack_.layers.size(); i++) { 1353 auto layer = layer_stack_.layers.at(i); 1354 const private_handle_t *pvt_handle = 1355 reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id); 1356 auto acquire_fence_fd = layer->input_buffer.acquire_fence_fd; 1357 1358 if (acquire_fence_fd >= 0) { 1359 int error = sync_wait(acquire_fence_fd, 1000); 1360 if (error < 0) { 1361 DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); 1362 return; 1363 } 1364 } 1365 1366 if (pvt_handle && pvt_handle->base) { 1367 char dump_file_name[PATH_MAX]; 1368 size_t result = 0; 1369 1370 snprintf(dump_file_name, sizeof(dump_file_name), "%s/input_layer%d_%dx%d_%s_frame%d.raw", 1371 dir_path, i, pvt_handle->width, pvt_handle->height, 1372 qdutils::GetHALPixelFormatString(pvt_handle->format), dump_frame_index_); 1373 1374 FILE *fp = fopen(dump_file_name, "w+"); 1375 if (fp) { 1376 result = fwrite(reinterpret_cast<void *>(pvt_handle->base), pvt_handle->size, 1, fp); 1377 fclose(fp); 1378 } 1379 1380 DLOGI("Frame Dump %s: is %s", dump_file_name, result ? "Successful" : "Failed"); 1381 } 1382 } 1383} 1384 1385void HWCDisplay::DumpOutputBuffer(const BufferInfo &buffer_info, void *base, int fence) { 1386 char dir_path[PATH_MAX]; 1387 1388 snprintf(dir_path, sizeof(dir_path), "/data/misc/display/frame_dump_%s", GetDisplayString()); 1389 1390 if (mkdir(dir_path, 777) != 0 && errno != EEXIST) { 1391 DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno)); 1392 return; 1393 } 1394 1395 // if directory exists already, need to explicitly change the permission. 1396 if (errno == EEXIST && chmod(dir_path, 0777) != 0) { 1397 DLOGW("Failed to change permissions on %s directory", dir_path); 1398 return; 1399 } 1400 1401 if (base) { 1402 char dump_file_name[PATH_MAX]; 1403 size_t result = 0; 1404 1405 if (fence >= 0) { 1406 int error = sync_wait(fence, 1000); 1407 if (error < 0) { 1408 DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); 1409 return; 1410 } 1411 } 1412 1413 snprintf(dump_file_name, sizeof(dump_file_name), "%s/output_layer_%dx%d_%s_frame%d.raw", 1414 dir_path, buffer_info.buffer_config.width, buffer_info.buffer_config.height, 1415 GetFormatString(buffer_info.buffer_config.format), dump_frame_index_); 1416 1417 FILE *fp = fopen(dump_file_name, "w+"); 1418 if (fp) { 1419 result = fwrite(base, buffer_info.alloc_buffer_info.size, 1, fp); 1420 fclose(fp); 1421 } 1422 1423 DLOGI("Frame Dump of %s is %s", dump_file_name, result ? "Successful" : "Failed"); 1424 } 1425} 1426 1427const char *HWCDisplay::GetDisplayString() { 1428 switch (type_) { 1429 case kPrimary: 1430 return "primary"; 1431 case kHDMI: 1432 return "hdmi"; 1433 case kVirtual: 1434 return "virtual"; 1435 default: 1436 return "invalid"; 1437 } 1438} 1439 1440int HWCDisplay::SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) { 1441 if (x_pixels <= 0 || y_pixels <= 0) { 1442 DLOGW("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels); 1443 return -EINVAL; 1444 } 1445 1446 DisplayConfigVariableInfo fb_config; 1447 DisplayError error = display_intf_->GetFrameBufferConfig(&fb_config); 1448 if (error != kErrorNone) { 1449 DLOGV("Get frame buffer config failed. Error = %d", error); 1450 return -EINVAL; 1451 } 1452 1453 fb_config.x_pixels = x_pixels; 1454 fb_config.y_pixels = y_pixels; 1455 1456 error = display_intf_->SetFrameBufferConfig(fb_config); 1457 if (error != kErrorNone) { 1458 DLOGV("Set frame buffer config failed. Error = %d", error); 1459 return -EINVAL; 1460 } 1461 1462 // Create rects to represent the new source and destination crops 1463 LayerRect crop = LayerRect(0, 0, FLOAT(x_pixels), FLOAT(y_pixels)); 1464 LayerRect dst = LayerRect(0, 0, FLOAT(fb_config.x_pixels), FLOAT(fb_config.y_pixels)); 1465 auto client_target_layer = client_target_->GetSDMLayer(); 1466 client_target_layer->src_rect = crop; 1467 client_target_layer->dst_rect = dst; 1468 1469 int aligned_width; 1470 int aligned_height; 1471 uint32_t usage = GRALLOC_USAGE_HW_FB; 1472 int format = HAL_PIXEL_FORMAT_RGBA_8888; 1473 int ubwc_enabled = 0; 1474 int flags = 0; 1475 HWCDebugHandler::Get()->GetProperty("debug.gralloc.enable_fb_ubwc", &ubwc_enabled); 1476 if (ubwc_enabled == 1) { 1477 usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC; 1478 flags |= private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; 1479 } 1480 1481#ifdef USE_GRALLOC1 1482 buffer_allocator_->GetAlignedWidthAndHeight(INT(x_pixels), INT(y_pixels), format, usage, 1483 &aligned_width, &aligned_height); 1484#else 1485 AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(INT(x_pixels), INT(y_pixels), format, 1486 INT(usage), aligned_width, aligned_height); 1487#endif 1488 1489 // TODO(user): How does the dirty region get set on the client target? File bug on Google 1490 client_target_layer->composition = kCompositionGPUTarget; 1491 client_target_layer->input_buffer.format = GetSDMFormat(format, flags); 1492 client_target_layer->input_buffer.width = UINT32(aligned_width); 1493 client_target_layer->input_buffer.height = UINT32(aligned_height); 1494 client_target_layer->input_buffer.unaligned_width = x_pixels; 1495 client_target_layer->input_buffer.unaligned_height = y_pixels; 1496 client_target_layer->plane_alpha = 255; 1497 1498 DLOGI("New framebuffer resolution (%dx%d)", fb_config.x_pixels, fb_config.y_pixels); 1499 1500 return 0; 1501} 1502 1503void HWCDisplay::GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels) { 1504 DisplayConfigVariableInfo fb_config; 1505 display_intf_->GetFrameBufferConfig(&fb_config); 1506 1507 *x_pixels = fb_config.x_pixels; 1508 *y_pixels = fb_config.y_pixels; 1509} 1510 1511DisplayError HWCDisplay::GetMixerResolution(uint32_t *x_pixels, uint32_t *y_pixels) { 1512 return display_intf_->GetMixerResolution(x_pixels, y_pixels); 1513} 1514 1515void HWCDisplay::GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels) { 1516 DisplayConfigVariableInfo display_config; 1517 uint32_t active_index = 0; 1518 1519 display_intf_->GetActiveConfig(&active_index); 1520 display_intf_->GetConfig(active_index, &display_config); 1521 1522 *x_pixels = display_config.x_pixels; 1523 *y_pixels = display_config.y_pixels; 1524} 1525 1526int HWCDisplay::SetDisplayStatus(uint32_t display_status) { 1527 int status = 0; 1528 1529 switch (display_status) { 1530 case kDisplayStatusResume: 1531 display_paused_ = false; 1532 case kDisplayStatusOnline: 1533 status = INT32(SetPowerMode(HWC2::PowerMode::On)); 1534 break; 1535 case kDisplayStatusPause: 1536 display_paused_ = true; 1537 case kDisplayStatusOffline: 1538 status = INT32(SetPowerMode(HWC2::PowerMode::Off)); 1539 break; 1540 default: 1541 DLOGW("Invalid display status %d", display_status); 1542 return -EINVAL; 1543 } 1544 1545 if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) { 1546 callbacks_->Refresh(HWC_DISPLAY_PRIMARY); 1547 } 1548 1549 return status; 1550} 1551 1552HWC2::Error HWCDisplay::SetCursorPosition(hwc2_layer_t layer, int x, int y) { 1553 if (shutdown_pending_) { 1554 return HWC2::Error::None; 1555 } 1556 1557 if (GetHWCLayer(layer) == nullptr) { 1558 return HWC2::Error::BadLayer; 1559 } 1560 1561 DisplayState state; 1562 if (display_intf_->GetDisplayState(&state) == kErrorNone) { 1563 if (state != kStateOn) { 1564 return HWC2::Error::None; 1565 } 1566 } 1567 1568 if (!validated_) { 1569 return HWC2::Error::NotValidated; 1570 } 1571 1572 auto error = display_intf_->SetCursorPosition(x, y); 1573 if (error != kErrorNone) { 1574 if (error == kErrorShutDown) { 1575 shutdown_pending_ = true; 1576 return HWC2::Error::None; 1577 } 1578 1579 DLOGE("Failed for x = %d y = %d, Error = %d", x, y, error); 1580 return HWC2::Error::BadDisplay; 1581 } 1582 1583 return HWC2::Error::None; 1584} 1585 1586int HWCDisplay::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) { 1587 DisplayError error = display_intf_->OnMinHdcpEncryptionLevelChange(min_enc_level); 1588 if (error != kErrorNone) { 1589 DLOGE("Failed. Error = %d", error); 1590 return -1; 1591 } 1592 1593 return 0; 1594} 1595 1596void HWCDisplay::MarkLayersForGPUBypass() { 1597 for (auto hwc_layer : layer_set_) { 1598 auto layer = hwc_layer->GetSDMLayer(); 1599 layer->composition = kCompositionSDE; 1600 } 1601} 1602 1603void HWCDisplay::MarkLayersForClientComposition() { 1604 // ClientComposition - GPU comp, to acheive this, set skip flag so that 1605 // SDM does not handle this layer and hwc_layer composition will be 1606 // set correctly at the end of Prepare. 1607 for (auto hwc_layer : layer_set_) { 1608 Layer *layer = hwc_layer->GetSDMLayer(); 1609 layer->flags.skip = true; 1610 } 1611} 1612 1613void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) { 1614} 1615 1616int HWCDisplay::SetPanelBrightness(int level) { 1617 int ret = 0; 1618 if (display_intf_) 1619 ret = display_intf_->SetPanelBrightness(level); 1620 else 1621 ret = -EINVAL; 1622 1623 return ret; 1624} 1625 1626int HWCDisplay::GetPanelBrightness(int *level) { 1627 return display_intf_->GetPanelBrightness(level); 1628} 1629 1630int HWCDisplay::ToggleScreenUpdates(bool enable) { 1631 display_paused_ = enable ? false : true; 1632 callbacks_->Refresh(HWC_DISPLAY_PRIMARY); 1633 return 0; 1634} 1635 1636int HWCDisplay::ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, 1637 PPDisplayAPIPayload *out_payload, 1638 PPPendingParams *pending_action) { 1639 int ret = 0; 1640 1641 if (display_intf_) 1642 ret = display_intf_->ColorSVCRequestRoute(in_payload, out_payload, pending_action); 1643 else 1644 ret = -EINVAL; 1645 1646 return ret; 1647} 1648 1649void HWCDisplay::SolidFillPrepare() { 1650 if (solid_fill_enable_) { 1651 if (solid_fill_layer_ == NULL) { 1652 // Create a dummy layer here 1653 solid_fill_layer_ = new Layer(); 1654 } 1655 uint32_t primary_width = 0, primary_height = 0; 1656 GetMixerResolution(&primary_width, &primary_height); 1657 1658 LayerBuffer *layer_buffer = &solid_fill_layer_->input_buffer; 1659 layer_buffer->width = primary_width; 1660 layer_buffer->height = primary_height; 1661 layer_buffer->unaligned_width = primary_width; 1662 layer_buffer->unaligned_height = primary_height; 1663 layer_buffer->acquire_fence_fd = -1; 1664 layer_buffer->release_fence_fd = -1; 1665 1666 LayerRect rect; 1667 rect.top = 0; rect.left = 0; 1668 rect.right = primary_width; 1669 rect.bottom = primary_height; 1670 1671 solid_fill_layer_->composition = kCompositionGPU; 1672 solid_fill_layer_->src_rect = rect; 1673 solid_fill_layer_->dst_rect = rect; 1674 1675 solid_fill_layer_->blending = kBlendingPremultiplied; 1676 solid_fill_layer_->solid_fill_color = solid_fill_color_; 1677 solid_fill_layer_->frame_rate = 60; 1678 solid_fill_layer_->visible_regions.push_back(solid_fill_layer_->dst_rect); 1679 solid_fill_layer_->flags.updating = 1; 1680 solid_fill_layer_->flags.solid_fill = true; 1681 } else { 1682 // delete the dummy layer 1683 delete solid_fill_layer_; 1684 solid_fill_layer_ = NULL; 1685 } 1686 1687 if (solid_fill_enable_ && solid_fill_layer_) { 1688 BuildSolidFillStack(); 1689 MarkLayersForGPUBypass(); 1690 } 1691 1692 return; 1693} 1694 1695void HWCDisplay::SolidFillCommit() { 1696 if (solid_fill_enable_ && solid_fill_layer_) { 1697 LayerBuffer *layer_buffer = &solid_fill_layer_->input_buffer; 1698 if (layer_buffer->release_fence_fd > 0) { 1699 close(layer_buffer->release_fence_fd); 1700 layer_buffer->release_fence_fd = -1; 1701 } 1702 if (layer_stack_.retire_fence_fd > 0) { 1703 close(layer_stack_.retire_fence_fd); 1704 layer_stack_.retire_fence_fd = -1; 1705 } 1706 } 1707} 1708 1709int HWCDisplay::GetVisibleDisplayRect(hwc_rect_t *visible_rect) { 1710 if (!IsValid(display_rect_)) { 1711 return -EINVAL; 1712 } 1713 1714 visible_rect->left = INT(display_rect_.left); 1715 visible_rect->top = INT(display_rect_.top); 1716 visible_rect->right = INT(display_rect_.right); 1717 visible_rect->bottom = INT(display_rect_.bottom); 1718 DLOGI("Dpy = %d Visible Display Rect(%d %d %d %d)", visible_rect->left, visible_rect->top, 1719 visible_rect->right, visible_rect->bottom); 1720 1721 return 0; 1722} 1723 1724void HWCDisplay::SetSecureDisplay(bool secure_display_active) { 1725 secure_display_active_ = secure_display_active; 1726 return; 1727} 1728 1729int HWCDisplay::SetActiveDisplayConfig(int config) { 1730 return display_intf_->SetActiveConfig(UINT32(config)) == kErrorNone ? 0 : -1; 1731} 1732 1733int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) { 1734 return display_intf_->GetActiveConfig(config) == kErrorNone ? 0 : -1; 1735} 1736 1737int HWCDisplay::GetDisplayConfigCount(uint32_t *count) { 1738 return display_intf_->GetNumVariableInfoConfigs(count) == kErrorNone ? 0 : -1; 1739} 1740 1741int HWCDisplay::GetDisplayAttributesForConfig(int config, 1742 DisplayConfigVariableInfo *display_attributes) { 1743 return display_intf_->GetConfig(UINT32(config), display_attributes) == kErrorNone ? 0 : -1; 1744} 1745 1746bool HWCDisplay::SingleLayerUpdating(void) { 1747 uint32_t updating_count = 0; 1748 1749 for (uint i = 0; i < layer_stack_.layers.size(); i++) { 1750 auto layer = layer_stack_.layers.at(i); 1751 if (layer->flags.updating) { 1752 updating_count++; 1753 } 1754 } 1755 1756 return (updating_count == 1); 1757} 1758 1759bool HWCDisplay::IsLayerUpdating(const Layer *layer) { 1760 // Layer should be considered updating if 1761 // a) layer is in single buffer mode, or 1762 // b) valid dirty_regions(android specific hint for updating status), or 1763 // c) layer stack geometry has changed (TODO(user): Remove when SDM accepts 1764 // geometry_changed as bit fields). 1765 return (layer->flags.single_buffer || IsSurfaceUpdated(layer->dirty_regions) || 1766 geometry_changes_); 1767} 1768 1769bool HWCDisplay::IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions) { 1770 // based on dirty_regions determine if its updating 1771 // dirty_rect count = 0 - whole layer - updating. 1772 // dirty_rect count = 1 or more valid rects - updating. 1773 // dirty_rect count = 1 with (0,0,0,0) - not updating. 1774 return (dirty_regions.empty() || IsValid(dirty_regions.at(0))); 1775} 1776 1777uint32_t HWCDisplay::SanitizeRefreshRate(uint32_t req_refresh_rate) { 1778 uint32_t refresh_rate = req_refresh_rate; 1779 1780 if (refresh_rate < min_refresh_rate_) { 1781 // Pick the next multiple of request which is within the range 1782 refresh_rate = 1783 (((min_refresh_rate_ / refresh_rate) + ((min_refresh_rate_ % refresh_rate) ? 1 : 0)) * 1784 refresh_rate); 1785 } 1786 1787 if (refresh_rate > max_refresh_rate_) { 1788 refresh_rate = max_refresh_rate_; 1789 } 1790 1791 return refresh_rate; 1792} 1793 1794DisplayClass HWCDisplay::GetDisplayClass() { 1795 return display_class_; 1796} 1797 1798void HWCDisplay::CloseAcquireFds() { 1799 for (auto hwc_layer : layer_set_) { 1800 auto layer = hwc_layer->GetSDMLayer(); 1801 if (layer->input_buffer.acquire_fence_fd >= 0) { 1802 close(layer->input_buffer.acquire_fence_fd); 1803 layer->input_buffer.acquire_fence_fd = -1; 1804 } 1805 } 1806 int32_t &client_target_acquire_fence = 1807 client_target_->GetSDMLayer()->input_buffer.acquire_fence_fd; 1808 if (client_target_acquire_fence >= 0) { 1809 close(client_target_acquire_fence); 1810 client_target_acquire_fence = -1; 1811 } 1812} 1813 1814void HWCDisplay::ClearRequestFlags() { 1815 for (Layer *layer : layer_stack_.layers) { 1816 layer->request.flags = {}; 1817 } 1818} 1819 1820std::string HWCDisplay::Dump() { 1821 std::ostringstream os; 1822 os << "-------------------------------" << std::endl; 1823 os << "HWC2 display_id: " << id_ << std::endl; 1824 for (auto layer : layer_set_) { 1825 auto sdm_layer = layer->GetSDMLayer(); 1826 auto transform = sdm_layer->transform; 1827 os << "layer: " << std::setw(4) << layer->GetId(); 1828 os << " z: " << layer->GetZ(); 1829 os << " compositon: " << 1830 to_string(layer->GetClientRequestedCompositionType()).c_str(); 1831 os << "/" << 1832 to_string(layer->GetDeviceSelectedCompositionType()).c_str(); 1833 os << " alpha: " << std::to_string(sdm_layer->plane_alpha).c_str(); 1834 os << " format: " << std::setw(22) << GetFormatString(sdm_layer->input_buffer.format); 1835 os << " dataspace:" << std::hex << "0x" << std::setw(8) << std::setfill('0') 1836 << layer->GetLayerDataspace() << std::dec << std::setfill(' '); 1837 os << " transform: " << transform.rotation << "/" << transform.flip_horizontal << 1838 "/"<< transform.flip_vertical; 1839 os << " buffer_id: " << std::hex << "0x" << sdm_layer->input_buffer.buffer_id << std::dec 1840 << std::endl; 1841 } 1842 if (color_mode_) { 1843 color_mode_->Dump(&os); 1844 } 1845 os << "-------------------------------" << std::endl; 1846 return os.str(); 1847} 1848} // namespace sdm 1849