Merge "hwc: Handle DOZE_SUSPEND properly"
diff --git a/displayengine/include/utils/constants.h b/displayengine/include/utils/constants.h
index 447b22a..8630d45 100644
--- a/displayengine/include/utils/constants.h
+++ b/displayengine/include/utils/constants.h
@@ -57,6 +57,8 @@
#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/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
index dac17fd..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;
}
}
}
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 6cab293..f3cdb8b 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -1178,6 +1178,7 @@
*target = width * 3;
break;
case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
case kFormatYCbCr420Planar:
case kFormatYCrCb420Planar:
case kFormatYCbCr420SemiPlanar:
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
index 66f5cba..27a4e41 100644
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -33,12 +33,13 @@
namespace sde {
-void ResManager::RotationConfig(const LayerTransform &transform, const float &downscale,
- LayerRect *src_rect, struct HWLayerConfig *layer_config,
- uint32_t *rotate_count) {
+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;
@@ -47,7 +48,7 @@
rotate->downscale_ratio = downscale;
// downscale when doing rotation
- if (IsRotationNeeded(transform.rotation)) {
+ if (rot90) {
if (downscale > 1.0f) {
src_height = ROUND_UP_ALIGN_DOWN(src_height, downscale);
src_rect->bottom = src_rect->top + src_height;
@@ -71,6 +72,14 @@
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)++;
@@ -83,9 +92,30 @@
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, align_x);
left_pipe->valid = true;
@@ -240,7 +270,8 @@
LayerTransform transform = layer.transform;
if (IsRotationNeeded(transform.rotation) || UINT32(rot_scale) != 1) {
- RotationConfig(layer.transform, rot_scale, &src_rect, layer_config, rotate_count);
+ 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();
}
@@ -493,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;
@@ -502,28 +532,17 @@
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;
+ if (CalculateDecimation(down_scale_h, &pipe->vertical_decimation) != kErrorNone) {
+ 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) - 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)));
-
DLOGI_IF(kTagResources, "horizontal_decimation %d, vertical_decimation %d",
pipe->horizontal_decimation, pipe->vertical_decimation);
@@ -628,4 +647,23 @@
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 9868ddf..14cf11f 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -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) {
@@ -385,12 +383,6 @@
i, layer_config.left_pipe.pipe_id, pipe_info->pipe_id);
}
- error = AllocRotatorBuffer(display_ctx, hw_layers);
- if (error != kErrorNone) {
- DLOGV_IF(kTagResources, "Rotator buffer allocation failed");
- goto CleanupOnError;
- }
-
#ifdef USES_SCALAR
if (!ScalarHelper::GetInstance()->ConfigureScale(hw_layers)) {
DLOGV_IF(kTagResources, "Scale data configuration has failed!");
@@ -403,6 +395,12 @@
goto CleanupOnError;
}
+ error = AllocRotatorBuffer(display_ctx, hw_layers);
+ if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "Rotator buffer allocation failed");
+ goto CleanupOnError;
+ }
+
return kErrorNone;
CleanupOnError:
@@ -621,6 +619,7 @@
case kFormatYCbCr420SemiPlanar:
case kFormatYCrCb420SemiPlanar:
case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
return 1.5f;
default:
DLOGE("GetBpp: Invalid buffer format: %x", format);
@@ -643,16 +642,9 @@
for (uint32_t i = 0; i < layer_info.count; i++) {
Layer& layer = layer_info.stack->layers[layer_info.index[i]];
HWRotateInfo *rotate = &hw_layers->config[i].rotates[0];
- bool rot90 = (layer.transform.rotation == 90.0f);
if (rotate->valid) {
- LayerBufferFormat rot_ouput_format;
- SetRotatorOutputFormat(layer.input_buffer->format, false, rot90, &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;
@@ -665,13 +657,7 @@
rotate = &hw_layers->config[i].rotates[1];
if (rotate->valid) {
- LayerBufferFormat rot_ouput_format;
- SetRotatorOutputFormat(layer.input_buffer->format, false, rot90, &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;
@@ -1093,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;
}
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index 9ff5384..d21984e 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -194,20 +194,21 @@
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 &downscale,
- LayerRect *src_rect, struct HWLayerConfig *layer_config,
- uint32_t *rotate_count);
+ 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);
void AssignRotator(HWRotateInfo *rotate, uint32_t *rotate_cnt);
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 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_;
diff --git a/displayengine/libs/core/scalar_helper.cpp b/displayengine/libs/core/scalar_helper.cpp
index 57c51c0..22488b3 100755
--- a/displayengine/libs/core/scalar_helper.cpp
+++ b/displayengine/libs/core/scalar_helper.cpp
@@ -126,7 +126,8 @@
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;
+ 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;
@@ -147,15 +148,17 @@
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)
- input_buffer = &rotate_info->hw_buffer_info.output_buffer;
+ 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 = input_buffer->width;
+ pipe->scale_data->src_width = width;
SetPipeInfo(hw_pipe, pipe);
}
- layer_info.src_format = GetScalarFormat(input_buffer->format);
+ 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]",
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/utils/debug_android.cpp b/displayengine/libs/utils/debug_android.cpp
index 7503999..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,7 @@
return atoi(property);
}
- return 0;
+ return IDLE_TIMEOUT_DEFAULT_MS;
}
bool Debug::IsRotatorDownScaleDisabled() {
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 05e7c9b..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);
@@ -841,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;
@@ -850,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,
@@ -886,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);
}
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ef83008..692ce29 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -49,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,
@@ -168,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;
@@ -191,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;
}
@@ -300,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;
@@ -319,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;
}
@@ -466,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;
@@ -487,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;
}
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 487ec77..9b1f81d 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -121,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
@@ -355,6 +350,121 @@
}
}
+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;
@@ -418,6 +528,19 @@
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_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 9c94b2f..d162fb5 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -93,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
@@ -234,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) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index ea8d652..26d036f 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -112,12 +112,6 @@
int mAsWidthRatio;
int mAsHeightRatio;
- //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;
-
// 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.
@@ -130,6 +124,18 @@
// HDMI_S3D_NONE
int s3dMode;
bool s3dModeForced;
+ //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
+ //following fields are used.
+ //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 {
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.h b/libqdutils/mdp_version.h
index aeb2218..ad92c83 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -152,11 +152,11 @@
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/IQService.h b/libqservice/IQService.h
index 78cbd2a..8c63f1f 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -63,6 +63,10 @@
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,
};