DisplayError ResourceDefault::Init() { DisplayError error = kErrorNone; num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe; if (!num_pipe_) { DLOGE("Number of H/W pipes is Zero!"); return kErrorParameters; } src_pipes_.resize(num_pipe_); // Priority order of pipes: VIG, RGB, DMA uint32_t vig_index = 0; uint32_t rgb_index = hw_res_info_.num_vig_pipe; uint32_t dma_index = rgb_index + hw_res_info_.num_rgb_pipe; for (uint32_t i = 0; i < num_pipe_; i++) { const HWPipeCaps &pipe_caps = hw_res_info_.hw_pipes.at(i); if (pipe_caps.type == kPipeTypeVIG) { src_pipes_[vig_index].type = kPipeTypeVIG; src_pipes_[vig_index].index = i; src_pipes_[vig_index].mdss_pipe_id = pipe_caps.id; vig_index++; } else if (pipe_caps.type == kPipeTypeRGB) { src_pipes_[rgb_index].type = kPipeTypeRGB; src_pipes_[rgb_index].index = i; src_pipes_[rgb_index].mdss_pipe_id = pipe_caps.id; rgb_index++; } else if (pipe_caps.type == kPipeTypeDMA) { src_pipes_[dma_index].type = kPipeTypeDMA; src_pipes_[dma_index].index = i; src_pipes_[dma_index].mdss_pipe_id = pipe_caps.id; dma_index++; } } for (uint32_t i = 0; i < num_pipe_; i++) { src_pipes_[i].priority = INT(i); } DLOGI("hw_rev=%x, DMA=%d RGB=%d VIG=%d", hw_res_info_.hw_revision, hw_res_info_.num_dma_pipe, hw_res_info_.num_rgb_pipe, hw_res_info_.num_vig_pipe); if (hw_res_info_.max_scale_down < 1 || hw_res_info_.max_scale_up < 1) { DLOGE("Max scaling setting is invalid! max_scale_down = %d, max_scale_up = %d", hw_res_info_.max_scale_down, hw_res_info_.max_scale_up); hw_res_info_.max_scale_down = 1; hw_res_info_.max_scale_up = 1; } // TODO(user): clean it up, query from driver for initial pipe status. #ifndef SDM_VIRTUAL_DRIVER rgb_index = hw_res_info_.num_vig_pipe; src_pipes_[rgb_index].owner = kPipeOwnerKernelMode; src_pipes_[rgb_index + 1].owner = kPipeOwnerKernelMode; #endif return error; }
void HWCDisplayPrimary::HandleFrameDump() { if (dump_frame_count_ && output_buffer_.release_fence_fd >= 0) { int ret = sync_wait(output_buffer_.release_fence_fd, 1000); ::close(output_buffer_.release_fence_fd); output_buffer_.release_fence_fd = -1; if (ret < 0) { DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno)); } else { DumpOutputBuffer(output_buffer_info_, output_buffer_base_, layer_stack_.retire_fence_fd); } } if (0 == dump_frame_count_) { dump_output_to_file_ = false; // Unmap and Free buffer if (munmap(output_buffer_base_, output_buffer_info_.alloc_buffer_info.size) != 0) { DLOGE("unmap failed with err %d", errno); } if (buffer_allocator_->FreeBuffer(&output_buffer_info_) != 0) { DLOGE("FreeBuffer failed"); } post_processed_output_ = false; output_buffer_ = {}; output_buffer_info_ = {}; output_buffer_base_ = nullptr; } }
int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info, bool post_processed_output) { // Note: This function is called in context of a binder thread and a lock is already held if (output_buffer_info.alloc_buffer_info.fd < 0) { DLOGE("Invalid fd %d", output_buffer_info.alloc_buffer_info.fd); return -1; } auto panel_width = 0u; auto panel_height = 0u; auto fb_width = 0u; auto fb_height = 0u; GetPanelResolution(&panel_width, &panel_height); GetFrameBufferResolution(&fb_width, &fb_height); if (post_processed_output && (output_buffer_info_.buffer_config.width < panel_width || output_buffer_info_.buffer_config.height < panel_height)) { DLOGE("Buffer dimensions should not be less than panel resolution"); return -1; } else if (!post_processed_output && (output_buffer_info_.buffer_config.width < fb_width || output_buffer_info_.buffer_config.height < fb_height)) { DLOGE("Buffer dimensions should not be less than FB resolution"); return -1; } SetLayerBuffer(output_buffer_info, &output_buffer_); post_processed_output_ = post_processed_output; frame_capture_buffer_queued_ = true; // Status is only cleared on a new call to dump and remains valid otherwise frame_capture_status_ = -EAGAIN; DisablePartialUpdateOneFrame(); return 0; }
HWCColorManager *HWCColorManager::CreateColorManager(HWCBufferAllocator * buffer_allocator) { HWCColorManager *color_mgr = new HWCColorManager(buffer_allocator); if (color_mgr) { // Load display API interface library. And retrieve color API function tables. DynLib &color_apis_lib = color_mgr->color_apis_lib_; if (color_apis_lib.Open(DISPLAY_API_INTERFACE_LIBRARY_NAME)) { if (!color_apis_lib.Sym(DISPLAY_API_FUNC_TABLES, &color_mgr->color_apis_)) { DLOGE("Fail to retrieve = %s from %s", DISPLAY_API_FUNC_TABLES, DISPLAY_API_INTERFACE_LIBRARY_NAME); delete color_mgr; return NULL; } } else { DLOGW("Unable to load = %s", DISPLAY_API_INTERFACE_LIBRARY_NAME); delete color_mgr; return NULL; } DLOGI("Successfully loaded %s", DISPLAY_API_INTERFACE_LIBRARY_NAME); // Load diagclient library and invokes its entry point to pass in display APIs. DynLib &diag_client_lib = color_mgr->diag_client_lib_; if (diag_client_lib.Open(QDCM_DIAG_CLIENT_LIBRARY_NAME)) { if (!diag_client_lib.Sym(INIT_QDCM_DIAG_CLIENT_NAME, reinterpret_cast<void **>(&color_mgr->qdcm_diag_init_)) || !diag_client_lib.Sym(DEINIT_QDCM_DIAG_CLIENT_NAME, reinterpret_cast<void **>(&color_mgr->qdcm_diag_deinit_))) { DLOGE("Fail to retrieve = %s from %s", INIT_QDCM_DIAG_CLIENT_NAME, QDCM_DIAG_CLIENT_LIBRARY_NAME); } else { // invoke Diag Client entry point to initialize. color_mgr->qdcm_diag_init_(color_mgr->color_apis_); DLOGI("Successfully loaded %s and %s and diag_init'ed", DISPLAY_API_INTERFACE_LIBRARY_NAME, QDCM_DIAG_CLIENT_LIBRARY_NAME); } } else { DLOGW("Unable to load = %s", QDCM_DIAG_CLIENT_LIBRARY_NAME); // only QDCM Diag client failed to be loaded and system still should function. } } else { DLOGE("Unable to create HWCColorManager"); return NULL; } return color_mgr; }
DisplayError CompManager::RegisterDisplay(DisplayType type, const HWDisplayAttributes &display_attributes, const HWPanelInfo &hw_panel_info, const HWMixerAttributes &mixer_attributes, const DisplayConfigVariableInfo &fb_config, Handle *display_ctx) { SCOPE_LOCK(locker_); DisplayError error = kErrorNone; DisplayCompositionContext *display_comp_ctx = new DisplayCompositionContext(); if (!display_comp_ctx) { return kErrorMemory; } Strategy *&strategy = display_comp_ctx->strategy; strategy = new Strategy(extension_intf_, type, hw_res_info_, hw_panel_info, mixer_attributes, display_attributes, fb_config); if (!strategy) { DLOGE("Unable to create strategy"); delete display_comp_ctx; return kErrorMemory; } error = strategy->Init(); if (error != kErrorNone) { delete strategy; delete display_comp_ctx; return error; } error = resource_intf_->RegisterDisplay(type, display_attributes, hw_panel_info, mixer_attributes, &display_comp_ctx->display_resource_ctx); if (error != kErrorNone) { strategy->Deinit(); delete strategy; delete display_comp_ctx; display_comp_ctx = NULL; return error; } registered_displays_[type] = 1; display_comp_ctx->is_primary_panel = hw_panel_info.is_primary_panel; display_comp_ctx->display_type = type; *display_ctx = display_comp_ctx; // New non-primary display device has been added, so move the composition mode to safe mode until // resources for the added display is configured properly. if (!display_comp_ctx->is_primary_panel) { safe_mode_ = true; } DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \ "display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(), display_comp_ctx->display_type); return kErrorNone; }
HWC2::Error HWCDisplayPrimary::SetColorModeById(int32_t color_mode_id) { auto status = color_mode_->SetColorModeById(color_mode_id); if (status != HWC2::Error::None) { DLOGE("failed for mode = %d", color_mode_id); return status; } callbacks_->Refresh(HWC_DISPLAY_PRIMARY); return status; }
DisplayError DisplayHDMI::Init() { lock_guard<recursive_mutex> obj(recursive_mutex_); DisplayError error = HWInterface::Create(kHDMI, hw_info_intf_, buffer_sync_handler_, &hw_intf_); if (error != kErrorNone) { return error; } uint32_t active_mode_index; char value[64] = "0"; Debug::GetProperty("sdm.hdmi.s3d_mode", value); HWS3DMode mode = (HWS3DMode)atoi(value); if (mode > kS3DModeNone && mode < kS3DModeMax) { active_mode_index = GetBestConfig(mode); } else { active_mode_index = GetBestConfig(kS3DModeNone); } error = hw_intf_->SetDisplayAttributes(active_mode_index); if (error != kErrorNone) { HWInterface::Destroy(hw_intf_); } error = DisplayBase::Init(); if (error != kErrorNone) { HWInterface::Destroy(hw_intf_); return error; } GetScanSupport(); underscan_supported_ = (scan_support_ == kScanAlwaysUnderscanned) || (scan_support_ == kScanBoth); s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> (kS3dFormatNone, kS3DModeNone)); s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> (kS3dFormatLeftRight, kS3DModeLR)); s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> (kS3dFormatRightLeft, kS3DModeRL)); s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> (kS3dFormatTopBottom, kS3DModeTB)); s3d_format_to_mode_.insert(std::pair<LayerBufferS3DFormat, HWS3DMode> (kS3dFormatFramePacking, kS3DModeFP)); error = HWEventsInterface::Create(INT(display_type_), this, event_list_, &hw_events_intf_); if (error != kErrorNone) { DisplayBase::Deinit(); HWInterface::Destroy(hw_intf_); DLOGE("Failed to create hardware events interface. Error = %d", error); } return error; }
HWC2::Error HWCDisplayPrimary::SetColorMode(android_color_mode_t mode) { validated_ = false; auto status = color_mode_->SetColorMode(mode); if (status != HWC2::Error::None) { DLOGE("failed for mode = %d", mode); return status; } callbacks_->Refresh(HWC_DISPLAY_PRIMARY); return status; }
void HWCDisplayPrimary::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) { HWCDisplay::SetFrameDumpConfig(count, bit_mask_layer_type); dump_output_to_file_ = bit_mask_layer_type & (1 << OUTPUT_LAYER_DUMP); DLOGI("output_layer_dump_enable %d", dump_output_to_file_); if (!count || !dump_output_to_file_) { return; } // Allocate and map output buffer output_buffer_info_ = {}; // Since we dump DSPP output use Panel resolution. GetPanelResolution(&output_buffer_info_.buffer_config.width, &output_buffer_info_.buffer_config.height); output_buffer_info_.buffer_config.format = kFormatRGB888; output_buffer_info_.buffer_config.buffer_count = 1; if (buffer_allocator_->AllocateBuffer(&output_buffer_info_) != 0) { DLOGE("Buffer allocation failed"); output_buffer_info_ = {}; return; } void *buffer = mmap(NULL, output_buffer_info_.alloc_buffer_info.size, PROT_READ | PROT_WRITE, MAP_SHARED, output_buffer_info_.alloc_buffer_info.fd, 0); if (buffer == MAP_FAILED) { DLOGE("mmap failed with err %d", errno); buffer_allocator_->FreeBuffer(&output_buffer_info_); output_buffer_info_ = {}; return; } output_buffer_base_ = buffer; post_processed_output_ = true; DisablePartialUpdateOneFrame(); }
int HWCColorManager::EnableQDCMMode(bool enable, HWCDisplay *hwc_display) { int ret = 0; if (!qdcm_mode_mgr_) { qdcm_mode_mgr_ = HWCQDCMModeManager::CreateQDCMModeMgr(); if (!qdcm_mode_mgr_) { DLOGE("Unable to create QDCM operating mode manager."); ret = -EFAULT; } } if (qdcm_mode_mgr_) { ret = qdcm_mode_mgr_->EnableQDCMMode(enable, hwc_display); } return ret; }
DisplayError ResourceDefault::CalculateDecimation(float downscale, uint8_t *decimation) { float max_down_scale = FLOAT(hw_res_info_.max_scale_down); if (downscale <= max_down_scale) { *decimation = 0; return kErrorNone; } else if (!hw_res_info_.has_decimation) { DLOGE("Downscaling exceeds the maximum MDP downscale limit but decimation not enabled"); return kErrorNotSupported; } // Decimation is the remaining downscale factor after doing max SDE downscale. // In SDE, decimation is supported in powers of 2. // For ex: If a pipe needs downscale of 8 but max_down_scale is 4 // So decimation = powf(2.0, ceilf(log2f(8 / 4))) = powf(2.0, 1.0) = 2 *decimation = UINT8(ceilf(log2f(downscale / max_down_scale))); return kErrorNone; }
HWC2::Error HWCDisplayPrimary::SetColorTransform(const float *matrix, android_color_transform_t hint) { validated_ = false; if (!matrix) { return HWC2::Error::BadParameter; } auto status = color_mode_->SetColorTransform(matrix, hint); if (status != HWC2::Error::None) { DLOGE("failed for hint = %d", hint); color_tranform_failed_ = true; return status; } callbacks_->Refresh(HWC_DISPLAY_PRIMARY); color_tranform_failed_ = false; return status; }
DisplayError Strategy::Init() { DisplayError error = kErrorNone; if (extension_intf_) { error = extension_intf_->CreateStrategyExtn(display_type_, hw_panel_info_.mode, hw_panel_info_.s3d_mode, mixer_attributes_, fb_config_, &strategy_intf_); if (error != kErrorNone) { DLOGE("Failed to create strategy"); return error; } error = extension_intf_->CreatePartialUpdate(display_type_, hw_resource_info_, hw_panel_info_, mixer_attributes_, display_attributes_, &partial_update_intf_); } return kErrorNone; }
DisplayError HWEvents::Init(int fb_num, HWEventHandler *event_handler, vector<const char *> *event_list) { if (!event_handler) return kErrorParameters; event_handler_ = event_handler; fb_num_ = fb_num; event_list_ = event_list; poll_fds_.resize(event_list_->size()); event_thread_name_ += " - " + std::to_string(fb_num_); PopulateHWEventData(); if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) { DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str()); return kErrorResources; } return kErrorNone; }
DisplayError CompManager::ReconfigureDisplay(Handle comp_handle, const HWDisplayAttributes &display_attributes, const HWPanelInfo &hw_panel_info, const HWMixerAttributes &mixer_attributes, const DisplayConfigVariableInfo &fb_config) { SCOPE_LOCK(locker_); DisplayError error = kErrorNone; DisplayCompositionContext *display_comp_ctx = reinterpret_cast<DisplayCompositionContext *>(comp_handle); error = resource_intf_->ReconfigureDisplay(display_comp_ctx->display_resource_ctx, display_attributes, hw_panel_info, mixer_attributes); if (error != kErrorNone) { return error; } if (display_comp_ctx->strategy) { error = display_comp_ctx->strategy->Reconfigure(hw_panel_info, display_attributes, mixer_attributes, fb_config); if (error != kErrorNone) { DLOGE("Unable to Reconfigure strategy."); display_comp_ctx->strategy->Deinit(); delete display_comp_ctx->strategy; display_comp_ctx->strategy = NULL; return error; } } // For HDMI S3D mode, set max_layers_ to 0 so that primary display would fall back // to GPU composition to release pipes for HDMI. if (display_comp_ctx->display_type == kHDMI) { if (hw_panel_info.s3d_mode != kS3DModeNone) { max_layers_ = 0; } else { max_layers_ = kMaxSDELayers; } } return error; }
DisplayError CoreImpl::CreateDisplay(DisplayType type, DisplayEventHandler *event_handler, DisplayInterface **intf) { SCOPE_LOCK(locker_); if (UNLIKELY(!event_handler || !intf)) { return kErrorParameters; } DisplayBase *display_base = NULL; switch (type) { case kPrimary: display_base = new DisplayPrimary(event_handler, hw_intf_, &comp_mgr_, &offline_ctrl_); break; case kHDMI: display_base = new DisplayHDMI(event_handler, hw_intf_, &comp_mgr_, &offline_ctrl_); break; case kVirtual: display_base = new DisplayVirtual(event_handler, hw_intf_, &comp_mgr_, &offline_ctrl_); break; default: DLOGE("Spurious display type %d", type); return kErrorParameters; } if (UNLIKELY(!display_base)) { return kErrorMemory; } DisplayError error = display_base->Init(); if (UNLIKELY(error != kErrorNone)) { delete display_base; display_base = NULL; return error; } *intf = display_base; return kErrorNone; }
DisplayError CompManager::ReConfigure(Handle display_ctx, HWLayers *hw_layers) { SCOPE_LOCK(locker_); DisplayCompositionContext *display_comp_ctx = reinterpret_cast<DisplayCompositionContext *>(display_ctx); Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; DisplayError error = kErrorUndefined; resource_intf_->Start(display_resource_ctx); error = resource_intf_->Acquire(display_resource_ctx, hw_layers); if (error != kErrorNone) { DLOGE("Reconfigure failed for display = %d", display_comp_ctx->display_type); } resource_intf_->Stop(display_resource_ctx); if (error != kErrorNone) { error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers); } return error; }
DisplayError CompManager::Prepare(Handle display_ctx, HWLayers *hw_layers) { SCOPE_LOCK(locker_); DisplayCompositionContext *display_comp_ctx = reinterpret_cast<DisplayCompositionContext *>(display_ctx); Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx; DisplayError error = kErrorUndefined; PrepareStrategyConstraints(display_ctx, hw_layers); // Select a composition strategy, and try to allocate resources for it. resource_intf_->Start(display_resource_ctx); bool exit = false; uint32_t &count = display_comp_ctx->remaining_strategies; for (; !exit && count > 0; count--) { error = display_comp_ctx->strategy->GetNextStrategy(&display_comp_ctx->constraints); if (error != kErrorNone) { // Composition strategies exhausted. Resource Manager could not allocate resources even for // GPU composition. This will never happen. exit = true; } if (!exit) { error = resource_intf_->Acquire(display_resource_ctx, hw_layers); // Exit if successfully allocated resource, else try next strategy. exit = (error == kErrorNone); } } if (error != kErrorNone) { DLOGE("Composition strategies exhausted for display = %d", display_comp_ctx->display_type); } resource_intf_->Stop(display_resource_ctx); return error; }
HWC2::Error HWCDisplayPrimary::Present(int32_t *out_retire_fence) { auto status = HWC2::Error::None; if (display_paused_) { // TODO(user): From old HWC implementation // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd // Revisit this when validating display_paused DisplayError error = display_intf_->Flush(); if (error != kErrorNone) { DLOGE("Flush failed. Error = %d", error); } } else { status = HWCDisplay::CommitLayerStack(); if (status == HWC2::Error::None) { HandleFrameOutput(); SolidFillCommit(); status = HWCDisplay::PostCommitLayerStack(out_retire_fence); } } CloseAcquireFds(); return status; }
int HWCColorManager::SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display) { SCOPE_LOCK(locker_); int ret = 0; PPFrameCaptureData *frame_capture_data = reinterpret_cast<PPFrameCaptureData *>(params); if (enable) { std::memset(&buffer_info, 0x00, sizeof(buffer_info)); hwc_display->GetPanelResolution(&buffer_info.buffer_config.width, &buffer_info.buffer_config.height); if (frame_capture_data->input_params.out_pix_format == PP_PIXEL_FORMAT_RGB_888) { buffer_info.buffer_config.format = kFormatRGB888; } else if (frame_capture_data->input_params.out_pix_format == PP_PIXEL_FORMAT_RGB_2101010) { buffer_info.buffer_config.format = kFormatRGBA1010102; } else { DLOGE("Pixel-format: %d NOT support.", frame_capture_data->input_params.out_pix_format); return -EFAULT; } buffer_info.buffer_config.buffer_count = 1; buffer_info.alloc_buffer_info.fd = -1; buffer_info.alloc_buffer_info.stride = 0; buffer_info.alloc_buffer_info.size = 0; ret = buffer_allocator_->AllocateBuffer(&buffer_info); if (ret != 0) { DLOGE("Buffer allocation failed. ret: %d", ret); return -ENOMEM; } else { void *buffer = mmap(NULL, buffer_info.alloc_buffer_info.size, PROT_READ | PROT_WRITE, MAP_SHARED, buffer_info.alloc_buffer_info.fd, 0); if (buffer == MAP_FAILED) { DLOGE("mmap failed. err = %d", errno); frame_capture_data->buffer = NULL; ret = buffer_allocator_->FreeBuffer(&buffer_info); return -EFAULT; } else { frame_capture_data->buffer = reinterpret_cast<uint8_t *>(buffer); frame_capture_data->buffer_stride = buffer_info.buffer_config.width; frame_capture_data->buffer_size = buffer_info.alloc_buffer_info.size; } ret = hwc_display->FrameCaptureAsync(buffer_info, 1); if (ret < 0) { DLOGE("FrameCaptureAsync failed. ret = %d", ret); } } } else { ret = hwc_display->GetFrameCaptureStatus(); if (!ret) { if (frame_capture_data->buffer != NULL) { if (munmap(frame_capture_data->buffer, buffer_info.alloc_buffer_info.size) != 0) { DLOGE("munmap failed. err = %d", errno); } } if (buffer_allocator_ != NULL) { std::memset(frame_capture_data, 0x00, sizeof(PPFrameCaptureData)); ret = buffer_allocator_->FreeBuffer(&buffer_info); if (ret != 0) { DLOGE("FreeBuffer failed. ret = %d", ret); } } } else { DLOGE("GetFrameCaptureStatus failed. ret = %d", ret); } } return ret; }