From 25927a6b47a4138c38efe713255e0873be0c69c3 Mon Sep 17 00:00:00 2001 From: Dileep Marchya Date: Thu, 15 Jan 2015 13:14:19 -0800 Subject: [PATCH] sde: Add support for flush. Add support for flush on a display. This flush shall release pipes, all pending buffers and associated fences that are currently held by display engine. Change-Id: I8a8d7030fb6af031b3760c172fce4f1f8ef3fedc --- .../include/core/display_interface.h | 13 ++++ displayengine/libs/core/display_base.cpp | 34 ++++++++-- displayengine/libs/core/display_base.h | 1 + displayengine/libs/core/display_hdmi.cpp | 24 +++++++ displayengine/libs/core/display_hdmi.h | 1 + displayengine/libs/core/hw_framebuffer.cpp | 64 ++++++++++--------- displayengine/libs/core/hw_framebuffer.h | 4 +- displayengine/libs/core/hw_interface.h | 1 + displayengine/libs/hwc/hwc_display.cpp | 64 +++++++++++-------- displayengine/libs/hwc/hwc_display.h | 1 + 10 files changed, 143 insertions(+), 64 deletions(-) diff --git a/displayengine/include/core/display_interface.h b/displayengine/include/core/display_interface.h index bdeb8a37..ff99cb8a 100755 --- a/displayengine/include/core/display_interface.h +++ b/displayengine/include/core/display_interface.h @@ -207,6 +207,19 @@ class DisplayInterface { */ virtual DisplayError Commit(LayerStack *layer_stack) = 0; + /*! @brief Method to flush any pending buffers/fences submitted previously via Commit() call. + + @details Client shall call this method to request the Display Engine to release all buffers and + respective fences currently in use. This operation may result in a blank display on the panel + until a new frame is submitted for composition. + + @return \link DisplayError \endlink + + @sa Prepare + @sa Commit + */ + virtual DisplayError Flush() = 0; + /*! @brief Method to get current state of the display device. @param[out] state \link DisplayState \endlink diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp index 080deb7a..4d8f5aac 100644 --- a/displayengine/libs/core/display_base.cpp +++ b/displayengine/libs/core/display_base.cpp @@ -135,6 +135,8 @@ DisplayError DisplayBase::Prepare(LayerStack *layer_stack) { } } comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_); + } else { + return kErrorNotSupported; } return error; @@ -149,18 +151,19 @@ DisplayError DisplayBase::Commit(LayerStack *layer_stack) { return kErrorParameters; } - if (!pending_commit_) { - DLOGE("Commit: Corresponding Prepare() is not called for display = %d", display_type_); - return kErrorUndefined; - } - if (state_ == kStateOn) { + if (!pending_commit_) { + DLOGE("Commit: Corresponding Prepare() is not called for display = %d", display_type_); + return kErrorUndefined; + } error = hw_intf_->Commit(hw_device_, &hw_layers_); if (error == kErrorNone) { comp_manager_->PostCommit(display_comp_ctx_, &hw_layers_); } else { DLOGE("Unexpected error. Commit failed on driver."); } + } else { + return kErrorNotSupported; } pending_commit_ = false; @@ -168,6 +171,27 @@ DisplayError DisplayBase::Commit(LayerStack *layer_stack) { return kErrorNone; } +DisplayError DisplayBase::Flush() { + SCOPE_LOCK(locker_); + + DisplayError error = kErrorNone; + + if (state_ != kStateOn) { + return kErrorNone; + } + + hw_layers_.info.count = 0; + error = hw_intf_->Flush(hw_device_); + if (error == kErrorNone) { + comp_manager_->Purge(display_comp_ctx_); + pending_commit_ = false; + } else { + DLOGV("Failed to flush device."); + } + + return error; +} + DisplayError DisplayBase::GetDisplayState(DisplayState *state) { SCOPE_LOCK(locker_); diff --git a/displayengine/libs/core/display_base.h b/displayengine/libs/core/display_base.h index 3f0e24f0..187ab8de 100644 --- a/displayengine/libs/core/display_base.h +++ b/displayengine/libs/core/display_base.h @@ -43,6 +43,7 @@ class DisplayBase : public DisplayInterface, HWEventHandler, DumpImpl { virtual DisplayError Deinit(); virtual DisplayError Prepare(LayerStack *layer_stack); virtual DisplayError Commit(LayerStack *layer_stack); + virtual DisplayError Flush(); virtual DisplayError GetDisplayState(DisplayState *state); virtual DisplayError GetNumVariableInfoConfigs(uint32_t *count); virtual DisplayError GetConfig(DisplayConfigFixedInfo *fixed_info); diff --git a/displayengine/libs/core/display_hdmi.cpp b/displayengine/libs/core/display_hdmi.cpp index 14a09f1e..07bbca07 100644 --- a/displayengine/libs/core/display_hdmi.cpp +++ b/displayengine/libs/core/display_hdmi.cpp @@ -77,5 +77,29 @@ int DisplayHDMI::GetBestConfig() { return best_config_mode; } +DisplayError DisplayHDMI::SetDisplayState(DisplayState state) { + DisplayError error = kErrorNone; + + DLOGI("Set state = %d", state); + + if (state == kStateOff) { + SCOPE_LOCK(locker_); + if (state == state_) { + DLOGI("Same state transition is requested."); + return kErrorNone; + } + error = hw_intf_->Flush(hw_device_); + if (error == kErrorNone) { + comp_manager_->Purge(display_comp_ctx_); + state_ = state; + hw_layers_.info.count = 0; + } + } else { + error = DisplayBase::SetDisplayState(state); + } + + return error; +} + } // namespace sde diff --git a/displayengine/libs/core/display_hdmi.h b/displayengine/libs/core/display_hdmi.h index 0bb9dc80..8de7fdfe 100644 --- a/displayengine/libs/core/display_hdmi.h +++ b/displayengine/libs/core/display_hdmi.h @@ -33,6 +33,7 @@ class DisplayHDMI : public DisplayBase { public: DisplayHDMI(DisplayEventHandler *event_handler, HWInterface *hw_intf, CompManager *comp_manager); virtual int GetBestConfig(); + virtual DisplayError SetDisplayState(DisplayState state); }; } // namespace sde diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp index 0644e7d6..97892403 100644 --- a/displayengine/libs/core/hw_framebuffer.cpp +++ b/displayengine/libs/core/hw_framebuffer.cpp @@ -392,17 +392,19 @@ DisplayError HWFrameBuffer::SetDisplayAttributes(Handle device, uint32_t index) break; } } + if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) { return kErrorParameters; } + STRUCT_VAR(msmfb_metadata, metadata); - memset(&metadata, 0 , sizeof(metadata)); metadata.op = metadata_op_vic; metadata.data.video_info_code = timing_mode->video_format; if (ioctl(hw_context->device_fd, MSMFB_METADATA_SET, &metadata) == -1) { IOCTL_LOGE(MSMFB_METADATA_SET, hw_context->type); return kErrorHardware; } + DLOGI("SetInfo", vscreeninfo.reserved[3] & 0xFF00, vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len, vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len, @@ -476,19 +478,6 @@ DisplayError HWFrameBuffer::PowerOff(Handle device) { return kErrorHardware; } break; - case kDeviceHDMI: - { - hw_context->ResetMDPCommit(); - mdp_layer_commit_v1 &mdp_commit = hw_context->mdp_commit.commit_v1; - mdp_commit.input_layer_cnt = 0; - mdp_commit.flags &= ~MDP_VALIDATE_LAYER; - if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_context->mdp_commit) == -1) { - IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type); - return kErrorHardware; - } - } - break; - case kDeviceVirtual: default: break; } @@ -634,6 +623,22 @@ DisplayError HWFrameBuffer::Commit(Handle device, HWLayers *hw_layers) { return kErrorNone; } +DisplayError HWFrameBuffer::Flush(Handle device) { + HWContext *hw_context = reinterpret_cast(device); + + hw_context->ResetMDPCommit(); + mdp_layer_commit_v1 &mdp_commit = hw_context->mdp_commit.commit_v1; + mdp_commit.input_layer_cnt = 0; + mdp_commit.flags &= ~MDP_VALIDATE_LAYER; + + if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_context->mdp_commit) == -1) { + IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type); + return kErrorHardware; + } + + return kErrorNone; +} + DisplayError HWFrameBuffer::SetFormat(const LayerBufferFormat &source, uint32_t *target) { switch (source) { case kFormatARGB8888: *target = MDP_ARGB_8888; break; @@ -775,16 +780,16 @@ void HWFrameBuffer::PopulateFBNodeIndex() { // TODO(user): For now, assume primary to be cmd/video/lvds/edp mode panel only // Need more concrete info from driver if ((strncmp(line, "mipi dsi cmd panel", strlen("mipi dsi cmd panel")) == 0)) { - pri_panel_info_.type = kCommandModePanel; + primary_panel_info_.type = kCommandModePanel; fb_node_index_[kDevicePrimary] = i; } else if ((strncmp(line, "mipi dsi video panel", strlen("mipi dsi video panel")) == 0)) { - pri_panel_info_.type = kVideoModePanel; + primary_panel_info_.type = kVideoModePanel; fb_node_index_[kDevicePrimary] = i; } else if ((strncmp(line, "lvds panel", strlen("lvds panel")) == 0)) { - pri_panel_info_.type = kLVDSPanel; + primary_panel_info_.type = kLVDSPanel; fb_node_index_[kDevicePrimary] = i; } else if ((strncmp(line, "edp panel", strlen("edp panel")) == 0)) { - pri_panel_info_.type = kEDPPanel; + primary_panel_info_.type = kEDPPanel; fb_node_index_[kDevicePrimary] = i; } else if ((strncmp(line, "dtv panel", strlen("dtv panel")) == 0)) { fb_node_index_[kDeviceHDMI] = i; @@ -816,27 +821,27 @@ void HWFrameBuffer::PopulatePanelInfo(int fb_index) { char *tokens[max_count] = { NULL }; if (!ParseLine(line, tokens, max_count, &token_count)) { if (!strncmp(tokens[0], "pu_en", strlen("pu_en"))) { - pri_panel_info_.partial_update = atoi(tokens[1]); + primary_panel_info_.partial_update = atoi(tokens[1]); } else if (!strncmp(tokens[0], "xstart", strlen("xstart"))) { - pri_panel_info_.left_align = atoi(tokens[1]); + primary_panel_info_.left_align = atoi(tokens[1]); } else if (!strncmp(tokens[0], "walign", strlen("walign"))) { - pri_panel_info_.width_align = atoi(tokens[1]); + primary_panel_info_.width_align = atoi(tokens[1]); } else if (!strncmp(tokens[0], "ystart", strlen("ystart"))) { - pri_panel_info_.top_align = atoi(tokens[1]); + primary_panel_info_.top_align = atoi(tokens[1]); } else if (!strncmp(tokens[0], "halign", strlen("halign"))) { - pri_panel_info_.height_align = atoi(tokens[1]); + primary_panel_info_.height_align = atoi(tokens[1]); } else if (!strncmp(tokens[0], "min_w", strlen("min_w"))) { - pri_panel_info_.min_roi_width = atoi(tokens[1]); + primary_panel_info_.min_roi_width = atoi(tokens[1]); } else if (!strncmp(tokens[0], "min_h", strlen("min_h"))) { - pri_panel_info_.min_roi_height = atoi(tokens[1]); + primary_panel_info_.min_roi_height = atoi(tokens[1]); } else if (!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) { - pri_panel_info_.needs_roi_merge = atoi(tokens[1]); + primary_panel_info_.needs_roi_merge = atoi(tokens[1]); } else if (!strncmp(tokens[0], "dynamic_fps_en", strlen("dyn_fps_en"))) { - pri_panel_info_.dynamic_fps = atoi(tokens[1]); + primary_panel_info_.dynamic_fps = atoi(tokens[1]); } else if (!strncmp(tokens[0], "min_fps", strlen("min_fps"))) { - pri_panel_info_.min_fps = atoi(tokens[1]); + primary_panel_info_.min_fps = atoi(tokens[1]); } else if (!strncmp(tokens[0], "max_fps", strlen("max_fps"))) { - pri_panel_info_.max_fps= atoi(tokens[1]); + primary_panel_info_.max_fps= atoi(tokens[1]); } } } @@ -1070,3 +1075,4 @@ bool HWFrameBuffer::MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode, } } // namespace sde + diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h index 2fe50787..d9c3a470 100644 --- a/displayengine/libs/core/hw_framebuffer.h +++ b/displayengine/libs/core/hw_framebuffer.h @@ -58,6 +58,7 @@ class HWFrameBuffer : public HWInterface { virtual DisplayError Standby(Handle device); virtual DisplayError Validate(Handle device, HWLayers *hw_layers); virtual DisplayError Commit(Handle device, HWLayers *hw_layers); + virtual DisplayError Flush(Handle device); private: struct HWContext { @@ -141,7 +142,6 @@ class HWFrameBuffer : public HWInterface { bool EnableHotPlugDetection(int enable); int GetHDMIModeCount(); bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode, fb_var_screeninfo *info); - void ResetHDMIModes(); // Pointers to system calls which are either mapped to actual system call or virtual driver. int (*ioctl_)(int, int, ...); @@ -166,7 +166,7 @@ class HWFrameBuffer : public HWInterface { HWResourceInfo hw_resource_; int fb_node_index_[kDeviceMax]; const char* fb_path_; - PanelInfo pri_panel_info_; + PanelInfo primary_panel_info_; bool hotplug_enabled_; uint32_t hdmi_mode_count_; uint32_t hdmi_modes_[256]; diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h index f4f33f93..1b3be67a 100644 --- a/displayengine/libs/core/hw_interface.h +++ b/displayengine/libs/core/hw_interface.h @@ -168,6 +168,7 @@ class HWInterface { virtual DisplayError Standby(Handle device) = 0; virtual DisplayError Validate(Handle device, HWLayers *hw_layers) = 0; virtual DisplayError Commit(Handle device, HWLayers *hw_layers) = 0; + virtual DisplayError Flush(Handle device) = 0; protected: virtual ~HWInterface() { } diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp index 771c07fb..7590be5b 100644 --- a/displayengine/libs/hwc/hwc_display.cpp +++ b/displayengine/libs/hwc/hwc_display.cpp @@ -35,7 +35,8 @@ namespace sde { HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id) - : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL) { + : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL), + flush_(false) { } int HWCDisplay::Init() { @@ -282,6 +283,7 @@ int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) { size_t num_hw_layers = content_list->numHwLayers; if (num_hw_layers <= 1) { + flush_ = true; return 0; } @@ -336,9 +338,14 @@ int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) { layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0); DisplayError error = display_intf_->Prepare(&layer_stack_); - if (UNLIKELY(error != kErrorNone)) { + if (error != kErrorNone) { DLOGE("Prepare failed. Error = %d", error); - return -EINVAL; + + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() so that + // previous buffer and fences are released, and override the error. + flush_ = true; + + return 0; } bool needs_fb_refresh = NeedsFrameBufferRefresh(content_list); @@ -372,38 +379,39 @@ int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) { int status = 0; size_t num_hw_layers = content_list->numHwLayers; - if (num_hw_layers <= 1) { - if (!num_hw_layers) { - return 0; + + if (!flush_) { + for (size_t i = 0; i < num_hw_layers; i++) { + hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; + const private_handle_t *pvt_handle = static_cast(hwc_layer.handle); + LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer; + + if (pvt_handle) { + layer_buffer->planes[0].fd = pvt_handle->fd; + layer_buffer->planes[0].offset = pvt_handle->offset; + layer_buffer->planes[0].stride = pvt_handle->width; + } + + layer_buffer->acquire_fence_fd = hwc_layer.acquireFenceFd; } - // TODO(user): handle if only 1 layer(fb target) is received. - int &acquireFenceFd = content_list->hwLayers[0].acquireFenceFd; - if (acquireFenceFd >= 0) { - close(acquireFenceFd); - } + DisplayError error = display_intf_->Commit(&layer_stack_); + if (error != kErrorNone) { + DLOGE("Commit failed. Error = %d", error); - return 0; + // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() so that + // previous buffer and fences are released, and override the error. + flush_ = true; + } } - for (size_t i = 0; i < num_hw_layers; i++) { - hwc_layer_1_t &hwc_layer = content_list->hwLayers[i]; - const private_handle_t *pvt_handle = static_cast(hwc_layer.handle); - LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer; - - if (pvt_handle) { - layer_buffer->planes[0].fd = pvt_handle->fd; - layer_buffer->planes[0].offset = pvt_handle->offset; - layer_buffer->planes[0].stride = pvt_handle->width; + if (flush_) { + DisplayError error = display_intf_->Flush(); + if (error != kErrorNone) { + DLOGE("Flush failed. Error = %d", error); } - layer_buffer->acquire_fence_fd = hwc_layer.acquireFenceFd; - } - - DisplayError error = display_intf_->Commit(&layer_stack_); - if (UNLIKELY(error != kErrorNone)) { - DLOGE("Commit failed. Error = %d", error); - status = -EINVAL; + flush_ = false; } for (size_t i = 0; i < num_hw_layers; i++) { diff --git a/displayengine/libs/hwc/hwc_display.h b/displayengine/libs/hwc/hwc_display.h index 0ba9ca75..b5e61f3f 100644 --- a/displayengine/libs/hwc/hwc_display.h +++ b/displayengine/libs/hwc/hwc_display.h @@ -97,6 +97,7 @@ class HWCDisplay : public DisplayEventHandler { LayerStackMemory layer_stack_memory_; LayerStack layer_stack_; LayerStackCache layer_stack_cache_; + bool flush_; }; } // namespace sde