Merge "sdm: Add support for resolution switch"
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index 2c24001..584737d 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -703,6 +703,12 @@
return GRALLOC1_ERROR_BAD_HANDLE;
}
*flag = hnd->flags &private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
+ int linear_format = 0;
+ if (getMetaData(hnd, GET_LINEAR_FORMAT, &linear_format) == 0) {
+ if (!linear_format) {
+ *flag = 0;
+ }
+ }
} break;
case GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS: {
diff --git a/libgralloc1/gr_utils.cpp b/libgralloc1/gr_utils.cpp
index 560bb08..d89b8fe 100644
--- a/libgralloc1/gr_utils.cpp
+++ b/libgralloc1/gr_utils.cpp
@@ -357,29 +357,33 @@
bool interlaced = false;
memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
- MetaData_t *metadata = reinterpret_cast<MetaData_t *>(hnd->base_metadata);
// Check if UBWC buffer has been rendered in linear format.
- if (metadata && (metadata->operation & LINEAR_FORMAT)) {
- format = INT(metadata->linearFormat);
+ int linear_format = 0;
+ if (getMetaData(const_cast<private_handle_t *>(hnd),
+ GET_LINEAR_FORMAT, &linear_format) == 0) {
+ format = INT(linear_format);
}
// Check metadata if the geometry has been updated.
- if (metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ BufferDim_t buffer_dim;
+ if (getMetaData(const_cast<private_handle_t *>(hnd),
+ GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
int usage = 0;
-
if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
usage = GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC;
}
- BufferInfo info(metadata->bufferDim.sliceWidth, metadata->bufferDim.sliceHeight, format,
+ BufferInfo info(buffer_dim.sliceWidth, buffer_dim.sliceHeight, format,
prod_usage, cons_usage);
GetAlignedWidthAndHeight(info, &width, &height);
}
// Check metadata for interlaced content.
- if (metadata && (metadata->operation & PP_PARAM_INTERLACED)) {
- interlaced = metadata->interlaced ? true : false;
+ int interlace_flag = 0;
+ if (getMetaData(const_cast<private_handle_t *>(hnd),
+ GET_PP_PARAM_INTERLACED, &interlace_flag) != 0) {
+ interlaced = interlace_flag;
}
// Get the chroma offsets from the handle width/height. We take advantage
diff --git a/libgralloc1/gralloc_priv.h b/libgralloc1/gralloc_priv.h
index 87604c6..2abdd84 100644
--- a/libgralloc1/gralloc_priv.h
+++ b/libgralloc1/gralloc_priv.h
@@ -78,6 +78,7 @@
#define GRALLOC_USAGE_PRIVATE_IOMMU_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_IOMMU_HEAP
#define GRALLOC_USAGE_PRIVATE_WFD GRALLOC1_CONSUMER_USAGE_PRIVATE_WFD
#define GRALLOC_USAGE_PRIVATE_CAMERA_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_CAMERA_HEAP
+#define GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY
#define GRALLOC_USAGE_PRIVATE_MM_HEAP 0x0
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 06d4749..6106baf 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;
@@ -104,10 +106,14 @@
HWC2::Error HWCColorMode::SetColorMode(android_color_mode_t mode) {
DTRACE_SCOPED();
// first mode in 2D matrix is the mode (identity)
- if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) {
+ if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3) {
DLOGE("Could not find mode: %d", mode);
return HWC2::Error::BadParameter;
}
+ if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) {
+ return HWC2::Error::Unsupported;
+ }
+
auto status = HandleColorModeTransform(mode, current_color_transform_, color_matrix_);
if (status != HWC2::Error::None) {
DLOGE("failed for mode = %d", mode);
@@ -126,7 +132,8 @@
}
HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t hint) {
- if (!matrix) {
+ if (!matrix || (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
+ hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)) {
return HWC2::Error::BadParameter;
}
@@ -349,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");
@@ -378,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;
@@ -408,8 +418,8 @@
HWCLayer *layer = *layer_set_.emplace(new HWCLayer(id_, buffer_allocator_));
layer_map_.emplace(std::make_pair(layer->GetId(), layer));
*out_layer_id = layer->GetId();
- validated_ = false;
geometry_changes_ |= GeometryChanges::kAdded;
+ validated_.reset();
return HWC2::Error::None;
}
@@ -439,9 +449,9 @@
break;
}
}
- validated_ = false;
geometry_changes_ |= GeometryChanges::kRemoved;
+ validated_.reset();
return HWC2::Error::None;
}
@@ -598,7 +608,6 @@
DLOGE("[%" PRIu64 "] updateLayerZ failed to find layer", id_);
return HWC2::Error::BadLayer;
}
- validated_ = false;
const auto layer = map_layer->second;
const auto z_range = layer_set_.equal_range(layer);
@@ -693,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 {
@@ -747,9 +758,18 @@
HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
int32_t *out_value) {
DisplayConfigVariableInfo variable_config;
- if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) {
- DLOGE("Get variable config failed");
- return HWC2::Error::BadDisplay;
+ // Get display attributes from config index only if resolution switch is supported.
+ // Otherwise always send mixer attributes. This is to support destination scaler.
+ if (num_configs_ > 1) {
+ if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) {
+ DLOGE("Get variable config failed");
+ return HWC2::Error::BadDisplay;
+ }
+ } else {
+ if (display_intf_->GetFrameBufferConfig(&variable_config) != kErrorNone) {
+ DLOGV("Get variable config failed");
+ return HWC2::Error::BadDisplay;
+ }
}
switch (attribute) {
@@ -857,6 +877,7 @@
return HWC2::Error::BadConfig;
}
+ validated_.reset();
return HWC2::Error::None;
}
@@ -874,6 +895,7 @@
}
DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
+ validated_.reset();
}
HWC2::PowerMode HWCDisplay::GetLastPowerMode() {
@@ -899,6 +921,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();
@@ -918,6 +954,8 @@
flush_ = true;
}
return HWC2::Error::BadDisplay;
+ } else {
+ validated_.set(type_);
}
} else {
// Skip is not set
@@ -946,10 +984,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 {
@@ -962,7 +1001,7 @@
return HWC2::Error::None;
}
- if (!validated_) {
+ if (!validated_.test(type_)) {
return HWC2::Error::NotValidated;
}
@@ -984,10 +1023,11 @@
return HWC2::Error::None;
}
- if (!validated_) {
+ if (!validated_.test(type_)) {
DLOGW("Display is not validated");
return HWC2::Error::NotValidated;
}
+
*out_num_elements = UINT32(layer_changes_.size());
if (out_layers != nullptr && out_types != nullptr) {
int i = 0;
@@ -1017,18 +1057,19 @@
HWC2::Error HWCDisplay::GetDisplayRequests(int32_t *out_display_requests,
uint32_t *out_num_elements, hwc2_layer_t *out_layers,
int32_t *out_layer_requests) {
- // No display requests for now
- // Use for sharing blit buffers and
- // writing wfd buffer directly to output if there is full GPU composition
- // and no color conversion needed
if (layer_set_.empty()) {
return HWC2::Error::None;
}
- if (!validated_) {
+ // No display requests for now
+ // 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_.test(type_)) {
DLOGW("Display is not validated");
return HWC2::Error::NotValidated;
}
+
*out_display_requests = 0;
*out_num_elements = UINT32(layer_requests_.size());
if (out_layers != nullptr && out_layer_requests != nullptr) {
@@ -1083,8 +1124,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;
}
@@ -1104,7 +1149,6 @@
}
}
error = display_intf_->Commit(&layer_stack_);
- validated_ = false;
if (error == kErrorNone) {
// A commit is successfully submitted, start flushing on failure now onwards.
@@ -1113,6 +1157,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()
@@ -1122,6 +1169,7 @@
}
}
+ skip_validate_ = true;
return HWC2::Error::None;
}
@@ -1131,6 +1179,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()) {
@@ -1178,6 +1227,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_--;
@@ -1202,6 +1252,7 @@
if (display_intf_) {
error = display_intf_->SetMaxMixerStages(max_mixer_stages);
+ validated_.reset();
}
return error;
@@ -1564,6 +1615,7 @@
if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) {
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+ validated_.reset();
}
return status;
@@ -1574,9 +1626,18 @@
return HWC2::Error::None;
}
- if (GetHWCLayer(layer) == nullptr) {
+ HWCLayer *hwc_layer = GetHWCLayer(layer);
+ if (hwc_layer == nullptr) {
return HWC2::Error::BadLayer;
}
+ if (hwc_layer->GetDeviceSelectedCompositionType() != HWC2::Composition::Cursor) {
+ return HWC2::Error::None;
+ }
+ 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;
+ }
DisplayState state;
if (display_intf_->GetDisplayState(&state) == kErrorNone) {
@@ -1585,9 +1646,9 @@
}
}
- if (!validated_) {
- return HWC2::Error::NotValidated;
- }
+ // TODO(user): HWC1.5 was not letting SetCursorPosition before validateDisplay,
+ // but HWC2.0 doesn't let setting cursor position after validate before present.
+ // Need to revisit.
auto error = display_intf_->SetCursorPosition(x, y);
if (error != kErrorNone) {
@@ -1610,6 +1671,7 @@
return -1;
}
+ validated_.reset();
return 0;
}
@@ -1618,7 +1680,7 @@
auto layer = hwc_layer->GetSDMLayer();
layer->composition = kCompositionSDE;
}
- validated_ = true;
+ validated_.set(type_);
}
void HWCDisplay::MarkLayersForClientComposition() {
@@ -1636,10 +1698,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;
}
@@ -1651,6 +1715,7 @@
int HWCDisplay::ToggleScreenUpdates(bool enable) {
display_paused_ = enable ? false : true;
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+ validated_.reset();
return 0;
}
@@ -1748,7 +1813,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) {
@@ -1866,4 +1933,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 e773e91..273b760 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -146,19 +146,6 @@
virtual int GetDisplayConfigCount(uint32_t *count);
virtual int GetDisplayAttributesForConfig(int config,
DisplayConfigVariableInfo *display_attributes);
- template <typename... Args>
- int32_t CallLayerFunction(hwc2_layer_t layer, HWC2::Error (HWCLayer::*member)(Args... ),
- Args... args) {
- auto status = HWC2::Error::BadLayer;
- validated_ = false;
- auto hwc_layer = GetHWCLayer(layer);
- if (hwc_layer != nullptr) {
- status = (hwc_layer->*member)(std::forward<Args>(args)...);
- }
-
- return INT32(status);
- }
-
virtual int SetState(bool connected) {
return kErrorNotSupported;
}
@@ -174,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);
@@ -234,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);
@@ -252,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;
@@ -295,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;
@@ -304,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 a45fb1f..a717305 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -84,7 +84,6 @@
close(release_fences_.front());
release_fences_.pop();
}
- close(ion_fd_);
if (layer_) {
delete layer_;
}
@@ -108,13 +107,8 @@
const private_handle_t *handle = static_cast<const private_handle_t *>(buffer);
- // Validate and dup ion fd from surfaceflinger
- // This works around bug 30281222
if (handle->fd < 0) {
return HWC2::Error::BadParameter;
- } else {
- close(ion_fd_);
- ion_fd_ = dup(handle->fd);
}
LayerBuffer *layer_buffer = &layer_->input_buffer;
@@ -125,36 +119,40 @@
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;
- }
- }
- if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
- layer_buffer->flags.secure_display = 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;
}
- layer_buffer->planes[0].fd = ion_fd_;
+ layer_buffer->flags.secure = secure;
+ layer_buffer->flags.secure_camera = secure_camera;
+ layer_buffer->flags.secure_display = secure_display;
+
+ layer_buffer->planes[0].fd = handle->fd;
layer_buffer->planes[0].offset = handle->offset;
layer_buffer->planes[0].stride = UINT32(handle->width);
layer_buffer->acquire_fence_fd = acquire_fence;
@@ -165,6 +163,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;
@@ -198,6 +210,9 @@
}
HWC2::Error HWCLayer::SetLayerColor(hwc_color_t color) {
+ if (client_requested_ != HWC2::Composition::SolidColor) {
+ return HWC2::Error::None;
+ }
layer_->solid_fill_color = GetUint32Color(color);
layer_->input_buffer.format = kFormatARGB8888;
DLOGV_IF(kTagCompManager, "[%" PRIu64 "][%" PRIu64 "] Layer color set to %x", display_id_, id_,
@@ -576,20 +591,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;
@@ -598,8 +616,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..e8e6e59 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;
@@ -95,11 +98,11 @@
const hwc2_display_t display_id_;
static std::atomic<hwc2_layer_t> next_id_;
std::queue<int32_t> release_fences_;
- int ion_fd_ = -1;
HWCBufferAllocator *buffer_allocator_ = NULL;
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 f7462d1..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>
@@ -344,7 +354,7 @@
int32_t HWCSession::DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display) {
SCOPE_LOCK(locker_);
- if (!device) {
+ if (!device || display != HWC_DISPLAY_VIRTUAL) {
return HWC2_ERROR_BAD_DISPLAY;
}
@@ -633,8 +643,12 @@
return HWC2_ERROR_BAD_DISPLAY;
}
+ if (display != HWC_DISPLAY_VIRTUAL) {
+ return HWC2_ERROR_UNSUPPORTED;
+ }
+
auto *hwc_session = static_cast<HWCSession *>(device);
- if (display == HWC_DISPLAY_VIRTUAL && hwc_session->hwc_display_[display]) {
+ if (hwc_session->hwc_display_[display]) {
auto vds = reinterpret_cast<HWCDisplayVirtual *>(hwc_session->hwc_display_[display]);
auto status = vds->SetOutputBuffer(buffer, releaseFence);
return INT32(status);
@@ -1306,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 288bbba..f09ed0e 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -99,11 +99,18 @@
}
HWCSession *hwc_session = static_cast<HWCSession *>(device);
- int32_t status = INT32(HWC2::Error::BadDisplay);
+ auto status = HWC2::Error::BadDisplay;
if (hwc_session->hwc_display_[display]) {
- status = hwc_session->hwc_display_[display]->CallLayerFunction(layer, member, args...);
+ status = HWC2::Error::BadLayer;
+ 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 status;
+ return INT32(status);
}
// HWC2 Functions that require a concrete implementation in hwc session
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;
}