Merge "hwc: increase app buffers to 3 on 8909_512 increase the app buffers to 3 to improve the performance of the Ux scenarios."
diff --git a/Android.mk b/Android.mk
index a128327..5070911 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,6 +5,7 @@
endif
display-hals := libgralloc libcopybit liblight libmemtrack libqservice libqdutils
+display-hals += hdmi_cec
ifeq ($(TARGET_USES_SDE), true)
sde-libs := displayengine/libs
diff --git a/displayengine/include/core/debug_interface.h b/displayengine/include/core/debug_interface.h
index c90e1ff..ff72321 100644
--- a/displayengine/include/core/debug_interface.h
+++ b/displayengine/include/core/debug_interface.h
@@ -48,6 +48,7 @@
kTagDriverConfig, //!< Debug log is tagged for driver config.
kTagBufferManager, //!< Debug log is tagged for buffer manager state transitions.
kTagOfflineCtrl, //!< Debug log is tagged for offline controller.
+ kTagScalar, //!< Debug log is tagged for Scalar Helper.
};
/*! @brief Display debug handler class.
diff --git a/displayengine/include/utils/constants.h b/displayengine/include/utils/constants.h
index 6f98b07..8630d45 100644
--- a/displayengine/include/utils/constants.h
+++ b/displayengine/include/utils/constants.h
@@ -33,6 +33,7 @@
#define INT(exp) static_cast<int>(exp)
#define FLOAT(exp) static_cast<float>(exp)
#define UINT8(exp) static_cast<uint8_t>(exp)
+#define UINT16(exp) static_cast<uint16_t>(exp)
#define UINT32(exp) static_cast<uint32_t>(exp)
#define INT32(exp) static_cast<int32_t>(exp)
@@ -53,6 +54,11 @@
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define ROUND_UP_ALIGN_DOWN(value, a) FLOAT(FloorToMultipleOf(UINT32(value + 0.5f), UINT32(a)))
+#define ROUND_UP_ALIGN_UP(value, a) FLOAT(CeilToMultipleOf(UINT32(value + 0.5f), UINT32(a)))
+
+#define IDLE_TIMEOUT_DEFAULT_MS 70
+
template <class T>
inline void Swap(T &a, T &b) {
T c(a);
diff --git a/displayengine/include/utils/debug.h b/displayengine/include/utils/debug.h
index 65079a9..5f65834 100644
--- a/displayengine/include/utils/debug.h
+++ b/displayengine/include/utils/debug.h
@@ -63,6 +63,8 @@
static uint32_t GetSimulationFlag();
static uint32_t GetHDMIResolution();
static uint32_t GetIdleTimeoutMs();
+ static bool IsRotatorDownScaleDisabled();
+ static bool IsDecimationDisabled();
private:
Debug();
diff --git a/displayengine/include/utils/rect.h b/displayengine/include/utils/rect.h
index f009cfd..0730529 100644
--- a/displayengine/include/utils/rect.h
+++ b/displayengine/include/utils/rect.h
@@ -40,7 +40,7 @@
bool IsValidRect(const LayerRect &rect);
LayerRect GetIntersection(const LayerRect &rect1, const LayerRect &rect2);
void LogRect(DebugTag debug_tag, const char *prefix, const LayerRect &roi);
- void NormalizeRect(const uint32_t &factor, LayerRect *rect);
+ void NormalizeRect(const uint32_t &align_x, const uint32_t &align_y, LayerRect *rect);
} // namespace sde
diff --git a/displayengine/libs/core/Android.mk b/displayengine/libs/core/Android.mk
index 56167e1..b7d2478 100644
--- a/displayengine/libs/core/Android.mk
+++ b/displayengine/libs/core/Android.mk
@@ -4,12 +4,15 @@
LOCAL_MODULE := libsde
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := hardware/qcom/display/displayengine/include/ \
- $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
- $(TARGET_OUT_HEADERS)/scalar/inc
+ $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_CFLAGS := -Wno-missing-field-initializers -Wno-unused-parameter \
-Wconversion -Wall -Werror \
-DLOG_TAG=\"SDE\"
-LOCAL_SHARED_LIBRARIES := libdl libsdeutils
+ifeq ($(TARGET_USES_SCALAR), true)
+ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/scalar/inc
+ LOCAL_CFLAGS += -DUSES_SCALAR
+endif
+LOCAL_SHARED_LIBRARIES := libdl libsdeutils libcutils
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_SRC_FILES := core_interface.cpp \
core_impl.cpp \
@@ -25,6 +28,7 @@
hw_interface.cpp \
hw_framebuffer.cpp \
dump_impl.cpp \
- buffer_manager.cpp
+ buffer_manager.cpp \
+ scalar_helper.cpp
include $(BUILD_SHARED_LIBRARY)
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index 7e888ee..06028a2 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -144,6 +144,10 @@
DisplayCompositionContext *display_comp_ctx =
reinterpret_cast<DisplayCompositionContext *>(comp_handle);
+ if (!display_comp_ctx) {
+ return kErrorParameters;
+ }
+
res_mgr_.UnregisterDisplay(display_comp_ctx->display_resource_ctx);
destroy_strategy_intf_(display_comp_ctx->strategy_intf);
@@ -154,11 +158,8 @@
"display type %d", registered_displays_, configured_displays_,
display_comp_ctx->display_type);
- if (display_comp_ctx) {
- delete display_comp_ctx;
- display_comp_ctx = NULL;
- }
-
+ delete display_comp_ctx;
+ display_comp_ctx = NULL;
return kErrorNone;
}
diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
index 058bacc..d403450 100644
--- a/displayengine/libs/core/display_base.cpp
+++ b/displayengine/libs/core/display_base.cpp
@@ -152,12 +152,9 @@
if (error == kErrorNone) {
error = hw_intf_->Validate(hw_device_, &hw_layers_);
if (error == kErrorNone) {
- error = comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
- if (error == kErrorNone) {
- // Strategy is successful now, wait for Commit().
- pending_commit_ = true;
- break;
- }
+ // Strategy is successful now, wait for Commit().
+ pending_commit_ = true;
+ break;
}
}
}
@@ -298,7 +295,7 @@
DisplayError error = kErrorNone;
- DLOGI("Set state = %d", state);
+ DLOGI("Set state = %d, display %d", state, display_type_);
if (state == state_) {
DLOGI("Same state transition is requested.");
@@ -307,13 +304,12 @@
switch (state) {
case kStateOff:
- // Invoke flush during suspend for HDMI and virtual displays. StateOff is handled
- // separately for primary in DisplayPrimary::SetDisplayState() function.
+ hw_layers_.info.count = 0;
error = hw_intf_->Flush(hw_device_);
if (error == kErrorNone) {
comp_manager_->Purge(display_comp_ctx_);
- state_ = state;
- hw_layers_.info.count = 0;
+
+ error = hw_intf_->PowerOff(hw_device_);
}
break;
diff --git a/displayengine/libs/core/display_primary.cpp b/displayengine/libs/core/display_primary.cpp
index ac44fe3..8eed8ee 100644
--- a/displayengine/libs/core/display_primary.cpp
+++ b/displayengine/libs/core/display_primary.cpp
@@ -35,29 +35,5 @@
CompManager *comp_manager, OfflineCtrl *offline_ctrl)
: DisplayBase(kPrimary, event_handler, kDevicePrimary, hw_intf, comp_manager, offline_ctrl) { }
-DisplayError DisplayPrimary::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_->PowerOff(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_primary.h b/displayengine/libs/core/display_primary.h
index 79fbddf..ea4cf2b 100644
--- a/displayengine/libs/core/display_primary.h
+++ b/displayengine/libs/core/display_primary.h
@@ -33,7 +33,6 @@
public:
DisplayPrimary(DisplayEventHandler *event_handler, HWInterface *hw_intf,
CompManager *comp_manager, OfflineCtrl *offline_ctrl);
- virtual DisplayError SetDisplayState(DisplayState state);
};
} // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 4a361da..f3cdb8b 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -43,7 +43,7 @@
#include <utils/debug.h>
#include "hw_framebuffer.h"
-
+#include "scalar_helper.h"
#define __CLASS__ "HWFrameBuffer"
@@ -542,49 +542,33 @@
return kErrorNone;
}
-DisplayError HWFrameBuffer::OpenRotatorSession(Handle device, HWLayers *hw_layers) {
+DisplayError HWFrameBuffer::OpenRotatorSession(Handle device, HWRotateInfo *rotate_info) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
HWRotator *hw_rotator = &hw_context->hw_rotator;
+ LayerBuffer *input_buffer = rotate_info->input_buffer;
+ HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
hw_rotator->Reset();
- HWLayersInfo &hw_layer_info = hw_layers->info;
+ STRUCT_VAR(mdp_rotation_config, mdp_rot_config);
+ mdp_rot_config.version = MDP_ROTATION_REQUEST_VERSION_1_0;
+ mdp_rot_config.input.width = input_buffer->width;
+ mdp_rot_config.input.height = input_buffer->height;
+ SetFormat(input_buffer->format, &mdp_rot_config.input.format);
+ mdp_rot_config.output.width = rot_buf_info->output_buffer.width;
+ mdp_rot_config.output.height = rot_buf_info->output_buffer.height;
+ SetFormat(rot_buf_info->output_buffer.format, &mdp_rot_config.output.format);
+ mdp_rot_config.frame_rate = rotate_info->frame_rate;
- for (uint32_t i = 0; i < hw_layer_info.count; i++) {
- Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
- LayerBuffer *input_buffer = layer.input_buffer;
- bool rot90 = (layer.transform.rotation == 90.0f);
-
- for (uint32_t count = 0; count < 2; count++) {
- HWRotateInfo *rotate_info = &hw_layers->config[i].rotates[count];
-
- if (rotate_info->valid) {
- HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
-
- if (rot_buf_info->session_id < 0) {
- STRUCT_VAR(mdp_rotation_config, mdp_rot_config);
- mdp_rot_config.version = MDP_ROTATION_REQUEST_VERSION_1_0;
- mdp_rot_config.input.width = input_buffer->width;
- mdp_rot_config.input.height = input_buffer->height;
- SetFormat(input_buffer->format, &mdp_rot_config.input.format);
- mdp_rot_config.output.width = rot_buf_info->output_buffer.width;
- mdp_rot_config.output.height = rot_buf_info->output_buffer.height;
- SetFormat(rot_buf_info->output_buffer.format, &mdp_rot_config.output.format);
- mdp_rot_config.frame_rate = layer.frame_rate;
-
- if (ioctl_(hw_context->device_fd, MDSS_ROTATION_OPEN, &mdp_rot_config) < 0) {
- IOCTL_LOGE(MDSS_ROTATION_OPEN, hw_context->type);
- return kErrorHardware;
- }
-
- rot_buf_info->session_id = mdp_rot_config.session_id;
-
- DLOGV_IF(kTagDriverConfig, "session_id %d", rot_buf_info->session_id);
- }
- }
- }
+ if (ioctl_(hw_context->device_fd, MDSS_ROTATION_OPEN, &mdp_rot_config) < 0) {
+ IOCTL_LOGE(MDSS_ROTATION_OPEN, hw_context->type);
+ return kErrorHardware;
}
+ rot_buf_info->session_id = mdp_rot_config.session_id;
+
+ DLOGV_IF(kTagDriverConfig, "session_id %d", rot_buf_info->session_id);
+
return kErrorNone;
}
@@ -700,7 +684,7 @@
}
mdp_layer.alpha = layer.plane_alpha;
- mdp_layer.z_order = static_cast<uint16_t>(i);
+ mdp_layer.z_order = UINT16(pipe_info->z_order);
mdp_layer.transp_mask = 0xffffffff;
SetBlending(layer.blending, &mdp_layer.blend_op);
mdp_layer.pipe_ndx = pipe_info->pipe_id;
@@ -722,14 +706,16 @@
}
}
- if (pipe_info->scale_data.enable_pxl_ext) {
+ mdp_scale_data* mdp_scale = hw_display->GetScaleDataRef(mdp_layer_count);
+#ifdef USES_SCALAR
+ // Set the configured scale data for MDP driver
+ ScalarHelper::GetInstance()->SetScaleData(i, !count, mdp_scale);
+ if (mdp_scale->enable_pxl_ext) {
if ((mdp_layer.flags & MDP_LAYER_DEINTERLACE) && (layer.transform.rotation == 90.0f))
- mdp_buffer.width = pipe_info->scale_data.src_width;
- hw_display->SetScaleData(pipe_info->scale_data, mdp_layer_count);
+ ScalarHelper::GetInstance()->UpdateSrcWidth(i, !count, &mdp_buffer.width);
}
-
- // Send scale data to MDP driver
- mdp_layer.scale = hw_display->GetScaleRef(mdp_layer_count);
+#endif
+ mdp_layer.scale = mdp_scale;
mdp_layer_count++;
DLOGV_IF(kTagDriverConfig, "******************* Layer[%d] %s pipe Input ******************",
@@ -780,12 +766,34 @@
mdp_commit.flags |= MDP_VALIDATE_LAYER;
if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+ DumpLayerCommit(hw_display->mdp_disp_commit);
return kErrorHardware;
}
return kErrorNone;
}
+void HWFrameBuffer::DumpLayerCommit(mdp_layer_commit &layer_commit) {
+ mdp_layer_commit_v1 &mdp_commit = layer_commit.commit_v1;
+ mdp_input_layer *mdp_layers = mdp_commit.input_layers;
+
+ DLOGE("mdp_commt: flags = %x, release fence = %x", mdp_commit.flags, mdp_commit.release_fence);
+ DLOGE("left_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.left_roi.x, mdp_commit.left_roi.y,
+ mdp_commit.left_roi.w, mdp_commit.left_roi.h);
+ DLOGE("right_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.right_roi.x,
+ mdp_commit.right_roi.y, mdp_commit.right_roi.w, mdp_commit.right_roi.h);
+ for (uint32_t i = 0; i < mdp_commit.input_layer_cnt; i++) {
+ DLOGE("mdp_commt: layer_cnt = %d, pipe_ndx = %x, zorder = %d, flags = %x",
+ i, mdp_layers[i].pipe_ndx, mdp_layers[i].z_order, mdp_layers[i].flags);
+ mdp_rect &src_rect = mdp_layers[i].src_rect;
+ DLOGE("src rect: x = %d, y = %d, w = %d, h = %d",
+ src_rect.x, src_rect.y, src_rect.w, src_rect.h);
+ mdp_rect &dst_rect = mdp_layers[i].dst_rect;
+ DLOGE("dst rect: x = %d, y = %d, w = %d, h = %d",
+ dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h);
+ }
+}
+
DisplayError HWFrameBuffer::DisplayCommit(HWContext *hw_context, HWLayers *hw_layers) {
DTRACE_SCOPED();
@@ -873,6 +881,7 @@
mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+ DumpLayerCommit(hw_display->mdp_disp_commit);
return kErrorHardware;
}
@@ -911,7 +920,7 @@
return kErrorNone;
}
-DisplayError HWFrameBuffer::RotatorValidate(HWContext *hw_context, HWLayers *hw_layers) {
+void HWFrameBuffer::SetRotatorCtrlParams(HWContext *hw_context, HWLayers *hw_layers) {
HWRotator *hw_rotator = &hw_context->hw_rotator;
DLOGV_IF(kTagDriverConfig, "************************* %s Validate Input ************************",
GetDeviceString(hw_context->type));
@@ -978,17 +987,9 @@
}
}
}
-
- mdp_rot_request->flags = MDSS_ROTATION_REQUEST_VALIDATE;
- if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, mdp_rot_request) < 0) {
- IOCTL_LOGE(MDSS_ROTATION_REQUEST, hw_context->type);
- return kErrorHardware;
- }
-
- return kErrorNone;
}
-DisplayError HWFrameBuffer::RotatorCommit(HWContext *hw_context, HWLayers *hw_layers) {
+void HWFrameBuffer::SetRotatorBufferParams(HWContext *hw_context, HWLayers *hw_layers) {
HWRotator *hw_rotator = &hw_context->hw_rotator;
mdp_rotation_request *mdp_rot_request = &hw_rotator->mdp_rot_req;
HWLayersInfo &hw_layer_info = hw_layers->info;
@@ -1041,14 +1042,36 @@
}
}
}
+}
- mdp_rot_request->flags &= ~MDSS_ROTATION_REQUEST_VALIDATE;
- if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, mdp_rot_request) < 0) {
+DisplayError HWFrameBuffer::RotatorValidate(HWContext *hw_context, HWLayers *hw_layers) {
+ HWRotator *hw_rotator = &hw_context->hw_rotator;
+ SetRotatorCtrlParams(hw_context, hw_layers);
+
+ hw_rotator->mdp_rot_req.flags = MDSS_ROTATION_REQUEST_VALIDATE;
+ if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, &hw_rotator->mdp_rot_req) < 0) {
IOCTL_LOGE(MDSS_ROTATION_REQUEST, hw_context->type);
return kErrorHardware;
}
- rot_count = 0;
+ return kErrorNone;
+}
+
+DisplayError HWFrameBuffer::RotatorCommit(HWContext *hw_context, HWLayers *hw_layers) {
+ HWRotator *hw_rotator = &hw_context->hw_rotator;
+ HWLayersInfo &hw_layer_info = hw_layers->info;
+ uint32_t rot_count = 0;
+
+ SetRotatorCtrlParams(hw_context, hw_layers);
+
+ SetRotatorBufferParams(hw_context, hw_layers);
+
+ hw_rotator->mdp_rot_req.flags &= ~MDSS_ROTATION_REQUEST_VALIDATE;
+ if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, &hw_rotator->mdp_rot_req) < 0) {
+ IOCTL_LOGE(MDSS_ROTATION_REQUEST, hw_context->type);
+ return kErrorHardware;
+ }
+
for (uint32_t i = 0; i < hw_layer_info.count; i++) {
Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
@@ -1059,7 +1082,7 @@
if (rotate_info->valid) {
HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
- mdp_rotation_item *mdp_rot_item = &mdp_rot_request->list[rot_count];
+ mdp_rotation_item *mdp_rot_item = &hw_rotator->mdp_rot_req.list[rot_count];
SyncMerge(layer.input_buffer->release_fence_fd, dup(mdp_rot_item->output.fence),
&layer.input_buffer->release_fence_fd);
@@ -1079,14 +1102,27 @@
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
HWDisplay *hw_display = &hw_context->hw_display;
- hw_display->Reset();
- mdp_layer_commit_v1 &mdp_commit = hw_display->mdp_disp_commit.commit_v1;
- mdp_commit.input_layer_cnt = 0;
- mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
+ switch (hw_context->type) {
+ case kDevicePrimary:
+ case kDeviceHDMI:
+ case kDeviceVirtual:
+ {
+ hw_display->Reset();
+ mdp_layer_commit_v1 &mdp_commit = hw_display->mdp_disp_commit.commit_v1;
+ mdp_commit.input_layer_cnt = 0;
+ mdp_commit.output_layer = NULL;
- if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) == -1) {
- IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
- return kErrorHardware;
+ mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
+ if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
+ IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+ DumpLayerCommit(hw_display->mdp_disp_commit);
+ return kErrorHardware;
+ }
+ }
+ break;
+ default:
+ DLOGE("Flush is not supported for the device %s", GetDeviceString(hw_context->type));
+ return kErrorNotSupported;
}
return kErrorNone;
@@ -1142,6 +1178,7 @@
*target = width * 3;
break;
case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
case kFormatYCbCr420Planar:
case kFormatYCrCb420Planar:
case kFormatYCbCr420SemiPlanar:
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index 5c01e5f..b2a37ab 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -56,7 +56,7 @@
virtual DisplayError Doze(Handle device);
virtual DisplayError SetVSyncState(Handle device, bool enable);
virtual DisplayError Standby(Handle device);
- virtual DisplayError OpenRotatorSession(Handle device, HWLayers *hw_layers);
+ virtual DisplayError OpenRotatorSession(Handle device, HWRotateInfo *rotate_info);
virtual DisplayError CloseRotatorSession(Handle device, int32_t session_id);
virtual DisplayError Validate(Handle device, HWLayers *hw_layers);
virtual DisplayError Commit(Handle device, HWLayers *hw_layers);
@@ -86,38 +86,10 @@
mdp_disp_commit.commit_v1.input_layers = mdp_in_layers;
mdp_disp_commit.commit_v1.output_layer = &mdp_out_layer;
mdp_disp_commit.commit_v1.release_fence = -1;
+ mdp_disp_commit.commit_v1.retire_fence = -1;
}
- mdp_scale_data* GetScaleRef(uint32_t index) { return &scale_data[index]; }
-
- void SetScaleData(scalar::Scale scale, uint32_t index) {
- mdp_scale_data *mdp_scale = &scale_data[index];
- mdp_scale->enable_pxl_ext = scale.enable_pxl_ext;
-
- for (int i = 0; i < MAX_PLANES; i++) {
- mdp_scale->init_phase_x[i] = scale.init_phase_x[i];
- mdp_scale->phase_step_x[i] = scale.phase_step_x[i];
- mdp_scale->init_phase_y[i] = scale.init_phase_y[i];
- mdp_scale->phase_step_y[i] = scale.phase_step_y[i];
-
- mdp_scale->num_ext_pxls_left[i] = scale.left.extension[i];
- mdp_scale->num_ext_pxls_top[i] = scale.top.extension[i];
- mdp_scale->num_ext_pxls_right[i] = scale.right.extension[i];
- mdp_scale->num_ext_pxls_btm[i] = scale.bottom.extension[i];
-
- mdp_scale->left_ftch[i] = scale.left.overfetch[i];
- mdp_scale->top_ftch[i] = scale.top.overfetch[i];
- mdp_scale->right_ftch[i] = scale.right.overfetch[i];
- mdp_scale->btm_ftch[i] = scale.bottom.overfetch[i];
-
- mdp_scale->left_rpt[i] = scale.left.repeat[i];
- mdp_scale->top_rpt[i] = scale.top.repeat[i];
- mdp_scale->right_rpt[i] = scale.right.repeat[i];
- mdp_scale->btm_rpt[i] = scale.bottom.repeat[i];
-
- mdp_scale->roi_w[i] = scale.roi_width[i];
- }
- }
+ mdp_scale_data* GetScaleDataRef(uint32_t index) { return &scale_data[index]; }
};
struct HWRotator {
@@ -192,9 +164,12 @@
DisplayError DisplayValidate(HWContext *device_ctx, HWLayers *hw_layers);
DisplayError DisplayCommit(HWContext *device_ctx, HWLayers *hw_layers);
+ void SetRotatorCtrlParams(HWContext *device_ctx, HWLayers *hw_layers);
+ void SetRotatorBufferParams(HWContext *device_ctx, HWLayers *hw_layers);
+
DisplayError RotatorValidate(HWContext *device_ctx, HWLayers *hw_layers);
DisplayError RotatorCommit(HWContext *device_ctx, HWLayers *hw_layers);
-
+ void DumpLayerCommit(mdp_layer_commit &layer_commit);
inline DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target);
inline DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format,
uint32_t width, uint32_t *target);
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index 084768e..b92846f 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -30,7 +30,6 @@
#include <utils/constants.h>
#include <core/buffer_allocator.h>
#include <core/buffer_sync_handler.h>
-#include <scalar.h>
namespace sde {
@@ -89,8 +88,8 @@
HWResourceInfo()
: hw_version(0), hw_revision(0), num_dma_pipe(0), num_vig_pipe(0), num_rgb_pipe(0),
num_cursor_pipe(0), num_blending_stages(0), num_rotator(0), num_control(0),
- num_mixer_to_disp(0), smp_total(0), smp_size(0), num_smp_per_pipe(0), max_scale_up(0),
- max_scale_down(0), max_bandwidth_low(0), max_bandwidth_high(0), max_mixer_width(2048),
+ num_mixer_to_disp(0), smp_total(0), smp_size(0), num_smp_per_pipe(0), max_scale_up(1),
+ max_scale_down(1), max_bandwidth_low(0), max_bandwidth_high(0), max_mixer_width(2048),
max_pipe_bw(0), max_sde_clk(0), clk_fudge_factor(1.0f), has_bwc(false),
has_decimation(false), has_macrotile(false), has_rotator_downscale(false),
has_non_scalar_rgb(false), is_src_split(false), always_src_split(false) { }
@@ -107,18 +106,20 @@
};
struct HWRotateInfo {
+ LayerBuffer *input_buffer;
uint32_t pipe_id;
LayerRect src_roi;
LayerRect dst_roi;
LayerBufferFormat dst_format;
HWBlockType writeback_id;
- float downscale_ratio_x;
- float downscale_ratio_y;
+ float downscale_ratio;
HWBufferInfo hw_buffer_info;
bool valid;
+ uint32_t frame_rate;
- HWRotateInfo() : pipe_id(0), dst_format(kFormatInvalid), writeback_id(kHWWriteback0),
- downscale_ratio_x(1.0f), downscale_ratio_y(1.0f), valid(false) { }
+ HWRotateInfo() : input_buffer(NULL), pipe_id(0), dst_format(kFormatInvalid),
+ writeback_id(kHWWriteback0), downscale_ratio(1.0f), valid(false),
+ frame_rate(0) { }
void Reset() { *this = HWRotateInfo(); }
};
@@ -129,10 +130,11 @@
LayerRect dst_roi;
uint8_t horizontal_decimation;
uint8_t vertical_decimation;
- scalar::Scale scale_data;
bool valid;
+ uint32_t z_order;
- HWPipeInfo() : pipe_id(0), horizontal_decimation(0), vertical_decimation(0), valid(false) { }
+ HWPipeInfo() : pipe_id(0), horizontal_decimation(0), vertical_decimation(0), valid(false),
+ z_order(0) { }
void Reset() { *this = HWPipeInfo(); }
};
@@ -195,7 +197,7 @@
virtual DisplayError Doze(Handle device) = 0;
virtual DisplayError SetVSyncState(Handle device, bool enable) = 0;
virtual DisplayError Standby(Handle device) = 0;
- virtual DisplayError OpenRotatorSession(Handle device, HWLayers *hw_layers) = 0;
+ virtual DisplayError OpenRotatorSession(Handle device, HWRotateInfo *rotate_info) = 0;
virtual DisplayError CloseRotatorSession(Handle device, int32_t session_id) = 0;
virtual DisplayError Validate(Handle device, HWLayers *hw_layers) = 0;
virtual DisplayError Commit(Handle device, HWLayers *hw_layers) = 0;
diff --git a/displayengine/libs/core/offline_ctrl.cpp b/displayengine/libs/core/offline_ctrl.cpp
index 5ffaf22..8794074 100644
--- a/displayengine/libs/core/offline_ctrl.cpp
+++ b/displayengine/libs/core/offline_ctrl.cpp
@@ -85,34 +85,30 @@
DisplayOfflineContext *disp_offline_ctx = reinterpret_cast<DisplayOfflineContext *>(display_ctx);
+ disp_offline_ctx->pending_rot_commit = false;
+
if (!hw_rotator_device_ && IsRotationRequired(hw_layers)) {
DLOGV_IF(kTagOfflineCtrl, "No Rotator device found");
return kErrorHardware;
}
- disp_offline_ctx->pending_rot_commit = false;
-
- uint32_t i = 0;
- while (hw_layers->closed_session_ids[i] >= 0) {
- error = hw_intf_->CloseRotatorSession(hw_rotator_device_, hw_layers->closed_session_ids[i]);
- if (LIKELY(error != kErrorNone)) {
- DLOGE("Rotator close session failed");
- return error;
- }
- hw_layers->closed_session_ids[i++] = -1;
+ error = CloseRotatorSession(hw_layers);
+ if (LIKELY(error != kErrorNone)) {
+ DLOGE("Close rotator session failed for display %d", disp_offline_ctx->display_type);
+ return error;
}
if (IsRotationRequired(hw_layers)) {
- error = hw_intf_->OpenRotatorSession(hw_rotator_device_, hw_layers);
+ error = OpenRotatorSession(hw_layers);
if (LIKELY(error != kErrorNone)) {
- DLOGE("Rotator open session failed");
+ DLOGE("Open rotator session failed for display %d", disp_offline_ctx->display_type);
return error;
}
error = hw_intf_->Validate(hw_rotator_device_, hw_layers);
if (LIKELY(error != kErrorNone)) {
- DLOGE("Rotator validation failed");
+ DLOGE("Rotator validation failed for display %d", disp_offline_ctx->display_type);
return error;
}
disp_offline_ctx->pending_rot_commit = true;
@@ -129,7 +125,7 @@
if (disp_offline_ctx->pending_rot_commit) {
error = hw_intf_->Commit(hw_rotator_device_, hw_layers);
if (error != kErrorNone) {
- DLOGE("Rotator commit failed");
+ DLOGE("Rotator commit failed for display %d", disp_offline_ctx->display_type);
return error;
}
disp_offline_ctx->pending_rot_commit = false;
@@ -138,6 +134,50 @@
return kErrorNone;
}
+DisplayError OfflineCtrl::OpenRotatorSession(HWLayers *hw_layers) {
+ HWLayersInfo &hw_layer_info = hw_layers->info;
+ DisplayError error = kErrorNone;
+
+ for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+ Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
+ bool rot90 = (layer.transform.rotation == 90.0f);
+
+ for (uint32_t count = 0; count < 2; count++) {
+ HWRotateInfo *rotate_info = &hw_layers->config[i].rotates[count];
+ HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
+
+ if (!rotate_info->valid || rot_buf_info->session_id >= 0) {
+ continue;
+ }
+
+ rotate_info->input_buffer = layer.input_buffer;
+ rotate_info->frame_rate = layer.frame_rate;
+
+ error = hw_intf_->OpenRotatorSession(hw_rotator_device_, rotate_info);
+ if (LIKELY(error != kErrorNone)) {
+ return error;
+ }
+ }
+ }
+
+ return kErrorNone;
+}
+
+DisplayError OfflineCtrl::CloseRotatorSession(HWLayers *hw_layers) {
+ DisplayError error = kErrorNone;
+ uint32_t i = 0;
+
+ while (hw_layers->closed_session_ids[i] >= 0) {
+ error = hw_intf_->CloseRotatorSession(hw_rotator_device_, hw_layers->closed_session_ids[i]);
+ if (LIKELY(error != kErrorNone)) {
+ return error;
+ }
+ hw_layers->closed_session_ids[i++] = -1;
+ }
+
+ return kErrorNone;
+}
+
bool OfflineCtrl::IsRotationRequired(HWLayers *hw_layers) {
HWLayersInfo &layer_info = hw_layers->info;
diff --git a/displayengine/libs/core/offline_ctrl.h b/displayengine/libs/core/offline_ctrl.h
index fafdf7c..fa8b264 100644
--- a/displayengine/libs/core/offline_ctrl.h
+++ b/displayengine/libs/core/offline_ctrl.h
@@ -50,6 +50,8 @@
DisplayOfflineContext() : display_type(kPrimary), pending_rot_commit(false) { }
};
+ DisplayError OpenRotatorSession(HWLayers *hw_layers);
+ DisplayError CloseRotatorSession(HWLayers *hw_layers);
bool IsRotationRequired(HWLayers *hw_layers);
HWInterface *hw_intf_;
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
index d3c2d26..27a4e41 100644
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -31,40 +31,55 @@
#define __CLASS__ "ResManager"
-using scalar::PipeInfo;
-using scalar::LayerInfo;
-
namespace sde {
-void ResManager::RotationConfig(const LayerTransform &transform, const float &scale_x,
- const float &scale_y, LayerRect *src_rect,
+void ResManager::RotationConfig(LayerBufferFormat format, const LayerTransform &transform,
+ const float &downscale, LayerRect *src_rect,
struct HWLayerConfig *layer_config, uint32_t *rotate_count) {
HWRotateInfo *rotate = &layer_config->rotates[0];
float src_width = src_rect->right - src_rect->left;
float src_height = src_rect->bottom - src_rect->top;
+ bool rot90 = IsRotationNeeded(transform.rotation);
LayerRect dst_rect;
// Rotate output is a temp buffer, always output to the top left corner for saving memory
dst_rect.top = 0.0f;
dst_rect.left = 0.0f;
- rotate->downscale_ratio_x = scale_x;
- rotate->downscale_ratio_y = scale_y;
+ rotate->downscale_ratio = downscale;
// downscale when doing rotation
- if (IsRotationNeeded(transform.rotation)) {
- dst_rect.right = src_height / rotate->downscale_ratio_x;
- dst_rect.bottom = src_width / rotate->downscale_ratio_y;
+ if (rot90) {
+ if (downscale > 1.0f) {
+ src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
+ src_rect->bottom = src_rect->top + src_height;
+ src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale);
+ src_rect->right = src_rect->left + src_width;
+ }
+ dst_rect.right = src_height / downscale;
+ dst_rect.bottom = src_width / downscale;
} else {
- dst_rect.right = src_width / rotate->downscale_ratio_x;
- dst_rect.bottom = src_height / rotate->downscale_ratio_y;
+ if (downscale > 1.0f) {
+ src_width = ROUND_UP_ALIGN_DOWN(src_width, downscale);
+ src_rect->right = src_rect->left + src_width;
+ src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
+ src_rect->bottom = src_rect->top + src_height;
+ }
+ dst_rect.right = src_width / downscale;
+ dst_rect.bottom = src_height / downscale;
}
- dst_rect.right = floorf(dst_rect.right);
- dst_rect.bottom = floorf(dst_rect.bottom);
rotate->src_roi = *src_rect;
rotate->valid = true;
rotate->dst_roi = dst_rect;
+ // Set WHF for Rotator output
+ LayerBufferFormat ouput_format;
+ SetRotatorOutputFormat(format, false /* bwc */, rot90, downscale, &ouput_format);
+ HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
+ hw_buffer_info->buffer_config.format = ouput_format;
+ hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right);
+ hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom);
+
*src_rect = dst_rect;
layer_config->num_rotate = 1;
(*rotate_count)++;
@@ -72,15 +87,37 @@
DisplayError ResManager::SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
const LayerTransform &transform, const LayerRect &src_rect,
- const LayerRect &dst_rect, HWLayerConfig *layer_config) {
+ const LayerRect &dst_rect, HWLayerConfig *layer_config,
+ uint32_t align_x) {
HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
HWPipeInfo *left_pipe = &layer_config->left_pipe;
HWPipeInfo *right_pipe = &layer_config->right_pipe;
+ float src_width = src_rect.right - src_rect.left;
+ float dst_width = dst_rect.right - dst_rect.left;
+ float src_height = src_rect.bottom - src_rect.top;
+ float dst_height = dst_rect.bottom - dst_rect.top;
+ float left_mixer_width = FLOAT(display_attributes.split_left);
- if ((src_rect.right - src_rect.left) > kMaxSourcePipeWidth ||
- (dst_rect.right - dst_rect.left) > kMaxInterfaceWidth || hw_res_info_.always_src_split) {
+ uint8_t decimation = 0;
+ if (CalculateDecimation((src_height / dst_height), &decimation) != kErrorNone) {
+ return kErrorNotSupported;
+ }
+ // Adjust source height to consider decimation
+ src_height /= powf(2.0f, decimation);
+
+ // No need to include common factors in clock calculation of pipe & mixer
+ float pipe_clock = MAX(dst_width, (dst_width * src_height / dst_height));
+ float mixer_clock = left_mixer_width;
+
+ // Layer cannot qualify for SrcSplit if source or destination width exceeds max pipe width.
+ // For perf/power optimization, even if "always_src_split" is enabled, use 2 pipes only if:
+ // 1. Source width is greater than split_left (left_mixer_width)
+ // 2. Pipe clock exceeds the mixer clock
+ if ((src_width > kMaxSourcePipeWidth) || (dst_width > kMaxSourcePipeWidth) ||
+ (hw_res_info_.always_src_split && ((src_width > left_mixer_width) ||
+ (pipe_clock > mixer_clock)))) {
SplitRect(transform.flip_horizontal, src_rect, dst_rect, &left_pipe->src_roi,
- &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi);
+ &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi, align_x);
left_pipe->valid = true;
right_pipe->valid = true;
} else {
@@ -96,7 +133,7 @@
DisplayError ResManager::DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
const LayerTransform &transform,
const LayerRect &src_rect, const LayerRect &dst_rect,
- HWLayerConfig *layer_config) {
+ HWLayerConfig *layer_config, uint32_t align_x) {
LayerRect scissor_dst_left, scissor_dst_right;
HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
@@ -111,36 +148,43 @@
dst_left = dst_rect;
crop_right = crop_left;
dst_right = dst_left;
- CalculateCropRects(scissor, transform, &crop_left, &dst_left);
+ bool crop_left_valid = CalculateCropRects(scissor, transform, &crop_left, &dst_left);
scissor.left = FLOAT(display_attributes.split_left);
scissor.top = 0.0f;
scissor.right = FLOAT(display_attributes.x_pixels);
scissor.bottom = FLOAT(display_attributes.y_pixels);
- CalculateCropRects(scissor, transform, &crop_right, &dst_right);
- if ((crop_left.right - crop_left.left) > kMaxSourcePipeWidth) {
- if (crop_right.right != crop_right.left) {
+ bool crop_right_valid = false;
+
+ if (IsValidRect(scissor)) {
+ crop_right_valid = CalculateCropRects(scissor, transform, &crop_right, &dst_right);
+ }
+
+ if (crop_left_valid && (crop_left.right - crop_left.left) > kMaxSourcePipeWidth) {
+ if (crop_right_valid) {
DLOGV_IF(kTagResources, "Need more than 2 pipes: left width = %.0f, right width = %.0f",
crop_left.right - crop_left.left, crop_right.right - crop_right.left);
return kErrorNotSupported;
}
// 2 pipes both are on the left
SplitRect(transform.flip_horizontal, crop_left, dst_left, &left_pipe->src_roi,
- &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi);
+ &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi, align_x);
left_pipe->valid = true;
right_pipe->valid = true;
- } else if ((crop_right.right - crop_right.left) > kMaxSourcePipeWidth) {
- if (crop_left.right != crop_left.left) {
+ crop_right_valid = true;
+ } else if (crop_right_valid && (crop_right.right - crop_right.left) > kMaxSourcePipeWidth) {
+ if (crop_left_valid) {
DLOGV_IF(kTagResources, "Need more than 2 pipes: left width = %.0f, right width = %.0f",
crop_left.right - crop_left.left, crop_right.right - crop_right.left);
return kErrorNotSupported;
}
// 2 pipes both are on the right
SplitRect(transform.flip_horizontal, crop_right, dst_right, &left_pipe->src_roi,
- &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi);
+ &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi, align_x);
left_pipe->valid = true;
right_pipe->valid = true;
- } else if (UINT32(dst_left.right) > UINT32(dst_left.left)) {
+ crop_left_valid = true;
+ } else if (crop_left_valid) {
// assign left pipe
left_pipe->src_roi = crop_left;
left_pipe->dst_roi = dst_left;
@@ -151,7 +195,7 @@
}
// assign right pipe if needed
- if (UINT32(dst_right.right) > UINT32(dst_right.left)) {
+ if (crop_right_valid) {
if (left_pipe->valid) {
right_pipe->src_roi = crop_right;
right_pipe->dst_roi = dst_right;
@@ -177,10 +221,11 @@
HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
HWLayersInfo &layer_info = hw_layers->info;
DisplayError error = kErrorNone;
+ uint32_t z_order = 0;
for (uint32_t i = 0; i < layer_info.count; i++) {
Layer& layer = layer_info.stack->layers[layer_info.index[i]];
- float rot_scale_x = 1.0f, rot_scale_y = 1.0f;
+ float rot_scale = 1.0f;
if (!IsValidDimension(layer.src_rect, layer.dst_rect)) {
DLOGV_IF(kTagResources, "Input is invalid");
LogRect(kTagResources, "input layer src_rect", layer.src_rect);
@@ -193,14 +238,30 @@
dst_rect = layer.dst_rect;
scissor.right = FLOAT(display_attributes.x_pixels);
scissor.bottom = FLOAT(display_attributes.y_pixels);
- CalculateCropRects(scissor, layer.transform, &src_rect, &dst_rect);
-
- if (ValidateScaling(layer, src_rect, dst_rect, &rot_scale_x, &rot_scale_y))
- return kErrorNotSupported;
struct HWLayerConfig *layer_config = &hw_layers->config[i];
HWPipeInfo &left_pipe = layer_config->left_pipe;
HWPipeInfo &right_pipe = layer_config->right_pipe;
+
+ if (!CalculateCropRects(scissor, layer.transform, &src_rect, &dst_rect)) {
+ layer_config->Reset();
+ left_pipe.Reset();
+ right_pipe.Reset();
+ continue;
+ }
+
+ uint32_t align_x = 1, align_y = 1;
+ if (IsYuvFormat(layer.input_buffer->format)) {
+ // TODO(user) Select x and y alignment according to the format
+ align_x = 2;
+ align_y = 2;
+ NormalizeRect(align_x, align_y, &src_rect);
+ }
+
+ if (ValidateScaling(layer, src_rect, dst_rect, &rot_scale)) {
+ return kErrorNotSupported;
+ }
+
// config rotator first
for (uint32_t j = 0; j < kMaxRotatePerLayer; j++) {
layer_config->rotates[j].Reset();
@@ -208,143 +269,152 @@
layer_config->num_rotate = 0;
LayerTransform transform = layer.transform;
- if (IsRotationNeeded(transform.rotation) ||
- UINT32(rot_scale_x) != 1 || UINT32(rot_scale_y) != 1) {
- RotationConfig(layer.transform, rot_scale_x, rot_scale_y, &src_rect, layer_config,
- rotate_count);
+ if (IsRotationNeeded(transform.rotation) || UINT32(rot_scale) != 1) {
+ RotationConfig(layer.input_buffer->format, layer.transform, rot_scale, &src_rect,
+ layer_config, rotate_count);
// rotator will take care of flipping, reset tranform
transform = LayerTransform();
}
if (hw_res_info_.is_src_split) {
error = SrcSplitConfig(display_resource_ctx, transform, src_rect,
- dst_rect, layer_config);
+ dst_rect, layer_config, align_x);
} else {
error = DisplaySplitConfig(display_resource_ctx, transform, src_rect,
- dst_rect, layer_config);
+ dst_rect, layer_config, align_x);
}
- if (error != kErrorNone)
+ if (error != kErrorNone) {
break;
-
- // 1. Normalize Video layer source rectangle to multiple of 2, as MDP hardware require source
- // rectangle of video layer to be even.
- // 2. Normalize source and destination rect of a layer to multiple of 1.
- uint32_t factor = (1 << layer.input_buffer->flags.video);
- if (left_pipe.valid) {
- NormalizeRect(factor, &left_pipe.src_roi);
- NormalizeRect(1, &left_pipe.dst_roi);
}
- if (right_pipe.valid) {
- NormalizeRect(factor, &right_pipe.src_roi);
- NormalizeRect(1, &right_pipe.dst_roi);
+ error = AlignPipeConfig(layer, transform, &left_pipe, &right_pipe, align_x, align_y);
+ if (error != kErrorNone) {
+ break;
}
- DLOGV_IF(kTagResources, "layer = %d, left pipe_id = %x",
- i, layer_config->left_pipe.pipe_id);
+ DLOGV_IF(kTagResources, "==== layer = %d, left pipe valid = %d ====",
+ i, layer_config->left_pipe.valid);
LogRect(kTagResources, "input layer src_rect", layer.src_rect);
LogRect(kTagResources, "input layer dst_rect", layer.dst_rect);
for (uint32_t k = 0; k < layer_config->num_rotate; k++) {
- DLOGV_IF(kTagResources, "rotate num = %d, scale_x = %.2f, scale_y = %.2f",
- k, rot_scale_x, rot_scale_y);
+ DLOGV_IF(kTagResources, "rotate num = %d, scale_x = %.2f", k, rot_scale);
LogRect(kTagResources, "rotate src", layer_config->rotates[k].src_roi);
LogRect(kTagResources, "rotate dst", layer_config->rotates[k].dst_roi);
}
+
LogRect(kTagResources, "cropped src_rect", src_rect);
LogRect(kTagResources, "cropped dst_rect", dst_rect);
LogRect(kTagResources, "left pipe src", layer_config->left_pipe.src_roi);
LogRect(kTagResources, "left pipe dst", layer_config->left_pipe.dst_roi);
- if (hw_layers->config[i].right_pipe.pipe_id) {
+ if (hw_layers->config[i].right_pipe.valid) {
LogRect(kTagResources, "right pipe src", layer_config->right_pipe.src_roi);
LogRect(kTagResources, "right pipe dst", layer_config->right_pipe.dst_roi);
}
+ // set z_order, left_pipe should always be valid
+ left_pipe.z_order = z_order;
+ if (layer_config->right_pipe.valid) {
+ // use different z_order if 2 pipes are on one mixer and without src split support
+ if (!hw_res_info_.is_src_split &&
+ ((left_pipe.dst_roi.right <= display_attributes.split_left &&
+ right_pipe.dst_roi.right <= display_attributes.split_left) ||
+ (left_pipe.dst_roi.left >= display_attributes.split_left &&
+ right_pipe.dst_roi.left >= display_attributes.split_left))) {
+ z_order++;
+ }
+ layer_config->right_pipe.z_order = z_order;
+ }
+ z_order++;
+ if (z_order >= hw_res_info_.num_blending_stages) {
+ DLOGV_IF(kTagResources, "z_order is over the limit: z_order = %d", z_order);
+ return kErrorResources;
+ }
}
return error;
}
DisplayError ResManager::ValidateScaling(const Layer &layer, const LayerRect &crop,
- const LayerRect &dst, float *rot_scale_x,
- float *rot_scale_y) {
- bool rotated90 = IsRotationNeeded(layer.transform.rotation);
+ const LayerRect &dst, float *rot_scale) {
+ bool rotated90 = IsRotationNeeded(layer.transform.rotation) && (rot_scale != NULL);
float crop_width = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
float crop_height = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
float dst_width = dst.right - dst.left;
float dst_height = dst.bottom - dst.top;
if ((dst_width < 1.0f) || (dst_height < 1.0f)) {
- DLOGV_IF(kTagResources, "Destination region is too small w = %d, h = %d",
- dst_width, dst_height);
+ DLOGV_IF(kTagResources, "dst ROI is too small w = %.0f, h = %.0f, right = %.0f, bottom = %.0f",
+ dst_width, dst_height, dst.right, dst.bottom);
return kErrorNotSupported;
}
if ((crop_width < 1.0f) || (crop_height < 1.0f)) {
- DLOGV_IF(kTagResources, "source region is too small w = %d, h = %d", crop_width, crop_height);
+ DLOGV_IF(kTagResources, "src ROI is too small w = %.0f, h = %.0f, right = %.0f, bottom = %.0f",
+ crop_width, crop_height, crop.right, crop.bottom);
return kErrorNotSupported;
}
- if (((crop_width - dst_width) == 1) || ((crop_height - dst_height) == 1)) {
- DLOGV_IF(kTagResources, "One pixel downscaling detected crop_w %d, dst_w %d, crop_h %d, " \
- "dst_h %d", crop_width, dst_width, crop_height, dst_height);
+ if ((UINT32(crop_width - dst_width) == 1) || (UINT32(crop_height - dst_height) == 1)) {
+ DLOGV_IF(kTagResources, "One pixel downscaling detected crop_w = %.0f, dst_w = %.0f, " \
+ "crop_h = %.0f, dst_h = %.0f", crop_width, dst_width, crop_height, dst_height);
return kErrorNotSupported;
}
float scale_x = crop_width / dst_width;
float scale_y = crop_height / dst_height;
+ uint32_t rot_scale_local = 1;
if ((UINT32(scale_x) > 1) || (UINT32(scale_y) > 1)) {
- const uint32_t max_scale_down = hw_res_info_.max_scale_down;
- uint32_t max_downscale_with_rotator;
+ float max_scale_down = FLOAT(hw_res_info_.max_scale_down);
- if (hw_res_info_.has_rotator_downscale)
- max_downscale_with_rotator = max_scale_down * kMaxRotateDownScaleRatio;
- else
- max_downscale_with_rotator = max_scale_down;
+ if (hw_res_info_.has_rotator_downscale && !property_setting_.disable_rotator_downscaling &&
+ rot_scale && !IsMacroTileFormat(layer.input_buffer)) {
+ float scale_min = MIN(scale_x, scale_y);
+ float scale_max = MAX(scale_x, scale_y);
+ // use rotator to downscale when over the pipe scaling ability
+ if (UINT32(scale_min) >= 2 && scale_max > max_scale_down) {
+ // downscaling ratio needs be the same for both direction, use the smaller one.
+ rot_scale_local = 1 << UINT32(ceilf(log2f(scale_min / max_scale_down)));
+ if (rot_scale_local > kMaxRotateDownScaleRatio)
+ rot_scale_local = kMaxRotateDownScaleRatio;
+ scale_x /= FLOAT(rot_scale_local);
+ scale_y /= FLOAT(rot_scale_local);
+ }
+ *rot_scale = FLOAT(rot_scale_local);
+ }
- if (((!hw_res_info_.has_decimation) || (IsMacroTileFormat(layer.input_buffer))) &&
- (scale_x > max_scale_down || scale_y > max_scale_down)) {
+ if (hw_res_info_.has_decimation && !property_setting_.disable_decimation &&
+ !IsMacroTileFormat(layer.input_buffer)) {
+ max_scale_down *= FLOAT(kMaxDecimationDownScaleRatio);
+ }
+
+ if (scale_x > max_scale_down || scale_y > max_scale_down) {
DLOGV_IF(kTagResources,
- "Scaling down is over the limit is_tile = %d, scale_x = %d, scale_y = %d",
- IsMacroTileFormat(layer.input_buffer), scale_x, scale_y);
- return kErrorNotSupported;
- } else if (scale_x > max_downscale_with_rotator || scale_y > max_downscale_with_rotator) {
- DLOGV_IF(kTagResources, "Scaling down is over the limit scale_x = %d, scale_y = %d",
- scale_x, scale_y);
+ "Scaling down is over the limit: is_tile = %d, scale_x = %.0f, scale_y = %.0f, " \
+ "crop_w = %.0f, dst_w = %.0f, has_deci = %d, disable_deci = %d, rot_scale = %d",
+ IsMacroTileFormat(layer.input_buffer), scale_x, scale_y, crop_width, dst_width,
+ hw_res_info_.has_decimation, property_setting_.disable_decimation, rot_scale_local);
return kErrorNotSupported;
}
}
- const uint32_t max_scale_up = hw_res_info_.max_scale_up;
+ float max_scale_up = FLOAT(hw_res_info_.max_scale_up);
if (UINT32(scale_x) < 1 && scale_x > 0.0f) {
if ((1.0f / scale_x) > max_scale_up) {
- DLOGV_IF(kTagResources, "Scaling up is over limit scale_x = %d", 1.0f / scale_x);
+ DLOGV_IF(kTagResources, "Scaling up is over limit scale_x = %f", 1.0f / scale_x);
return kErrorNotSupported;
}
}
if (UINT32(scale_y) < 1 && scale_y > 0.0f) {
if ((1.0f / scale_y) > max_scale_up) {
- DLOGV_IF(kTagResources, "Scaling up is over limit scale_y = %d", 1.0f / scale_y);
+ DLOGV_IF(kTagResources, "Scaling up is over limit scale_y = %f", 1.0f / scale_y);
return kErrorNotSupported;
}
}
- // Calculate rotator downscale ratio
- float rot_scale = 1.0f;
- while (scale_x > hw_res_info_.max_scale_down) {
- scale_x /= 2;
- rot_scale *= 2;
- }
- *rot_scale_x = rot_scale;
-
- rot_scale = 1.0f;
- while (scale_y > hw_res_info_.max_scale_down) {
- scale_y /= 2;
- rot_scale *= 2;
- }
- *rot_scale_y = rot_scale;
- DLOGV_IF(kTagResources, "rotator scaling hor = %.0f, ver = %.0f", *rot_scale_x, *rot_scale_y);
+ DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f, rot_scale = %d",
+ scale_x, scale_y, rot_scale_local);
return kErrorNone;
}
@@ -370,7 +440,7 @@
}
}
-void ResManager::CalculateCropRects(const LayerRect &scissor, const LayerTransform &transform,
+bool ResManager::CalculateCropRects(const LayerRect &scissor, const LayerTransform &transform,
LayerRect *crop, LayerRect *dst) {
float &crop_left = crop->left;
float &crop_top = crop->top;
@@ -419,7 +489,7 @@
}
if (!need_cut)
- return;
+ return true;
CalculateCut(transform, &left_cut_ratio, &top_cut_ratio, &right_cut_ratio, &bottom_cut_ratio);
@@ -427,6 +497,12 @@
crop_top += crop_height * top_cut_ratio;
crop_right -= crop_width * right_cut_ratio;
crop_bottom -= crop_height * bottom_cut_ratio;
+ NormalizeRect(1, 1, crop);
+ NormalizeRect(1, 1, dst);
+ if (IsValidRect(*crop) && IsValidRect(*dst))
+ return true;
+ else
+ return false;
}
bool ResManager::IsValidDimension(const LayerRect &src, const LayerRect &dst) {
@@ -448,7 +524,6 @@
}
DisplayError ResManager::SetDecimationFactor(HWPipeInfo *pipe) {
- float max_down_scale = FLOAT(hw_res_info_.max_scale_down);
float src_h = pipe->src_roi.bottom - pipe->src_roi.top;
float dst_h = pipe->dst_roi.bottom - pipe->dst_roi.top;
float down_scale_h = src_h / dst_h;
@@ -457,26 +532,16 @@
float dst_w = pipe->dst_roi.right - pipe->dst_roi.left;
float down_scale_w = src_w / dst_w;
-
pipe->horizontal_decimation = 0;
pipe->vertical_decimation = 0;
- // TODO(user): Need to check for the maximum downscale limit for decimation and return error
- if (!hw_res_info_.has_decimation && ((down_scale_w > max_down_scale) ||
- (down_scale_h > max_down_scale))) {
- DLOGV("Downscaling exceeds the maximum MDP downscale limit and decimation not enabled");
+ if (CalculateDecimation(down_scale_w, &pipe->horizontal_decimation) != kErrorNone) {
return kErrorNotSupported;
}
- if ((down_scale_w <= max_down_scale) && (down_scale_h <= max_down_scale))
- return kErrorNone;
-
- // Decimation is the remaining downscale factor after doing max SDE downscale.
- // In SDE, decimation is supported in powers of 2.
- // For ex: If a pipe needs downscale of 8 but max_down_scale is 4
- // So decimation = powf(2.0, ceilf(log2f(8) - log2f(4))) = powf(2.0, 1.0) = 2
- pipe->horizontal_decimation = UINT8(ceilf(log2f(down_scale_w) - log2f(max_down_scale)));
- pipe->vertical_decimation = UINT8(ceilf(log2f(down_scale_h) - log2f(max_down_scale)));
+ if (CalculateDecimation(down_scale_h, &pipe->vertical_decimation) != kErrorNone) {
+ return kErrorNotSupported;
+ }
DLOGI_IF(kTagResources, "horizontal_decimation %d, vertical_decimation %d",
pipe->horizontal_decimation, pipe->vertical_decimation);
@@ -486,18 +551,22 @@
void ResManager::SplitRect(bool flip_horizontal, const LayerRect &src_rect,
const LayerRect &dst_rect, LayerRect *src_left, LayerRect *dst_left,
- LayerRect *src_right, LayerRect *dst_right) {
+ LayerRect *src_right, LayerRect *dst_right, uint32_t align_x) {
// Split rectangle horizontally and evenly into two.
float src_width = src_rect.right - src_rect.left;
float dst_width = dst_rect.right - dst_rect.left;
+ float src_width_ori = src_width;
+ src_width = ROUND_UP_ALIGN_DOWN(src_width / 2, align_x);
+ dst_width = ROUND_UP_ALIGN_DOWN(dst_width * src_width / src_width_ori, 1);
+
if (flip_horizontal) {
src_left->top = src_rect.top;
src_left->left = src_rect.left;
- src_left->right = src_rect.left + (src_width / 2);
+ src_left->right = src_rect.left + src_width;
src_left->bottom = src_rect.bottom;
dst_left->top = dst_rect.top;
- dst_left->left = dst_rect.left + (dst_width / 2);
+ dst_left->left = dst_rect.left + dst_width;
dst_left->right = dst_rect.right;
dst_left->bottom = dst_rect.bottom;
@@ -513,12 +582,12 @@
} else {
src_left->top = src_rect.top;
src_left->left = src_rect.left;
- src_left->right = src_rect.left + (src_width / 2);
+ src_left->right = src_rect.left + src_width;
src_left->bottom = src_rect.bottom;
dst_left->top = dst_rect.top;
dst_left->left = dst_rect.left;
- dst_left->right = dst_rect.left + (dst_width / 2);
+ dst_left->right = dst_rect.left + dst_width;
dst_left->bottom = dst_rect.bottom;
src_right->top = src_rect.top;
@@ -533,123 +602,68 @@
}
}
-// Scalar helper functions
-static void SetPipeInfo(HWPipeInfo* hw_pipe, PipeInfo* pipe) {
- pipe->id = hw_pipe->pipe_id;
- pipe->scale_data = &hw_pipe->scale_data;
- pipe->horz_deci = hw_pipe->horizontal_decimation;
- pipe->vert_deci = hw_pipe->vertical_decimation;
+DisplayError ResManager::AlignPipeConfig(const Layer &layer, const LayerTransform &transform,
+ HWPipeInfo *left_pipe, HWPipeInfo *right_pipe,
+ uint32_t align_x, uint32_t align_y) {
+ DisplayError error = kErrorNone;
+ if (!left_pipe->valid) {
+ DLOGE_IF(kTagResources, "left_pipe should not be invalid");
+ return kErrorNotSupported;
+ }
+ // 1. Normalize video layer source rectangle to multiple of 2, as MDP hardware require source
+ // rectangle of video layer to be even.
+ // 2. Normalize source and destination rect of a layer to multiple of 1.
+ // TODO(user) Check buffer format and check if rotate is involved.
- pipe->src_rect.x = UINT32(hw_pipe->src_roi.left);
- pipe->src_rect.y = UINT32(hw_pipe->src_roi.top);
- pipe->src_rect.w = UINT32(hw_pipe->src_roi.right) - pipe->src_rect.x;
- pipe->src_rect.h = UINT32(hw_pipe->src_roi.bottom) - pipe->src_rect.y;
+ NormalizeRect(align_x, align_y, &left_pipe->src_roi);
+ NormalizeRect(1, 1, &left_pipe->dst_roi);
- pipe->dst_rect.x = UINT32(hw_pipe->dst_roi.left);
- pipe->dst_rect.y = UINT32(hw_pipe->dst_roi.top);
- pipe->dst_rect.w = UINT32(hw_pipe->dst_roi.right) - pipe->dst_rect.x;
- pipe->dst_rect.h = UINT32(hw_pipe->dst_roi.bottom) - pipe->dst_rect.y;
-}
-
-static void UpdateSrcRoi(PipeInfo* pipe, HWPipeInfo* hw_pipe) {
- hw_pipe->src_roi.left = FLOAT(pipe->src_rect.x);
- hw_pipe->src_roi.top = FLOAT(pipe->src_rect.y);
- hw_pipe->src_roi.right = FLOAT(pipe->src_rect.x + pipe->src_rect.w);
- hw_pipe->src_roi.bottom = FLOAT(pipe->src_rect.y + pipe->src_rect.h);
-}
-
-static uint32_t GetScalarFormat(LayerBufferFormat source) {
- uint32_t format = scalar::UNKNOWN_FORMAT;
-
- switch (source) {
- case kFormatARGB8888: format = scalar::ARGB_8888; break;
- case kFormatRGBA8888: format = scalar::RGBA_8888; break;
- case kFormatBGRA8888: format = scalar::BGRA_8888; break;
- case kFormatXRGB8888: format = scalar::XRGB_8888; break;
- case kFormatRGBX8888: format = scalar::RGBX_8888; break;
- case kFormatBGRX8888: format = scalar::BGRX_8888; break;
- case kFormatRGB888: format = scalar::RGB_888; break;
- case kFormatRGB565: format = scalar::RGB_565; break;
- case kFormatYCbCr420Planar: format = scalar::Y_CB_CR_H2V2; break;
- case kFormatYCrCb420Planar: format = scalar::Y_CR_CB_H2V2; break;
- case kFormatYCbCr420SemiPlanar: format = scalar::Y_CBCR_H2V2; break;
- case kFormatYCrCb420SemiPlanar: format = scalar::Y_CRCB_H2V2; break;
- case kFormatYCbCr422Packed: format = scalar::YCBYCR_H2V1; break;
- case kFormatYCbCr420SemiPlanarVenus: format = scalar::Y_CBCR_H2V2_VENUS; break;
- case kFormatRGBA8888Ubwc: format = scalar::RGBA_8888_UBWC; break;
- case kFormatRGB565Ubwc: format = scalar::RGB_565_UBWC; break;
- case kFormatYCbCr420SPVenusUbwc: format = scalar::Y_CBCR_H2V2_UBWC; break;
- default:
- DLOGE("Unsupported source format: %x", source);
- break;
+ if (right_pipe->valid) {
+ NormalizeRect(align_x, align_y, &right_pipe->src_roi);
+ NormalizeRect(1, 1, &right_pipe->dst_roi);
}
- return format;
-}
-
-bool ResManager::ConfigureScaling(HWLayers *hw_layers) {
- HWLayersInfo &hw_layer_info = hw_layers->info;
-
- for (uint32_t i = 0; i < hw_layer_info.count; i++) {
- Layer &layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
- LayerBuffer *input_buffer = layer.input_buffer;
- HWPipeInfo* left_pipe = &hw_layers->config[i].left_pipe;
- HWPipeInfo* right_pipe = &hw_layers->config[i].right_pipe;
-
- // Prepare data structure for lib scalar
- uint32_t flags = 0;
- struct LayerInfo layer_info;
-
- if (layer.transform.rotation == 90.0f) {
- // Flips will be taken care by rotator, if layer requires 90 rotation
- flags |= scalar::SCALAR_SOURCE_ROTATED_90;
+ if (right_pipe->valid) {
+ // Make sure the left and right ROI are conjunct
+ right_pipe->src_roi.left = left_pipe->src_roi.right;
+ if (transform.flip_horizontal) {
+ right_pipe->dst_roi.right = left_pipe->dst_roi.left;
} else {
- flags |= layer.transform.flip_vertical ? scalar::SCALAR_FLIP_UD : 0;
- flags |= layer.transform.flip_horizontal ? scalar::SCALAR_FLIP_LR : 0;
+ right_pipe->dst_roi.left = left_pipe->dst_roi.right;
}
-
- for (uint32_t count = 0; count < 2; count++) {
- HWPipeInfo* hw_pipe = (count == 0) ? left_pipe : right_pipe;
- HWRotateInfo* rotate_info = &hw_layers->config[i].rotates[count];
- PipeInfo* scalar_pipe = (count == 0) ? &layer_info.left_pipe : &layer_info.right_pipe;
-
- if (rotate_info->valid)
- input_buffer = &rotate_info->hw_buffer_info.output_buffer;
-
- scalar_pipe->flags = flags;
- hw_pipe->scale_data.src_width = input_buffer->width;
- SetPipeInfo(hw_pipe, scalar_pipe);
- }
- layer_info.src_format = GetScalarFormat(input_buffer->format);
-
- DLOGV_IF(kTagResources, "Scalar Input[%d] flags=%x format=%x", i, flags, layer_info.src_format);
- DLOGV_IF(kTagResources, "Left: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
- layer_info.left_pipe.id, layer_info.left_pipe.horz_deci, layer_info.left_pipe.vert_deci,
- layer_info.left_pipe.src_rect.x, layer_info.left_pipe.src_rect.y,
- layer_info.left_pipe.src_rect.w, layer_info.left_pipe.src_rect.h,
- layer_info.left_pipe.dst_rect.x, layer_info.left_pipe.dst_rect.y,
- layer_info.left_pipe.dst_rect.w, layer_info.left_pipe.dst_rect.h);
- DLOGV_IF(kTagResources, "Right: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
- layer_info.right_pipe.id, layer_info.right_pipe.horz_deci, layer_info.right_pipe.vert_deci,
- layer_info.right_pipe.src_rect.x, layer_info.right_pipe.src_rect.y,
- layer_info.right_pipe.src_rect.w, layer_info.right_pipe.src_rect.h,
- layer_info.right_pipe.dst_rect.x, layer_info.right_pipe.dst_rect.y,
- layer_info.right_pipe.dst_rect.w, layer_info.right_pipe.dst_rect.h);
-
- // Configure scale data structure
- if (ScalarConfigureScale(&layer_info) < 0) {
- DLOGE("Scalar library failed to configure scale data!");
- return false;
- }
-
- // Update Src Roi in HWPipeInfo
- if (left_pipe->scale_data.enable_pxl_ext)
- UpdateSrcRoi(&layer_info.left_pipe, left_pipe);
- if (right_pipe->scale_data.enable_pxl_ext)
- UpdateSrcRoi(&layer_info.right_pipe, right_pipe);
+ }
+ error = ValidateScaling(layer, left_pipe->src_roi, left_pipe->dst_roi, NULL);
+ if (error != kErrorNone) {
+ goto PipeConfigExit;
}
- return true;
+ if (right_pipe->valid) {
+ error = ValidateScaling(layer, right_pipe->src_roi, right_pipe->dst_roi, NULL);
+ }
+PipeConfigExit:
+ if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "AlignPipeConfig failed");
+ }
+ return error;
+}
+
+DisplayError ResManager::CalculateDecimation(float downscale, uint8_t* decimation) {
+ float max_down_scale = FLOAT(hw_res_info_.max_scale_down);
+
+ if (downscale <= max_down_scale) {
+ *decimation = 0;
+ return kErrorNone;
+ } else if (!hw_res_info_.has_decimation) {
+ DLOGE("Downscaling exceeds the maximum MDP downscale limit but decimation not enabled");
+ return kErrorNotSupported;
+ }
+
+ // Decimation is the remaining downscale factor after doing max SDE downscale.
+ // In SDE, decimation is supported in powers of 2.
+ // For ex: If a pipe needs downscale of 8 but max_down_scale is 4
+ // So decimation = powf(2.0, ceilf(log2f(8 / 4))) = powf(2.0, 1.0) = 2
+ *decimation = UINT8(ceilf(log2f(downscale / max_down_scale)));
+ return kErrorNone;
}
} // namespace sde
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index fb8f2eb..14cf11f 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -28,9 +28,9 @@
#include <dlfcn.h>
#include "res_manager.h"
+#include "scalar_helper.h"
#define __CLASS__ "ResManager"
-#define SCALAR_LIBRARY_NAME "libscalar.so"
namespace sde {
@@ -54,8 +54,6 @@
DisplayError error = kErrorNone;
- // TODO(user): Remove this. Disable src_split as kernel not supported yet
- hw_res_info_.is_src_split = false;
num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe;
if (num_pipe_ > kPipeIdMax) {
@@ -98,7 +96,14 @@
if (hw_res_info_.num_rotator > kMaxNumRotator) {
DLOGE("Number of rotator is over the limit! %d", hw_res_info_.num_rotator);
- return kErrorParameters;
+ hw_res_info_.num_rotator = kMaxNumRotator;
+ }
+
+ if (hw_res_info_.max_scale_down < 1 || hw_res_info_.max_scale_up < 1) {
+ DLOGE("Max scaling setting is invalid! max_scale_down = %d, max_scale_up = %d",
+ hw_res_info_.max_scale_down, hw_res_info_.max_scale_up);
+ hw_res_info_.max_scale_down = 1;
+ hw_res_info_.max_scale_up = 1;
}
if (hw_res_info_.num_rotator > 0) {
@@ -114,23 +119,16 @@
rgb_pipes_[0].state = kPipeStateOwnedByKernel;
rgb_pipes_[1].state = kPipeStateOwnedByKernel;
- ScalarConfigureScale = NULL;
- lib_scalar_handle_ = dlopen(SCALAR_LIBRARY_NAME, RTLD_NOW);
- if (lib_scalar_handle_) {
- void **scalar_func = reinterpret_cast<void **>(&ScalarConfigureScale);
- *scalar_func = ::dlsym(lib_scalar_handle_, "configureScale");
- } else {
- DLOGW("Unable to load %s !", SCALAR_LIBRARY_NAME);
- }
-
+#ifdef USES_SCALAR
+ ScalarHelper::GetInstance()->Init();
+#endif
return kErrorNone;
}
DisplayError ResManager::Deinit() {
- if (lib_scalar_handle_) {
- dlclose(lib_scalar_handle_);
- lib_scalar_handle_ = NULL;
- }
+#ifdef USES_SCALAR
+ ScalarHelper::GetInstance()->Deinit();
+#endif
return kErrorNone;
}
@@ -248,6 +246,9 @@
}
}
+ property_setting_.disable_rotator_downscaling = Debug::IsRotatorDownScaleDisabled();
+ property_setting_.disable_decimation = Debug::IsDecimationDisabled();
+
return kErrorNone;
}
@@ -266,20 +267,24 @@
DisplayError error = kErrorNone;
const struct HWLayersInfo &layer_info = hw_layers->info;
+ HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
- if (layer_info.count > num_pipe_) {
+ DLOGV_IF(kTagResources, "==== Resource reserving start: hw_block = %d ====", hw_block_id);
+
+ if (layer_info.count > num_pipe_ || layer_info.count >= hw_res_info_.num_blending_stages) {
+ DLOGV_IF(kTagResources, "layer count is over the limit: layer count = %d", layer_info.count);
return kErrorResources;
}
uint32_t rotate_count = 0;
error = Config(display_resource_ctx, hw_layers, &rotate_count);
if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "Resource config failed");
return error;
}
uint32_t left_index = kPipeIdMax;
bool need_scale = false;
- HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
HWBlockType rotator_block = kHWBlockMax;
// Clear reserved marking
@@ -319,6 +324,10 @@
need_scale = IsScalingNeeded(pipe_info);
left_index = GetPipe(hw_block_id, is_yuv, need_scale, false, use_non_dma_pipe);
if (left_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "Get left pipe failed: hw_block_id = %d, is_yuv = %d, " \
+ "need_scale = %d, use_non_dma_pipe= %d",
+ hw_block_id, is_yuv, need_scale, use_non_dma_pipe);
+ ResourceStateLog();
goto CleanupOnError;
}
src_pipes_[left_index].reserved_hw_block = hw_block_id;
@@ -336,6 +345,8 @@
layer_config.left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
src_pipes_[left_index].at_right = false;
}
+ DLOGV_IF(kTagResources, "1 pipe acquired, layer index = %d, left_pipe = %x",
+ i, layer_config.left_pipe.pipe_id);
continue;
}
@@ -344,6 +355,10 @@
uint32_t right_index;
right_index = GetPipe(hw_block_id, is_yuv, need_scale, true, use_non_dma_pipe);
if (right_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "Get right pipe failed: hw_block_id = %d, is_yuv = %d, " \
+ "need_scale = %d, use_non_dma_pipe= %d",
+ hw_block_id, is_yuv, need_scale, use_non_dma_pipe);
+ ResourceStateLog();
goto CleanupOnError;
}
@@ -364,8 +379,20 @@
goto CleanupOnError;
}
- DLOGV_IF(kTagResources, "Pipe acquired, layer index = %d, left_pipe = %x, right_pipe = %x",
- i, layer_config.left_pipe.pipe_id, pipe_info->pipe_id);
+ DLOGV_IF(kTagResources, "2 pipes acquired, layer index = %d, left_pipe = %x, right_pipe = %x",
+ i, layer_config.left_pipe.pipe_id, pipe_info->pipe_id);
+ }
+
+#ifdef USES_SCALAR
+ if (!ScalarHelper::GetInstance()->ConfigureScale(hw_layers)) {
+ DLOGV_IF(kTagResources, "Scale data configuration has failed!");
+ goto CleanupOnError;
+ }
+#endif
+
+ if (!CheckBandwidth(display_resource_ctx, hw_layers)) {
+ DLOGV_IF(kTagResources, "Bandwidth check failed!");
+ goto CleanupOnError;
}
error = AllocRotatorBuffer(display_ctx, hw_layers);
@@ -374,18 +401,6 @@
goto CleanupOnError;
}
- if (lib_scalar_handle_ && ScalarConfigureScale) {
- if (!ConfigureScaling(hw_layers)) {
- DLOGV_IF(kTagResources, "Scale data configuration has failed!");
- goto CleanupOnError;
- }
- }
-
- if (!CheckBandwidth(display_resource_ctx, hw_layers)) {
- DLOGV_IF(kTagResources, "Bandwidth check failed!");
- goto CleanupOnError;
- }
-
return kErrorNone;
CleanupOnError:
@@ -604,6 +619,7 @@
case kFormatYCbCr420SemiPlanar:
case kFormatYCrCb420SemiPlanar:
case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
return 1.5f;
default:
DLOGE("GetBpp: Invalid buffer format: %x", format);
@@ -628,13 +644,8 @@
HWRotateInfo *rotate = &hw_layers->config[i].rotates[0];
if (rotate->valid) {
- LayerBufferFormat rot_ouput_format;
- SetRotatorOutputFormat(layer.input_buffer->format, false, true, &rot_ouput_format);
-
HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
- hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right - rotate->dst_roi.left);
- hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom - rotate->dst_roi.top);
- hw_buffer_info->buffer_config.format = rot_ouput_format;
+ // Allocate two rotator output buffers by default for double buffering.
hw_buffer_info->buffer_config.buffer_count = 2;
hw_buffer_info->buffer_config.secure = layer.input_buffer->flags.secure;
@@ -646,13 +657,8 @@
rotate = &hw_layers->config[i].rotates[1];
if (rotate->valid) {
- LayerBufferFormat rot_ouput_format;
- SetRotatorOutputFormat(layer.input_buffer->format, false, true, &rot_ouput_format);
-
HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
- hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right - rotate->dst_roi.left);
- hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom - rotate->dst_roi.top);
- hw_buffer_info->buffer_config.format = rot_ouput_format;
+ // Allocate two rotator output buffers by default for double buffering.
hw_buffer_info->buffer_config.buffer_count = 2;
hw_buffer_info->buffer_config.secure = layer.input_buffer->flags.secure;
@@ -802,6 +808,7 @@
src_pipes_[i].ResetState();
}
ClearRotator(display_resource_ctx);
+ DLOGV_IF(kTagResources, "display id = %d", display_resource_ctx->hw_block_id);
}
uint32_t ResManager::GetMdssPipeId(PipeType type, uint32_t index) {
@@ -973,6 +980,27 @@
}
}
+void ResManager::ResourceStateLog() {
+ DLOGV_IF(kTagResources, "==== resource manager pipe state ====");
+ uint32_t i;
+ for (i = 0; i < num_pipe_; i++) {
+ SourcePipe *src_pipe = &src_pipes_[i];
+ DLOGV_IF(kTagResources,
+ "index = %d, id = %x, reserved = %d, state = %d, hw_block = %d, dedicated = %d",
+ src_pipe->index, src_pipe->mdss_pipe_id, src_pipe->reserved_hw_block,
+ src_pipe->state, src_pipe->hw_block_id, src_pipe->dedicated_hw_block);
+ }
+
+ for (i = 0; i < hw_res_info_.num_rotator; i++) {
+ if (rotators_[i].client_bit_mask || rotators_[i].request_bit_mask) {
+ DLOGV_IF(kTagResources,
+ "rotator = %d, pipe index = %x, client_bit_mask = %x, request_bit_mask = %x",
+ i, rotators_[i].pipe_index, rotators_[i].client_bit_mask,
+ rotators_[i].request_bit_mask);
+ }
+ }
+}
+
DisplayError ResManager::AcquireRotator(DisplayResourceContext *display_resource_ctx,
const uint32_t rotate_count) {
if (rotate_count == 0)
@@ -1051,33 +1079,32 @@
}
void ResManager::SetRotatorOutputFormat(const LayerBufferFormat &input_format, bool bwc, bool rot90,
- LayerBufferFormat *output_format) {
+ bool downscale, LayerBufferFormat *output_format) {
+ *output_format = input_format;
+
switch (input_format) {
case kFormatRGB565:
if (rot90)
*output_format = kFormatRGB888;
- else
- *output_format = input_format;
break;
case kFormatRGBA8888:
if (bwc)
*output_format = kFormatBGRA8888;
- else
- *output_format = input_format;
break;
case kFormatYCbCr420SemiPlanarVenus:
case kFormatYCbCr420SemiPlanar:
if (rot90)
*output_format = kFormatYCrCb420SemiPlanar;
- else
- *output_format = input_format;
+ break;
+ case kFormatYCbCr420SPVenusUbwc:
+ if (downscale)
+ *output_format = kFormatYCrCb420SemiPlanar;
break;
case kFormatYCbCr420Planar:
case kFormatYCrCb420Planar:
*output_format = kFormatYCrCb420SemiPlanar;
break;
default:
- *output_format = input_format;
break;
}
@@ -1087,8 +1114,5 @@
return;
}
-void* ResManager::lib_scalar_handle_ = NULL;
-int (*ResManager::ScalarConfigureScale)(struct scalar::LayerInfo* layer) = NULL;
-
} // namespace sde
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index c80dc2c..d21984e 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -88,6 +88,7 @@
kMaxSourcePipeWidth = 2048,
kMaxInterfaceWidth = 2048,
kMaxRotateDownScaleRatio = 8,
+ kMaxDecimationDownScaleRatio = 8,
kMaxNumRotator = 2,
};
@@ -150,7 +151,11 @@
CLEAR_BIT(request_bit_mask, block); }
};
- static const int kPipeIdNeedsAssignment = -1;
+ struct PropertySetting {
+ bool disable_rotator_downscaling;
+ bool disable_decimation;
+ PropertySetting() : disable_rotator_downscaling(false), disable_decimation(false) { }
+ };
uint32_t GetMdssPipeId(PipeType pipe_type, uint32_t index);
uint32_t NextPipe(PipeType pipe_type, HWBlockType hw_block_id, bool at_right);
@@ -163,15 +168,17 @@
uint32_t *rotate_count);
DisplayError DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
const LayerTransform &transform, const LayerRect &src_rect,
- const LayerRect &dst_rect, HWLayerConfig *layer_config);
+ const LayerRect &dst_rect, HWLayerConfig *layer_config,
+ uint32_t align_x);
DisplayError ValidateScaling(const Layer &layer, const LayerRect &crop,
- const LayerRect &dst, float *rot_scale_x, float *rot_scale_y);
+ const LayerRect &dst, float *rot_scale);
DisplayError SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
const LayerTransform &transform, const LayerRect &src_rect,
- const LayerRect &dst_rect, HWLayerConfig *layer_config);
+ const LayerRect &dst_rect, HWLayerConfig *layer_config,
+ uint32_t align_x);
void CalculateCut(const LayerTransform &transform, float *left_cut_ratio, float *top_cut_ratio,
float *right_cut_ratio, float *bottom_cut_ratio);
- void CalculateCropRects(const LayerRect &scissor, const LayerTransform &transform,
+ bool CalculateCropRects(const LayerRect &scissor, const LayerTransform &transform,
LayerRect *crop, LayerRect *dst);
bool IsValidDimension(const LayerRect &src, const LayerRect &dst);
bool CheckBandwidth(DisplayResourceContext *display_ctx, HWLayers *hw_layers);
@@ -182,13 +189,13 @@
float GetBpp(LayerBufferFormat format);
void SplitRect(bool flip_horizontal, const LayerRect &src_rect, const LayerRect &dst_rect,
LayerRect *src_left, LayerRect *dst_left, LayerRect *src_right,
- LayerRect *dst_right);
+ LayerRect *dst_right, uint32_t align_x);
bool IsMacroTileFormat(const LayerBuffer *buffer) { return buffer->flags.macro_tile; }
bool IsYuvFormat(LayerBufferFormat format) { return (format >= kFormatYCbCr420Planar); }
bool IsRotationNeeded(float rotation)
{ return (UINT32(rotation) == 90 || UINT32(rotation) == 270); }
- void RotationConfig(const LayerTransform &transform, const float &scale_x,
- const float &scale_y, LayerRect *src_rect,
+ void RotationConfig(LayerBufferFormat format, const LayerTransform &transform,
+ const float &downscale, LayerRect *src_rect,
struct HWLayerConfig *layer_config, uint32_t *rotate_count);
DisplayError AcquireRotator(DisplayResourceContext *display_resource_ctx,
const uint32_t roate_cnt);
@@ -196,8 +203,12 @@
void ClearRotator(DisplayResourceContext *display_resource_ctx);
DisplayError AllocRotatorBuffer(Handle display_ctx, HWLayers *hw_layers);
void SetRotatorOutputFormat(const LayerBufferFormat &input_format, bool bwc, bool rot90,
- LayerBufferFormat *output_format);
- bool ConfigureScaling(HWLayers *hw_layers);
+ bool downscale, LayerBufferFormat *output_format);
+ DisplayError AlignPipeConfig(const Layer &layer, const LayerTransform &transform,
+ HWPipeInfo *left_pipe, HWPipeInfo *right_pipe,
+ uint32_t align_x, uint32_t align_y);
+ void ResourceStateLog(void);
+ DisplayError CalculateDecimation(float downscale, uint8_t* decimation);
Locker locker_;
HWResourceInfo hw_res_info_;
@@ -216,8 +227,7 @@
BufferAllocator *buffer_allocator_;
BufferSyncHandler *buffer_sync_handler_; // Pointer to buffer sync handler that was defined by
// the display engine's client
- static void* lib_scalar_handle_; // Scalar library handle
- static int (*ScalarConfigureScale)(struct scalar::LayerInfo* layer);
+ PropertySetting property_setting_;
};
} // namespace sde
diff --git a/displayengine/libs/core/scalar_helper.cpp b/displayengine/libs/core/scalar_helper.cpp
new file mode 100755
index 0000000..22488b3
--- /dev/null
+++ b/displayengine/libs/core/scalar_helper.cpp
@@ -0,0 +1,231 @@
+/*
+* Copyright (c) 2015, 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef USES_SCALAR
+
+#include <dlfcn.h>
+#include <utils/debug.h>
+#include "scalar_helper.h"
+
+#define __CLASS__ "ScalarHelper"
+
+namespace sde {
+
+ScalarHelper* ScalarHelper::scalar_helper_ = NULL;
+
+ScalarHelper* ScalarHelper::GetInstance() {
+ if (scalar_helper_ == NULL) {
+ scalar_helper_ = new ScalarHelper();
+ }
+ return scalar_helper_;
+}
+
+// Scalar helper functions
+static void SetPipeInfo(HWPipeInfo* hw_pipe, scalar::PipeInfo* pipe) {
+ pipe->id = hw_pipe->pipe_id;
+ pipe->horz_deci = hw_pipe->horizontal_decimation;
+ pipe->vert_deci = hw_pipe->vertical_decimation;
+
+ pipe->src_rect.x = UINT32(hw_pipe->src_roi.left);
+ pipe->src_rect.y = UINT32(hw_pipe->src_roi.top);
+ pipe->src_rect.w = UINT32(hw_pipe->src_roi.right) - pipe->src_rect.x;
+ pipe->src_rect.h = UINT32(hw_pipe->src_roi.bottom) - pipe->src_rect.y;
+
+ pipe->dst_rect.x = UINT32(hw_pipe->dst_roi.left);
+ pipe->dst_rect.y = UINT32(hw_pipe->dst_roi.top);
+ pipe->dst_rect.w = UINT32(hw_pipe->dst_roi.right) - pipe->dst_rect.x;
+ pipe->dst_rect.h = UINT32(hw_pipe->dst_roi.bottom) - pipe->dst_rect.y;
+}
+
+static void UpdateSrcRoi(scalar::PipeInfo* pipe, HWPipeInfo* hw_pipe) {
+ hw_pipe->src_roi.left = FLOAT(pipe->src_rect.x);
+ hw_pipe->src_roi.top = FLOAT(pipe->src_rect.y);
+ hw_pipe->src_roi.right = FLOAT(pipe->src_rect.x + pipe->src_rect.w);
+ hw_pipe->src_roi.bottom = FLOAT(pipe->src_rect.y + pipe->src_rect.h);
+}
+
+static uint32_t GetScalarFormat(LayerBufferFormat source) {
+ uint32_t format = scalar::UNKNOWN_FORMAT;
+
+ switch (source) {
+ case kFormatARGB8888: format = scalar::ARGB_8888; break;
+ case kFormatRGBA8888: format = scalar::RGBA_8888; break;
+ case kFormatBGRA8888: format = scalar::BGRA_8888; break;
+ case kFormatXRGB8888: format = scalar::XRGB_8888; break;
+ case kFormatRGBX8888: format = scalar::RGBX_8888; break;
+ case kFormatBGRX8888: format = scalar::BGRX_8888; break;
+ case kFormatRGB888: format = scalar::RGB_888; break;
+ case kFormatRGB565: format = scalar::RGB_565; break;
+ case kFormatYCbCr420Planar: format = scalar::Y_CB_CR_H2V2; break;
+ case kFormatYCrCb420Planar: format = scalar::Y_CR_CB_H2V2; break;
+ case kFormatYCbCr420SemiPlanar: format = scalar::Y_CBCR_H2V2; break;
+ case kFormatYCrCb420SemiPlanar: format = scalar::Y_CRCB_H2V2; break;
+ case kFormatYCbCr422Packed: format = scalar::YCBYCR_H2V1; break;
+ case kFormatYCbCr420SemiPlanarVenus: format = scalar::Y_CBCR_H2V2_VENUS; break;
+ case kFormatRGBA8888Ubwc: format = scalar::RGBA_8888_UBWC; break;
+ case kFormatRGB565Ubwc: format = scalar::RGB_565_UBWC; break;
+ case kFormatYCbCr420SPVenusUbwc: format = scalar::Y_CBCR_H2V2_UBWC; break;
+ default:
+ DLOGE("Unsupported source format: %x", source);
+ break;
+ }
+ return format;
+}
+
+void ScalarHelper::Init() {
+ lib_scalar_handle_ = NULL;
+ ScalarConfigureScale = NULL;
+
+ lib_scalar_handle_ = dlopen(SCALAR_LIBRARY_NAME, RTLD_NOW);
+ if (lib_scalar_handle_) {
+ void **scalar_func = reinterpret_cast<void **>(&ScalarConfigureScale);
+ *scalar_func = ::dlsym(lib_scalar_handle_, "configureScale");
+ } else {
+ DLOGW("Unable to load %s !", SCALAR_LIBRARY_NAME);
+ }
+}
+
+void ScalarHelper::Deinit() {
+ if (lib_scalar_handle_) {
+ dlclose(lib_scalar_handle_);
+ lib_scalar_handle_ = NULL;
+ }
+}
+
+bool ScalarHelper::ConfigureScale(HWLayers *hw_layers) {
+
+ if (!lib_scalar_handle_ || !ScalarConfigureScale) {
+ // No scalar library
+ return true;
+ }
+
+ // Reset scale data
+ memset(&scale_data_, 0, sizeof(scale_data_));
+ HWLayersInfo &hw_layer_info = hw_layers->info;
+
+ for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+ Layer &layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
+ uint32_t width = layer.input_buffer->width;
+ LayerBufferFormat format = layer.input_buffer->format;
+ HWPipeInfo* left_pipe = &hw_layers->config[i].left_pipe;
+ HWPipeInfo* right_pipe = &hw_layers->config[i].right_pipe;
+
+ // Prepare data structure for lib scalar
+ uint32_t flags = 0;
+ struct scalar::LayerInfo layer_info;
+
+ if (layer.transform.rotation == 90.0f) {
+ // Flips will be taken care by rotator, if layer requires 90 rotation
+ flags |= scalar::SCALAR_SOURCE_ROTATED_90;
+ } else {
+ flags |= layer.transform.flip_vertical ? scalar::SCALAR_FLIP_UD : 0;
+ flags |= layer.transform.flip_horizontal ? scalar::SCALAR_FLIP_LR : 0;
+ }
+
+ for (uint32_t count = 0; count < 2; count++) {
+ HWPipeInfo* hw_pipe = (count == 0) ? left_pipe : right_pipe;
+ HWRotateInfo* rotate_info = &hw_layers->config[i].rotates[count];
+ scalar::PipeInfo* pipe = (count == 0) ? &layer_info.left_pipe : &layer_info.right_pipe;
+
+ if (rotate_info->valid) {
+ width = rotate_info->hw_buffer_info.buffer_config.width;
+ format = rotate_info->hw_buffer_info.buffer_config.format;
+ }
+
+ pipe->flags = flags;
+ pipe->scale_data = GetScaleRef(i, !count);
+ pipe->scale_data->src_width = width;
+ SetPipeInfo(hw_pipe, pipe);
+ }
+ layer_info.src_format = GetScalarFormat(format);
+
+ DLOGV_IF(kTagScalar, "Scalar Input[%d] flags=%x format=%x", i, flags, layer_info.src_format);
+ DLOGV_IF(kTagScalar, "Left: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
+ layer_info.left_pipe.id, layer_info.left_pipe.horz_deci, layer_info.left_pipe.vert_deci,
+ layer_info.left_pipe.src_rect.x, layer_info.left_pipe.src_rect.y,
+ layer_info.left_pipe.src_rect.w, layer_info.left_pipe.src_rect.h,
+ layer_info.left_pipe.dst_rect.x, layer_info.left_pipe.dst_rect.y,
+ layer_info.left_pipe.dst_rect.w, layer_info.left_pipe.dst_rect.h);
+ DLOGV_IF(kTagScalar, "Right: id=%d hD=%d vD=%d srcRect=[%d %d %d %d] dstRect=[%d %d %d %d]",
+ layer_info.right_pipe.id, layer_info.right_pipe.horz_deci, layer_info.right_pipe.vert_deci,
+ layer_info.right_pipe.src_rect.x, layer_info.right_pipe.src_rect.y,
+ layer_info.right_pipe.src_rect.w, layer_info.right_pipe.src_rect.h,
+ layer_info.right_pipe.dst_rect.x, layer_info.right_pipe.dst_rect.y,
+ layer_info.right_pipe.dst_rect.w, layer_info.right_pipe.dst_rect.h);
+
+ // Configure scale data structure
+ if (ScalarConfigureScale(&layer_info) < 0) {
+ DLOGE("Scalar library failed to configure scale data!");
+ return false;
+ }
+
+ // Update Src Roi in HWPipeInfo
+ if (layer_info.left_pipe.scale_data->enable_pxl_ext)
+ UpdateSrcRoi(&layer_info.left_pipe, left_pipe);
+ if (layer_info.right_pipe.scale_data->enable_pxl_ext)
+ UpdateSrcRoi(&layer_info.right_pipe, right_pipe);
+ }
+ return true;
+}
+
+void ScalarHelper::UpdateSrcWidth(uint32_t index, bool left, uint32_t* width) {
+ *width = GetScaleRef(index, left)->src_width;
+}
+
+void ScalarHelper::SetScaleData(uint32_t index, bool left, mdp_scale_data* mdp_scale) {
+
+ if (!lib_scalar_handle_ || !ScalarConfigureScale)
+ return;
+
+ scalar::Scale* scale = GetScaleRef(index, left);
+ mdp_scale->enable_pxl_ext = scale->enable_pxl_ext;
+
+ for (int i = 0; i < MAX_PLANES; i++) {
+ mdp_scale->init_phase_x[i] = scale->init_phase_x[i];
+ mdp_scale->phase_step_x[i] = scale->phase_step_x[i];
+ mdp_scale->init_phase_y[i] = scale->init_phase_y[i];
+ mdp_scale->phase_step_y[i] = scale->phase_step_y[i];
+
+ mdp_scale->num_ext_pxls_left[i] = scale->left.extension[i];
+ mdp_scale->num_ext_pxls_top[i] = scale->top.extension[i];
+ mdp_scale->num_ext_pxls_right[i] = scale->right.extension[i];
+ mdp_scale->num_ext_pxls_btm[i] = scale->bottom.extension[i];
+
+ mdp_scale->left_ftch[i] = scale->left.overfetch[i];
+ mdp_scale->top_ftch[i] = scale->top.overfetch[i];
+ mdp_scale->right_ftch[i] = scale->right.overfetch[i];
+ mdp_scale->btm_ftch[i] = scale->bottom.overfetch[i];
+
+ mdp_scale->left_rpt[i] = scale->left.repeat[i];
+ mdp_scale->top_rpt[i] = scale->top.repeat[i];
+ mdp_scale->right_rpt[i] = scale->right.repeat[i];
+ mdp_scale->btm_rpt[i] = scale->bottom.repeat[i];
+
+ mdp_scale->roi_w[i] = scale->roi_width[i];
+ }
+}
+
+} // namespace sde
+
+#endif
diff --git a/displayengine/libs/core/scalar_helper.h b/displayengine/libs/core/scalar_helper.h
new file mode 100755
index 0000000..a54cb0c
--- /dev/null
+++ b/displayengine/libs/core/scalar_helper.h
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2015, 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:
+* * Redistributions of source code must retain the above copyright notice, this list of
+* conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright notice, this list of
+* conditions and the following disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its contributors may be used to
+* endorse or promote products derived from this software without specific prior written
+* permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __SCALAR_HELPER_H__
+#define __SCALAR_HELPER_H__
+
+#ifdef USES_SCALAR
+
+#include <sys/types.h>
+#include <linux/msm_mdp_ext.h>
+#include <hw_interface.h>
+#include <scalar.h>
+
+#define SCALAR_LIBRARY_NAME "libscalar.so"
+
+namespace sde {
+
+class ScalarHelper {
+
+ public:
+ void Init();
+ void Deinit();
+ bool ConfigureScale(HWLayers *hw_layers);
+ void UpdateSrcWidth(uint32_t index, bool left, uint32_t* src_width);
+ void SetScaleData(uint32_t index, bool left, mdp_scale_data* mdp_scale);
+ static ScalarHelper* GetInstance();
+
+ private:
+ explicit ScalarHelper() { }
+ struct ScaleData {
+ scalar::Scale left_scale;
+ scalar::Scale right_scale;
+ };
+ struct ScaleData scale_data_[kMaxSDELayers];
+ void* lib_scalar_handle_;
+ int (*ScalarConfigureScale)(struct scalar::LayerInfo* layer);
+ scalar::Scale* GetScaleRef(uint32_t index, bool left) {
+ return (left ? &scale_data_[index].left_scale : &scale_data_[index].right_scale);
+ }
+ static ScalarHelper* scalar_helper_; // Singleton Instance
+};
+
+} // namespace sde
+
+#endif
+#endif // __SCALAR_HELPER_H__
diff --git a/displayengine/libs/hwc/hwc_buffer_allocator.cpp b/displayengine/libs/hwc/hwc_buffer_allocator.cpp
index d4f4bac..f2383b2 100644
--- a/displayengine/libs/hwc/hwc_buffer_allocator.cpp
+++ b/displayengine/libs/hwc/hwc_buffer_allocator.cpp
@@ -159,6 +159,7 @@
case kFormatYCbCr420SemiPlanar: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP; break;
case kFormatYCbCr422Packed: *target = HAL_PIXEL_FORMAT_YCbCr_422_I; break;
case kFormatYCbCr420SemiPlanarVenus: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; break;
+ case kFormatYCbCr420SPVenusUbwc: *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC; break;
default:
DLOGE("Unsupported format = 0x%x", format);
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 3bc4fd1..40eae99 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -94,7 +94,7 @@
android::defaultServiceManager()->getService(android::String16(qservice_name)));
if (qservice.get()) {
- qservice->connect(this);
+ qservice->connect(android::sp<qClient::IQClient>(this));
} else {
DLOGE("Failed to acquire %s", qservice_name);
return -EINVAL;
@@ -329,17 +329,18 @@
switch (disp) {
case HWC_DISPLAY_PRIMARY:
status = hwc_session->display_primary_->SetPowerMode(mode);
+ // Set the power mode for virtual display while setting power mode for primary, as surfaceflinger
+ // does not invoke SetPowerMode() for virtual display.
+ case HWC_DISPLAY_VIRTUAL:
+ if (hwc_session->display_virtual_) {
+ status = hwc_session->display_virtual_->SetPowerMode(mode);
+ }
break;
case HWC_DISPLAY_EXTERNAL:
if (hwc_session->display_external_) {
status = hwc_session->display_external_->SetPowerMode(mode);
}
break;
- case HWC_DISPLAY_VIRTUAL:
- if (hwc_session->display_virtual_) {
- status = hwc_session->display_virtual_->SetPowerMode(mode);
- }
- break;
default:
status = -EINVAL;
}
diff --git a/displayengine/libs/utils/debug_android.cpp b/displayengine/libs/utils/debug_android.cpp
index 1b08fe9..96339df 100644
--- a/displayengine/libs/utils/debug_android.cpp
+++ b/displayengine/libs/utils/debug_android.cpp
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <utils/debug.h>
+#include <utils/constants.h>
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -67,7 +68,25 @@
return atoi(property);
}
- return 0;
+ return IDLE_TIMEOUT_DEFAULT_MS;
+}
+
+bool Debug::IsRotatorDownScaleDisabled() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("sde.disable_rotator_downscaling", property, NULL) > 0) {
+ return (atoi(property) ? 0 : false, true);
+ }
+
+ return false;
+}
+
+bool Debug::IsDecimationDisabled() {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("sde.disable_decimation", property, NULL) > 0) {
+ return (atoi(property) ? 0 : false, true);
+ }
+
+ return false;
}
} // namespace sde
diff --git a/displayengine/libs/utils/rect.cpp b/displayengine/libs/utils/rect.cpp
index 2725750..8dfd7dd 100644
--- a/displayengine/libs/utils/rect.cpp
+++ b/displayengine/libs/utils/rect.cpp
@@ -64,16 +64,11 @@
prefix, roi.left, roi.top, roi.right, roi.bottom);
}
-void NormalizeRect(const uint32_t &factor, LayerRect *rect) {
- uint32_t left = UINT32(ceilf(rect->left));
- uint32_t top = UINT32(ceilf(rect->top));
- uint32_t right = UINT32(floorf(rect->right));
- uint32_t bottom = UINT32(floorf(rect->bottom));
-
- rect->left = FLOAT(CeilToMultipleOf(left, factor));
- rect->top = FLOAT(CeilToMultipleOf(top, factor));
- rect->right = FLOAT(FloorToMultipleOf(right, factor));
- rect->bottom = FLOAT(FloorToMultipleOf(bottom, factor));
+void NormalizeRect(const uint32_t &align_x, const uint32_t &align_y, LayerRect *rect) {
+ rect->left = ROUND_UP_ALIGN_UP(rect->left, align_x);
+ rect->right = ROUND_UP_ALIGN_DOWN(rect->right, align_x);
+ rect->top = ROUND_UP_ALIGN_UP(rect->top, align_y);
+ rect->bottom = ROUND_UP_ALIGN_DOWN(rect->bottom, align_y);
}
} // namespace sde
diff --git a/hdmi_cec/Android.mk b/hdmi_cec/Android.mk
new file mode 100644
index 0000000..ed06da1
--- /dev/null
+++ b/hdmi_cec/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := hdmi_cec.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) libqservice libbinder libqdutils
+
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhdmi_cec\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES := qhdmi_cec.cpp \
+ QHDMIClient.cpp
+include $(BUILD_SHARED_LIBRARY)
diff --git a/hdmi_cec/QHDMIClient.cpp b/hdmi_cec/QHDMIClient.cpp
new file mode 100644
index 0000000..2b2b1e6
--- /dev/null
+++ b/hdmi_cec/QHDMIClient.cpp
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2014 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG 0
+#include <QServiceUtils.h>
+#include "QHDMIClient.h"
+
+using namespace android;
+using namespace qhdmicec;
+using namespace qService;
+
+namespace qClient {
+
+void QHDMIClient::binderDied(const wp<IBinder>& who __unused)
+{
+ ALOGW("%s: Display QService died", __FUNCTION__);
+}
+
+void QHDMIClient::onHdmiHotplug(int connected)
+{
+ ALOGD("%s: HDMI connected event connected: %d", __FUNCTION__, connected);
+ cec_hdmi_hotplug(mCtx, connected);
+}
+
+void QHDMIClient::onCECMessageRecieved(char *msg, ssize_t len)
+{
+ ALOGD_IF(DEBUG, "%s: CEC message received len: %zd", __FUNCTION__, len);
+ cec_receive_message(mCtx, msg, len);
+}
+
+void QHDMIClient::registerClient(sp<QHDMIClient>& client)
+{
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("display.qservice"));
+ binder->linkToDeath(client);
+ mQService = interface_cast<IQService>(binder);
+ mQService->connect(interface_cast<IQHDMIClient>(client));
+}
+
+};
diff --git a/hdmi_cec/QHDMIClient.h b/hdmi_cec/QHDMIClient.h
new file mode 100644
index 0000000..9e54f2f
--- /dev/null
+++ b/hdmi_cec/QHDMIClient.h
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2014 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "IQHDMIClient.h"
+#include "qhdmi_cec.h"
+#include <IQService.h>
+
+namespace qClient {
+
+class QHDMIClient: public android::IBinder::DeathRecipient,
+ public BnQHDMIClient
+{
+public:
+ QHDMIClient() {}
+
+ virtual void binderDied(const android::wp<android::IBinder>& who);
+
+ virtual void onHdmiHotplug(int connected);
+
+ virtual void onCECMessageRecieved(char *msg, ssize_t len);
+
+ void setCECContext(qhdmicec::cec_context_t* ctx) { mCtx = ctx; }
+
+ void registerClient(android::sp<QHDMIClient>& client);
+
+private:
+ qhdmicec::cec_context_t* mCtx;
+ android::sp<qService::IQService> mQService;
+
+};
+};
diff --git a/hdmi_cec/qhdmi_cec.cpp b/hdmi_cec/qhdmi_cec.cpp
new file mode 100644
index 0000000..6e46254
--- /dev/null
+++ b/hdmi_cec/qhdmi_cec.cpp
@@ -0,0 +1,519 @@
+/*
+* Copyright (c) 2014 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG 0
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+#include <cstdlib>
+#include <cutils/log.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <hardware/hdmi_cec.h>
+#include <utils/Trace.h>
+#include "qhdmi_cec.h"
+#include "QHDMIClient.h"
+
+namespace qhdmicec {
+
+const int NUM_HDMI_PORTS = 1;
+const int MAX_SYSFS_DATA = 128;
+const int MAX_CEC_FRAME_SIZE = 20;
+const int MAX_SEND_MESSAGE_RETRIES = 1;
+
+enum {
+ LOGICAL_ADDRESS_SET = 1,
+ LOGICAL_ADDRESS_UNSET = -1,
+};
+
+// Offsets of members of struct hdmi_cec_msg
+// drivers/video/msm/mdss/mdss_hdmi_cec.c
+// XXX: Get this from a driver header
+enum {
+ CEC_OFFSET_SENDER_ID,
+ CEC_OFFSET_RECEIVER_ID,
+ CEC_OFFSET_OPCODE,
+ CEC_OFFSET_OPERAND,
+ CEC_OFFSET_FRAME_LENGTH = 18,
+ CEC_OFFSET_RETRANSMIT,
+};
+
+//Forward declarations
+static void cec_close_context(cec_context_t* ctx __unused);
+static int cec_enable(cec_context_t *ctx, int enable);
+static int cec_is_connected(const struct hdmi_cec_device* dev, int port_id);
+
+static ssize_t read_node(const char *path, char *data)
+{
+ ssize_t err = 0;
+ FILE *fp = NULL;
+ err = access(path, R_OK);
+ if (!err) {
+ fp = fopen(path, "r");
+ if (fp) {
+ err = fread(data, sizeof(char), MAX_SYSFS_DATA ,fp);
+ fclose(fp);
+ }
+ }
+ return err;
+}
+
+static ssize_t write_node(const char *path, const char *data, size_t len)
+{
+ ssize_t err = 0;
+ int fd = -1;
+ err = access(path, W_OK);
+ if (!err) {
+ fd = open(path, O_WRONLY);
+ errno = 0;
+ err = write(fd, data, len);
+ if (err < 0) {
+ err = -errno;
+ }
+ close(fd);
+ } else {
+ ALOGE("%s: Failed to access path: %s error: %s",
+ __FUNCTION__, path, strerror(errno));
+ err = -errno;
+ }
+ return err;
+}
+
+// Helper function to write integer values to the full sysfs path
+static ssize_t write_int_to_node(cec_context_t *ctx,
+ const char *path_postfix,
+ const int value)
+{
+ char sysfs_full_path[MAX_PATH_LENGTH];
+ char sysfs_data[MAX_SYSFS_DATA];
+ snprintf(sysfs_data, sizeof(sysfs_data), "%d",value);
+ snprintf(sysfs_full_path,sizeof(sysfs_full_path), "%s/%s",
+ ctx->fb_sysfs_path, path_postfix);
+ ssize_t err = write_node(sysfs_full_path, sysfs_data, strlen(sysfs_data));
+ return err;
+}
+
+static void hex_to_string(const char *msg, ssize_t len, char *str)
+{
+ //Functions assumes sufficient memory in str
+ char *ptr = str;
+ for(int i=0; i < len ; i++) {
+ ptr += snprintf(ptr, 3, "%02X", msg[i]);
+ // Overwrite null termination of snprintf in all except the last byte
+ if (i < len - 1)
+ *ptr = ':';
+ ptr++;
+ }
+}
+
+static ssize_t cec_get_fb_node_number(cec_context_t *ctx)
+{
+ //XXX: Do this from a common utility library across the display HALs
+ const int MAX_FB_DEVICES = 2;
+ ssize_t len = 0;
+ char fb_type_path[MAX_PATH_LENGTH];
+ char fb_type[MAX_SYSFS_DATA];
+ const char *dtv_panel_str = "dtv panel";
+
+ for(int num = 0; num < MAX_FB_DEVICES; num++) {
+ snprintf(fb_type_path, sizeof(fb_type_path),"%s%d/msm_fb_type",
+ SYSFS_BASE,num);
+ ALOGD_IF(DEBUG, "%s: num: %d fb_type_path: %s", __FUNCTION__, num, fb_type_path);
+ len = read_node(fb_type_path, fb_type);
+ ALOGD_IF(DEBUG, "%s: fb_type:%s", __FUNCTION__, fb_type);
+ if(len > 0 && (strncmp(fb_type, dtv_panel_str, strlen(dtv_panel_str)) == 0)){
+ ALOGD_IF(DEBUG, "%s: Found DTV panel at fb%d", __FUNCTION__, num);
+ ctx->fb_num = num;
+ snprintf(ctx->fb_sysfs_path, sizeof(ctx->fb_sysfs_path),
+ "%s%d", SYSFS_BASE, num);
+ break;
+ }
+ }
+ if (len < 0)
+ return len;
+ else
+ return 0;
+}
+
+static int cec_add_logical_address(const struct hdmi_cec_device* dev,
+ cec_logical_address_t addr)
+{
+ if (addr < CEC_ADDR_TV || addr > CEC_ADDR_BROADCAST) {
+ ALOGE("%s: Received invalid address: %d ", __FUNCTION__, addr);
+ return -EINVAL;
+ }
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ ctx->logical_address[addr] = LOGICAL_ADDRESS_SET;
+
+ //XXX: We can get multiple logical addresses here but we can only send one
+ //to the driver. Store locally for now
+ ssize_t err = write_int_to_node(ctx, "cec/logical_addr", addr);
+ ALOGI("%s: Allocated logical address: %d ", __FUNCTION__, addr);
+ return (int) err;
+}
+
+static void cec_clear_logical_address(const struct hdmi_cec_device* dev)
+{
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ memset(ctx->logical_address, LOGICAL_ADDRESS_UNSET,
+ sizeof(ctx->logical_address));
+ //XXX: Find logical_addr that needs to be reset
+ write_int_to_node(ctx, "cec/logical_addr", 15);
+ ALOGD_IF(DEBUG, "%s: Cleared logical addresses", __FUNCTION__);
+}
+
+static int cec_get_physical_address(const struct hdmi_cec_device* dev,
+ uint16_t* addr)
+{
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ char pa_path[MAX_PATH_LENGTH];
+ char pa_data[MAX_SYSFS_DATA];
+ snprintf (pa_path, sizeof(pa_path),"%s/pa",
+ ctx->fb_sysfs_path);
+ int err = (int) read_node(pa_path, pa_data);
+ *addr = (uint16_t) atoi(pa_data);
+ ALOGD_IF(DEBUG, "%s: Physical Address: 0x%x", __FUNCTION__, *addr);
+ if (err < 0)
+ return err;
+ else
+ return 0;
+}
+
+static int cec_send_message(const struct hdmi_cec_device* dev,
+ const cec_message_t* msg)
+{
+ ATRACE_CALL();
+ if(cec_is_connected(dev, 0) <= 0)
+ return HDMI_RESULT_FAIL;
+
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ ALOGD_IF(DEBUG, "%s: initiator: %d destination: %d length: %u",
+ __FUNCTION__, msg->initiator, msg->destination,
+ (uint32_t) msg->length);
+
+ // Dump message received from framework
+ char dump[128];
+ if(msg->length > 0) {
+ hex_to_string((char*)msg->body, msg->length, dump);
+ ALOGD_IF(DEBUG, "%s: message from framework: %s", __FUNCTION__, dump);
+ }
+
+ char write_msg_path[MAX_PATH_LENGTH];
+ char write_msg[MAX_CEC_FRAME_SIZE];
+ memset(write_msg, 0, sizeof(write_msg));
+ // See definition of struct hdmi_cec_msg in driver code
+ // drivers/video/msm/mdss/mdss_hdmi_cec.c
+ // Write header block
+ // XXX: Include this from header in kernel
+ write_msg[CEC_OFFSET_SENDER_ID] = msg->initiator;
+ write_msg[CEC_OFFSET_RECEIVER_ID] = msg->destination;
+ //Kernel splits opcode/operand, but Android sends it in one byte array
+ write_msg[CEC_OFFSET_OPCODE] = msg->body[0];
+ if(msg->length > 1) {
+ memcpy(&write_msg[CEC_OFFSET_OPERAND], &msg->body[1],
+ sizeof(char)*(msg->length - 1));
+ }
+ //msg length + initiator + destination
+ write_msg[CEC_OFFSET_FRAME_LENGTH] = (unsigned char) (msg->length + 1);
+ hex_to_string(write_msg, sizeof(write_msg), dump);
+ ALOGD_IF(DEBUG, "%s: message to driver: %s", __FUNCTION__, dump);
+ snprintf(write_msg_path, sizeof(write_msg_path), "%s/cec/wr_msg",
+ ctx->fb_sysfs_path);
+ int retry_count = 0;
+ ssize_t err = 0;
+ //HAL spec requires us to retry at least once.
+ while (true) {
+ err = write_node(write_msg_path, write_msg, sizeof(write_msg));
+ retry_count++;
+ if (err == -EAGAIN && retry_count <= MAX_SEND_MESSAGE_RETRIES) {
+ ALOGE("%s: CEC line busy, retrying", __FUNCTION__);
+ } else {
+ break;
+ }
+ }
+
+ if (err < 0) {
+ if (err == -ENXIO) {
+ ALOGI("%s: No device exists with the destination address",
+ __FUNCTION__);
+ return HDMI_RESULT_NACK;
+ } else if (err == -EAGAIN) {
+ ALOGE("%s: CEC line is busy, max retry count exceeded",
+ __FUNCTION__);
+ return HDMI_RESULT_BUSY;
+ } else {
+ return HDMI_RESULT_FAIL;
+ ALOGE("%s: Failed to send CEC message err: %zd - %s",
+ __FUNCTION__, err, strerror(int(-err)));
+ }
+ } else {
+ ALOGD_IF(DEBUG, "%s: Sent CEC message - %zd bytes written",
+ __FUNCTION__, err);
+ return HDMI_RESULT_SUCCESS;
+ }
+}
+
+void cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len)
+{
+ if(!ctx->system_control)
+ return;
+
+ char dump[128];
+ if(len > 0) {
+ hex_to_string(msg, len, dump);
+ ALOGD_IF(DEBUG, "%s: Message from driver: %s", __FUNCTION__, dump);
+ }
+
+ hdmi_event_t event;
+ event.type = HDMI_EVENT_CEC_MESSAGE;
+ event.dev = (hdmi_cec_device *) ctx;
+ // Remove initiator/destination from this calculation
+ event.cec.length = msg[CEC_OFFSET_FRAME_LENGTH] - 1;
+ event.cec.initiator = (cec_logical_address_t) msg[CEC_OFFSET_SENDER_ID];
+ event.cec.destination = (cec_logical_address_t) msg[CEC_OFFSET_RECEIVER_ID];
+ //Copy opcode and operand
+ memcpy(event.cec.body, &msg[CEC_OFFSET_OPCODE], event.cec.length);
+ hex_to_string((char *) event.cec.body, event.cec.length, dump);
+ ALOGD_IF(DEBUG, "%s: Message to framework: %s", __FUNCTION__, dump);
+ ctx->callback.callback_func(&event, ctx->callback.callback_arg);
+}
+
+void cec_hdmi_hotplug(cec_context_t *ctx, int connected)
+{
+ //Ignore unplug events when system control is disabled
+ if(!ctx->system_control && connected == 0)
+ return;
+ hdmi_event_t event;
+ event.type = HDMI_EVENT_HOT_PLUG;
+ event.dev = (hdmi_cec_device *) ctx;
+ event.hotplug.connected = connected ? HDMI_CONNECTED : HDMI_NOT_CONNECTED;
+ ctx->callback.callback_func(&event, ctx->callback.callback_arg);
+}
+
+static void cec_register_event_callback(const struct hdmi_cec_device* dev,
+ event_callback_t callback, void* arg)
+{
+ ALOGD_IF(DEBUG, "%s: Registering callback", __FUNCTION__);
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ ctx->callback.callback_func = callback;
+ ctx->callback.callback_arg = arg;
+}
+
+static void cec_get_version(const struct hdmi_cec_device* dev, int* version)
+{
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ *version = ctx->version;
+ ALOGD_IF(DEBUG, "%s: version: %d", __FUNCTION__, *version);
+}
+
+static void cec_get_vendor_id(const struct hdmi_cec_device* dev,
+ uint32_t* vendor_id)
+{
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ *vendor_id = ctx->vendor_id;
+ ALOGD_IF(DEBUG, "%s: vendor id: %u", __FUNCTION__, *vendor_id);
+}
+
+static void cec_get_port_info(const struct hdmi_cec_device* dev,
+ struct hdmi_port_info* list[], int* total)
+{
+ ALOGD_IF(DEBUG, "%s: Get port info", __FUNCTION__);
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ *total = NUM_HDMI_PORTS;
+ *list = ctx->port_info;
+}
+
+static void cec_set_option(const struct hdmi_cec_device* dev, int flag,
+ int value)
+{
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ switch (flag) {
+ case HDMI_OPTION_WAKEUP:
+ ALOGD_IF(DEBUG, "%s: Wakeup: value: %d", __FUNCTION__, value);
+ //XXX
+ break;
+ case HDMI_OPTION_ENABLE_CEC:
+ ALOGD_IF(DEBUG, "%s: Enable CEC: value: %d", __FUNCTION__, value);
+ cec_enable(ctx, value? 1 : 0);
+ break;
+ case HDMI_OPTION_SYSTEM_CEC_CONTROL:
+ ALOGD_IF(DEBUG, "%s: system_control: value: %d",
+ __FUNCTION__, value);
+ ctx->system_control = !!value;
+ break;
+ }
+}
+
+static void cec_set_audio_return_channel(const struct hdmi_cec_device* dev,
+ int flag)
+{
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ ctx->arc_enabled = flag ? true : false;
+ ALOGD_IF(DEBUG, "%s: ARC flag: %d", __FUNCTION__, flag);
+}
+
+static int cec_is_connected(const struct hdmi_cec_device* dev, int port_id)
+{
+ // Ignore port_id since we have only one port
+ int connected = 0;
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ char connected_path[MAX_PATH_LENGTH];
+ char connected_data[MAX_SYSFS_DATA];
+ snprintf (connected_path, sizeof(connected_path),"%s/connected",
+ ctx->fb_sysfs_path);
+ ssize_t err = read_node(connected_path, connected_data);
+ connected = atoi(connected_data);
+
+ ALOGD_IF(DEBUG, "%s: HDMI at port %d is - %s", __FUNCTION__, port_id,
+ connected ? "connected":"disconnected");
+ if (err < 0)
+ return (int) err;
+ else
+ return connected;
+}
+
+static int cec_device_close(struct hw_device_t *dev)
+{
+ ALOGD_IF(DEBUG, "%s: Close CEC HAL ", __FUNCTION__);
+ if (!dev) {
+ ALOGE("%s: NULL device pointer", __FUNCTION__);
+ return -EINVAL;
+ }
+ cec_context_t* ctx = (cec_context_t*)(dev);
+ cec_close_context(ctx);
+ free(dev);
+ return 0;
+}
+
+static int cec_enable(cec_context_t *ctx, int enable)
+{
+ ssize_t err;
+ // Enable CEC
+ // TODO: Set to 0x3 to enable CEC wakeup once driver has support
+ int value = enable ? 0x1 : 0x0;
+ err = write_int_to_node(ctx, "cec/enable", value);
+ if(err < 0) {
+ ALOGE("%s: Failed to toggle CEC: enable: %d",
+ __FUNCTION__, enable);
+ return (int) err;
+ }
+ ctx->enabled = enable;
+ return 0;
+}
+
+static void cec_init_context(cec_context_t *ctx)
+{
+ ALOGD_IF(DEBUG, "%s: Initializing context", __FUNCTION__);
+ cec_get_fb_node_number(ctx);
+
+ //Initialize ports - We support only one output port
+ ctx->port_info = new hdmi_port_info[NUM_HDMI_PORTS];
+ ctx->port_info[0].type = HDMI_OUTPUT;
+ ctx->port_info[0].port_id = 1;
+ ctx->port_info[0].cec_supported = 1;
+ //XXX: Enable ARC if supported
+ ctx->port_info[0].arc_supported = 0;
+ cec_get_physical_address((hdmi_cec_device *) ctx,
+ &ctx->port_info[0].physical_address );
+
+ ctx->version = 0x4;
+ ctx->vendor_id = 0xA47733;
+ cec_clear_logical_address((hdmi_cec_device_t*)ctx);
+
+ //Set up listener for HDMI events
+ ctx->disp_client = new qClient::QHDMIClient();
+ ctx->disp_client->setCECContext(ctx);
+ ctx->disp_client->registerClient(ctx->disp_client);
+
+ //Enable CEC - framework expects it to be enabled by default
+ cec_enable(ctx, true);
+
+ ALOGD("%s: CEC enabled", __FUNCTION__);
+}
+
+static void cec_close_context(cec_context_t* ctx __unused)
+{
+ ALOGD("%s: Closing context", __FUNCTION__);
+}
+
+static int cec_device_open(const struct hw_module_t* module,
+ const char* name,
+ struct hw_device_t** device)
+{
+ ALOGD_IF(DEBUG, "%s: name: %s", __FUNCTION__, name);
+ int status = -EINVAL;
+ if (!strcmp(name, HDMI_CEC_HARDWARE_INTERFACE )) {
+ struct cec_context_t *dev;
+ dev = (cec_context_t *) calloc (1, sizeof(*dev));
+ if (dev) {
+ cec_init_context(dev);
+
+ //Setup CEC methods
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = HDMI_CEC_DEVICE_API_VERSION_1_0;
+ dev->device.common.module = const_cast<hw_module_t* >(module);
+ dev->device.common.close = cec_device_close;
+ dev->device.add_logical_address = cec_add_logical_address;
+ dev->device.clear_logical_address = cec_clear_logical_address;
+ dev->device.get_physical_address = cec_get_physical_address;
+ dev->device.send_message = cec_send_message;
+ dev->device.register_event_callback = cec_register_event_callback;
+ dev->device.get_version = cec_get_version;
+ dev->device.get_vendor_id = cec_get_vendor_id;
+ dev->device.get_port_info = cec_get_port_info;
+ dev->device.set_option = cec_set_option;
+ dev->device.set_audio_return_channel = cec_set_audio_return_channel;
+ dev->device.is_connected = cec_is_connected;
+
+ *device = &dev->device.common;
+ status = 0;
+ } else {
+ status = -EINVAL;
+ }
+ }
+ return status;
+}
+}; //namespace qhdmicec
+
+// Standard HAL module, should be outside qhdmicec namespace
+static struct hw_module_methods_t cec_module_methods = {
+ .open = qhdmicec::cec_device_open
+};
+
+hdmi_module_t HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = HDMI_CEC_HARDWARE_MODULE_ID,
+ .name = "QTI HDMI CEC module",
+ .author = "The Linux Foundation",
+ .methods = &cec_module_methods,
+ }
+};
+
+
diff --git a/hdmi_cec/qhdmi_cec.h b/hdmi_cec/qhdmi_cec.h
new file mode 100644
index 0000000..aa97620
--- /dev/null
+++ b/hdmi_cec/qhdmi_cec.h
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2014 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef QHDMI_CEC_H
+#define QHDMI_CEC_H
+
+#include <hardware/hdmi_cec.h>
+#include <utils/RefBase.h>
+
+namespace qClient {
+ class QHDMIClient;
+};
+
+namespace qhdmicec {
+
+#define SYSFS_BASE "/sys/class/graphics/fb"
+#define MAX_PATH_LENGTH 128
+
+struct cec_callback_t {
+ // Function in HDMI service to call back on CEC messages
+ event_callback_t callback_func;
+ // This stores the object to pass back to the framework
+ void* callback_arg;
+
+};
+
+struct cec_context_t {
+ hdmi_cec_device_t device; // Device for HW module
+ cec_callback_t callback; // Struct storing callback object
+ bool enabled;
+ bool arc_enabled;
+ bool system_control; // If true, HAL/driver handle CEC messages
+ int fb_num; // Framebuffer node for HDMI
+ char fb_sysfs_path[MAX_PATH_LENGTH];
+ hdmi_port_info *port_info; // HDMI port info
+
+ // Logical address is stored in an array, the index of the array is the
+ // logical address and the value in the index shows whether it is set or not
+ int logical_address[CEC_ADDR_BROADCAST];
+ int version;
+ uint32_t vendor_id;
+ android::sp<qClient::QHDMIClient> disp_client;
+};
+
+void cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len);
+void cec_hdmi_hotplug(cec_context_t *ctx, int connected);
+
+}; //namespace
+#endif /* end of include guard: QHDMI_CEC_H */
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index e4624e0..02f0c7e 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -64,6 +64,7 @@
int relFence;
struct mdp_buf_sync sync;
struct blitReq list;
+ uint8_t dynamic_fps;
};
/**
@@ -122,6 +123,10 @@
out->b = min(lhs->b, rhs->b);
}
+static bool validateCopybitRect(struct copybit_rect_t *rect) {
+ return ((rect->b > rect->t) && (rect->r > rect->l)) ;
+}
+
/** convert COPYBIT_FORMAT to MDP format */
static int get_format(int format) {
switch (format) {
@@ -161,7 +166,7 @@
img->memory_id = hnd->fd;
}
/** setup rectangles */
-static void set_rects(struct copybit_context_t *dev,
+static bool set_rects(struct copybit_context_t *dev,
struct mdp_blit_req *e,
const struct copybit_rect_t *dst,
const struct copybit_rect_t *src,
@@ -169,6 +174,9 @@
struct copybit_rect_t clip;
intersect(&clip, scissor, dst);
+ if (!validateCopybitRect(&clip))
+ return false;
+
e->dst_rect.x = clip.l;
e->dst_rect.y = clip.t;
e->dst_rect.w = clip.r - clip.l;
@@ -212,6 +220,7 @@
e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w);
}
}
+ return true;
}
/** setup mdp request */
@@ -219,6 +228,7 @@
struct mdp_blit_req *req, int flags)
{
req->alpha = dev->mAlpha;
+ req->fps = dev->dynamic_fps;
req->transp_mask = MDP_TRANSP_NOP;
req->flags = dev->mFlags | flags;
// check if we are blitting to f/b
@@ -250,7 +260,7 @@
for (unsigned int i=0 ; i<l->count ; i++) {
ALOGE("%d: src={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n"
" dst={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n"
- " flags=%08x"
+ " flags=%08x, fps=%d"
,
i,
l->req[i].src.width,
@@ -267,7 +277,8 @@
l->req[i].dst_rect.y,
l->req[i].dst_rect.w,
l->req[i].dst_rect.h,
- l->req[i].flags
+ l->req[i].flags,
+ l->req[i].fps
);
}
#endif
@@ -315,6 +326,9 @@
if (value >= 256) value = 255;
ctx->mAlpha = (uint8_t)value;
break;
+ case COPYBIT_DYNAMIC_FPS:
+ ctx->dynamic_fps = (uint8_t)value;
+ break;
case COPYBIT_DITHER:
if (value == COPYBIT_ENABLE) {
ctx->mFlags |= MDP_DITHER;
@@ -512,7 +526,11 @@
// Set Color Space for MDP to configure CSC matrix
req->color_space = ITU_R_601;
- MetaData_t *metadata = (MetaData_t *)src_hnd->base_metadata;
+ MetaData_t *metadata = NULL;
+
+ if (src_hnd != NULL)
+ metadata = (MetaData_t *)src_hnd->base_metadata;
+
if (metadata && (metadata->operation & UPDATE_COLOR_SPACE)) {
req->color_space = metadata->colorSpace;
}
@@ -520,7 +538,8 @@
set_infos(ctx, req, flags);
set_image(&req->dst, dst);
set_image(&req->src, src);
- set_rects(ctx, req, dst_rect, src_rect, &clip);
+ if (set_rects(ctx, req, dst_rect, src_rect, &clip) == false)
+ continue;
if (req->src_rect.w<=0 || req->src_rect.h<=0)
continue;
@@ -722,6 +741,11 @@
}
copybit_context_t *ctx;
ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
+
+ if (ctx == NULL ) {
+ return COPYBIT_FAILURE;
+ }
+
memset(ctx, 0, sizeof(*ctx));
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
@@ -738,6 +762,9 @@
ctx->device.flush_get_fence = flush_get_fence;
ctx->device.clear = clear_copybit;
ctx->mAlpha = MDP_ALPHA_NOP;
+ //dynamic_fps is zero means default
+ //panel refresh rate for driver.
+ ctx->dynamic_fps = 0;
ctx->mFlags = 0;
ctx->sync.flags = 0;
ctx->relFence = -1;
diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h
index 6428023..1fc17ed 100644
--- a/libcopybit/copybit.h
+++ b/libcopybit/copybit.h
@@ -79,6 +79,7 @@
/* FB height */
COPYBIT_FRAMEBUFFER_HEIGHT = 8,
COPYBIT_FG_LAYER = 9,
+ COPYBIT_DYNAMIC_FPS = 10,
};
/* values for copybit_set_parameter(COPYBIT_TRANSFORM) */
diff --git a/libgralloc/adreno_utils.h b/libgralloc/adreno_utils.h
index 6cb7810..78f49da 100644
--- a/libgralloc/adreno_utils.h
+++ b/libgralloc/adreno_utils.h
@@ -36,6 +36,7 @@
ADRENO_PIXELFORMAT_NV12 = 103,
ADRENO_PIXELFORMAT_YUY2 = 107,
ADRENO_PIXELFORMAT_B4G4R4A4 = 115,
+ ADRENO_PIXELFORMAT_NV12_EXT = 506, // NV12 with non-std alignment and offsets
ADRENO_PIXELFORMAT_R8G8B8 = 508, // GL_RGB8
ADRENO_PIXELFORMAT_A1B5G5R5 = 519, // GL_RGB5_A1
ADRENO_PIXELFORMAT_R8G8B8X8_SRGB = 520, // GL_SRGB8
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index fd98154..508564a 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -308,9 +308,10 @@
case HAL_PIXEL_FORMAT_sRGB_A_8888:
return ADRENO_PIXELFORMAT_R8G8B8A8_SRGB;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ return ADRENO_PIXELFORMAT_NV12;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
- return ADRENO_PIXELFORMAT_NV12;
+ return ADRENO_PIXELFORMAT_NV12_EXT;
default:
ALOGE("%s: No map for format: 0x%x", __FUNCTION__, hal_format);
break;
@@ -627,6 +628,7 @@
int width = hnd->width;
int height = hnd->height;
unsigned int ystride, cstride;
+ unsigned int alignment = 4096;
memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
@@ -654,6 +656,34 @@
ycbcr->chroma_step = 2;
break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
+ // NV12_UBWC buffer has these 4 planes in the following sequence:
+ // Y_Meta_Plane, Y_Plane, UV_Meta_Plane, UV_Plane
+ unsigned int y_meta_stride, y_meta_height, y_meta_size;
+ unsigned int y_stride, y_height, y_size;
+ unsigned int c_meta_stride, c_meta_height, c_meta_size;
+
+ y_meta_stride = VENUS_Y_META_STRIDE(COLOR_FMT_NV12_UBWC, width);
+ y_meta_height = VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_UBWC, height);
+ y_meta_size = ALIGN((y_meta_stride * y_meta_height), alignment);
+
+ y_stride = VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width);
+ y_height = VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height);
+ y_size = ALIGN((y_stride * y_height), alignment);
+
+ c_meta_stride = VENUS_UV_META_STRIDE(COLOR_FMT_NV12_UBWC, width);
+ c_meta_height = VENUS_UV_META_SCANLINES(COLOR_FMT_NV12_UBWC, height);
+ c_meta_size = ALIGN((c_meta_stride * c_meta_height), alignment);
+
+ ycbcr->y = (void*)(hnd->base + y_meta_size);
+ ycbcr->cb = (void*)(hnd->base + y_meta_size + y_size + c_meta_size);
+ ycbcr->cr = (void*)(hnd->base + y_meta_size + y_size +
+ c_meta_size + 1);
+ ycbcr->ystride = y_stride;
+ ycbcr->cstride = VENUS_UV_STRIDE(COLOR_FMT_NV12_UBWC, width);
+ ycbcr->chroma_step = 2;
+ break;
+
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index e9b9d9d..f973b76 100755
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -33,44 +33,42 @@
#define ROUND_UP_PAGESIZE(x) ( (((unsigned long)(x)) + PAGE_SIZE-1) & \
(~(PAGE_SIZE-1)) )
-enum {
- /* gralloc usage bits indicating the type
- * of allocation that should be used */
+/* Gralloc usage bits indicating the type of allocation that should be used */
+/* SYSTEM heap comes from kernel vmalloc, can never be uncached,
+ * is not secured */
+#define GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP GRALLOC_USAGE_PRIVATE_0
- /* SYSTEM heap comes from kernel vmalloc,
- * can never be uncached, is not secured*/
- GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_0,
+/* Non linear, Universal Bandwidth Compression */
+#define GRALLOC_USAGE_PRIVATE_ALLOC_UBWC GRALLOC_USAGE_PRIVATE_1
- /* Non linear, Universal Bandwidth Compression */
- GRALLOC_USAGE_PRIVATE_ALLOC_UBWC = GRALLOC_USAGE_PRIVATE_1,
+/* IOMMU heap comes from manually allocated pages, can be cached/uncached,
+ * is not secured */
+#define GRALLOC_USAGE_PRIVATE_IOMMU_HEAP GRALLOC_USAGE_PRIVATE_2
- /* IOMMU heap comes from manually allocated pages,
- * can be cached/uncached, is not secured */
- GRALLOC_USAGE_PRIVATE_IOMMU_HEAP = GRALLOC_USAGE_PRIVATE_2,
- /* MM heap is a carveout heap for video, can be secured*/
- GRALLOC_USAGE_PRIVATE_MM_HEAP = GRALLOC_USAGE_PRIVATE_3,
- /* ADSP heap is a carveout heap, is not secured*/
- GRALLOC_USAGE_PRIVATE_ADSP_HEAP = 0x01000000,
+/* MM heap is a carveout heap for video, can be secured */
+#define GRALLOC_USAGE_PRIVATE_MM_HEAP GRALLOC_USAGE_PRIVATE_3
- /* Set this for allocating uncached memory (using O_DSYNC)
- * cannot be used with noncontiguous heaps */
- GRALLOC_USAGE_PRIVATE_UNCACHED = 0x02000000,
+/* ADSP heap is a carveout heap, is not secured */
+#define GRALLOC_USAGE_PRIVATE_ADSP_HEAP 0x01000000
- /* Buffer content should be displayed on an primary display only */
- GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY = 0x04000000,
+/* Set this for allocating uncached memory (using O_DSYNC),
+ * cannot be used with noncontiguous heaps */
+#define GRALLOC_USAGE_PRIVATE_UNCACHED 0x02000000
- /* Buffer content should be displayed on an external display only */
- GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY = 0x08000000,
+/* Buffer content should be displayed on an primary display only */
+#define GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY 0x04000000
- /* This flag is set for WFD usecase */
- GRALLOC_USAGE_PRIVATE_WFD = 0x00200000,
+/* Buffer content should be displayed on an external display only */
+#define GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY 0x08000000
- /* CAMERA heap is a carveout heap for camera, is not secured*/
- GRALLOC_USAGE_PRIVATE_CAMERA_HEAP = 0x00400000,
+/* This flag is set for WFD usecase */
+#define GRALLOC_USAGE_PRIVATE_WFD 0x00200000
- /* This flag is used for SECURE display usecase */
- GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY = 0x00800000,
-};
+/* CAMERA heap is a carveout heap for camera, is not secured */
+#define GRALLOC_USAGE_PRIVATE_CAMERA_HEAP 0x00400000
+
+/* This flag is used for SECURE display usecase */
+#define GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY 0x00800000
/* define Gralloc perform */
#define GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER 1
@@ -84,6 +82,7 @@
#define GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE 6
#define GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO 7
#define GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO 8
+#define GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG 9
#define GRALLOC_HEAP_MASK (GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |\
GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |\
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 44f4fb2..5382300 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -447,6 +447,17 @@
}
} break;
+ case GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG:
+ {
+ private_handle_t* hnd = va_arg(args, private_handle_t*);
+ int *flag = va_arg(args, int *);
+ if (private_handle_t::validate(hnd)) {
+ return res;
+ }
+ *flag = hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
+ res = 0;
+ } break;
+
default:
break;
}
diff --git a/libhdmi/hdmi.cpp b/libhdmi/hdmi.cpp
index bca7a0b..fb6493a 100644
--- a/libhdmi/hdmi.cpp
+++ b/libhdmi/hdmi.cpp
@@ -95,6 +95,7 @@
mUnderscanSupported(false), mMDPDownscaleEnabled(false)
{
memset(&mVInfo, 0, sizeof(mVInfo));
+ mFbNum = qdutils::getHDMINode();
mDisplayId = HWC_DISPLAY_EXTERNAL;
// Update the display if HDMI is connected as primary
@@ -102,7 +103,6 @@
mDisplayId = HWC_DISPLAY_PRIMARY;
}
- mFbNum = overlay::Overlay::getInstance()->getFbForDpy(mDisplayId);
// Disable HPD at start if HDMI is external, it will be enabled later
// when the display powers on
// This helps for framework reboot or adb shell stop/start
@@ -412,8 +412,9 @@
// for all the timing info read, get the best config
for (int configIndex = 0; configIndex < mModeCount; configIndex++) {
currentModeInfo = mDisplayConfigs[configIndex];
+ edidMode = mEDIDModes[configIndex];
- if (!currentModeInfo.supported) {
+ if (!isValidMode(edidMode)) {
ALOGD("%s EDID Mode %d is not supported", __FUNCTION__, edidMode);
continue;
}
@@ -684,8 +685,7 @@
}
bool HDMIDisplay::isHDMIPrimaryDisplay() {
- int hdmiNode = qdutils::getHDMINode();
- return (hdmiNode == HWC_DISPLAY_PRIMARY);
+ return (mFbNum == HWC_DISPLAY_PRIMARY);
}
int HDMIDisplay::getConnectedState() {
@@ -739,6 +739,124 @@
return 0;
}
+static const char* getS3DStringFromMode(int s3dMode) {
+ const char* ret ;
+ switch(s3dMode) {
+ case HDMI_S3D_NONE:
+ ret = "None";
+ break;
+ case HDMI_S3D_SIDE_BY_SIDE:
+ ret = "SSH";
+ break;
+ case HDMI_S3D_TOP_AND_BOTTOM:
+ ret = "TAB";
+ break;
+ //FP (FramePacked) mode is not supported in the HAL
+ default:
+ ALOGD("%s: Unsupported s3d mode: %d", __FUNCTION__, s3dMode);
+ ret = NULL;
+ }
+ return ret;
+}
+
+bool HDMIDisplay::isS3DModeSupported(int s3dMode) {
+ if(s3dMode == HDMI_S3D_NONE)
+ return true;
+
+ char s3dEdidStr[PAGE_SIZE] = {'\0'};
+
+ const char *s3dModeString = getS3DStringFromMode(s3dMode);
+
+ if(s3dModeString == NULL)
+ return false;
+
+ int s3dEdidNode = openDeviceNode("edid_3d_modes", O_RDONLY);
+ if(s3dEdidNode >= 0) {
+ ssize_t len = read(s3dEdidNode, s3dEdidStr, sizeof(s3dEdidStr)-1);
+ if (len > 0) {
+ ALOGI("%s: s3dEdidStr: %s mCurrentMode:%d", __FUNCTION__,
+ s3dEdidStr, mCurrentMode);
+ //Three level inception!
+ //The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH
+ char *saveptr_l1, *saveptr_l2, *saveptr_l3;
+ char *l1, *l2, *l3;
+ int mode = 0;
+ l1 = strtok_r(s3dEdidStr,",", &saveptr_l1);
+ while (l1 != NULL) {
+ l2 = strtok_r(l1, "=", &saveptr_l2);
+ if (l2 != NULL)
+ mode = atoi(l2);
+ while (l2 != NULL) {
+ if (mode != mCurrentMode) {
+ break;
+ }
+ l3 = strtok_r(l2, ":", &saveptr_l3);
+ while (l3 != NULL) {
+ if (strncmp(l3, s3dModeString,
+ strlen(s3dModeString)) == 0) {
+ close(s3dEdidNode);
+ return true;
+ }
+ l3 = strtok_r(NULL, ":", &saveptr_l3);
+ }
+ l2 = strtok_r(NULL, "=", &saveptr_l2);
+ }
+ l1 = strtok_r(NULL, ",", &saveptr_l1);
+ }
+
+ }
+ } else {
+ ALOGI("%s: /sys/class/graphics/fb%d/edid_3d_modes could not be opened : %s",
+ __FUNCTION__, mFbNum, strerror(errno));
+ }
+ close(s3dEdidNode);
+ return false;
+}
+
+bool HDMIDisplay::writeS3DMode(int s3dMode) {
+ bool ret = true;
+ if(mFbNum != -1) {
+ int hdmiS3DModeFile = openDeviceNode("s3d_mode", O_RDWR);
+ if(hdmiS3DModeFile >=0 ) {
+ char curModeStr[PROPERTY_VALUE_MAX];
+ int currentS3DMode = -1;
+ size_t len = read(hdmiS3DModeFile, curModeStr, sizeof(curModeStr) - 1);
+ if(len > 0) {
+ currentS3DMode = atoi(curModeStr);
+ } else {
+ ret = false;
+ ALOGE("%s: Failed to read s3d_mode", __FUNCTION__);
+ }
+
+ if (currentS3DMode >=0 && currentS3DMode != s3dMode) {
+ ssize_t err = -1;
+ ALOGD_IF(DEBUG, "%s: mode = %d",
+ __FUNCTION__, s3dMode);
+ char mode[PROPERTY_VALUE_MAX];
+ snprintf(mode,sizeof(mode),"%d",s3dMode);
+ err = write(hdmiS3DModeFile, mode, sizeof(mode));
+ if (err <= 0) {
+ ALOGE("%s: file write failed 's3d_mode'", __FUNCTION__);
+ ret = false;
+ }
+ }
+ close(hdmiS3DModeFile);
+ }
+ }
+ return ret;
+}
+
+bool HDMIDisplay::configure3D(int s3dMode) {
+ if(isS3DModeSupported(s3dMode)) {
+ if(!writeS3DMode(s3dMode))
+ return false;
+ } else {
+ ALOGE("%s: 3D mode: %d is not supported", __FUNCTION__, s3dMode);
+ return false;
+ }
+ return true;
+}
+
// returns false if the xres or yres of the new config do
// not match the current config
bool HDMIDisplay::isValidConfigChange(int newConfig) {
diff --git a/libhdmi/hdmi.h b/libhdmi/hdmi.h
index 32c48ff..d1d5759 100644
--- a/libhdmi/hdmi.h
+++ b/libhdmi/hdmi.h
@@ -64,6 +64,8 @@
int getAttrForConfig(int config, uint32_t& xres,
uint32_t& yres, uint32_t& refresh, uint32_t& fps) const;
int getDisplayConfigs(uint32_t* configs, size_t* numConfigs) const;
+ bool configure3D(int s3dMode);
+ bool isS3DModeSupported(int s3dMode);
private:
int getModeCount() const;
@@ -87,6 +89,7 @@
void requestNewPage(int pageNumber);
void readConfigs();
bool readResFile(char* configBuffer);
+ bool writeS3DMode(int s3dMode);
int mFd;
int mFbNum;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index adf48e7..f3b34c3 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -226,18 +226,11 @@
}
-static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
- hwc_display_contents_1_t *list) {
- uint32_t origXres = ctx->dpyAttr[dpy].xres;
- uint32_t origYres = ctx->dpyAttr[dpy].yres;
- uint32_t newXres = ctx->dpyAttr[dpy].xres_new;
- uint32_t newYres = ctx->dpyAttr[dpy].yres_new;
- float xresRatio = (float)origXres / (float)newXres;
- float yresRatio = (float)origYres / (float)newYres;
+static void scaleDisplayFrame(hwc_display_contents_1_t *list, float xresRatio,
+ float yresRatio) {
for (size_t i = 0; i < list->numHwLayers; i++) {
hwc_layer_1_t *layer = &list->hwLayers[i];
hwc_rect_t& displayFrame = layer->displayFrame;
- hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
uint32_t layerWidth = displayFrame.right - displayFrame.left;
uint32_t layerHeight = displayFrame.bottom - displayFrame.top;
displayFrame.left = (int)(xresRatio * (float)displayFrame.left);
@@ -249,6 +242,35 @@
}
}
+static void handleFbScaling(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t *list) {
+ //We could switch to a config that does not lead to fb scaling, but
+ //we need to update older display frames and ratios.
+ if (ctx->dpyAttr[dpy].fbScaling or ctx->dpyAttr[dpy].configSwitched) {
+ uint32_t xresPanel = ctx->dpyAttr[dpy].xres;
+ uint32_t yresPanel = ctx->dpyAttr[dpy].yres;
+ uint32_t xresFB = ctx->dpyAttr[dpy].xresFB;
+ uint32_t yresFB = ctx->dpyAttr[dpy].yresFB;
+ float xresRatio = (float)xresPanel / (float)xresFB;
+ float yresRatio = (float)yresPanel / (float)yresFB;
+ if(list->flags & HWC_GEOMETRY_CHANGED) {
+ //In case of geometry changes f/w resets displays frames w.r.t to
+ //FB's dimensions. So any config switch is automatically absorbed.
+ scaleDisplayFrame(list, xresRatio, yresRatio);
+ } else if (ctx->dpyAttr[dpy].configSwitched) {
+ //If there is a primary panel resolution switch without a geometry
+ //change we need to scale-back the previous ratio used and then use
+ //the current ratio. i.e use current ratio / prev ratio
+ scaleDisplayFrame(list,
+ xresRatio / ctx->dpyAttr[dpy].fbWidthScaleRatio,
+ yresRatio / ctx->dpyAttr[dpy].fbHeightScaleRatio);
+ }
+ ctx->dpyAttr[dpy].configSwitched = false;
+ ctx->dpyAttr[dpy].fbWidthScaleRatio = xresRatio;
+ ctx->dpyAttr[dpy].fbHeightScaleRatio = yresRatio;
+ }
+}
+
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) {
ATRACE_CALL();
@@ -277,9 +299,7 @@
ctx->dpyAttr[dpy].isActive = true;
}
- if (ctx->dpyAttr[dpy].customFBSize &&
- list->flags & HWC_GEOMETRY_CHANGED)
- scaleDisplayFrame(ctx, dpy, list);
+ handleFbScaling(ctx, dpy, list);
reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
setListStats(ctx, list, dpy);
@@ -449,7 +469,13 @@
value = FB_BLANK_POWERDOWN;
break;
case HWC_POWER_MODE_DOZE:
+ // FB_BLANK_NORMAL is being used here to map to doze mode
+ // This definition is specific to our fbdev implementation
+ value = FB_BLANK_NORMAL;
+ break;
case HWC_POWER_MODE_DOZE_SUSPEND:
+ // FB_BLANK_VSYNC_SUSPEND is being used here to map to doze_suspend
+ // This definition is specific to our fbdev implementation
value = FB_BLANK_VSYNC_SUSPEND;
break;
case HWC_POWER_MODE_NORMAL:
@@ -485,7 +511,8 @@
ctx->mHPDEnabled = true;
}
- ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+ ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF ||
+ mode == HWC_POWER_MODE_DOZE_SUSPEND);
}
//Deliberate fall through since there is no explicit power mode for
//virtual displays.
@@ -635,7 +662,11 @@
}
}
- int lSplit = getLeftSplit(ctx, dpy);
+ /* When source split is enabled, right ROI will always be NULL since the
+ * ROI for the whole panel generated in a single coordinate system will
+ * be populuated in left ROI. So leave the right ROI untouched */
+ int lSplit = qdutils::MDPVersion::getInstance().isSrcSplit() ? 0
+ :getLeftSplit(ctx, dpy);
qhwc::ovutils::Dim lRoi = qhwc::ovutils::Dim(
ctx->listStats[dpy].lRoi.left,
ctx->listStats[dpy].lRoi.top,
@@ -830,8 +861,8 @@
hotPluggable ? refresh : ctx->dpyAttr[disp].vsync_period;
break;
case HWC_DISPLAY_WIDTH:
- if (ctx->dpyAttr[disp].customFBSize)
- values[i] = ctx->dpyAttr[disp].xres_new;
+ if (ctx->dpyAttr[disp].fbScaling)
+ values[i] = ctx->dpyAttr[disp].xresFB;
else
values[i] = hotPluggable ? xres : ctx->dpyAttr[disp].xres;
@@ -839,8 +870,8 @@
values[i]);
break;
case HWC_DISPLAY_HEIGHT:
- if (ctx->dpyAttr[disp].customFBSize)
- values[i] = ctx->dpyAttr[disp].yres_new;
+ if (ctx->dpyAttr[disp].fbScaling)
+ values[i] = ctx->dpyAttr[disp].yresFB;
else
values[i] = hotPluggable ? yres : ctx->dpyAttr[disp].yres;
ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
@@ -875,6 +906,10 @@
dumpsys_log(aBuf, " DynRefreshRate=%d\n",
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].dynRefreshRate);
for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) {
+ if(dpy == HWC_DISPLAY_PRIMARY)
+ dumpsys_log(aBuf, "Dpy %d: FB Scale Ratio w %.1f, h %.1f\n", dpy,
+ ctx->dpyAttr[dpy].fbWidthScaleRatio,
+ ctx->dpyAttr[dpy].fbHeightScaleRatio);
if(ctx->mMDPComp[dpy])
ctx->mMDPComp[dpy]->dump(aBuf, ctx);
}
@@ -889,6 +924,7 @@
dumpsys_log(aBuf, ovDump);
ovDump[0] = '\0';
}
+ dumpsys_log(aBuf, "Copybit::isAbcInUse=%d\n\n",isAbcInUse(ctx) ? 1 : 0);
strlcpy(buff, aBuf.string(), buff_len);
}
@@ -962,7 +998,11 @@
memset(dev, 0, sizeof(*dev));
//Initialize hwc context
- initContext(dev);
+ status = initContext(dev);
+ if (status < 0) {
+ free(dev);
+ return status;
+ }
//Setup HWC methods
dev->device.common.tag = HARDWARE_DEVICE_TAG;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 65482d7..744195f 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -131,8 +131,10 @@
return renderArea;
}
-bool CopyBit::isLayerChanging(hwc_display_contents_1_t *list, int k) {
+bool CopyBit::isLayerChanging(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int k) {
if((mLayerCache.hnd[k] != list->hwLayers[k].handle) ||
+ (mLayerCache.drop[k] != ctx->copybitDrop[k]) ||
(mLayerCache.displayFrame[k].left !=
list->hwLayers[k].displayFrame.left) ||
(mLayerCache.displayFrame[k].top !=
@@ -161,7 +163,7 @@
int updatingLayerCount = 0;
for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
//swap rect will kick in only for single updating layer
- if(isLayerChanging(list, k)) {
+ if(isLayerChanging(ctx, list, k)) {
updatingLayerCount ++;
if(updatingLayerCount == 1)
changingLayerIndex = k;
@@ -181,7 +183,8 @@
for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--) {
//disable swap rect in case of scaling and video .
private_handle_t *hnd =(private_handle_t *)list->hwLayers[k].handle;
- if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd))) {
+ if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd)) ||
+ (list->hwLayers[k].transform & HAL_TRANSFORM_ROT_90)) {
mFbCache.reset();
return -1;
}
@@ -352,10 +355,18 @@
dx = (float)dst_w/(float)src_w;
dy = (float)dst_h/(float)src_h;
- if (dx > MAX_SCALE_FACTOR || dx < MIN_SCALE_FACTOR)
+ float scale_factor_max = MAX_SCALE_FACTOR;
+ float scale_factor_min = MIN_SCALE_FACTOR;
+
+ if (isAlphaPresent(layer)) {
+ scale_factor_max = MAX_SCALE_FACTOR/4;
+ scale_factor_min = MIN_SCALE_FACTOR*4;
+ }
+
+ if (dx > scale_factor_max || dx < scale_factor_min)
return false;
- if (dy > MAX_SCALE_FACTOR || dy < MIN_SCALE_FACTOR)
+ if (dy > scale_factor_max || dy < scale_factor_min)
return false;
}
}
@@ -808,7 +819,13 @@
ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
return -1;
}
-
+ uint32_t dynamic_fps = 0;
+#ifdef DYNAMIC_FPS
+ MetaData_t *mdata = hnd ? (MetaData_t *)hnd->base_metadata : NULL;
+ if (mdata && (mdata->operation & UPDATE_REFRESH_RATE)) {
+ dynamic_fps = roundOff(mdata->refreshrate);
+ }
+#endif
// Set the copybit source:
copybit_image_t src;
src.w = getWidth(hnd);
@@ -1023,6 +1040,7 @@
layerTransform);
//TODO: once, we are able to read layer alpha, update this
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+ copybit->set_parameter(copybit, COPYBIT_DYNAMIC_FPS, dynamic_fps);
copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
layer->blending);
copybit->set_parameter(copybit, COPYBIT_DITHER,
@@ -1233,6 +1251,7 @@
for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
hnd[i] = list->hwLayers[i].handle;
displayFrame[i] = list->hwLayers[i].displayFrame;
+ drop[i] = ctx->copybitDrop[i];
}
}
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 6ead4a7..4442afc 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -61,6 +61,7 @@
int layerCount;
buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS];
+ bool drop[MAX_NUM_APP_LAYERS];
/* c'tor */
LayerCache();
/* clear caching info*/
@@ -135,7 +136,8 @@
int dpy);
int checkDirtyRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
- bool isLayerChanging(hwc_display_contents_1_t *list, int k);
+ bool isLayerChanging(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int k);
};
}; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 8660740..692ce29 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -25,6 +25,7 @@
#include <overlayRotator.h>
#include "hwc_fbupdate.h"
#include "mdp_version.h"
+#include <video/msm_hdmi_modes.h>
using namespace qdutils;
using namespace overlay;
@@ -48,11 +49,9 @@
unsigned int size = 0;
uint32_t xres = ctx->dpyAttr[mDpy].xres;
uint32_t yres = ctx->dpyAttr[mDpy].yres;
- if (ctx->dpyAttr[dpy].customFBSize) {
- //GPU will render and compose at new resolution
- //So need to have FB at new resolution
- xres = ctx->dpyAttr[mDpy].xres_new;
- yres = ctx->dpyAttr[mDpy].yres_new;
+ if (ctx->dpyAttr[dpy].fbScaling) {
+ xres = ctx->dpyAttr[mDpy].xresFB;
+ yres = ctx->dpyAttr[mDpy].yresFB;
}
getBufferAttributes((int)xres, (int)yres,
HAL_PIXEL_FORMAT_RGBA_8888,
@@ -167,7 +166,7 @@
// No FB update optimization on (1) Custom FB resolution,
// (2) External Mirror mode, (3) External orientation
- if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+ if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
&& !ctx->mExtOrientation) {
sourceCrop = fbUpdatingRect;
displayFrame = fbUpdatingRect;
@@ -190,7 +189,7 @@
} else if((mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
- !ctx->dpyAttr[mDpy].customFBSize) {
+ !ctx->dpyAttr[mDpy].fbScaling) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
@@ -299,7 +298,7 @@
// No FB update optimization on (1) Custom FB resolution,
// (2) External Mirror mode, (3) External orientation
- if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+ if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
&& !ctx->mExtOrientation) {
sourceCrop = fbUpdatingRect;
displayFrame = fbUpdatingRect;
@@ -318,7 +317,7 @@
} else if((mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
if(!qdutils::MDPVersion::getInstance().is8x26() &&
- !ctx->dpyAttr[mDpy].customFBSize) {
+ !ctx->dpyAttr[mDpy].fbScaling) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
@@ -465,7 +464,7 @@
// No FB update optimization on (1) Custom FB resolution,
// (2) External Mirror mode, (3) External orientation
- if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+ if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
&& !ctx->mExtOrientation) {
sourceCrop = fbUpdatingRect;
displayFrame = fbUpdatingRect;
@@ -486,7 +485,7 @@
} else if((mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
if(!qdutils::MDPVersion::getInstance().is8x26() &&
- !ctx->dpyAttr[mDpy].customFBSize) {
+ !ctx->dpyAttr[mDpy].fbScaling) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
@@ -499,10 +498,25 @@
hwc_rect_t dstL = displayFrame;
hwc_rect_t dstR = displayFrame;
+ if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_SIDE_BY_SIDE) {
+ dstL.left = displayFrame.left/2;
+ dstL.right = displayFrame.right/2;
+
+ dstR.left = mAlignedFBWidth/2 + displayFrame.left/2;
+ dstR.right = mAlignedFBWidth/2 + displayFrame.right/2;
+ } else if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_TOP_AND_BOTTOM) {
+ dstL.top = displayFrame.top/2;
+ dstL.bottom = displayFrame.bottom/2;
+
+ dstR.top = mAlignedFBHeight/2 + displayFrame.top/2;
+ dstR.bottom = mAlignedFBHeight/2 + displayFrame.bottom/2;
+ }
+
//Request left pipe (or 1 by default)
Overlay::PipeSpecs pipeSpecs;
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
- pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+ pipeSpecs.needsScaling = (qhwc::needsScaling(layer) ||
+ needs3DComposition(ctx,mDpy));
pipeSpecs.dpy = mDpy;
pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
pipeSpecs.fb = true;
@@ -519,6 +533,7 @@
a) FB's width is > Mixer width or
b) On primary, driver has indicated with caps to split always. This is
based on an empirically derived value of panel height.
+ c) The composition is 3D
*/
const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
@@ -533,7 +548,8 @@
if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
(primarySplitAlways and
- (cropWidth > lSplit or layerClock > mixerClock))) {
+ (cropWidth > lSplit or layerClock > mixerClock)) or
+ needs3DComposition(ctx, mDpy)) {
destR = ov.getPipe(pipeSpecs);
if(destR == ovutils::OV_INVALID) {
ALOGE("%s: No pipes available to configure fb for dpy %d's right"
@@ -546,10 +562,12 @@
}
//Split crop equally when using 2 pipes
- cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
- cropR.left = cropL.right;
- dstL.right = (displayFrame.right + displayFrame.left) / 2;
- dstR.left = dstL.right;
+ if(!needs3DComposition(ctx, mDpy)) {
+ cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
+ cropR.left = cropL.right;
+ dstL.right = (displayFrame.right + displayFrame.left) / 2;
+ dstR.left = dstL.right;
+ }
}
mDestLeft = destL;
@@ -563,6 +581,12 @@
}
}
+ // XXX: Figure out why we need this with source split
+ // Currently, the driver silently fails to configure the right pipe
+ // if we don't increment the zorder
+ if (needs3DComposition(ctx, mDpy))
+ parg.zorder = eZorder(parg.zorder + 1);
+
//configure right pipe
if(destR != OV_INVALID) {
if(configMdp(ctx->mOverlay, parg, orient,
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index caa1344..b130193 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -217,9 +217,6 @@
mCurrentFrame.reset(numLayers);
ctx->mOverlay->clear(mDpy);
ctx->mLayerRotMap[mDpy]->clear();
- resetROI(ctx, mDpy);
- memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
- mCurrentFrame.dropCount = 0;
}
void MDPComp::reset() {
@@ -806,6 +803,10 @@
return false;
}
+ // No MDP composition for 3D
+ if(needs3DComposition(ctx, mDpy))
+ return false;
+
// check for action safe flag and MDP scaling mode which requires scaling.
if(ctx->dpyAttr[mDpy].mActionSafePresent
|| ctx->dpyAttr[mDpy].mMDPScalingMode) {
@@ -1340,7 +1341,7 @@
if(mCurrentFrame.fbCount)
mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
- if(sEnableYUVsplit){
+ if(sEnableYUVsplit || needs3DComposition(ctx, mDpy)){
adjustForSourceSplit(ctx, list);
}
@@ -1370,6 +1371,10 @@
return false;
}
+ // No MDP composition for 3D
+ if(needs3DComposition(ctx,mDpy))
+ return false;
+
const bool secureOnly = true;
return mdpOnlyLayersComp(ctx, list, not secureOnly) or
mdpOnlyLayersComp(ctx, list, secureOnly);
@@ -1831,6 +1836,9 @@
}
continue;
}
+ if(needs3DComposition(ctx,mDpy) && get3DFormat(hnd) != HAL_NO_3D) {
+ mdpNextZOrder++;
+ }
if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
layer %d",__FUNCTION__, index);
@@ -2083,7 +2091,7 @@
return ret;
}
-bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index) {
+bool MDPComp::allocSplitVGPipes(hwc_context_t *ctx, int index) {
bool bRet = true;
int mdpIndex = mCurrentFrame.layerToMDP[index];
@@ -2186,7 +2194,7 @@
hwc_layer_1_t* layer = &list->hwLayers[index];
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
- if(allocSplitVGPipesfor4k2k(ctx, index)){
+ if(allocSplitVGPipes(ctx, index)){
continue;
}
}
@@ -2363,7 +2371,9 @@
mdpNextZOrder++;
hwc_layer_1_t* layer = &list->hwLayers[index];
private_handle_t *hnd = (private_handle_t *)layer->handle;
- if(isYUVSplitNeeded(hnd)) {
+ if(isYUVSplitNeeded(hnd) ||
+ (needs3DComposition(ctx,mDpy) &&
+ get3DFormat(hnd) != HAL_NO_3D)) {
hwc_rect_t dst = layer->displayFrame;
if((dst.left > lSplit) || (dst.right < lSplit)) {
mCurrentFrame.mdpCount += 1;
@@ -2426,11 +2436,16 @@
const int lSplit = getLeftSplit(ctx, mDpy);
if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
if((dst.left > lSplit)||(dst.right < lSplit)){
- if(allocSplitVGPipesfor4k2k(ctx, index)){
+ if(allocSplitVGPipes(ctx, index)){
continue;
}
}
}
+ //XXX: Check for forced 2D composition
+ if(needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D)
+ if(allocSplitVGPipes(ctx,index))
+ continue;
+
int mdpIndex = mCurrentFrame.layerToMDP[index];
PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
info.pipeInfo = new MdpPipeInfoSplit;
@@ -2493,7 +2508,9 @@
}
// Set the Handle timeout to true for MDP or MIXED composition.
- if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+ if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount &&
+ !(needs3DComposition(ctx, HWC_DISPLAY_PRIMARY) ||
+ needs3DComposition(ctx, HWC_DISPLAY_EXTERNAL))) {
sHandleTimeout = true;
}
@@ -2518,7 +2535,8 @@
int mdpIndex = mCurrentFrame.layerToMDP[i];
- if(isYUVSplitNeeded(hnd) && sEnableYUVsplit)
+ if((isYUVSplitNeeded(hnd) && sEnableYUVsplit) ||
+ (needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D))
{
MdpYUVPipeInfo& pipe_info =
*(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
@@ -2826,6 +2844,7 @@
int rotFlags = ROT_FLAGS_NONE;
uint32_t format = ovutils::getMdpFormat(hnd->format, hnd->flags);
Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+ eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
"dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
@@ -2841,6 +2860,12 @@
trimAgainstROI(ctx, crop, dst);
}
+ if(needs3DComposition(ctx, mDpy) &&
+ get3DFormat(hnd) != HAL_NO_3D){
+ return configure3DVideo(ctx, layer, mDpy, mdpFlags, z, lDest,
+ rDest, &PipeLayerPair.rot);
+ }
+
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
@@ -2857,7 +2882,6 @@
calcExtDisplayPosition(ctx, hnd, mDpy, crop, dst, transform, orient);
int downscale = getRotDownscale(ctx, layer);
- eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
if(lDest != OV_INVALID && rDest != OV_INVALID) {
@@ -2988,7 +3012,6 @@
return -1;
}
close(fd);
- sIsPartialUpdateActive = enable;
return 0;
}
@@ -3044,9 +3067,7 @@
int perfHint = 0x4501; // 45-display layer hint, 01-Enable
sPerfLockHandle = sPerfLockAcquire(0 /*handle*/, 0/*duration*/,
&perfHint, sizeof(perfHint)/sizeof(int));
- if(sPerfLockHandle < 0) {
- ALOGE("Perf Lock Acquire Failed");
- } else {
+ if(sPerfLockHandle > 0) {
perflockFlag = 1;
}
}
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7c46c1a..7752384 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -58,6 +58,8 @@
static void setMaxPipesPerMixer(const uint32_t value);
static int setPartialUpdatePref(hwc_context_t *ctx, bool enable);
static bool getPartialUpdatePref(hwc_context_t *ctx);
+ static void enablePartialUpdate(bool enable)
+ { sIsPartialUpdateActive = enable; };
void setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
protected:
@@ -270,7 +272,7 @@
//Enable 4kx2k yuv layer split
static bool sEnableYUVsplit;
bool mModeOn; // if prepare happened
- bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
+ bool allocSplitVGPipes(hwc_context_t *ctx, int index);
//Enable Partial Update for MDP3 targets
static bool enablePartialUpdateForMDP3;
static void *sLibPerfHint;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 09013c6..34de2e6 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -35,6 +35,8 @@
#include <hwc_virtual.h>
#include <overlay.h>
#include <display_config.h>
+#include <hdmi.h>
+#include <video/msm_hdmi_modes.h>
#define QCLIENT_DEBUG 0
@@ -119,13 +121,8 @@
Parcel* outParcel) {
int dpy = inParcel->readInt32();
outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
- if (ctx->dpyAttr[dpy].customFBSize) {
- outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
- outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
- } else {
- outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
- outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
- }
+ outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
//XXX: Need to check what to return for HDMI
@@ -311,11 +308,25 @@
}
}
-static status_t setPartialUpdatePref(hwc_context_t *ctx, uint32_t enable) {
- ALOGD("%s: enable: %d", __FUNCTION__, enable);
- if(qhwc::MDPComp::setPartialUpdatePref(ctx, (bool)enable) < 0)
- return NO_INIT;
- return NO_ERROR;
+static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) {
+ ALOGD("%s: state: %d", __FUNCTION__, state);
+ switch(state) {
+ case IQService::PREF_PARTIAL_UPDATE:
+ if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0)
+ return NO_INIT;
+ return NO_ERROR;
+ case IQService::PREF_POST_PROCESSING:
+ if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0)
+ return NO_INIT;
+ qhwc::MDPComp::enablePartialUpdate(false);
+ return NO_ERROR;
+ case IQService::ENABLE_PARTIAL_UPDATE:
+ qhwc::MDPComp::enablePartialUpdate(true);
+ return NO_ERROR;
+ default:
+ ALOGE("%s: Invalid state", __FUNCTION__);
+ return NO_ERROR;
+ };
}
static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
@@ -338,6 +349,136 @@
}
}
+static void setS3DMode(hwc_context_t* ctx, int mode) {
+ if (ctx->mHDMIDisplay) {
+ if(ctx->mHDMIDisplay->isS3DModeSupported(mode)) {
+ ALOGD("%s: Force S3D mode to %d", __FUNCTION__, mode);
+ Locker::Autolock _sl(ctx->mDrawLock);
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].s3dModeForced = true;
+ setup3DMode(ctx, HWC_DISPLAY_EXTERNAL, mode);
+ } else {
+ ALOGD("%s: mode %d is not supported", __FUNCTION__, mode);
+ }
+ } else {
+ ALOGE("%s: No HDMI Display detected", __FUNCTION__);
+ }
+}
+
+static status_t setActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
+ Parcel *outParcel) {
+ uint32_t index = inParcel->readInt32();
+ int dpy = inParcel->readInt32();
+ //Currently only primary supported
+ if(dpy > HWC_DISPLAY_PRIMARY) {
+ return BAD_VALUE;
+ }
+
+ Configs *configs = Configs::getInstance();
+ if(configs == NULL) {
+ ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if(configs->getActiveConfig() == index) {
+ ALOGI("%s(): Config %u is already set", __FUNCTION__, index);
+ return ALREADY_EXISTS;
+ }
+
+ ctx->mDrawLock.lock();
+ //Updates the necessary sysfs nodes and reads split info again which is
+ //needed to reinitialize composition resources.
+ if(configs->setActiveConfig(index) == false) {
+ ALOGE("%s(): Failed to set config %u", __FUNCTION__, index);
+ ctx->mDrawLock.unlock();
+ return UNKNOWN_ERROR;
+ }
+
+ qdutils::DisplayAttributes attr = configs->getAttributes(index);
+
+ ctx->dpyAttr[dpy].xres = attr.xres;
+ ctx->dpyAttr[dpy].yres = attr.yres;
+
+ ctx->dpyAttr[dpy].fbScaling = ((ctx->dpyAttr[dpy].xres !=
+ ctx->dpyAttr[dpy].xresFB) || (ctx->dpyAttr[dpy].yres !=
+ ctx->dpyAttr[dpy].yresFB));
+
+ destroyCompositionResources(ctx, dpy);
+ initCompositionResources(ctx, dpy);
+ ctx->dpyAttr[dpy].configSwitched = true;
+ ctx->mDrawLock.unlock();
+ ctx->proc->invalidate(ctx->proc);
+ return NO_ERROR;
+}
+
+static status_t getActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
+ Parcel *outParcel) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ int dpy = inParcel->readInt32();
+ //Currently only primary supported
+ if(dpy > HWC_DISPLAY_PRIMARY) {
+ return BAD_VALUE;
+ }
+
+ Configs *configs = Configs::getInstance();
+ if(configs == NULL) {
+ ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ outParcel->writeInt32(configs->getActiveConfig());
+ return NO_ERROR;
+}
+
+static status_t getConfigCount(hwc_context_t* ctx, const Parcel *inParcel,
+ Parcel *outParcel) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ int dpy = inParcel->readInt32();
+ //Currently only primary supported
+ if(dpy > HWC_DISPLAY_PRIMARY) {
+ return BAD_VALUE;
+ }
+
+ Configs *configs = Configs::getInstance();
+ if(configs == NULL) {
+ ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ outParcel->writeInt32(configs->getConfigCount());
+ return NO_ERROR;
+}
+
+static status_t getDisplayAttributesForConfig(hwc_context_t* ctx,
+ const Parcel *inParcel, Parcel *outParcel) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ uint32_t index = inParcel->readInt32();
+ int dpy = inParcel->readInt32();
+ //Currently only primary supported
+ if(dpy > HWC_DISPLAY_PRIMARY) {
+ return BAD_VALUE;
+ }
+
+ Configs *configs = Configs::getInstance();
+ if(configs == NULL) {
+ ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ //xres, yres are used from the Config class, we assume for now that the
+ //other params are the same. This might change in the future.
+ outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
+
+ qdutils::DisplayAttributes attr = configs->getAttributes(index);
+ outParcel->writeInt32(attr.xres);
+ outParcel->writeInt32(attr.yres);
+
+ outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
+ outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
+ outParcel->writeInt32(ctx->mMDP.panel);
+
+ return NO_ERROR;
+}
+
status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
@@ -387,7 +528,7 @@
setMaxPipesPerMixer(mHwcContext, inParcel);
break;
case IQService::SET_PARTIAL_UPDATE:
- ret = setPartialUpdatePref(mHwcContext, inParcel->readInt32());
+ ret = setPartialUpdateState(mHwcContext, inParcel->readInt32());
break;
case IQService::TOGGLE_BWC:
toggleBWC(mHwcContext, inParcel);
@@ -398,6 +539,22 @@
case IQService::TOGGLE_SCREEN_UPDATE:
toggleScreenUpdate(mHwcContext, inParcel->readInt32());
break;
+ case IQService::SET_S3D_MODE:
+ setS3DMode(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::SET_ACTIVE_CONFIG:
+ ret = setActiveConfig(mHwcContext, inParcel, outParcel);
+ break;
+ case IQService::GET_ACTIVE_CONFIG:
+ ret = getActiveConfig(mHwcContext, inParcel, outParcel);
+ break;
+ case IQService::GET_CONFIG_COUNT:
+ ret = getConfigCount(mHwcContext, inParcel, outParcel);
+ break;
+ case IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
+ ret = getDisplayAttributesForConfig(mHwcContext, inParcel,
+ outParcel);
+ break;
default:
ret = NO_ERROR;
}
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index c6179e4..b387642 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -125,10 +125,13 @@
ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
}
+ // Report Hotplug via CEC HAL
+ ctx->mQService->onHdmiHotplug((int)ctx->dpyAttr[dpy].connected);
+
//On 8994, 8992 due to hardware limitations, we disable bwc
//when HDMI intf is active
if((qdutils::MDPVersion::getInstance().is8994() or
- qdutils::MDPVersion::getInstance().is8092()) and
+ qdutils::MDPVersion::getInstance().is8992()) and
qdutils::MDPVersion::getInstance().supportsBWC()) {
Locker::Autolock _l(ctx->mDrawLock);
ctx->mBWCEnabled = true;
@@ -148,7 +151,7 @@
//On 8994, 8992 due to hardware limitations, we disable bwc
//when HDMI intf is active
if((qdutils::MDPVersion::getInstance().is8994() or
- qdutils::MDPVersion::getInstance().is8092()) and
+ qdutils::MDPVersion::getInstance().is8992()) and
qdutils::MDPVersion::getInstance().supportsBWC()) {
Locker::Autolock _l(ctx->mDrawLock);
ctx->mBWCEnabled = false;
@@ -158,7 +161,7 @@
ctx->mDrawLock.lock();
handle_online(ctx, dpy);
ctx->mDrawLock.unlock();
-
+ ctx->mQService->onHdmiHotplug(ctx->dpyAttr[dpy].connected);
ctx->proc->invalidate(ctx->proc);
break;
} else {
@@ -199,7 +202,15 @@
"uevent thread", __FUNCTION__);
ctx->mWfdSyncLock.unlock();
}
- ctx->mHDMIDisplay->configure();
+ // If FB open fails ignore this hotplug event
+ int error = ctx->mHDMIDisplay->configure();
+ if (error < 0) {
+ ALOGE("%s: Open Framebuffer for dpy = %d", __FUNCTION__, dpy);
+ ctx->mDrawLock.lock();
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ ctx->mDrawLock.unlock();
+ break;
+ }
ctx->mHDMIDisplay->activateDisplay();
ctx->mDrawLock.lock();
@@ -213,6 +224,7 @@
/* External display is HDMI */
ALOGI("%s: Sending EXTERNAL ONLINE event", __FUNCTION__);
ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_ONLINE);
+ ctx->mQService->onHdmiHotplug(ctx->dpyAttr[dpy].connected);
break;
}
default:
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 75b365d..2d4363e 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -45,6 +45,7 @@
#include "qd_utils.h"
#include <sys/sysinfo.h>
#include <dlfcn.h>
+#include <video/msm_hdmi_modes.h>
using namespace qClient;
using namespace qService;
@@ -75,7 +76,7 @@
#endif
#endif
-#define PROP_DEFAULT_APPBUFFER "sf.default.app_buffer_count"
+#define PROP_DEFAULT_APPBUFFER "hw.sf.app_buff_count"
#define MAX_RAM_SIZE 512*1024*1024
#define qHD_WIDTH 540
@@ -92,33 +93,38 @@
(xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
}
-void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig,
- int width, int height) {
+static void handleFbScaling(hwc_context_t *ctx, int xresPanel, int yresPanel,
+ int width, int height) {
+ const int dpy = HWC_DISPLAY_PRIMARY;
//Store original display resolution.
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false;
+ ctx->dpyAttr[dpy].xresFB = xresPanel;
+ ctx->dpyAttr[dpy].yresFB = yresPanel;
+ ctx->dpyAttr[dpy].fbScaling = false;
char property[PROPERTY_VALUE_MAX] = {'\0'};
char *yptr = NULL;
if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
yptr = strcasestr(property,"x");
if(yptr) {
- int xres_new = atoi(property);
- int yres_new = atoi(yptr + 1);
- if (isValidResolution(ctx,xres_new,yres_new) &&
- xres_new != xres_orig && yres_new != yres_orig) {
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_new;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_new;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+ int xresFB = atoi(property);
+ int yresFB = atoi(yptr + 1);
+ if (isValidResolution(ctx, xresFB, yresFB) &&
+ xresFB != xresPanel && yresFB != yresPanel) {
+ ctx->dpyAttr[dpy].xresFB = xresFB;
+ ctx->dpyAttr[dpy].yresFB = yresFB;
+ ctx->dpyAttr[dpy].fbScaling = true;
- //Caluculate DPI according to changed resolution.
- float xdpi = ((float)xres_new * 25.4f) / (float)width;
- float ydpi = ((float)yres_new * 25.4f) / (float)height;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi;
- ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
+ //Calculate DPI according to changed resolution.
+ float xdpi = ((float)xresFB * 25.4f) / (float)width;
+ float ydpi = ((float)yresFB * 25.4f) / (float)height;
+ ctx->dpyAttr[dpy].xdpi = xdpi;
+ ctx->dpyAttr[dpy].ydpi = ydpi;
}
}
}
+ ctx->dpyAttr[dpy].fbWidthScaleRatio = (float) ctx->dpyAttr[dpy].xres /
+ (float) ctx->dpyAttr[dpy].xresFB;
+ ctx->dpyAttr[dpy].fbHeightScaleRatio = (float) ctx->dpyAttr[dpy].yres /
+ (float) ctx->dpyAttr[dpy].yresFB;
}
// Initialize hdmi display attributes based on
@@ -233,8 +239,7 @@
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period =
(uint32_t)(1000000000l / fps);
- //To change resolution of primary display
- changeResolution(ctx, info.xres, info.yres, info.width, info.height);
+ handleFbScaling(ctx, info.xres, info.yres, info.width, info.height);
//Unblank primary on first boot
if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
@@ -265,8 +270,26 @@
}
}
-void initContext(hwc_context_t *ctx)
+int initContext(hwc_context_t *ctx)
{
+ int error = -1;
+ int compositionType = 0;
+
+ //Right now hwc starts the service but anybody could do it, or it could be
+ //independent process as well.
+ QService::init();
+ sp<IQClient> client = new QClient(ctx);
+ sp<IQService> iqs = interface_cast<IQService>(
+ defaultServiceManager()->getService(
+ String16("display.qservice")));
+ if (iqs.get()) {
+ iqs->connect(client);
+ ctx->mQService = reinterpret_cast<QService* >(iqs.get());
+ } else {
+ ALOGE("%s: Failed to acquire service pointer", __FUNCTION__);
+ return error;
+ }
+
overlay::Overlay::initOverlay();
ctx->mHDMIDisplay = new HDMIDisplay();
uint32_t priW = 0, priH = 0;
@@ -279,15 +302,24 @@
if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
int connected = ctx->mHDMIDisplay->getConnectedState();
if(connected == 1) {
- ctx->mHDMIDisplay->configure();
+ error = ctx->mHDMIDisplay->configure();
+ if (error < 0) {
+ goto OpenFBError;
+ }
updateDisplayInfo(ctx, HWC_DISPLAY_PRIMARY);
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
} else {
- openFramebufferDevice(ctx);
+ error = openFramebufferDevice(ctx);
+ if(error < 0) {
+ goto OpenFBError;
+ }
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = false;
}
} else {
- openFramebufferDevice(ctx);
+ error = openFramebufferDevice(ctx);
+ if(error < 0) {
+ goto OpenFBError;
+ }
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
// Send the primary resolution to the hdmi display class
// to be used for MDP scaling functionality
@@ -313,8 +345,8 @@
// Check if the target supports copybit compostion (dyn/mdp) to
// decide if we need to open the copybit module.
- int compositionType =
- qdutils::QCCompositionType::getInstance().getCompositionType();
+ compositionType =
+ qdutils::QCCompositionType::getInstance().getCompositionType();
// Only MDP copybit is used
if ((compositionType & (qdutils::COMPOSITION_TYPE_DYN |
@@ -351,8 +383,14 @@
ctx->dpyAttr[i].mActionSafePresent = false;
ctx->dpyAttr[i].mAsWidthRatio = 0;
ctx->dpyAttr[i].mAsHeightRatio = 0;
+ ctx->dpyAttr[i].s3dMode = HDMI_S3D_NONE;
+ ctx->dpyAttr[i].s3dModeForced = false;
}
+ //Make sure that the 3D mode is unset at bootup
+ //This makes sure that the state is accurate on framework reboots
+ ctx->mHDMIDisplay->configure3D(HDMI_S3D_NONE);
+
for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
ctx->mPrevHwLayerCount[i] = 0;
}
@@ -365,20 +403,6 @@
ctx->mExtOrientation = 0;
ctx->numActiveDisplays = 1;
- //Right now hwc starts the service but anybody could do it, or it could be
- //independent process as well.
- QService::init();
- sp<IQClient> client = new QClient(ctx);
- android::sp<qService::IQService> qservice_sp = interface_cast<IQService>(
- defaultServiceManager()->getService(
- String16("display.qservice")));
- if (qservice_sp.get()) {
- qservice_sp->connect(client);
- } else {
- ALOGE("%s: Failed to acquire service pointer", __FUNCTION__);
- return ;
- }
-
// Initialize device orientation to its default orientation
ctx->deviceOrientation = 0;
ctx->mBufferMirrorMode = false;
@@ -420,6 +444,13 @@
ctx->mHPDEnabled = false;
ALOGI("Initializing Qualcomm Hardware Composer");
ALOGI("MDP version: %d", ctx->mMDP.version);
+
+ return 0;
+
+OpenFBError:
+ ALOGE("%s: Fatal Error: FB Open failed!!!", __FUNCTION__);
+ delete ctx->mHDMIDisplay;
+ return error;
}
void closeContext(hwc_context_t *ctx)
@@ -472,7 +503,10 @@
ctx->mAD = NULL;
}
-
+ if(ctx->mQService) {
+ delete ctx->mQService;
+ ctx->mQService = NULL;
+ }
}
//Helper to roundoff the refreshrates
@@ -1008,6 +1042,8 @@
ctx->listStats[dpy].refreshRateRequest = ctx->dpyAttr[dpy].refreshRate;
uint32_t refreshRate = 0;
qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+ int s3dFormat = HAL_NO_3D;
+ int s3dLayerCount = 0;
ctx->listStats[dpy].mAIVVideoMode = false;
resetROI(ctx, dpy);
@@ -1063,6 +1099,14 @@
ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = (int)i;
yuv4k2kCount++;
}
+
+ // Gets set if one YUV layer is 3D
+ if (displaySupports3D(ctx,dpy)) {
+ s3dFormat = get3DFormat(hnd);
+ if(s3dFormat != HAL_NO_3D)
+ s3dLayerCount++;
+ }
+
}
if(layer->blending == HWC_BLENDING_PREMULT)
ctx->listStats[dpy].preMultipliedAlpha = true;
@@ -1089,6 +1133,17 @@
}
#endif
}
+
+ //Set the TV's 3D mode based on format if it was not forced
+ //Only one 3D YUV layer is supported on external
+ //If there is more than one 3D YUV layer, the switch to 3D cannot occur.
+ if( !ctx->dpyAttr[dpy].s3dModeForced && (s3dLayerCount <= 1)) {
+ //XXX: Rapidly going in and out of 3D mode in some cases such
+ // as rotation might cause flickers. The OEMs are recommended to disable
+ // rotation on HDMI globally or in the app that plays 3D video
+ setup3DMode(ctx, dpy, convertS3DFormatToMode(s3dFormat));
+ }
+
if(ctx->listStats[dpy].yuvCount > 0) {
if (property_get("hw.cabl.yuv", property, NULL) > 0) {
if (atoi(property) != 1) {
@@ -2197,6 +2252,113 @@
return 0;
}
+int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+ const eDest& lDest, const eDest& rDest,
+ Rotator **rot) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s: layer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+ //Both pipes are configured to the same mixer
+ eZorder lz = z;
+ eZorder rz = (eZorder)(z + 1);
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ int rotFlags = ROT_FLAGS_NONE;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, hnd->flags);
+ Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
+
+ int downscale = getRotDownscale(ctx, layer);
+ setMdpFlags(ctx, layer, mdpFlagsL, downscale, transform);
+
+ //XXX: Check if rotation is supported and valid for 3D
+ if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
+ (*rot) = ctx->mRotMgr->getNext();
+ if((*rot) == NULL) return -1;
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ return -1;
+ }
+ updateSource(orient, whf, crop, *rot);
+ rotFlags |= ROT_PREROTATED;
+ }
+
+ eMdpFlags mdpFlagsR = mdpFlagsL;
+
+ hwc_rect_t cropL = crop, dstL = dst;
+ hwc_rect_t cropR = crop, dstR = dst;
+ int hw_w = ctx->dpyAttr[dpy].xres;
+ int hw_h = ctx->dpyAttr[dpy].yres;
+
+ if(get3DFormat(hnd) == HAL_3D_SIDE_BY_SIDE_L_R ||
+ get3DFormat(hnd) == HAL_3D_SIDE_BY_SIDE_R_L) {
+ // Calculate Left rects
+ // XXX: This assumes crop.right/2 is the center point of the video
+ cropL.right = crop.right/2;
+ dstL.left = dst.left/2;
+ dstL.right = dst.right/2;
+
+ // Calculate Right rects
+ cropR.left = crop.right/2;
+ dstR.left = hw_w/2 + dst.left/2;
+ dstR.right = hw_w/2 + dst.right/2;
+ } else if(get3DFormat(hnd) == HAL_3D_TOP_BOTTOM) {
+ // Calculate Left rects
+ cropL.bottom = crop.bottom/2;
+ dstL.top = dst.top/2;
+ dstL.bottom = dst.bottom/2;
+
+ // Calculate Right rects
+ cropR.top = crop.bottom/2;
+ dstR.top = hw_h/2 + dst.top/2;
+ dstR.bottom = hw_h/2 + dst.bottom/2;
+ } else {
+ ALOGE("%s: Unsupported 3D mode ", __FUNCTION__);
+ return -1;
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+
+ //configure left pipe
+ if(lDest != OV_INVALID) {
+ PipeArgs pargL(mdpFlagsL, whf, lz,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, pargL, orient,
+ cropL, dstL, metadata, lDest) < 0) {
+ ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ //configure right pipe
+ if(rDest != OV_INVALID) {
+ PipeArgs pargR(mdpFlagsR, whf, rz,
+ static_cast<eRotFlags>(rotFlags),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+ if(configMdp(ctx->mOverlay, pargR, orient,
+ cropR, dstR, metadata, rDest) < 0) {
+ ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
const eDest& lDest, const eDest& rDest,
@@ -2634,7 +2796,13 @@
void resetROI(hwc_context_t *ctx, const int dpy) {
const int fbXRes = (int)ctx->dpyAttr[dpy].xres;
const int fbYRes = (int)ctx->dpyAttr[dpy].yres;
- if(isDisplaySplit(ctx, dpy)) {
+
+ /* When source split is enabled, both the panels are calibrated
+ * in a single coordinate system. So only one ROI is generated
+ * for the whole panel extending equally from the midpoint and
+ * populated for the left side. */
+ if(!qdutils::MDPVersion::getInstance().isSrcSplit() &&
+ isDisplaySplit(ctx, dpy)) {
const int lSplit = getLeftSplit(ctx, dpy);
ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0, lSplit, fbYRes};
ctx->listStats[dpy].rRoi = (struct hwc_rect){lSplit, 0, fbXRes, fbYRes};
@@ -2787,7 +2955,11 @@
// TODO: If HDMI is connected after the display has booted up,
// and the best configuration is different from the default
// then we need to deal with this appropriately.
- ctx->mHDMIDisplay->configure();
+ int error = ctx->mHDMIDisplay->configure();
+ if (error < 0) {
+ ALOGE("Error opening FrameBuffer");
+ return;
+ }
updateDisplayInfo(ctx, dpy);
initCompositionResources(ctx, dpy);
ctx->dpyAttr[dpy].connected = true;
@@ -2810,4 +2982,41 @@
ctx->dpyAttr[dpy].isActive = false;
}
+int convertS3DFormatToMode(int s3DFormat) {
+ int ret;
+ switch(s3DFormat) {
+ case HAL_3D_SIDE_BY_SIDE_L_R:
+ case HAL_3D_SIDE_BY_SIDE_R_L:
+ ret = HDMI_S3D_SIDE_BY_SIDE;
+ break;
+ case HAL_3D_TOP_BOTTOM:
+ ret = HDMI_S3D_TOP_AND_BOTTOM;
+ break;
+ default:
+ ret = HDMI_S3D_NONE;
+ }
+ return ret;
+}
+
+bool needs3DComposition(hwc_context_t* ctx, int dpy) {
+ return (displaySupports3D(ctx, dpy) && ctx->dpyAttr[dpy].connected &&
+ ctx->dpyAttr[dpy].s3dMode != HDMI_S3D_NONE);
+}
+
+void setup3DMode(hwc_context_t *ctx, int dpy, int s3dMode) {
+ if (ctx->dpyAttr[dpy].s3dMode != s3dMode) {
+ ALOGD("%s: setup 3D mode: %d", __FUNCTION__, s3dMode);
+ if(ctx->mHDMIDisplay->configure3D(s3dMode)) {
+ ctx->dpyAttr[dpy].s3dMode = s3dMode;
+ }
+ }
+}
+
+bool displaySupports3D(hwc_context_t* ctx, int dpy) {
+ return ((dpy == HWC_DISPLAY_EXTERNAL) ||
+ ((dpy == HWC_DISPLAY_PRIMARY) &&
+ ctx->mHDMIDisplay->isHDMIPrimaryDisplay()));
+}
+
+
};//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index a97c59b..26d036f 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -35,6 +35,7 @@
#include <overlayUtils.h>
#include <overlayRotator.h>
#include <EGL/egl.h>
+#include <QService.h>
#define ALIGN_TO(x, align) (((x) + ((align)-1)) & ~((align)-1))
@@ -111,12 +112,30 @@
int mAsWidthRatio;
int mAsHeightRatio;
+ // This is the 3D mode to which the TV is set
+ // The mode may be set via the appearance of a layer with 3D format
+ // or by forcing the mode via binder.
+ // If the mode is set via binder, the s3dModeForced flag is set, so that the
+ // mode is not changed back when the 3D video layer drops out.
+ // If the forced mode is different from the one in 3D video, the results
+ // are unpredictable. The assumption is made here that the caller forcing
+ // the mode via binder knows the right formats to use.
+ // The s3dModeForced flag is also used to force 2D if the s3dMode is
+ // HDMI_S3D_NONE
+ int s3dMode;
+ bool s3dModeForced;
//If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
//following fields are used.
- bool customFBSize;
- uint32_t xres_new;
- uint32_t yres_new;
-
+ //Also used when the actual panel's dimensions change and FB remains
+ //constant
+ bool fbScaling;
+ uint32_t xresFB; //FB's width, by default from VSCREEN overridden by prop
+ uint32_t yresFB; //FB's height, by default from VSCREEN overridden by prop
+ float fbWidthScaleRatio; // Panel Width / FB Width
+ float fbHeightScaleRatio; // Panel Height / FB Height
+ //If configuration changed dynamically without subsequent GEOMETRY changes
+ //we may still need to adjust destination params
+ bool configSwitched;
};
struct ListStats {
@@ -267,7 +286,7 @@
void dumpLayer(hwc_layer_1_t const* l);
void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
-void initContext(hwc_context_t *ctx);
+int initContext(hwc_context_t *ctx);
void closeContext(hwc_context_t *ctx);
//Crops source buffer against destination and FB boundaries
void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
@@ -411,6 +430,15 @@
const ovutils::eDest& lDest,
const ovutils::eDest& rDest, overlay::Rotator **rot);
+//Check if the current round needs 3D composition
+bool needs3DComposition(hwc_context_t* ctx, int dpy);
+
+//Routine to configure 3D video
+int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ const ovutils::eDest& lDest,
+ const ovutils::eDest& rDest, overlay::Rotator **rot);
+
//Routine to split and configure high resolution YUV layer (> 2048 width)
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
const int& dpy,
@@ -444,6 +472,16 @@
// Checks if boot animation has completed and applies default mode
void processBootAnimCompleted(hwc_context_t *ctx);
+//The gralloc API and driver have different formats
+//The format needs to be converted before passing to libhdmi
+int convertS3DFormatToMode(int s3DFormat);
+
+//Configure resources for 3D mode
+void setup3DMode(hwc_context_t* ctx, int dpy, int s3dMode);
+
+//Checks if this display supports 3D
+bool displaySupports3D(hwc_context_t* ctx, int dpy);
+
// Inline utility functions
static inline bool isSkipLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
@@ -489,6 +527,14 @@
return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY));
}
+static inline uint32_t get3DFormat(const private_handle_t* hnd) {
+ MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+ if(isYuvBuffer(hnd) && metadata && metadata->operation & S3D_FORMAT) {
+ return metadata->s3dFormat;
+ }
+ return HAL_NO_3D;
+}
+
static inline int getWidth(const private_handle_t* hnd) {
MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
@@ -644,10 +690,12 @@
bool mBWCEnabled;
// Provides a way for OEM's to disable setting dynfps via metadata.
bool mUseMetaDataRefreshRate;
- // Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
+ // Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
bool mHPDEnabled;
//Used to notify that boot has completed
bool mBootAnimCompleted;
+ // Display binder service
+ qService::QService* mQService;
};
namespace qhwc {
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index 89f8044..1a7a836 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -33,6 +33,7 @@
#include "overlay.h"
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
+#define DEBUG 0
using namespace qdutils;
namespace qhwc {
@@ -56,7 +57,8 @@
return ret;
}
-static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data)
+static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data,
+ ssize_t len __unused)
{
// extract timestamp
uint64_t timestamp = 0;
@@ -69,7 +71,8 @@
ctx->proc->vsync(ctx->proc, dpy, timestamp);
}
-static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data)
+static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data,
+ ssize_t len __unused)
{
if (!strncmp(data, PANEL_ON_STR, strlen(PANEL_ON_STR))) {
unsigned long int poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0);
@@ -80,7 +83,8 @@
}
}
-static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data)
+static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data,
+ ssize_t len __unused)
{
// extract thermal level
uint64_t thermalLevel = 0;
@@ -95,15 +99,24 @@
ctx->mThermalBurstMode = false;
}
+static void handle_cec_event(hwc_context_t* ctx, int dpy, char *data,
+ ssize_t len)
+{
+ ALOGD_IF(DEBUG, "%s: Got CEC event from driver dpy:%d",
+ __FUNCTION__, dpy);
+ ctx->mQService->onCECMessageReceived(data, len);
+}
+
struct event {
const char* name;
- void (*callback)(hwc_context_t* ctx, int dpy, char *data);
+ void (*callback)(hwc_context_t* ctx, int dpy, char *data, ssize_t len);
};
struct event event_list[] = {
{ "vsync_event", handle_vsync_event },
{ "show_blank_event", handle_blank_event },
{ "msm_fb_thermal_level", handle_thermal_event },
+ { "cec/rd_msg", handle_cec_event },
};
#define num_events ARRAY_LENGTH(event_list)
@@ -185,7 +198,7 @@
continue;
}
vdata[len] = '\0';
- event_list[ev].callback(ctx, dpy, vdata);
+ event_list[ev].callback(ctx, dpy, vdata, len);
}
}
}
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index a34e599..b7c7fcc 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -151,6 +151,8 @@
return getPipe_8x39(pipeSpecs);
} else if(MDPVersion::getInstance().is8994()) {
return getPipe_8994(pipeSpecs);
+ } else if(MDPVersion::getInstance().is8992()) {
+ return getPipe_8992(pipeSpecs);
}
eDest dest = OV_INVALID;
@@ -251,6 +253,13 @@
//supported since we at least need 1 round in between where the DMA is
//unused
eDest dest = OV_INVALID;
+
+ // Reset format type to FORMAT_NONE to select the pipe irrespective of the
+ // format specifed by the client. This is required for the device where
+ // SMP starvation is unlikely, we need not keep track of formats
+ // programmed in the pipes to avoid potential pipe crunching.
+ resetPipeBookFormat(pipeSpecs.dpy);
+
if(pipeSpecs.formatClass == FORMAT_YUV) {
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
} else {
@@ -262,9 +271,14 @@
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
}
+
return dest;
}
+utils::eDest Overlay::getPipe_8992(const PipeSpecs& pipeSpecs) {
+ return getPipe_8994(pipeSpecs);
+}
+
void Overlay::endAllSessions() {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 45b5e57..49be930 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -178,6 +178,9 @@
utils::eDest getPipe_8x16(const PipeSpecs& pipeSpecs);
utils::eDest getPipe_8x39(const PipeSpecs& pipeSpecs);
utils::eDest getPipe_8994(const PipeSpecs& pipeSpecs);
+ utils::eDest getPipe_8992(const PipeSpecs& pipeSpecs);
+
+ void resetPipeBookFormat(const int &dpy);
/* Returns the handle to libscale.so's programScale function */
static int (*getFnProgramScale())(struct mdp_overlay_list *);
@@ -443,6 +446,14 @@
return "Invalid";
}
+inline void Overlay::resetPipeBookFormat(const int &dpy) {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if (mPipeBook[i].mDisplay == dpy) {
+ mPipeBook[i].mFormatType = FORMAT_NONE;
+ }
+ }
+}
+
}; // overlay
#endif // OVERLAY_H
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 1290f32..0c31dd3 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -353,8 +353,31 @@
mdp_overlay* ovArray[count];
memset(&ovArray, 0, sizeof(ovArray));
+ uint8_t max_horz_deci = 0, max_vert_deci = 0;
+
+ // Decimation factor for the left and right pipe differs, when there is a
+ // one pixel difference in the dst width of right pipe and the left pipe.
+ // libscalar returns a failure as it expects decimation on both the pipe
+ // to be same. So compare the decimation factor on both the pipes and assign
+ // the maximum of it.
for(int i = 0; i < count; i++) {
- ovArray[i] = &mdpCtrlArray[i]->mOVInfo;
+ mdp_overlay *ov_current = &mdpCtrlArray[i]->mOVInfo;
+ for(int j = i + 1; j < count; j++) {
+ mdp_overlay *ov_next = &mdpCtrlArray[j]->mOVInfo;
+ if(ov_current->z_order == ov_next->z_order) {
+ max_horz_deci = utils::max(ov_current->horz_deci,
+ ov_next->horz_deci);
+ max_vert_deci = utils::max(ov_current->vert_deci,
+ ov_next->vert_deci);
+
+ ov_current->horz_deci = max_horz_deci;
+ ov_next->horz_deci = max_horz_deci;
+ ov_current->vert_deci = max_vert_deci;
+ ov_next->vert_deci = max_vert_deci;
+ break;
+ }
+ }
+ ovArray[i] = ov_current;
}
struct mdp_overlay_list list;
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 03a7046..40b1ef7 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -27,14 +27,24 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <display_config.h>
#include <QServiceUtils.h>
+#include <qd_utils.h>
using namespace android;
using namespace qService;
namespace qdutils {
+//=============================================================================
+// The functions below run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
+
int isExternalConnected(void) {
int ret;
status_t err = (status_t) FAILED_TRANSACTION;
@@ -70,7 +80,7 @@
dpyattr.ydpi = outParcel.readFloat();
dpyattr.panel_type = (char) outParcel.readInt32();
} else {
- ALOGE("%s: Failed to get display attributes err=%d", __FUNCTION__, err);
+ ALOGE("%s() failed with err %d", __FUNCTION__, err);
}
return err;
}
@@ -170,6 +180,238 @@
return err;
}
+int getConfigCount(int /*dpy*/) {
+ int numConfigs = -1;
+ sp<IQService> binder = getBinder();
+ if(binder != NULL) {
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(DISPLAY_PRIMARY);
+ status_t err = binder->dispatch(IQService::GET_CONFIG_COUNT,
+ &inParcel, &outParcel);
+ if(!err) {
+ numConfigs = outParcel.readInt32();
+ ALOGI("%s() Received num configs %d", __FUNCTION__, numConfigs);
+ } else {
+ ALOGE("%s() failed with err %d", __FUNCTION__, err);
+ }
+ }
+ return numConfigs;
+}
+
+int getActiveConfig(int /*dpy*/) {
+ int configIndex = -1;
+ sp<IQService> binder = getBinder();
+ if(binder != NULL) {
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(DISPLAY_PRIMARY);
+ status_t err = binder->dispatch(IQService::GET_ACTIVE_CONFIG,
+ &inParcel, &outParcel);
+ if(!err) {
+ configIndex = outParcel.readInt32();
+ ALOGI("%s() Received active config index %d", __FUNCTION__,
+ configIndex);
+ } else {
+ ALOGE("%s() failed with err %d", __FUNCTION__, err);
+ }
+ }
+ return configIndex;
+}
+
+int setActiveConfig(int configIndex, int /*dpy*/) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ if(binder != NULL) {
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(configIndex);
+ inParcel.writeInt32(DISPLAY_PRIMARY);
+ err = binder->dispatch(IQService::SET_ACTIVE_CONFIG,
+ &inParcel, &outParcel);
+ if(!err) {
+ ALOGI("%s() Successfully set active config index %d", __FUNCTION__,
+ configIndex);
+ } else {
+ ALOGE("%s() failed with err %d", __FUNCTION__, err);
+ }
+ }
+ return err;
+}
+
+DisplayAttributes getDisplayAttributes(int configIndex, int /*dpy*/) {
+ DisplayAttributes dpyattr;
+ sp<IQService> binder = getBinder();
+ if(binder != NULL) {
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(configIndex);
+ inParcel.writeInt32(DISPLAY_PRIMARY);
+ status_t err = binder->dispatch(
+ IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG, &inParcel,
+ &outParcel);
+ if(!err) {
+ dpyattr.vsync_period = outParcel.readInt32();
+ dpyattr.xres = outParcel.readInt32();
+ dpyattr.yres = outParcel.readInt32();
+ dpyattr.xdpi = outParcel.readFloat();
+ dpyattr.ydpi = outParcel.readFloat();
+ dpyattr.panel_type = (char) outParcel.readInt32();
+ ALOGI("%s() Received attrs for index %d: xres %d, yres %d",
+ __FUNCTION__, configIndex, dpyattr.xres, dpyattr.yres);
+ } else {
+ ALOGE("%s() failed with err %d", __FUNCTION__, err);
+ }
+ }
+ return dpyattr;
+}
+
+//=============================================================================
+// The functions/methods below run in the context of HWC and
+// are called in response to binder calls from clients
+
+Configs* Configs::getInstance() {
+ if(sConfigs == NULL) {
+ sConfigs = new Configs();
+ if(sConfigs->init() == false) {
+ ALOGE("%s(): Configs initialization failed", __FUNCTION__);
+ delete sConfigs;
+ sConfigs = NULL;
+ }
+ }
+ return sConfigs;
+}
+
+Configs::Configs() : mActiveConfig(0), mConfigsSupported(0) {}
+
+bool Configs::init() {
+ DisplayAttributes dpyAttr;
+ if(not getCurrentMode(dpyAttr)) {
+ ALOGE("%s(): Mode switch is disabled", __FUNCTION__);
+ return false;
+ }
+
+ FILE *fHnd;
+ size_t len = PAGE_SIZE;
+ ssize_t read = 0;
+ uint32_t configCount = 0;
+ char sysfsPath[MAX_SYSFS_FILE_PATH];
+
+ memset(sysfsPath, '\0', sizeof(sysfsPath));
+ snprintf(sysfsPath , sizeof(sysfsPath),
+ "/sys/class/graphics/fb0/modes");
+
+ fHnd = fopen(sysfsPath, "r");
+ if (fHnd == NULL) {
+ ALOGE("%s(): Opening file %s failed with error %s", __FUNCTION__,
+ sysfsPath, strerror(errno));
+ return false;
+ }
+
+ memset(mModeStr, 0, sizeof(mModeStr));
+ while((configCount < CONFIGS_MAX) and
+ ((read = getline(&mModeStr[configCount], &len, fHnd)) > 0)) {
+ //String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in the
+ //kernel has more info on the format.
+ char *xptr = strcasestr(mModeStr[configCount], ":");
+ char *yptr = strcasestr(mModeStr[configCount], "x");
+ if(xptr && yptr) {
+ mConfigs[configCount].xres = atoi(xptr + 1);
+ mConfigs[configCount].yres = atoi(yptr + 1);
+ ALOGI("%s(): Parsed Config %s", __FUNCTION__,
+ mModeStr[configCount]);
+ ALOGI("%s(): Config %u: %u x %u", __FUNCTION__, configCount,
+ mConfigs[configCount].xres, mConfigs[configCount].yres);
+ if(mConfigs[configCount].xres == dpyAttr.xres and
+ mConfigs[configCount].yres == dpyAttr.yres) {
+ mActiveConfig = configCount;
+ }
+ } else {
+ ALOGE("%s(): Tokenizing str %s failed", __FUNCTION__,
+ mModeStr[configCount]);
+ //Free memory allocated internally by getline()
+ for(uint32_t i = 0; i <= configCount; i++) {
+ free(mModeStr[i]);
+ }
+ fclose(fHnd);
+ return false;
+ }
+ configCount++;
+ }
+
+ fclose(fHnd);
+
+ if(configCount == 0) {
+ ALOGE("%s No configs found", __FUNCTION__);
+ return false;
+ }
+ mConfigsSupported = configCount;
+ return true;
+}
+
+bool Configs::getCurrentMode(DisplayAttributes& dpyAttr) {
+ bool ret = false;
+ FILE *fHnd = fopen("/sys/class/graphics/fb0/mode", "r");
+ if(fHnd) {
+ char *buffer = NULL; //getline will allocate
+ size_t len = PAGE_SIZE;
+ if(getline(&buffer, &len, fHnd) > 0) {
+ //String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
+ //kernel has more info on the format.
+ char *xptr = strcasestr(buffer, ":");
+ char *yptr = strcasestr(buffer, "x");
+ if(xptr && yptr) {
+ dpyAttr.xres = atoi(xptr + 1);
+ dpyAttr.yres = atoi(yptr + 1);
+ ALOGI("%s(): Parsed Current Config Str %s", __FUNCTION__,
+ buffer);
+ ALOGI("%s(): Current Config: %u x %u", __FUNCTION__,
+ dpyAttr.xres, dpyAttr.yres);
+ ret = true;
+ }
+ }
+
+ if(buffer)
+ free(buffer);
+
+ fclose(fHnd);
+ }
+ return ret;
+}
+
+bool Configs::setActiveConfig(const uint32_t& index) {
+ if(index >= mConfigsSupported) {
+ ALOGE("%s(): Invalid Index %u", __FUNCTION__, index);
+ return false;
+ }
+
+ bool ret = true;
+ int fd = -1;
+ size_t len = PAGE_SIZE;
+ char sysfsPath[MAX_SYSFS_FILE_PATH];
+ memset(sysfsPath, '\0', sizeof(sysfsPath));
+ snprintf(sysfsPath , sizeof(sysfsPath),
+ "/sys/class/graphics/fb0/mode");
+
+ fd = open(sysfsPath, O_WRONLY);
+ if (fd < 0) {
+ ALOGE("%s(): Opening file %s failed", __FUNCTION__, sysfsPath);
+ return false;
+ }
+
+ ssize_t written = pwrite(fd, mModeStr[index], strlen(mModeStr[index]), 0);
+ if(written <= 0) {
+ ALOGE("%s(): Writing config %s to %s failed with error: %s",
+ __FUNCTION__, mModeStr[index], sysfsPath, strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ ALOGI("%s(): Successfully set config %u", __FUNCTION__, index);
+ mActiveConfig = index;
+ MDPVersion::getInstance().updateSplitInfo();
+ close(fd);
+ return true;
+}
+
+Configs* Configs::sConfigs = NULL;
+
}; //namespace
// ----------------------------------------------------------------------------
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 8bafe91..6a66e9f 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -31,11 +31,8 @@
#include <mdp_version.h>
#include <hardware/hwcomposer.h>
-// This header is for clients to use to set/get global display configuration
-// The functions in this header run in the client process and wherever necessary
-// do a binder call to HWC to get/set data.
+// This header is for clients to use to set/get global display configuration.
// Only primary and external displays are supported here.
-// WiFi/virtual displays are not supported.
namespace qdutils {
@@ -69,14 +66,20 @@
// Display Attributes that are available to clients of this library
// Not to be confused with a similar struct in hwc_utils (in the hwc namespace)
-struct DisplayAttributes_t {
+typedef struct DisplayAttributes {
uint32_t vsync_period; //nanoseconds
uint32_t xres;
uint32_t yres;
float xdpi;
float ydpi;
char panel_type;
-};
+ DisplayAttributes() : vsync_period(0), xres(0), yres(0), xdpi(0.0f),
+ ydpi(0.0f), panel_type(0) {}
+} DisplayAttributes_t;
+
+//=============================================================================
+// The functions below run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
// Check if external display is connected. Useful to check before making
// calls for external displays
@@ -104,4 +107,66 @@
// Enable/Disable/Set refresh rate dynamically
int configureDynRefreshRate(uint32_t op, uint32_t refreshRate);
+
+// Returns the number of configs supported for the display on success.
+// Returns -1 on error.
+// Only primary display supported for now, value of dpy ignored.
+int getConfigCount(int dpy);
+
+// Returns the index of config that is current set for the display on success.
+// Returns -1 on error.
+// Only primary display supported for now, value of dpy ignored.
+int getActiveConfig(int dpy);
+
+// Sets the config for the display on success and returns 0.
+// Returns -1 on error.
+// Only primary display supported for now, value of dpy ignored
+int setActiveConfig(int configIndex, int dpy);
+
+// Returns the attributes for the specified config for the display on success.
+// Returns xres and yres as 0 on error.
+// Only primary display supported for now, value of dpy ignored
+DisplayAttributes getDisplayAttributes(int configIndex, int dpy);
+
+//=============================================================================
+// The functions and methods below run in the context of HWC and
+// are called in response to binder calls from clients
+
+class Configs {
+public:
+ DisplayAttributes getAttributes(const uint32_t& index) const;
+ uint32_t getActiveConfig() const;
+ bool setActiveConfig(const uint32_t& index);
+ uint32_t getConfigCount() const;
+ static Configs *getInstance();
+private:
+ enum { CONFIGS_MAX = 32 };
+ Configs();
+ bool init();
+ bool getCurrentMode(DisplayAttributes& dpyAttr);
+ DisplayAttributes mConfigs[CONFIGS_MAX];
+ char *mModeStr[CONFIGS_MAX];
+ uint32_t mActiveConfig;
+ uint32_t mConfigsSupported;
+ static Configs *sConfigs;
+};
+
+inline DisplayAttributes Configs::getAttributes(const uint32_t& index) const {
+ if(index >= mConfigsSupported) {
+ ALOGE("%s() Invalid index %d, max %d", __FUNCTION__, index,
+ mConfigsSupported);
+ return DisplayAttributes(); //All 0s
+ }
+ return mConfigs[index];
+}
+
+// Retuns the current config index, -1 if called without a setActiveConfig
+inline uint32_t Configs::getActiveConfig() const {
+ return mActiveConfig;
+}
+
+inline uint32_t Configs::getConfigCount() const {
+ return mConfigsSupported;
+}
+
}; //namespace
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 402e129..e045918 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -501,6 +501,10 @@
mMdpRev < MDSS_MDP_HW_REV_109);
}
+bool MDPVersion::is8992() {
+ return ((mMdpRev >= MDSS_MDP_HW_REV_110 and
+ mMdpRev < MDSS_MDP_HW_REV_200));
+}
}; //namespace qdutils
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 3b10010..ad92c83 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -151,11 +151,12 @@
bool is8994();
bool is8x16();
bool is8x39();
+ bool is8992();
+ bool updateSplitInfo();
private:
bool updateSysFsInfo();
void updatePanelInfo();
- bool updateSplitInfo();
int tokenizeParams(char *inputParams, const char *delim,
char* tokenStr[], int *idx);
int mFd;
diff --git a/libqservice/Android.mk b/libqservice/Android.mk
index 78b1d77..287e6ce 100644
--- a/libqservice/Android.mk
+++ b/libqservice/Android.mk
@@ -10,7 +10,8 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := QService.cpp \
IQService.cpp \
- IQClient.cpp
+ IQClient.cpp \
+ IQHDMIClient.cpp
LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
LOCAL_COPY_HEADERS := IQService.h \
IQClient.h
diff --git a/libqservice/IQHDMIClient.cpp b/libqservice/IQHDMIClient.cpp
new file mode 100644
index 0000000..9f5044a
--- /dev/null
+++ b/libqservice/IQHDMIClient.cpp
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2014 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include "IQHDMIClient.h"
+
+using namespace android;
+namespace qClient {
+
+enum {
+ HDMI_CONNECTED = IBinder::FIRST_CALL_TRANSACTION,
+ CEC_MESSAGE_RECEIVED
+};
+
+class BpQHDMIClient : public BpInterface<IQHDMIClient>
+{
+public:
+ BpQHDMIClient(const sp<IBinder>& impl)
+ :BpInterface<IQHDMIClient>(impl)
+ {
+ }
+
+ void onHdmiHotplug(int connected)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IQHDMIClient::getInterfaceDescriptor());
+ data.writeInt32(connected);
+ remote()->transact(HDMI_CONNECTED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ void onCECMessageRecieved(char *msg, ssize_t len)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IQHDMIClient::getInterfaceDescriptor());
+ data.writeInt32((int32_t)len);
+ void *buf = data.writeInplace(len);
+ if (buf != NULL)
+ memcpy(buf, msg, len);
+ remote()->transact(CEC_MESSAGE_RECEIVED, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(QHDMIClient,
+ "android.display.IQHDMIClient");
+
+status_t BnQHDMIClient::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case HDMI_CONNECTED: {
+ CHECK_INTERFACE(IQHDMIClient, data, reply);
+ int connected = data.readInt32();
+ onHdmiHotplug(connected);
+ return NO_ERROR;
+ }
+ case CEC_MESSAGE_RECEIVED: {
+ CHECK_INTERFACE(IQHDMIClient, data, reply);
+ ssize_t len = data.readInt32();
+ const void* msg;
+ if(len >= 0 && len <= (ssize_t) data.dataAvail()) {
+ msg = data.readInplace(len);
+ } else {
+ msg = NULL;
+ len = 0;
+ }
+ if (msg != NULL)
+ onCECMessageRecieved((char*) msg, len);
+ return NO_ERROR;
+ }
+ default: {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+}
+
+}; //namespace qClient
diff --git a/libqservice/IQHDMIClient.h b/libqservice/IQHDMIClient.h
new file mode 100644
index 0000000..c3d012a
--- /dev/null
+++ b/libqservice/IQHDMIClient.h
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2014 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:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation. nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HDMI_EVENTS_LISTENER_H_
+#define HDMI_EVENTS_LISTENER_H_
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+
+namespace qClient {
+
+class IQHDMIClient : public android::IInterface
+{
+public:
+ DECLARE_META_INTERFACE(QHDMIClient);
+ virtual void onHdmiHotplug(int connected) = 0;
+ virtual void onCECMessageRecieved(char *msg, ssize_t len) = 0;
+};
+
+class BnQHDMIClient : public android::BnInterface<IQHDMIClient>
+{
+public:
+ virtual android::status_t onTransact( uint32_t code,
+ const android::Parcel& data,
+ android::Parcel* reply, uint32_t flags = 0);
+};
+
+}; //namespace qhdmi
+
+#endif // HDMI_EVENTS_LISTENER_H_
+
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index eee22f0..5e67b15 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -45,13 +45,22 @@
: BpInterface<IQService>(impl) {}
virtual void connect(const sp<IQClient>& client) {
- ALOGD_IF(QSERVICE_DEBUG, "%s: connect client", __FUNCTION__);
+ ALOGD_IF(QSERVICE_DEBUG, "%s: connect HWC client", __FUNCTION__);
Parcel data, reply;
data.writeInterfaceToken(IQService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
- remote()->transact(CONNECT, data, &reply);
+ remote()->transact(CONNECT_HWC_CLIENT, data, &reply);
}
+ virtual void connect(const sp<IQHDMIClient>& client) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: connect HDMI client", __FUNCTION__);
+ Parcel data, reply;
+ data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+ data.writeStrongBinder(client->asBinder());
+ remote()->transact(CONNECT_HDMI_CLIENT, data, &reply);
+ }
+
+
virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel);
@@ -90,10 +99,10 @@
callerUid == AID_ROOT ||
callerUid == AID_SYSTEM);
- if (code == CONNECT) {
+ if (code == CONNECT_HWC_CLIENT) {
CHECK_INTERFACE(IQService, data, reply);
if(callerUid != AID_GRAPHICS) {
- ALOGE("display.qservice CONNECT access denied: \
+ ALOGE("display.qservice CONNECT_HWC_CLIENT access denied: \
pid=%d uid=%d process=%s",
callerPid, callerUid, callingProcName);
return PERMISSION_DENIED;
@@ -102,6 +111,18 @@
interface_cast<IQClient>(data.readStrongBinder());
connect(client);
return NO_ERROR;
+ } else if(code == CONNECT_HDMI_CLIENT) {
+ CHECK_INTERFACE(IQService, data, reply);
+ if(callerUid != AID_SYSTEM && callerUid != AID_ROOT) {
+ ALOGE("display.qservice CONNECT_HDMI_CLIENT access denied: \
+ pid=%d uid=%d process=%s",
+ callerPid, callerUid, callingProcName);
+ return PERMISSION_DENIED;
+ }
+ sp<IQHDMIClient> client =
+ interface_cast<IQHDMIClient>(data.readStrongBinder());
+ connect(client);
+ return NO_ERROR;
} else if (code > COMMAND_LIST_START && code < COMMAND_LIST_END) {
if(!permission) {
ALOGE("display.qservice access denied: command=%d\
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index cd2d116..932d670 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -28,6 +28,7 @@
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <IQClient.h>
+#include <IQHDMIClient.h>
namespace qService {
@@ -41,7 +42,7 @@
COMMAND_LIST_START = android::IBinder::FIRST_CALL_TRANSACTION,
SECURING = 2, // Hardware securing start/end notification
UNSECURING = 3, // Hardware unsecuring start/end notification
- CONNECT = 4, // Connect to qservice
+ CONNECT_HWC_CLIENT = 4, // Connect to qservice
SCREEN_REFRESH = 5, // Refresh screen through SF invalidate
EXTERNAL_ORIENTATION = 6,// Set external orientation
BUFFER_MIRRORMODE = 7, // Buffer mirrormode
@@ -60,6 +61,12 @@
SET_PARTIAL_UPDATE = 19, // Preference on partial update feature
TOGGLE_SCREEN_UPDATE = 20, // Provides ability to disable screen updates
SET_FRAME_DUMP_CONFIG = 21, // Provides ability to set the frame dump config
+ SET_S3D_MODE = 22, // Set the 3D mode as specified in msm_hdmi_modes.h
+ CONNECT_HDMI_CLIENT = 23, // Connect HDMI CEC HAL Client
+ SET_ACTIVE_CONFIG = 25, //Set a specified display config
+ GET_ACTIVE_CONFIG = 26, //Get the current config index
+ GET_CONFIG_COUNT = 27, //Get the number of supported display configs
+ GET_DISPLAY_ATTRIBUTES_FOR_CONFIG = 28, //Get attr for specified config
COMMAND_LIST_END = 400,
};
@@ -79,13 +86,24 @@
};
enum {
+ PREF_PARTIAL_UPDATE,
+ PREF_POST_PROCESSING,
+ ENABLE_PARTIAL_UPDATE,
+ };
+
+ enum {
DUMP_PRIMARY_DISPLAY,
DUMP_HDMI_DISPLAY,
DUMP_VIRTUAL_DISPLAY,
};
- // Register a client that can be notified
+ // Register a HWC client that can be notified
+ // This client is generic and is intended to get
+ // dispatches of all events calling into QService
virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
+ // Register an HDMI client. This client gets notification of HDMI events
+ // such as plug/unplug and CEC messages
+ virtual void connect(const android::sp<qClient::IQHDMIClient>& client) = 0;
// Generic function to dispatch binder commands
// The type of command decides how the data is parceled
virtual android::status_t dispatch(uint32_t command,
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index 12dd995..ddb4b18 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -50,24 +50,52 @@
}
void QService::connect(const sp<qClient::IQClient>& client) {
- ALOGD_IF(QSERVICE_DEBUG,"client connected");
+ ALOGD_IF(QSERVICE_DEBUG,"HWC client connected");
mClient = client;
}
+void QService::connect(const sp<qClient::IQHDMIClient>& client) {
+ ALOGD_IF(QSERVICE_DEBUG,"HWC client connected");
+ mHDMIClient = client;
+}
+
status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t err = (status_t) FAILED_TRANSACTION;
IPCThreadState* ipc = IPCThreadState::self();
//Rewind parcel in case we're calling from the same process
- if (ipc->getCallingPid() == getpid())
+ bool sameProcess = (ipc->getCallingPid() == getpid());
+ if(sameProcess)
inParcel->setDataPosition(0);
if (mClient.get()) {
ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
err = mClient->notifyCallback(command, inParcel, outParcel);
+ //Rewind parcel in case we're calling from the same process
+ if (sameProcess)
+ outParcel->setDataPosition(0);
}
return err;
}
+void QService::onHdmiHotplug(int connected) {
+ if(mHDMIClient.get()) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: HDMI hotplug", __FUNCTION__);
+ mHDMIClient->onHdmiHotplug(connected);
+ } else {
+ ALOGE("%s: Failed to get a valid HDMI client", __FUNCTION__);
+ }
+}
+
+void QService::onCECMessageReceived(char *msg, ssize_t len) {
+ if(mHDMIClient.get()) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: CEC message received", __FUNCTION__);
+ mHDMIClient->onCECMessageRecieved(msg, len);
+ } else {
+ ALOGE("%s: Failed to get a valid HDMI client", __FUNCTION__);
+ }
+}
+
+
void QService::init()
{
if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index a8e4cdb..719c9b7 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -46,13 +46,17 @@
public:
virtual ~QService();
virtual void connect(const android::sp<qClient::IQClient>& client);
+ virtual void connect(const android::sp<qClient::IQHDMIClient>& client);
virtual android::status_t dispatch(uint32_t command,
const android::Parcel* data,
android::Parcel* reply);
+ void onHdmiHotplug(int connected);
+ void onCECMessageReceived(char *msg, ssize_t len);
static void init();
private:
QService();
android::sp<qClient::IQClient> mClient;
+ android::sp<qClient::IQHDMIClient> mHDMIClient;
static QService *sQService;
};
}; // namespace qService