sde: resource manager: rotator support
Use rotator when 90 rotation or downscaling is needed.
Configure rotator input/output ROI, acquire source pipe
and writeback block for the rotator.
Change-Id: I4b8348714eade9a57e553f0f23e6b0b62dd32bad
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index bbedc65..99d392d 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -92,6 +92,20 @@
has_non_scalar_rgb(false), is_src_split(false), always_src_split(false) { }
};
+struct HWRotateInfo {
+ uint32_t pipe_id;
+ LayerRect src_roi;
+ LayerRect dst_roi;
+ HWBlockType writeback_id;
+ float downscale_ratio_x;
+ float downscale_ratio_y;
+
+ HWRotateInfo() : pipe_id(0), writeback_id(kHWWriteback0), downscale_ratio_x(1.0f),
+ downscale_ratio_y(1.0f) { }
+
+ inline void Reset() { *this = HWRotateInfo(); }
+};
+
struct HWPipeInfo {
uint32_t pipe_id;
LayerRect src_roi;
@@ -108,6 +122,8 @@
bool is_right_pipe; // indicate if right pipe is valid
HWPipeInfo left_pipe; // pipe for left side of the buffer
HWPipeInfo right_pipe; // pipe for right side of the buffer
+ HWRotateInfo left_rotate; // rotation for left side of the buffer
+ HWRotateInfo right_rotate; // rotation for right side of the buffer
HWLayerConfig() : use_non_dma_pipe(false), is_right_pipe(false) { }
};
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
index fdf4177..974897c 100644
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -32,16 +32,37 @@
namespace sde {
+void ResManager::RotationConfig(const LayerTransform &transform, LayerRect *src_rect,
+ HWRotateInfo *left_rotate, HWRotateInfo *right_rotate,
+ uint32_t *rotate_count) {
+ float src_width = src_rect->right - src_rect->left;
+ float src_height = src_rect->bottom - src_rect->top;
+ 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;
+ // downscale when doing rotation
+ dst_rect.right = src_height / left_rotate->downscale_ratio_x;
+ dst_rect.bottom = src_width / left_rotate->downscale_ratio_y;
+
+ left_rotate->src_roi = *src_rect;
+ left_rotate->pipe_id = kPipeIdNeedsAssignment;
+ left_rotate->dst_roi = dst_rect;
+ // Always use one rotator for now
+ right_rotate->Reset();
+
+ *src_rect = dst_rect;
+ (*rotate_count)++;
+}
+
DisplayError ResManager::SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
- const Layer &layer, const LayerRect &src_rect,
+ const LayerTransform &transform, const LayerRect &src_rect,
const LayerRect &dst_rect, HWLayerConfig *layer_config) {
HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
HWPipeInfo *left_pipe = &layer_config->left_pipe;
HWPipeInfo *right_pipe = &layer_config->right_pipe;
layer_config->is_right_pipe = false;
- LayerTransform transform = layer.transform;
- transform.rotation = 0.0f;
if ((src_rect.right - src_rect.left) >= kMaxSourcePipeWidth ||
(dst_rect.right - dst_rect.left) >= kMaxInterfaceWidth || hw_res_info_.always_src_split) {
SplitRect(transform.flip_horizontal, src_rect, dst_rect, &left_pipe->src_roi,
@@ -59,8 +80,8 @@
}
DisplayError ResManager::DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
- const Layer &layer, const LayerRect &src_rect,
- const LayerRect &dst_rect,
+ const LayerTransform &transform,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
HWLayerConfig *layer_config) {
HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
// for display split case
@@ -75,8 +96,8 @@
dst_left = dst_rect;
crop_right = crop_left;
dst_right = dst_left;
- LayerTransform transform = layer.transform;
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);
@@ -159,11 +180,32 @@
if (ValidateScaling(layer, src_rect, dst_rect, &rot_scale_x, &rot_scale_y))
return kErrorNotSupported;
+ HWRotateInfo *left_rotate, *right_rotate;
+ // config rotator first
+ left_rotate = &hw_layers->config[i].left_rotate;
+ right_rotate = &hw_layers->config[i].right_rotate;
+
+ LayerTransform transform = layer.transform;
+ if (IsRotationNeeded(transform.rotation) ||
+ UINT32(rot_scale_x) != 1 || UINT32(rot_scale_y) != 1) {
+ left_rotate->downscale_ratio_x = rot_scale_x;
+ right_rotate->downscale_ratio_x = rot_scale_x;
+ left_rotate->downscale_ratio_y = rot_scale_y;
+ right_rotate->downscale_ratio_y = rot_scale_y;
+
+ RotationConfig(layer.transform, &src_rect, left_rotate, right_rotate, rotate_count);
+ // rotator will take care of flipping, reset tranform
+ transform = LayerTransform();
+ } else {
+ left_rotate->Reset();
+ right_rotate->Reset();
+ }
+
if (hw_res_info_.is_src_split) {
- error = SrcSplitConfig(display_resource_ctx, layer, src_rect,
+ error = SrcSplitConfig(display_resource_ctx, transform, src_rect,
dst_rect, &hw_layers->config[i]);
} else {
- error = DisplaySplitConfig(display_resource_ctx, layer, src_rect,
+ error = DisplaySplitConfig(display_resource_ctx, transform, src_rect,
dst_rect, &hw_layers->config[i]);
}
@@ -190,7 +232,7 @@
DisplayError ResManager::ValidateScaling(const Layer &layer, const LayerRect &crop,
const LayerRect &dst, float *rot_scale_x,
float *rot_scale_y) {
- bool rotated90 = (UINT32(layer.transform.rotation) == 90);
+ bool rotated90 = IsRotationNeeded(layer.transform.rotation);
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;
@@ -212,12 +254,23 @@
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;
+
+ 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_decimation) || (IsMacroTileFormat(layer.input_buffer))) &&
(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);
+ return kErrorNotSupported;
}
}
@@ -266,7 +319,7 @@
Swap(*top_cut_ratio, *bottom_cut_ratio);
}
- if (UINT32(transform.rotation) == 90) {
+ if (IsRotationNeeded(transform.rotation)) {
// Anti clock swapping
float tmp_cut_ratio = *left_cut_ratio;
*left_cut_ratio = *top_cut_ratio;
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index 9579128..38ef319 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -79,6 +79,20 @@
DLOGI("hw_rev=%x, DMA=%d RGB=%d VIG=%d", hw_res_info_.hw_revision, hw_res_info_.num_dma_pipe,
hw_res_info_.num_rgb_pipe, hw_res_info_.num_vig_pipe);
+ if (hw_res_info_.num_rotator > kMaxNumRotator) {
+ DLOGE("Number of rotator is over the limit! %d", hw_res_info_.num_rotator);
+ return kErrorParameters;
+ }
+
+ if (hw_res_info_.num_rotator > 0) {
+ rotators_[0].pipe_index = dma_pipes_[0].index;
+ rotators_[0].writeback_id = kHWWriteback0;
+ }
+ if (hw_res_info_.num_rotator > 1) {
+ rotators_[1].pipe_index = dma_pipes_[1].index;
+ rotators_[1].writeback_id = kHWWriteback1;
+ }
+
// Used by splash screen
rgb_pipes_[0].state = kPipeStateOwnedByKernel;
rgb_pipes_[1].state = kPipeStateOwnedByKernel;
@@ -153,6 +167,9 @@
} else {
hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false;
}
+ if (!hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use)
+ ClearDedicated(display_resource_ctx->hw_block_id);
+
delete display_resource_ctx;
return kErrorNone;
@@ -181,6 +198,19 @@
}
}
+ // Clear rotator usage
+ for (uint32_t i = 0; i < hw_res_info_.num_rotator; i++) {
+ uint32_t pipe_index;
+ pipe_index = rotators_[i].pipe_index;
+ if (rotators_[i].client_bit_mask == 0 &&
+ src_pipes_[pipe_index].state == kPipeStateToRelease &&
+ src_pipes_[pipe_index].hw_block_id == rotators_[i].writeback_id) {
+ src_pipes_[pipe_index].dedicated_hw_block = kHWBlockMax;
+ src_pipes_[pipe_index].state = kPipeStateIdle;
+ }
+ CLEAR_BIT(rotators_[i].client_bit_mask, display_resource_ctx->hw_block_id);
+ }
+
return kErrorNone;
}
@@ -221,6 +251,12 @@
src_pipes_[i].reserved_hw_block = kHWBlockMax;
}
+ // allocate rotator
+ error = AcquireRotator(display_resource_ctx, rotate_count);
+ if (error != kErrorNone)
+ return error;
+
+ rotate_count = 0;
for (uint32_t i = 0; i < layer_info.count; i++) {
Layer &layer = layer_info.stack->layers[layer_info.index[i]];
bool use_non_dma_pipe = hw_layers->config[i].use_non_dma_pipe;
@@ -230,6 +266,9 @@
use_non_dma_pipe = true;
}
+ AssignRotator(&hw_layers->config[i].left_rotate, &rotate_count);
+ AssignRotator(&hw_layers->config[i].right_rotate, &rotate_count);
+
HWPipeInfo *pipe_info = &hw_layers->config[i].left_pipe;
// Should have a generic macro
@@ -539,6 +578,20 @@
}
}
}
+ // set rotator pipes
+ for (uint32_t i = 0; i < hw_res_info_.num_rotator; i++) {
+ uint32_t pipe_index;
+ pipe_index = rotators_[i].pipe_index;
+ if (IS_BIT_SET(rotators_[i].client_bit_mask, hw_block_id)) {
+ src_pipes_[pipe_index].hw_block_id = rotators_[i].writeback_id;
+ src_pipes_[pipe_index].state = kPipeStateAcquired;
+ } else if (!rotators_[i].client_bit_mask) {
+ src_pipes_[pipe_index].dedicated_hw_block = kHWBlockMax;
+ if (src_pipes_[pipe_index].hw_block_id == rotators_[i].writeback_id &&
+ src_pipes_[pipe_index].state == kPipeStateAcquired)
+ src_pipes_[pipe_index].state = kPipeStateToRelease;
+ }
+ }
display_resource_ctx->frame_start = false;
}
@@ -553,6 +606,7 @@
if (src_pipes_[i].hw_block_id == hw_block_id)
src_pipes_[i].ResetState();
}
+ ClearRotator(display_resource_ctx);
}
uint32_t ResManager::GetMdssPipeId(PipeType type, uint32_t index) {
@@ -714,5 +768,175 @@
}
}
+// This is to reserve resources for the device or rotator
+DisplayError ResManager::MarkDedicated(DisplayResourceContext *display_resource_ctx,
+ struct HWRotator *rotator) {
+ uint32_t num_base_pipe = 0, base_pipe_index = 0, num_vig_pipe = 0, i, vig_pipe_index = 0;
+ bool force = false;
+ SourcePipe *src_pipe = NULL;
+ HWBlockType hw_block_id;
+ if (rotator == NULL) {
+ hw_block_id = display_resource_ctx->hw_block_id;
+ switch (display_resource_ctx->display_type) {
+ case kPrimary:
+ src_pipe= rgb_pipes_;
+ if (display_resource_ctx->display_attributes.is_device_split ||
+ hw_res_info_.is_src_split) {
+ num_base_pipe = 2;
+ num_vig_pipe = 2;
+ } else {
+ num_base_pipe = 1;
+ num_vig_pipe = 1;
+ }
+ src_pipe = rgb_pipes_;
+ force = true;
+ break;
+ // HDMI and Virtual are using the same strategy
+ case kHDMI:
+ case kVirtual:
+ if (display_resource_ctx && display_resource_ctx->display_attributes.is_device_split) {
+ num_base_pipe = 2;
+ num_vig_pipe = 2;
+ } else {
+ num_base_pipe = 1;
+ num_vig_pipe = 1;
+ }
+ break;
+ default:
+ DLOGE("Wrong device type %d", display_resource_ctx->display_type);
+ break;
+ }
+ } else {
+ hw_block_id = rotator->writeback_id;
+ num_base_pipe = 1;
+ base_pipe_index = rotator->pipe_index;
+ src_pipe = &src_pipes_[base_pipe_index];
+ force = true;
+ }
+
+ if (!num_base_pipe) {
+ DLOGE("Cannot reserve dedicated pipe %d", hw_block_id);
+ return kErrorResources;
+ }
+
+ // Only search the assigned pipe type
+ if (force) {
+ for (i = 0; i < num_base_pipe; i++) {
+ if (src_pipe->dedicated_hw_block != kHWBlockMax)
+ DLOGV_IF(kTagResources, "Overwrite dedicated block %d", src_pipe->dedicated_hw_block);
+ src_pipe->dedicated_hw_block = hw_block_id;
+ src_pipe++;
+ }
+ num_base_pipe = 0;
+ } else {
+ // search available pipes
+ src_pipe = rgb_pipes_;
+ uint32_t num_pipe = hw_res_info_.num_rgb_pipe + hw_res_info_.num_vig_pipe;
+ for (i = 0; i < num_pipe; i++) {
+ if (src_pipe->dedicated_hw_block == kHWBlockMax ||
+ src_pipe->dedicated_hw_block == hw_block_id) {
+ src_pipe->dedicated_hw_block = hw_block_id;
+ num_base_pipe--;
+ if (!num_base_pipe)
+ break;
+ }
+ src_pipe++;
+ }
+ if (num_base_pipe) {
+ for (i = 0; i < num_pipe; i++) {
+ if (src_pipe->dedicated_hw_block == hw_block_id)
+ src_pipe->dedicated_hw_block = kHWBlockMax;
+ src_pipe++;
+ }
+ DLOGE("Cannot reserve dedicated pipe %d", hw_block_id);
+ return kErrorResources;
+ }
+ }
+ // optional for vig pipes
+ src_pipe= vig_pipes_;
+ for (i = 0; i < num_vig_pipe; i++) {
+ if (src_pipe->dedicated_hw_block == kHWBlockMax ||
+ src_pipe->dedicated_hw_block == hw_block_id) {
+ src_pipe->dedicated_hw_block = hw_block_id;
+ num_vig_pipe--;
+ if (!num_vig_pipe)
+ break;
+ }
+ src_pipe++;
+ }
+ return kErrorNone;
+}
+
+void ResManager::ClearDedicated(HWBlockType hw_block_id) {
+ SourcePipe *src_pipe = src_pipes_;
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ if (src_pipe->dedicated_hw_block == hw_block_id)
+ src_pipe->dedicated_hw_block = kHWBlockMax;
+ }
+}
+
+DisplayError ResManager::AcquireRotator(DisplayResourceContext *display_resource_ctx,
+ const uint32_t rotate_count) {
+ if (rotate_count == 0)
+ return kErrorNone;
+ if (hw_res_info_.num_rotator == 0)
+ return kErrorResources;
+
+ uint32_t i, j, pipe_index, num_rotator;
+ if (rotate_count > hw_res_info_.num_rotator)
+ num_rotator = hw_res_info_.num_rotator;
+ else
+ num_rotator = rotate_count;
+
+ for (i = 0; i < num_rotator; i++) {
+ uint32_t rotate_pipe_index = rotators_[i].pipe_index;
+ MarkDedicated(display_resource_ctx, &rotators_[i]);
+ if (src_pipes_[rotate_pipe_index].reserved_hw_block != kHWBlockMax) {
+ DLOGV_IF(kTagResources, "pipe %x is reserved by block:%d",
+ src_pipes_[rotate_pipe_index].mdss_pipe_id,
+ src_pipes_[rotate_pipe_index].reserved_hw_block);
+ return kErrorResources;
+ }
+ pipe_index = SearchPipe(rotators_[i].writeback_id, &src_pipes_[rotate_pipe_index], 1, false);
+ if (pipe_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "pipe %x is not ready for rotator",
+ src_pipes_[rotate_pipe_index].mdss_pipe_id);
+ return kErrorResources;
+ }
+ }
+
+ for (i = 0; i < num_rotator; i++)
+ SET_BIT(rotators_[i].client_bit_mask, display_resource_ctx->hw_block_id);
+
+ return kErrorNone;
+}
+
+void ResManager::AssignRotator(HWRotateInfo *rotate, uint32_t *rotate_count) {
+ if (!rotate->pipe_id)
+ return;
+ // Interleave rotator assignment
+ if ((*rotate_count & 0x1) && (hw_res_info_.num_rotator > 1)) {
+ rotate->pipe_id = src_pipes_[rotators_[1].pipe_index].mdss_pipe_id;
+ rotate->writeback_id = rotators_[1].writeback_id;
+ } else {
+ rotate->pipe_id = src_pipes_[rotators_[0].pipe_index].mdss_pipe_id;
+ rotate->writeback_id = rotators_[0].writeback_id;
+ }
+ (*rotate_count)++;
+}
+
+void ResManager::ClearRotator(DisplayResourceContext *display_resource_ctx) {
+ for (uint32_t i = 0; i < hw_res_info_.num_rotator; i++) {
+ uint32_t pipe_index;
+ pipe_index = rotators_[i].pipe_index;
+ CLEAR_BIT(rotators_[i].client_bit_mask, display_resource_ctx->hw_block_id);
+ if (rotators_[i].client_bit_mask == 0 &&
+ src_pipes_[pipe_index].dedicated_hw_block == rotators_[i].writeback_id) {
+ src_pipes_[pipe_index].dedicated_hw_block = kHWBlockMax;
+ src_pipes_[pipe_index].state = kPipeStateIdle;
+ }
+ }
+}
+
} // namespace sde
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index 52d0464..18900f3 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -146,12 +146,12 @@
DisplayError Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers,
uint32_t *rotate_count);
DisplayError DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
- const Layer &layer, const LayerRect &src_rect,
+ const LayerTransform &transform, const LayerRect &src_rect,
const LayerRect &dst_rect, HWLayerConfig *layer_config);
DisplayError ValidateScaling(const Layer &layer, const LayerRect &crop,
const LayerRect &dst, float *rot_scale_x, float *rot_scale_y);
DisplayError SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
- const Layer &layer, const LayerRect &src_rect,
+ const LayerTransform &transform, const LayerRect &src_rect,
const LayerRect &dst_rect, HWLayerConfig *layer_config);
void CalculateCut(const LayerTransform &transform, float *left_cut_ratio, float *top_cut_ratio,
float *right_cut_ratio, float *bottom_cut_ratio);
@@ -169,7 +169,18 @@
LayerRect *dst_right);
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 LogRectVerbose(const char *prefix, const LayerRect &roi);
+ DisplayError MarkDedicated(DisplayResourceContext *display_resource_ctx,
+ struct HWRotator *rotator);
+ void ClearDedicated(HWBlockType hw_block_id);
+ void RotationConfig(const LayerTransform &transform, LayerRect *src_rect,
+ HWRotateInfo *left_rotate, HWRotateInfo *right_rotate, uint32_t *rotate_cnt);
+ 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);
template <class T>
inline void Swap(T &a, T &b) {
@@ -191,6 +202,7 @@
float clk_claimed_; // Clock claimed by other display
float last_primary_bw_;
uint32_t virtual_count_;
+ struct HWRotator rotators_[kMaxNumRotator];
};
} // namespace sde