sdm: hwc2: Support Skip Validate feature
1. Set HWC2_CAPABILITY_SKIP_VALIDATE cap in GetCapabilities api.
2. If HWC2_CAPABILITY_SKIP_VALIDATE cap is exposed by HWC HAL, then
SF just calls PresentDisplay api. It is the responsibility of HWC
HAL to request for ValidateDisplay, if it is required. If the cap
is not exposed by HWC HAL, then there will be ValidateDisplay call
followed by PresentDisplay.
3. In case of Surface Damage update on a layer, SDM needs a Validate
call to program SDE driver for Partial Update feature.
4. SDM needs Validate call to enter in safe Mode for use cases like
Idle / Thermal fallback, HDMI and Virtual Connect/Disconnet, etc.
5. In case of layer buffer geometry, metadata or secure attributes
change, SDM needs Validate call to program the SDE driver.
6. SDM needs Validate call if GPU tonemapping is required on a layer
during HDR Video playback.
7. Read user defined underscan width and height, when the External
display gets created and initialized.
8. SDM needs Validate call for few APIs which are exposed by the Binder
Interface or by HWComposer APIs, since they need re-configuration of
SDE driver or they modify Panel / LayerMixer / Display configuration.
9. The feature is enabled by default. "sdm.debug.disable_skip_validate"
system property can be set to '1' to disable the feature.
CRs-Fixed: 2071632
Change-Id: I68f0db3af16afa4ad4eb789cd1f6b12caf6381e4
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 524141e..b8e2a9e 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -135,6 +135,12 @@
kPortDP, // Display is connected to DP port.
};
+/*! @brief This enum represents the events received by Display HAL. */
+enum DisplayEvent {
+ kIdleTimeout, // Event triggered by Idle Timer.
+ kThermalEvent, // Event triggered by Thermal.
+};
+
/*! @brief This structure defines configuration for fixed properties of a display device.
@sa DisplayInterface::GetConfig
@@ -245,6 +251,9 @@
*/
virtual DisplayError CECMessage(char *message) = 0;
+ /*! @brief Event handler for events received by Display HAL. */
+ virtual DisplayError HandleEvent(DisplayEvent event) = 0;
+
protected:
virtual ~DisplayEventHandler() { }
};
diff --git a/sdm/include/core/sdm_types.h b/sdm/include/core/sdm_types.h
index ce356bf..72ad6b2 100644
--- a/sdm/include/core/sdm_types.h
+++ b/sdm/include/core/sdm_types.h
@@ -56,6 +56,7 @@
kErrorPerfValidation, //!< Bandwidth or Clock requirement validation failure.
kErrorNoAppLayers, //!< No App layer(s) in the draw cycle.
kErrorRotatorValidation, //!< Rotator configuration validation failure.
+ kErrorNotValidated, //!< Draw cycle has not been validated.
};
/*! @brief This structure is defined for client and library compatibility check purpose only. This
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index b76c3d1..538d38e 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -211,6 +211,7 @@
DisplayError DisplayBase::Prepare(LayerStack *layer_stack) {
lock_guard<recursive_mutex> obj(recursive_mutex_);
DisplayError error = kErrorNone;
+ needs_validate_ = true;
if (!active_) {
return kErrorPermission;
@@ -250,7 +251,7 @@
error = hw_intf_->Validate(&hw_layers_);
if (error == kErrorNone) {
// Strategy is successful now, wait for Commit().
- pending_commit_ = true;
+ needs_validate_ = false;
break;
}
if (error == kErrorShutDown) {
@@ -269,7 +270,7 @@
DisplayError error = kErrorNone;
if (!active_) {
- pending_commit_ = false;
+ needs_validate_ = true;
return kErrorPermission;
}
@@ -277,13 +278,11 @@
return kErrorParameters;
}
- if (!pending_commit_) {
+ if (needs_validate_) {
DLOGE("Commit: Corresponding Prepare() is not called for display = %d", display_type_);
- return kErrorUndefined;
+ return kErrorNotValidated;
}
- pending_commit_ = false;
-
// Layer stack attributes has changed, need to Reconfigure, currently in use for Hybrid Comp
if (layer_stack->flags.attributes_changed) {
error = comp_manager_->ReConfigure(display_comp_ctx_, &hw_layers_);
@@ -343,7 +342,7 @@
error = hw_intf_->Flush();
if (error == kErrorNone) {
comp_manager_->Purge(display_comp_ctx_);
- pending_commit_ = false;
+ needs_validate_ = true;
} else {
DLOGW("Unable to flush display = %d", display_type_);
}
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 4023229..223e5eb 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -153,7 +153,7 @@
Handle hw_device_ = 0;
Handle display_comp_ctx_ = 0;
HWLayers hw_layers_;
- bool pending_commit_ = false;
+ bool needs_validate_ = true;
bool vsync_enable_ = false;
uint32_t max_mixer_stages_ = 0;
HWInfoInterface *hw_info_intf_ = NULL;
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index 52b71c7..64a0bcc 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -283,6 +283,7 @@
handle_idle_timeout_ = true;
event_handler_->Refresh();
comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+ event_handler_->HandleEvent(kIdleTimeout);
}
void DisplayPrimary::PingPongTimeout() {
@@ -293,6 +294,7 @@
void DisplayPrimary::ThermalEvent(int64_t thermal_level) {
lock_guard<recursive_mutex> obj(recursive_mutex_);
comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level);
+ event_handler_->HandleEvent(kThermalEvent);
}
void DisplayPrimary::IdlePowerCollapse() {
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 43c53fd..5be9bcf 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -53,6 +53,8 @@
namespace sdm {
+std::bitset<kDisplayMax> HWCDisplay::validated_ = 0;
+
// This weight function is needed because the color primaries are not sorted by gamut size
static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) {
int weight = 10;
@@ -354,6 +356,7 @@
return -EINVAL;
}
+ validated_.reset();
HWCDebugHandler::Get()->GetProperty("sys.hwc_disable_hdr", &disable_hdr_handling_);
if (disable_hdr_handling_) {
DLOGI("HDR Handling disabled");
@@ -383,6 +386,8 @@
display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
current_refresh_rate_ = max_refresh_rate_;
+
+ GetUnderScanConfig();
DLOGI("Display created with id: %d", id_);
return 0;
@@ -414,6 +419,7 @@
layer_map_.emplace(std::make_pair(layer->GetId(), layer));
*out_layer_id = layer->GetId();
geometry_changes_ |= GeometryChanges::kAdded;
+ validated_.reset();
return HWC2::Error::None;
}
@@ -445,6 +451,7 @@
}
geometry_changes_ |= GeometryChanges::kRemoved;
+ validated_.reset();
return HWC2::Error::None;
}
@@ -695,6 +702,8 @@
ATRACE_INT("SetPowerMode ", state);
DisplayError error = display_intf_->SetDisplayState(state);
+ validated_.reset();
+
if (error == kErrorNone) {
flush_on_error_ = flush_on_error;
} else {
@@ -859,6 +868,7 @@
return HWC2::Error::BadConfig;
}
+ validated_.reset();
return HWC2::Error::None;
}
@@ -876,6 +886,7 @@
}
DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
+ validated_.reset();
}
HWC2::PowerMode HWCDisplay::GetLastPowerMode() {
@@ -901,6 +912,20 @@
return kErrorNone;
}
+DisplayError HWCDisplay::HandleEvent(DisplayEvent event) {
+ switch (event) {
+ case kIdleTimeout:
+ case kThermalEvent:
+ validated_.reset();
+ break;
+ default:
+ DLOGW("Unknown event: %d", event);
+ break;
+ }
+
+ return kErrorNone;
+}
+
HWC2::Error HWCDisplay::PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests) {
layer_changes_.clear();
layer_requests_.clear();
@@ -920,6 +945,8 @@
flush_ = true;
}
return HWC2::Error::BadDisplay;
+ } else {
+ validated_.set(type_);
}
} else {
// Skip is not set
@@ -948,10 +975,11 @@
if (requested_composition != device_composition) {
layer_changes_[hwc_layer->GetId()] = device_composition;
}
+ hwc_layer->ResetValidation();
}
*out_num_types = UINT32(layer_changes_.size());
*out_num_requests = UINT32(layer_requests_.size());
- validated_ = true;
+ skip_validate_ = false;
if (*out_num_types > 0) {
return HWC2::Error::HasChanges;
} else {
@@ -964,7 +992,7 @@
return HWC2::Error::None;
}
- if (!validated_) {
+ if (!validated_.test(type_)) {
return HWC2::Error::NotValidated;
}
@@ -986,7 +1014,7 @@
return HWC2::Error::None;
}
- if (!validated_) {
+ if (!validated_.test(type_)) {
DLOGW("Display is not validated");
return HWC2::Error::NotValidated;
}
@@ -1028,7 +1056,7 @@
// Use for sharing blit buffers and
// writing wfd buffer directly to output if there is full GPU composition
// and no color conversion needed
- if (!validated_) {
+ if (!validated_.test(type_)) {
DLOGW("Display is not validated");
return HWC2::Error::NotValidated;
}
@@ -1087,8 +1115,12 @@
return HWC2::Error::None;
}
- if (!validated_) {
- DLOGW("Display is not validated");
+ if (skip_validate_ && !CanSkipValidate()) {
+ validated_.reset(type_);
+ }
+
+ if (!validated_.test(type_)) {
+ DLOGV_IF(kTagCompManager, "Display %d is not validated", id_);
return HWC2::Error::NotValidated;
}
@@ -1108,7 +1140,6 @@
}
}
error = display_intf_->Commit(&layer_stack_);
- validated_ = false;
if (error == kErrorNone) {
// A commit is successfully submitted, start flushing on failure now onwards.
@@ -1117,6 +1148,9 @@
if (error == kErrorShutDown) {
shutdown_pending_ = true;
return HWC2::Error::Unsupported;
+ } else if (error == kErrorNotValidated) {
+ validated_.reset(type_);
+ return HWC2::Error::NotValidated;
} else if (error != kErrorPermission) {
DLOGE("Commit failed. Error = %d", error);
// To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
@@ -1126,6 +1160,7 @@
}
}
+ skip_validate_ = true;
return HWC2::Error::None;
}
@@ -1135,6 +1170,7 @@
// Do no call flush on errors, if a successful buffer is never submitted.
if (flush_ && flush_on_error_) {
display_intf_->Flush();
+ validated_.reset();
}
if (tone_mapper_ && tone_mapper_->IsActive()) {
@@ -1182,6 +1218,7 @@
layer_stack_.retire_fence_fd = -1;
}
*out_retire_fence = layer_stack_.retire_fence_fd;
+ layer_stack_.retire_fence_fd = -1;
if (dump_frame_count_) {
dump_frame_count_--;
@@ -1206,6 +1243,7 @@
if (display_intf_) {
error = display_intf_->SetMaxMixerStages(max_mixer_stages);
+ validated_.reset();
}
return error;
@@ -1568,6 +1606,7 @@
if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) {
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+ validated_.reset();
}
return status;
@@ -1585,7 +1624,7 @@
if (hwc_layer->GetDeviceSelectedCompositionType() != HWC2::Composition::Cursor) {
return HWC2::Error::None;
}
- if (validated_ == true) {
+ if (!skip_validate_ && validated_.test(type_)) {
// the device is currently in the middle of the validate/present sequence,
// cannot set the Position(as per HWC2 spec)
return HWC2::Error::NotValidated;
@@ -1623,6 +1662,7 @@
return -1;
}
+ validated_.reset();
return 0;
}
@@ -1631,7 +1671,7 @@
auto layer = hwc_layer->GetSDMLayer();
layer->composition = kCompositionSDE;
}
- validated_ = true;
+ validated_.set(type_);
}
void HWCDisplay::MarkLayersForClientComposition() {
@@ -1649,10 +1689,12 @@
int HWCDisplay::SetPanelBrightness(int level) {
int ret = 0;
- if (display_intf_)
+ if (display_intf_) {
ret = display_intf_->SetPanelBrightness(level);
- else
+ validated_.reset();
+ } else {
ret = -EINVAL;
+ }
return ret;
}
@@ -1664,6 +1706,7 @@
int HWCDisplay::ToggleScreenUpdates(bool enable) {
display_paused_ = enable ? false : true;
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+ validated_.reset();
return 0;
}
@@ -1761,7 +1804,9 @@
}
int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
- return display_intf_->SetActiveConfig(config) == kErrorNone ? 0 : -1;
+ int status = (display_intf_->SetActiveConfig(config) == kErrorNone) ? 0 : -1;
+ validated_.reset();
+ return status;
}
int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) {
@@ -1879,4 +1924,25 @@
os << "-------------------------------" << std::endl;
return os.str();
}
+
+bool HWCDisplay::CanSkipValidate() {
+ // Layer Stack checks
+ if (layer_stack_.flags.hdr_present && (tone_mapper_ && tone_mapper_->IsActive())) {
+ return false;
+ }
+
+ for (auto hwc_layer : layer_set_) {
+ if (hwc_layer->NeedsValidation()) {
+ return false;
+ }
+
+ // Do not allow Skip Validate, if any layer needs GPU Composition.
+ if (hwc_layer->GetDeviceSelectedCompositionType() == HWC2::Composition::Client) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 55e1eb3..273b760 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -161,6 +161,8 @@
void BuildLayerStack(void);
void BuildSolidFillStack(void);
HWCLayer *GetHWCLayer(hwc2_layer_t layer);
+ void ResetValidation() { validated_.reset(); }
+ uint32_t GetGeometryChanges() { return geometry_changes_; }
// HWC2 APIs
virtual HWC2::Error AcceptDisplayChanges(void);
@@ -221,6 +223,7 @@
virtual DisplayError VSync(const DisplayEventVSync &vsync);
virtual DisplayError Refresh();
virtual DisplayError CECMessage(char *message);
+ virtual DisplayError HandleEvent(DisplayEvent event);
virtual void DumpOutputBuffer(const BufferInfo &buffer_info, void *base, int fence);
virtual HWC2::Error PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests);
virtual HWC2::Error CommitLayerStack(void);
@@ -239,12 +242,14 @@
uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
virtual void CloseAcquireFds();
virtual void ClearRequestFlags();
+ virtual void GetUnderScanConfig() { }
enum {
INPUT_LAYER_DUMP,
OUTPUT_LAYER_DUMP,
};
+ static std::bitset<kDisplayMax> validated_;
CoreInterface *core_intf_ = nullptr;
HWCCallbacks *callbacks_ = nullptr;
HWCBufferAllocator *buffer_allocator_ = NULL;
@@ -282,7 +287,6 @@
LayerRect solid_fill_rect_ = {};
uint32_t solid_fill_color_ = 0;
LayerRect display_rect_;
- bool validated_ = false;
bool color_tranform_failed_ = false;
HWCColorMode *color_mode_ = NULL;
HWCToneMapper *tone_mapper_ = nullptr;
@@ -291,9 +295,11 @@
private:
void DumpInputBuffers(void);
+ bool CanSkipValidate();
qService::QService *qservice_ = NULL;
DisplayClass display_class_;
uint32_t geometry_changes_ = GeometryChanges::kNone;
+ bool skip_validate_ = false;
};
inline int HWCDisplay::Perform(uint32_t operation, ...) {
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index e89451d..97507ee 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -142,20 +142,12 @@
}
void HWCDisplayExternal::ApplyScanAdjustment(hwc_rect_t *display_frame) {
- if (display_intf_->IsUnderscanSupported()) {
+ if ((underscan_width_ <= 0) || (underscan_height_ <= 0)) {
return;
}
- // Read user defined width and height ratio
- int width = 0, height = 0;
- HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &width);
- float width_ratio = FLOAT(width) / 100.0f;
- HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &height);
- float height_ratio = FLOAT(height) / 100.0f;
-
- if (width_ratio == 0.0f || height_ratio == 0.0f) {
- return;
- }
+ float width_ratio = FLOAT(underscan_width_) / 100.0f;
+ float height_ratio = FLOAT(underscan_height_) / 100.0f;
uint32_t mixer_width = 0;
uint32_t mixer_height = 0;
@@ -188,6 +180,7 @@
if (secure_display_active_) {
DisplayError error = display_intf_->Flush();
+ validated_.reset();
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
@@ -241,6 +234,7 @@
display_null_.GetDisplayState(&state);
display_intf_->SetDisplayState(state);
+ validated_.reset();
SetVsyncEnabled(HWC2::Vsync::Enable);
@@ -277,4 +271,12 @@
return 0;
}
+void HWCDisplayExternal::GetUnderScanConfig() {
+ if (!display_intf_->IsUnderscanSupported()) {
+ // Read user defined underscan width and height
+ HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &underscan_width_);
+ HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &underscan_height_);
+ }
+}
+
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 7aa84b2..fbee6a3 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -54,10 +54,13 @@
HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
HWCCallbacks *callbacks, qService::QService *qservice);
void ApplyScanAdjustment(hwc_rect_t *display_frame);
+ void GetUnderScanConfig();
static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
uint32_t *virtual_width, uint32_t *virtual_height);
DisplayNull display_null_;
+ int underscan_width_ = 0;
+ int underscan_height_ = 0;
};
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 1094100..4079cbc 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -217,6 +217,7 @@
// If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
// Revisit this when validating display_paused
DisplayError error = display_intf_->Flush();
+ validated_.reset();
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
@@ -252,6 +253,7 @@
}
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+ validated_.reset();
return status;
}
@@ -264,6 +266,7 @@
}
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+ validated_.reset();
return status;
}
@@ -283,6 +286,7 @@
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
color_tranform_failed_ = false;
+ validated_.reset();
return status;
}
@@ -324,6 +328,7 @@
return -EINVAL;
}
va_end(args);
+ validated_.reset();
return 0;
}
@@ -410,6 +415,7 @@
void HWCDisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
display_intf_->SetIdleTimeoutMs(timeout_ms);
+ validated_.reset();
}
static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
@@ -509,6 +515,7 @@
output_buffer_base_ = buffer;
post_processed_output_ = true;
DisablePartialUpdateOneFrame();
+ validated_.reset();
}
int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
@@ -553,6 +560,7 @@
if (display_intf_) {
error = display_intf_->SetDetailEnhancerData(de_data);
+ validated_.reset();
}
return error;
}
@@ -562,6 +570,7 @@
if (display_intf_) {
error = display_intf_->ControlPartialUpdate(enable, pending);
+ validated_.reset();
}
return error;
@@ -572,6 +581,7 @@
if (display_intf_) {
error = display_intf_->DisablePartialUpdateOneFrame();
+ validated_.reset();
}
return error;
@@ -579,7 +589,9 @@
DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) {
- return display_intf_->SetMixerResolution(width, height);
+ DisplayError error = display_intf_->SetMixerResolution(width, height);
+ validated_.reset();
+ return error;
}
DisplayError HWCDisplayPrimary::GetMixerResolution(uint32_t *width, uint32_t *height) {
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index 8ac9be6..8837ad0 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -131,6 +131,7 @@
auto status = HWC2::Error::None;
if (display_paused_) {
DisplayError error = display_intf_->Flush();
+ validated_.reset();
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index dba00b4..4e6dba2 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -125,34 +125,38 @@
AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(handle, aligned_width, aligned_height);
#endif
+ LayerBufferFormat format = GetSDMFormat(handle->format, handle->flags);
+ if ((format != layer_buffer->format) || (UINT32(aligned_width) != layer_buffer->width) ||
+ (UINT32(aligned_height) != layer_buffer->height)) {
+ // Layer buffer geometry has changed.
+ geometry_changes_ |= kBufferGeometry;
+ }
+
+ layer_buffer->format = format;
layer_buffer->width = UINT32(aligned_width);
layer_buffer->height = UINT32(aligned_height);
layer_buffer->unaligned_width = UINT32(handle->unaligned_width);
layer_buffer->unaligned_height = UINT32(handle->unaligned_height);
- layer_buffer->format = GetSDMFormat(handle->format, handle->flags);
if (SetMetaData(const_cast<private_handle_t *>(handle), layer_) != kErrorNone) {
return HWC2::Error::BadLayer;
}
-#ifdef USE_GRALLOC1
- // TODO(user): Clean this up
- if (handle->buffer_type == BUFFER_TYPE_VIDEO) {
-#else
- if (handle->bufferType == BUFFER_TYPE_VIDEO) {
-#endif
- layer_buffer->flags.video = true;
- }
+ layer_buffer->flags.video = (handle->buffer_type == BUFFER_TYPE_VIDEO) ? true : false;
+
// TZ Protected Buffer - L1
- if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
- layer_buffer->flags.secure = true;
- if (handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE) {
- layer_buffer->flags.secure_camera = true;
- }
+ bool secure = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER);
+ bool secure_camera = secure && (handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE);
+ bool secure_display = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY);
+ if (secure != layer_buffer->flags.secure || secure_camera != layer_buffer->flags.secure_camera ||
+ secure_display != layer_buffer->flags.secure_display) {
+ // Secure attribute of layer buffer has changed.
+ needs_validate_ = true;
}
- if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
- layer_buffer->flags.secure_display = true;
- }
+
+ layer_buffer->flags.secure = secure;
+ layer_buffer->flags.secure_camera = secure_camera;
+ layer_buffer->flags.secure_display = secure_display;
layer_buffer->planes[0].fd = ion_fd_;
layer_buffer->planes[0].offset = handle->offset;
@@ -165,6 +169,20 @@
}
HWC2::Error HWCLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
+ // Check if there is an update in SurfaceDamage rects
+ if (layer_->dirty_regions.size() != damage.numRects) {
+ needs_validate_ = true;
+ } else {
+ for (uint32_t j = 0; j < damage.numRects; j++) {
+ LayerRect damage_rect;
+ SetRect(damage.rects[j], &damage_rect);
+ if (damage_rect != layer_->dirty_regions.at(j)) {
+ needs_validate_ = true;
+ break;
+ }
+ }
+ }
+
layer_->dirty_regions.clear();
for (uint32_t i = 0; i < damage.numRects; i++) {
LayerRect rect;
@@ -579,20 +597,23 @@
LayerBuffer *layer_buffer = &layer->input_buffer;
private_handle_t *handle = const_cast<private_handle_t *>(pvt_handle);
IGC_t igc = {};
+ LayerIGC layer_igc = layer_buffer->igc;
if (getMetaData(handle, GET_IGC, &igc) == 0) {
- if (SetIGC(igc, &layer_buffer->igc) != kErrorNone) {
+ if (SetIGC(igc, &layer_igc) != kErrorNone) {
return kErrorNotSupported;
}
}
float fps = 0;
- if (getMetaData(handle, GET_REFRESH_RATE , &fps) == 0) {
- layer->frame_rate = RoundToStandardFPS(fps);
+ uint32_t frame_rate = layer->frame_rate;
+ if (getMetaData(handle, GET_REFRESH_RATE, &fps) == 0) {
+ frame_rate = RoundToStandardFPS(fps);
}
int32_t interlaced = 0;
+ bool interlace = layer_buffer->flags.interlace;
if (getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced) == 0) {
- layer_buffer->flags.interlace = interlaced ? true : false;
+ interlace = interlaced ? true : false;
}
uint32_t linear_format = 0;
@@ -601,8 +622,19 @@
}
uint32_t s3d = 0;
+ LayerBufferS3DFormat s3d_format = layer_buffer->s3d_format;
if (getMetaData(handle, GET_S3D_FORMAT, &s3d) == 0) {
- layer_buffer->s3d_format = GetS3DFormat(s3d);
+ s3d_format = GetS3DFormat(s3d);
+ }
+
+ if ((layer_igc != layer_buffer->igc) || (interlace != layer_buffer->flags.interlace) ||
+ (frame_rate != layer->frame_rate) || (s3d_format != layer_buffer->s3d_format)) {
+ // Layer buffer metadata has changed.
+ needs_validate_ = true;
+ layer_buffer->igc = layer_igc;
+ layer->frame_rate = frame_rate;
+ layer_buffer->s3d_format = s3d_format;
+ layer_buffer->flags.interlace = interlace;
}
// Check if metadata is set
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 25ec4dc..0260fd0 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -52,6 +52,7 @@
kZOrder = 0x040,
kAdded = 0x080,
kRemoved = 0x100,
+ kBufferGeometry = 0x200,
};
class HWCLayer {
@@ -87,6 +88,8 @@
int32_t PopReleaseFence(void);
bool ValidateAndSetCSC();
bool SupportLocalConversion(ColorPrimaries working_primaries);
+ void ResetValidation() { needs_validate_ = false; }
+ bool NeedsValidation() { return (needs_validate_ || geometry_changes_); }
private:
Layer *layer_ = nullptr;
@@ -100,6 +103,7 @@
int32_t dataspace_ = HAL_DATASPACE_UNKNOWN;
LayerTransform layer_transform_ = {};
LayerRect dst_rect_ = {};
+ bool needs_validate_ = true;
// Composition requested by client(SF)
HWC2::Composition client_requested_ = HWC2::Composition::Device;
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 3fce394..272b2f6 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -290,10 +290,20 @@
void HWCSession::GetCapabilities(struct hwc2_device *device, uint32_t *outCount,
int32_t *outCapabilities) {
- if (outCapabilities != nullptr && *outCount >= 1) {
- outCapabilities[0] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+ int value = 0;
+ bool disable_skip_validate = false;
+ if (Debug::Get()->GetProperty("sdm.debug.disable_skip_validate", &value) == kErrorNone) {
+ disable_skip_validate = (value == 1);
}
- *outCount = 1;
+ uint32_t count = 1 + (disable_skip_validate ? 0 : 1);
+
+ if (outCapabilities != nullptr && (*outCount >= count)) {
+ outCapabilities[0] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+ if (!disable_skip_validate) {
+ outCapabilities[1] = HWC2_CAPABILITY_SKIP_VALIDATE;
+ }
+ }
+ *outCount = count;
}
template <typename PFN, typename T>
@@ -1310,6 +1320,7 @@
HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel);
req_payload.DestroyPayload();
resp_payload.DestroyPayload();
+ hwc_display_[display_id]->ResetValidation();
return (ret ? -EINVAL : 0);
}
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 6c45134..f09ed0e 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -105,6 +105,9 @@
auto hwc_layer = hwc_session->hwc_display_[display]->GetHWCLayer(layer);
if (hwc_layer != nullptr) {
status = (hwc_layer->*member)(std::forward<Args>(args)...);
+ if (hwc_session->hwc_display_[display]->GetGeometryChanges()) {
+ hwc_session->hwc_display_[display]->ResetValidation();
+ }
}
}
return INT32(status);
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index 383ec3b..425ffbe 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -451,6 +451,7 @@
new_bw_mode_ = true;
need_invalidate_ = true;
+ hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
return 0;
}