Merge "display: Add display specific make include"
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 97660ea..8dcab3a 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -211,6 +211,12 @@
*/
CRTC_SET_DRAM_IB,
/*
+ * Op: Sets Rotator BW for inline rotation
+ * Arg: uint32_t - CRTC ID
+ * uint32_t - rot_bw
+ */
+ CRTC_SET_ROT_PREFILL_BW,
+ /*
* Op: Sets rotator clock for inline rotation
* Arg: uint32_t - CRTC ID
* uint32_t - rot_clk
@@ -311,6 +317,12 @@
*/
CONNECTOR_SET_CRTC,
/*
+ * Op: Sets PP feature
+ * Arg: uint32_t - Connector ID
+ * DRMPPFeatureInfo * - PP feature data pointer
+ */
+ CONNECTOR_SET_POST_PROC,
+ /*
* Op: Sets connector hdr metadata
* Arg: uint32_t - Connector ID
* drm_msm_ext_hdr_metadata - hdr_metadata
@@ -498,6 +510,7 @@
struct DRMDisplayToken {
uint32_t conn_id;
uint32_t crtc_id;
+ uint32_t crtc_index;
};
enum DRMPPFeatureID {
@@ -531,6 +544,7 @@
uint32_t version;
uint32_t payload_size;
void *payload;
+ uint32_t object_type;
};
enum DRMCscType {
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 52bc73e..80e91ca 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -560,6 +560,7 @@
uint64_t llcc_ib_bps = 0;
uint64_t dram_ab_bps = 0;
uint64_t dram_ib_bps = 0;
+ uint64_t rot_prefill_bw_bps = 0;
uint32_t clock_hz = 0;
uint32_t rot_clock_hz = 0;
};
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 383bdba..136168b 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -488,9 +488,11 @@
default:
DLOGE("Spurious state = %d transition requested.", state);
- break;
+ return kErrorParameters;
}
+ DisablePartialUpdateOneFrame();
+
if (error == kErrorNone) {
active_ = active;
state_ = state;
diff --git a/sdm/libs/core/drm/hw_color_manager_drm.cpp b/sdm/libs/core/drm/hw_color_manager_drm.cpp
index 7563647..295dafd 100644
--- a/sdm/libs/core/drm/hw_color_manager_drm.cpp
+++ b/sdm/libs/core/drm/hw_color_manager_drm.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -797,14 +797,43 @@
DRMPPFeatureInfo *out_data) {
DisplayError ret = kErrorNone;
#ifdef PP_DRM_ENABLE
+ struct SDEDitherCfg *sde_dither = NULL;
+ struct drm_msm_dither *mdp_dither = NULL;
+
if (!out_data) {
DLOGE("Invalid input parameter for dither");
return kErrorParameters;
}
- out_data->id = kPPFeaturesMax;
+ sde_dither = (struct SDEDitherCfg *)in_data.GetConfigData();
+ out_data->id = kFeatureDither;
out_data->type = sde_drm::kPropBlob;
out_data->version = in_data.feature_version_;
+ out_data->payload_size = sizeof(struct drm_msm_dither);
+
+ if (in_data.enable_flags_ & kOpsDisable) {
+ out_data->payload = NULL;
+ return ret;
+ } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+ out_data->payload = NULL;
+ return kErrorParameters;
+ }
+
+ mdp_dither = new drm_msm_dither();
+ if (!mdp_dither) {
+ DLOGE("Failed to allocate memory for dither");
+ return kErrorMemory;
+ }
+
+ mdp_dither->flags = 0;
+ std::memcpy(mdp_dither->matrix, sde_dither->dither_matrix,
+ sizeof(sde_dither->dither_matrix));
+ mdp_dither->temporal_en = sde_dither->temporal_en;
+ mdp_dither->c0_bitdepth = sde_dither->g_y_depth;
+ mdp_dither->c1_bitdepth = sde_dither->b_cb_depth;
+ mdp_dither->c2_bitdepth = sde_dither->r_cr_depth;
+ mdp_dither->c3_bitdepth = 0;
+ out_data->payload = mdp_dither;
#endif
return ret;
}
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index c734f4c..d5bf482 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -57,6 +57,7 @@
#include <unordered_map>
#include <utility>
#include <vector>
+#include <limits>
#include "hw_device_drm.h"
#include "hw_info_interface.h"
@@ -737,6 +738,7 @@
return kErrorUndefined;
}
+ SetFullROI();
drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::OFF);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
int ret = drm_atomic_intf_->Commit(true /* synchronous */, false /* retain_planes */);
@@ -918,14 +920,17 @@
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_LLCC_IB, token_.crtc_id, qos_data.llcc_ib_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DRAM_AB, token_.crtc_id, qos_data.dram_ab_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_DRAM_IB, token_.crtc_id, qos_data.dram_ib_bps);
+ drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ROT_PREFILL_BW, token_.crtc_id,
+ qos_data.rot_prefill_bw_bps);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ROT_CLK, token_.crtc_id, qos_data.rot_clock_hz);
drm_atomic_intf_->Perform(DRMOps::CRTC_SET_SECURITY_LEVEL, token_.crtc_id, crtc_security_level);
- DLOGI_IF(kTagDriverConfig, "System Clock=%d Hz, Core: AB=%llu Bps, IB=%llu Bps, " \
- "LLCC: AB=%llu Bps, IB=%llu Bps, DRAM AB=%llu Bps, IB=%llu Bps Rot Clock=%d",
+ DLOGI_IF(kTagDriverConfig, "%s::%s System Clock=%d Hz, Core: AB=%llu Bps, IB=%llu Bps, " \
+ "LLCC: AB=%llu Bps, IB=%llu Bps, DRAM AB=%llu Bps, IB=%llu Bps, "\
+ "Rot: Bw=%llu Bps, Clock=%d Hz", validate ? "Validate" : "Commit", device_name_,
qos_data.clock_hz, qos_data.core_ab_bps, qos_data.core_ib_bps, qos_data.llcc_ab_bps,
qos_data.llcc_ib_bps, qos_data.dram_ab_bps, qos_data.dram_ib_bps,
- qos_data.rot_clock_hz);
+ qos_data.rot_prefill_bw_bps, qos_data.rot_clock_hz);
// Set refresh rate
if (vrefresh_) {
@@ -1258,13 +1263,18 @@
DisplayError HWDeviceDRM::SetPPFeatures(PPFeaturesConfig *feature_list) {
int ret = 0;
PPFeatureInfo *feature = NULL;
+ DRMPPFeatureInfo kernel_params = {};
+ bool crtc_feature = true;
while (true) {
- DRMPPFeatureInfo kernel_params = {};
+ crtc_feature = true;
ret = feature_list->RetrieveNextFeature(&feature);
if (ret)
break;
-
+ kernel_params.id = HWColorManagerDrm::ToDrmFeatureId(feature->feature_id_);
+ drm_mgr_intf_->GetCrtcPPInfo(0, &kernel_params);
+ if (kernel_params.version == std::numeric_limits<uint32_t>::max())
+ crtc_feature = false;
if (feature) {
DLOGV_IF(kTagDriverConfig, "feature_id = %d", feature->feature_id_);
auto drm_features = DrmPPfeatureMap_.find(feature->feature_id_);
@@ -1279,9 +1289,11 @@
continue;
}
ret = HWColorManagerDrm::GetDrmFeature[drm_feature](*feature, &kernel_params);
- if (!ret)
- drm_atomic_intf_->Perform(DRMOps::CRTC_SET_POST_PROC, token_.crtc_id, &kernel_params);
- HWColorManagerDrm::FreeDrmFeatureData(&kernel_params);
+ if (!ret && crtc_feature)
+ drm_atomic_intf_->Perform(DRMOps::CRTC_SET_POST_PROC, token_.crtc_id, &kernel_params);
+ else if (!ret && !crtc_feature)
+ drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POST_PROC, token_.conn_id, &kernel_params);
+ HWColorManagerDrm::FreeDrmFeatureData(&kernel_params);
}
}
}
@@ -1484,8 +1496,7 @@
}
void HWDeviceDRM::GetDRMDisplayToken(sde_drm::DRMDisplayToken *token) const {
- token->conn_id = token_.conn_id;
- token->crtc_id = token_.crtc_id;
+ *token = token_;
}
void HWDeviceDRM::UpdateMixerAttributes() {
@@ -1549,4 +1560,17 @@
}
}
+void HWDeviceDRM::SetFullROI() {
+ // Reset the CRTC ROI and connector ROI only for the panel that supports partial update
+ if (!hw_panel_info_.partial_update) {
+ return;
+ }
+ uint32_t index = current_mode_index_;
+ DRMRect crtc_rects = {0, 0, mixer_attributes_.width, mixer_attributes_.height};
+ DRMRect conn_rects = {0, 0, display_attributes_[index].x_pixels,
+ display_attributes_[index].y_pixels};
+ drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ROI, token_.crtc_id, 1, &crtc_rects);
+ drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_ROI, token_.conn_id, 1, &conn_rects);
+}
+
} // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index b08c0e6..3af3b77 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -133,6 +133,7 @@
bool IsResolutionSwitchEnabled() const { return resolution_switch_enabled_; }
void SetTopology(sde_drm::DRMTopology drm_topology, HWTopology *hw_topology);
void SetMultiRectMode(const uint32_t flags, sde_drm::DRMMultiRectMode *target);
+ void SetFullROI();
class Registry {
public:
diff --git a/sdm/libs/core/drm/hw_events_drm.cpp b/sdm/libs/core/drm/hw_events_drm.cpp
index 86a3f54..4d1eea9 100644
--- a/sdm/libs/core/drm/hw_events_drm.cpp
+++ b/sdm/libs/core/drm/hw_events_drm.cpp
@@ -64,19 +64,18 @@
switch (event_data.event_type) {
case HWEvent::VSYNC: {
- if (!is_primary_) {
- // TODO(user): Once secondary support is added, use a different fd by calling drmOpen
- break;
- }
-
poll_fds_[i].events = POLLIN | POLLPRI | POLLERR;
- DRMMaster *master = nullptr;
- int ret = DRMMaster::GetInstance(&master);
- if (ret < 0) {
- DLOGE("Failed to acquire DRMMaster instance");
- return kErrorNotSupported;
+ if (is_primary_) {
+ DRMMaster *master = nullptr;
+ int ret = DRMMaster::GetInstance(&master);
+ if (ret < 0) {
+ DLOGE("Failed to acquire DRMMaster instance");
+ return kErrorNotSupported;
+ }
+ master->GetHandle(&poll_fds_[i].fd);
+ } else {
+ poll_fds_[i].fd = drmOpen("msm_drm", nullptr);
}
- master->GetHandle(&poll_fds_[i].fd);
vsync_index_ = i;
} break;
case HWEvent::EXIT: {
@@ -197,11 +196,8 @@
return kErrorResources;
}
- if (is_primary_) {
- RegisterVSync();
- vsync_registered_ = true;
- }
-
+ RegisterVSync();
+ vsync_registered_ = true;
RegisterPanelDead(true);
RegisterIdleNotify(true);
RegisterIdlePowerCollapse(true);
@@ -226,9 +222,6 @@
switch (event) {
case HWEvent::VSYNC: {
std::lock_guard<std::mutex> lock(vsync_mutex_);
- if (!is_primary_) {
- break;
- }
vsync_enabled_ = enable;
if (vsync_enabled_ && !vsync_registered_) {
RegisterVSync();
@@ -261,7 +254,9 @@
for (uint32_t i = 0; i < event_data_list_.size(); i++) {
switch (event_data_list_[i].event_type) {
case HWEvent::VSYNC:
- // TODO(user): close for secondary
+ if (!is_primary_) {
+ Sys::close_(poll_fds_[i].fd);
+ }
poll_fds_[i].fd = -1;
break;
case HWEvent::EXIT:
@@ -347,9 +342,10 @@
}
DisplayError HWEventsDRM::RegisterVSync() {
- // TODO(user): For secondary use DRM_VBLANK_HIGH_CRTC_MASK and DRM_VBLANK_HIGH_CRTC_SHIFT
- drmVBlank vblank{};
- vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT);
+ drmVBlank vblank {};
+ uint32_t high_crtc = token_.crtc_index << DRM_VBLANK_HIGH_CRTC_SHIFT;
+ vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT |
+ (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
vblank.request.sequence = 1;
// DRM hack to pass in context to unused field signal. Driver will write this to the node being
// polled on, and will be read as part of drm event handling and sent to handler
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index f1d0d80..245b573 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -37,6 +37,7 @@
#include <drm_res_mgr.h>
#include <stdio.h>
#include <unistd.h>
+#include <fcntl.h>
#include <string>
#include <vector>
#include <map>
@@ -290,5 +291,31 @@
hdr_metadata_.white_point_x, hdr_metadata_.white_point_y, hdr_metadata_.eotf);
}
+DisplayError HWTVDRM::OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level) {
+ DisplayError error = kErrorNone;
+ int fd = -1;
+ char data[kMaxStringLength] = {'\0'};
+
+ snprintf(data, sizeof(data), "/sys/devices/virtual/hdcp/msm_hdcp/min_level_change");
+
+ fd = Sys::open_(data, O_WRONLY);
+ if (fd < 0) {
+ DLOGE("File '%s' could not be opened. errno = %d, desc = %s", data, errno, strerror(errno));
+ return kErrorHardware;
+ }
+
+ snprintf(data, sizeof(data), "%d", min_enc_level);
+
+ ssize_t err = Sys::pwrite_(fd, data, strlen(data), 0);
+ if (err <= 0) {
+ DLOGE("Write failed, Error = %s", strerror(errno));
+ error = kErrorHardware;
+ }
+
+ Sys::close_(fd);
+
+ return error;
+}
+
} // namespace sdm
diff --git a/sdm/libs/core/drm/hw_tv_drm.h b/sdm/libs/core/drm/hw_tv_drm.h
index 5661bc2..49384a2 100644
--- a/sdm/libs/core/drm/hw_tv_drm.h
+++ b/sdm/libs/core/drm/hw_tv_drm.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
@@ -48,6 +48,7 @@
virtual DisplayError Standby();
virtual DisplayError Commit(HWLayers *hw_layers);
virtual void PopulateHWPanelInfo();
+ virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
private:
DisplayError UpdateHDRMetaData(HWLayers *hw_layers);
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 142b84b..213230f 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1334,6 +1334,7 @@
dump_frame_index_++;
}
}
+ config_pending_ = false;
geometry_changes_ = GeometryChanges::kNone;
flush_ = false;
@@ -1940,9 +1941,16 @@
}
int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
- int status = (display_intf_->SetActiveConfig(config) == kErrorNone) ? 0 : -1;
+ if (display_config_ == config) {
+ return 0;
+ }
+ display_config_ = config;
+ config_pending_ = true;
validated_ = false;
- return status;
+
+ callbacks_->Refresh(id_);
+
+ return 0;
}
int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) {
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index a5e1457..3977e73 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright 2015 The Android Open Source Project
@@ -150,6 +150,10 @@
virtual int SetState(bool connected) {
return kErrorNotSupported;
}
+ virtual DisplayError Flush() {
+ return kErrorNotSupported;
+ }
+
int SetPanelBrightness(int level);
int GetPanelBrightness(int *level);
int ToggleScreenUpdates(bool enable);
@@ -300,6 +304,8 @@
HWCToneMapper *tone_mapper_ = nullptr;
uint32_t num_configs_ = 0;
int disable_hdr_handling_ = 0; // disables HDR handling.
+ uint32_t display_config_ = 0;
+ bool config_pending_ = false;
private:
void DumpInputBuffers(void);
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index 2bc2d18..8e00cfd 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -115,6 +115,14 @@
return status;
}
+ if (config_pending_) {
+ if (display_intf_->SetActiveConfig(display_config_) != kErrorNone) {
+ DLOGW("Invalid display config %d", display_config_);
+ // Reset the display config with active config
+ display_intf_->GetActiveConfig(&display_config_);
+ }
+ }
+
BuildLayerStack();
if (layer_set_.empty()) {
@@ -278,4 +286,8 @@
}
}
+DisplayError HWCDisplayExternal::Flush() {
+ return display_intf_->Flush();
+}
+
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index fbee6a3..5eb1704 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -49,6 +49,7 @@
virtual HWC2::Error Present(int32_t *out_retire_fence);
virtual void SetSecureDisplay(bool secure_display_active);
virtual int SetState(bool connected);
+ virtual DisplayError Flush();
private:
HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 1f2fdf6..531f209 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -178,6 +178,13 @@
MarkLayersForClientComposition();
}
+ if (config_pending_) {
+ if (display_intf_->SetActiveConfig(display_config_) != kErrorNone) {
+ DLOGW("Invalid display config %d", display_config_);
+ // Reset the display config with active config
+ display_intf_->GetActiveConfig(&display_config_);
+ }
+ }
// Fill in the remaining blanks in the layers and add them to the SDM layerstack
BuildLayerStack();
// Checks and replaces layer stack for solid fill
@@ -210,7 +217,8 @@
// Avoid flush for Command mode panel.
DisplayConfigFixedInfo display_config;
display_intf_->GetConfig(&display_config);
- flush_ = !display_config.is_cmdmode;
+ flush_ = !(display_config.is_cmdmode && secure_display_active_);
+ validated_ = true;
return status;
}
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index cfc1cb0..71ca78d 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -731,10 +731,9 @@
}
int32_t interlaced = 0;
- bool interlace = layer_buffer->flags.interlace;
- if (getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced) == 0) {
- interlace = interlaced ? true : false;
- }
+ getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced);
+ bool interlace = interlaced ? true : false;
+
if (interlace != layer_buffer->flags.interlace) {
DLOGI("Layer buffer interlaced metadata has changed. old=%d, new=%d",
layer_buffer->flags.interlace, interlace);
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 74ffe38..aed9334 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -944,6 +944,10 @@
DLOGI("Display = %d", disp);
if (disp == HWC_DISPLAY_EXTERNAL) {
+ DisplayError error = hwc_display_[disp]->Flush();
+ if (error != kErrorNone) {
+ DLOGW("Flush failed. Error = %d", error);
+ }
HWCDisplayExternal::Destroy(hwc_display_[disp]);
} else if (disp == HWC_DISPLAY_VIRTUAL) {
HWCDisplayVirtual::Destroy(hwc_display_[disp]);