summaryrefslogtreecommitdiff
path: root/msm8909/sdm/libs/core/resource_default.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'msm8909/sdm/libs/core/resource_default.cpp')
-rw-r--r--msm8909/sdm/libs/core/resource_default.cpp950
1 files changed, 950 insertions, 0 deletions
diff --git a/msm8909/sdm/libs/core/resource_default.cpp b/msm8909/sdm/libs/core/resource_default.cpp
new file mode 100644
index 00000000..6a4f3e5b
--- /dev/null
+++ b/msm8909/sdm/libs/core/resource_default.cpp
@@ -0,0 +1,950 @@
+/*
+* Copyright (c) 2014 - 2016, 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 <math.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <utils/rect.h>
+#include <utils/formats.h>
+#include <utils/sys.h>
+#include <dlfcn.h>
+#include <algorithm>
+
+#include "resource_default.h"
+
+#define __CLASS__ "ResourceDefault"
+
+namespace sdm {
+
+DisplayError ResourceDefault::CreateResourceDefault(const HWResourceInfo &hw_resource_info,
+ ResourceInterface **resource_intf) {
+ DisplayError error = kErrorNone;
+
+ ResourceDefault *resource_default = new ResourceDefault(hw_resource_info);
+ if (!resource_default) {
+ return kErrorNone;
+ }
+
+ error = resource_default->Init();
+ if (error != kErrorNone) {
+ delete resource_default;
+ }
+
+ *resource_intf = resource_default;
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::DestroyResourceDefault(ResourceInterface *resource_intf) {
+ ResourceDefault *resource_default = static_cast<ResourceDefault *>(resource_intf);
+
+ resource_default->Deinit();
+ delete resource_default;
+
+ return kErrorNone;
+}
+
+ResourceDefault::ResourceDefault(const HWResourceInfo &hw_res_info)
+ : hw_res_info_(hw_res_info) {
+}
+
+DisplayError ResourceDefault::Init() {
+ DisplayError error = kErrorNone;
+
+ num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe;
+
+ if (!num_pipe_) {
+ DLOGE("Number of H/W pipes is Zero!");
+ return kErrorParameters;
+ }
+
+ src_pipes_.resize(num_pipe_);
+
+ // Priority order of pipes: VIG, RGB, DMA
+ uint32_t vig_index = 0;
+ uint32_t rgb_index = hw_res_info_.num_vig_pipe;
+ uint32_t dma_index = rgb_index + hw_res_info_.num_rgb_pipe;
+
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ const HWPipeCaps &pipe_caps = hw_res_info_.hw_pipes.at(i);
+ if (pipe_caps.type == kPipeTypeVIG) {
+ src_pipes_[vig_index].type = kPipeTypeVIG;
+ src_pipes_[vig_index].index = i;
+ src_pipes_[vig_index].mdss_pipe_id = pipe_caps.id;
+ vig_index++;
+ } else if (pipe_caps.type == kPipeTypeRGB) {
+ src_pipes_[rgb_index].type = kPipeTypeRGB;
+ src_pipes_[rgb_index].index = i;
+ src_pipes_[rgb_index].mdss_pipe_id = pipe_caps.id;
+ rgb_index++;
+ } else if (pipe_caps.type == kPipeTypeDMA) {
+ src_pipes_[dma_index].type = kPipeTypeDMA;
+ src_pipes_[dma_index].index = i;
+ src_pipes_[dma_index].mdss_pipe_id = pipe_caps.id;
+ dma_index++;
+ }
+ }
+
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ src_pipes_[i].priority = INT(i);
+ }
+
+ 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_.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;
+ }
+
+ // TODO(user): clean it up, query from driver for initial pipe status.
+#ifndef SDM_VIRTUAL_DRIVER
+ rgb_index = hw_res_info_.num_vig_pipe;
+ src_pipes_[rgb_index].owner = kPipeOwnerKernelMode;
+ src_pipes_[rgb_index + 1].owner = kPipeOwnerKernelMode;
+#endif
+
+ return error;
+}
+
+DisplayError ResourceDefault::Deinit() {
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::RegisterDisplay(DisplayType type,
+ const HWDisplayAttributes &display_attributes,
+ const HWPanelInfo &hw_panel_info,
+ const HWMixerAttributes &mixer_attributes,
+ Handle *display_ctx) {
+ DisplayError error = kErrorNone;
+
+ HWBlockType hw_block_id = kHWBlockMax;
+ switch (type) {
+ case kPrimary:
+ if (!hw_block_ctx_[kHWPrimary].is_in_use) {
+ hw_block_id = kHWPrimary;
+ }
+ break;
+
+ case kHDMI:
+ if (!hw_block_ctx_[kHWHDMI].is_in_use) {
+ hw_block_id = kHWHDMI;
+ }
+ break;
+
+ default:
+ DLOGW("RegisterDisplay, invalid type %d", type);
+ return kErrorParameters;
+ }
+
+ if (hw_block_id == kHWBlockMax) {
+ return kErrorResources;
+ }
+
+ DisplayResourceContext *display_resource_ctx = new DisplayResourceContext();
+ if (!display_resource_ctx) {
+ return kErrorMemory;
+ }
+
+ hw_block_ctx_[hw_block_id].is_in_use = true;
+
+ display_resource_ctx->display_attributes = display_attributes;
+ display_resource_ctx->hw_block_id = hw_block_id;
+ display_resource_ctx->mixer_attributes = mixer_attributes;
+
+ *display_ctx = display_resource_ctx;
+ return error;
+}
+
+DisplayError ResourceDefault::UnregisterDisplay(Handle display_ctx) {
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+ Purge(display_ctx);
+
+ hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false;
+
+ delete display_resource_ctx;
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ReconfigureDisplay(Handle display_ctx,
+ const HWDisplayAttributes &display_attributes,
+ const HWPanelInfo &hw_panel_info,
+ const HWMixerAttributes &mixer_attributes) {
+ SCOPE_LOCK(locker_);
+
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+
+ display_resource_ctx->display_attributes = display_attributes;
+ display_resource_ctx->mixer_attributes = mixer_attributes;
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Start(Handle display_ctx) {
+ locker_.Lock();
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Stop(Handle display_ctx, HWLayers *hw_layers) {
+ locker_.Unlock();
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Prepare(Handle display_ctx, HWLayers *hw_layers) {
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+
+ DisplayError error = kErrorNone;
+ const struct HWLayersInfo &layer_info = hw_layers->info;
+ HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+
+ DLOGV_IF(kTagResources, "==== Resource reserving start: hw_block = %d ====", hw_block_id);
+
+ if (layer_info.hw_layers.size() > 1) {
+ DLOGV_IF(kTagResources, "More than one FB layers");
+ return kErrorResources;
+ }
+
+ const Layer &layer = layer_info.hw_layers.at(0);
+
+ if (layer.composition != kCompositionGPUTarget) {
+ DLOGV_IF(kTagResources, "Not an FB layer");
+ return kErrorParameters;
+ }
+
+ error = Config(display_resource_ctx, hw_layers);
+ if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "Resource config failed");
+ return error;
+ }
+
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerUserMode) {
+ src_pipes_[i].ResetState();
+ }
+ }
+
+ uint32_t left_index = num_pipe_;
+ uint32_t right_index = num_pipe_;
+ bool need_scale = false;
+
+ struct HWLayerConfig &layer_config = hw_layers->config[0];
+
+ HWPipeInfo *left_pipe = &layer_config.left_pipe;
+ HWPipeInfo *right_pipe = &layer_config.right_pipe;
+
+ // left pipe is needed
+ if (left_pipe->valid) {
+ need_scale = IsScalingNeeded(left_pipe);
+ left_index = GetPipe(hw_block_id, need_scale);
+ if (left_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "Get left pipe failed: hw_block_id = %d, need_scale = %d",
+ hw_block_id, need_scale);
+ ResourceStateLog();
+ goto CleanupOnError;
+ }
+ }
+
+ error = SetDecimationFactor(left_pipe);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ if (!right_pipe->valid) {
+ // assign single pipe
+ if (left_index < num_pipe_) {
+ left_pipe->pipe_id = src_pipes_[left_index].mdss_pipe_id;
+ }
+ DLOGV_IF(kTagResources, "1 pipe acquired for FB layer, left_pipe = %x", left_pipe->pipe_id);
+ return kErrorNone;
+ }
+
+ need_scale = IsScalingNeeded(right_pipe);
+
+ right_index = GetPipe(hw_block_id, need_scale);
+ if (right_index >= num_pipe_) {
+ DLOGV_IF(kTagResources, "Get right pipe failed: hw_block_id = %d, need_scale = %d", hw_block_id,
+ need_scale);
+ ResourceStateLog();
+ goto CleanupOnError;
+ }
+
+ if (src_pipes_[right_index].priority < src_pipes_[left_index].priority) {
+ // Swap pipe based on priority
+ std::swap(left_index, right_index);
+ }
+
+ // assign dual pipes
+ left_pipe->pipe_id = src_pipes_[left_index].mdss_pipe_id;
+ right_pipe->pipe_id = src_pipes_[right_index].mdss_pipe_id;
+
+ error = SetDecimationFactor(right_pipe);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
+
+ DLOGV_IF(kTagResources, "2 pipes acquired for FB layer, left_pipe = %x, right_pipe = %x",
+ left_pipe->pipe_id, right_pipe->pipe_id);
+
+ return kErrorNone;
+
+CleanupOnError:
+ DLOGV_IF(kTagResources, "Resource reserving failed! hw_block = %d", hw_block_id);
+
+ return kErrorResources;
+}
+
+DisplayError ResourceDefault::PostPrepare(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Commit(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+ HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+ uint64_t frame_count = display_resource_ctx->frame_count;
+
+ DLOGV_IF(kTagResources, "Resource for hw_block = %d, frame_count = %d", hw_block_id, frame_count);
+
+ // handoff pipes which are used by splash screen
+ if ((frame_count == 0) && (hw_block_id == kHWPrimary)) {
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerKernelMode) {
+ src_pipes_[i].owner = kPipeOwnerUserMode;
+ }
+ }
+ }
+
+ if (hw_layers->info.sync_handle >= 0)
+ Sys::close_(hw_layers->info.sync_handle);
+
+ display_resource_ctx->frame_count++;
+
+ return kErrorNone;
+}
+
+void ResourceDefault::Purge(Handle display_ctx) {
+ SCOPE_LOCK(locker_);
+
+ DisplayResourceContext *display_resource_ctx =
+ reinterpret_cast<DisplayResourceContext *>(display_ctx);
+ HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+
+ for (uint32_t i = 0; i < num_pipe_; i++) {
+ if (src_pipes_[i].hw_block_id == hw_block_id && src_pipes_[i].owner == kPipeOwnerUserMode) {
+ src_pipes_[i].ResetState();
+ }
+ }
+ DLOGV_IF(kTagResources, "display id = %d", display_resource_ctx->hw_block_id);
+}
+
+DisplayError ResourceDefault::SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) {
+ SCOPE_LOCK(locker_);
+
+ return kErrorNone;
+}
+
+uint32_t ResourceDefault::SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes,
+ uint32_t num_pipe) {
+ uint32_t index = num_pipe_;
+ SourcePipe *src_pipe;
+
+ // search the pipe being used
+ for (uint32_t i = 0; i < num_pipe; i++) {
+ src_pipe = &src_pipes[i];
+ if (src_pipe->owner == kPipeOwnerUserMode && src_pipe->hw_block_id == kHWBlockMax) {
+ index = src_pipe->index;
+ src_pipe->hw_block_id = hw_block_id;
+ break;
+ }
+ }
+
+ return index;
+}
+
+uint32_t ResourceDefault::NextPipe(PipeType type, HWBlockType hw_block_id) {
+ uint32_t num_pipe = 0;
+ SourcePipe *src_pipes = NULL;
+
+ switch (type) {
+ case kPipeTypeVIG:
+ src_pipes = &src_pipes_[0];
+ num_pipe = hw_res_info_.num_vig_pipe;
+ break;
+ case kPipeTypeRGB:
+ src_pipes = &src_pipes_[hw_res_info_.num_vig_pipe];
+ num_pipe = hw_res_info_.num_rgb_pipe;
+ break;
+ case kPipeTypeDMA:
+ default:
+ src_pipes = &src_pipes_[hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe];
+ num_pipe = hw_res_info_.num_dma_pipe;
+ break;
+ }
+
+ return SearchPipe(hw_block_id, src_pipes, num_pipe);
+}
+
+uint32_t ResourceDefault::GetPipe(HWBlockType hw_block_id, bool need_scale) {
+ uint32_t index = num_pipe_;
+
+ // The default behavior is to assume RGB and VG pipes have scalars
+ if (!need_scale) {
+ index = NextPipe(kPipeTypeDMA, hw_block_id);
+ }
+
+ if ((index >= num_pipe_) && (!need_scale || !hw_res_info_.has_non_scalar_rgb)) {
+ index = NextPipe(kPipeTypeRGB, hw_block_id);
+ }
+
+ if (index >= num_pipe_) {
+ index = NextPipe(kPipeTypeVIG, hw_block_id);
+ }
+
+ return index;
+}
+
+bool ResourceDefault::IsScalingNeeded(const HWPipeInfo *pipe_info) {
+ const LayerRect &src_roi = pipe_info->src_roi;
+ const LayerRect &dst_roi = pipe_info->dst_roi;
+
+ return ((dst_roi.right - dst_roi.left) != (src_roi.right - src_roi.left)) ||
+ ((dst_roi.bottom - dst_roi.top) != (src_roi.bottom - src_roi.top));
+}
+
+void ResourceDefault::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, hw_block = %d, owner = %s",
+ src_pipe->index, src_pipe->mdss_pipe_id, src_pipe->hw_block_id,
+ (src_pipe->owner == kPipeOwnerUserMode) ? "user mode" : "kernel mode");
+ }
+}
+
+DisplayError ResourceDefault::SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
+ HWLayerConfig *layer_config) {
+ 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;
+
+ // Layer cannot qualify for SrcSplit if source or destination width exceeds max pipe width.
+ if ((src_width > hw_res_info_.max_pipe_width) || (dst_width > hw_res_info_.max_pipe_width)) {
+ SplitRect(src_rect, dst_rect, &left_pipe->src_roi, &left_pipe->dst_roi, &right_pipe->src_roi,
+ &right_pipe->dst_roi);
+ left_pipe->valid = true;
+ right_pipe->valid = true;
+ } else {
+ left_pipe->src_roi = src_rect;
+ left_pipe->dst_roi = dst_rect;
+ left_pipe->valid = true;
+ right_pipe->Reset();
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
+ const LayerRect &src_rect, const LayerRect &dst_rect,
+ HWLayerConfig *layer_config) {
+ HWMixerAttributes &mixer_attributes = display_resource_ctx->mixer_attributes;
+
+ // for display split case
+ HWPipeInfo *left_pipe = &layer_config->left_pipe;
+ HWPipeInfo *right_pipe = &layer_config->right_pipe;
+ LayerRect scissor_left, scissor_right, dst_left, crop_left, crop_right, dst_right;
+
+ scissor_left.right = FLOAT(mixer_attributes.split_left);
+ scissor_left.bottom = FLOAT(mixer_attributes.height);
+
+ scissor_right.left = FLOAT(mixer_attributes.split_left);
+ scissor_right.top = 0.0f;
+ scissor_right.right = FLOAT(mixer_attributes.width);
+ scissor_right.bottom = FLOAT(mixer_attributes.height);
+
+ crop_left = src_rect;
+ dst_left = dst_rect;
+ crop_right = crop_left;
+ dst_right = dst_left;
+
+ bool crop_left_valid = CalculateCropRects(scissor_left, &crop_left, &dst_left);
+ bool crop_right_valid = false;
+
+ if (IsValid(scissor_right)) {
+ crop_right_valid = CalculateCropRects(scissor_right, &crop_right, &dst_right);
+ }
+
+ // Reset left_pipe and right_pipe to invalid by default
+ left_pipe->Reset();
+ right_pipe->Reset();
+
+ if (crop_left_valid) {
+ // assign left pipe
+ left_pipe->src_roi = crop_left;
+ left_pipe->dst_roi = dst_left;
+ left_pipe->valid = true;
+ }
+
+ // assign right pipe if needed
+ if (crop_right_valid) {
+ right_pipe->src_roi = crop_right;
+ right_pipe->dst_roi = dst_right;
+ right_pipe->valid = true;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::Config(DisplayResourceContext *display_resource_ctx,
+ HWLayers *hw_layers) {
+ HWLayersInfo &layer_info = hw_layers->info;
+ DisplayError error = kErrorNone;
+ const Layer &layer = layer_info.hw_layers.at(0);
+
+ error = ValidateLayerParams(&layer);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ struct HWLayerConfig *layer_config = &hw_layers->config[0];
+ HWPipeInfo &left_pipe = layer_config->left_pipe;
+ HWPipeInfo &right_pipe = layer_config->right_pipe;
+
+ LayerRect src_rect = layer.src_rect;
+ LayerRect dst_rect = layer.dst_rect;
+
+ error = ValidateDimensions(src_rect, dst_rect);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ BufferLayout layout = GetBufferLayout(layer.input_buffer.format);
+ error = ValidateScaling(src_rect, dst_rect, false /*rotated90 */, layout,
+ false /* use_rotator_downscale */);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ if (hw_res_info_.is_src_split) {
+ error = SrcSplitConfig(display_resource_ctx, src_rect, dst_rect, layer_config);
+ } else {
+ error = DisplaySplitConfig(display_resource_ctx, src_rect, dst_rect, layer_config);
+ }
+
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = AlignPipeConfig(&layer, &left_pipe, &right_pipe);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ // set z_order, left_pipe should always be valid
+ left_pipe.z_order = 0;
+
+ DLOGV_IF(kTagResources, "==== FB layer Config ====");
+ Log(kTagResources, "input layer src_rect", layer.src_rect);
+ Log(kTagResources, "input layer dst_rect", layer.dst_rect);
+ Log(kTagResources, "cropped src_rect", src_rect);
+ Log(kTagResources, "cropped dst_rect", dst_rect);
+ Log(kTagResources, "left pipe src", layer_config->left_pipe.src_roi);
+ Log(kTagResources, "left pipe dst", layer_config->left_pipe.dst_roi);
+ if (right_pipe.valid) {
+ right_pipe.z_order = 0;
+ Log(kTagResources, "right pipe src", layer_config->right_pipe.src_roi);
+ Log(kTagResources, "right pipe dst", layer_config->right_pipe.dst_roi);
+ }
+
+ return error;
+}
+
+bool ResourceDefault::CalculateCropRects(const LayerRect &scissor, LayerRect *crop,
+ LayerRect *dst) {
+ float &crop_left = crop->left;
+ float &crop_top = crop->top;
+ float &crop_right = crop->right;
+ float &crop_bottom = crop->bottom;
+ float crop_width = crop->right - crop->left;
+ float crop_height = crop->bottom - crop->top;
+
+ float &dst_left = dst->left;
+ float &dst_top = dst->top;
+ float &dst_right = dst->right;
+ float &dst_bottom = dst->bottom;
+ float dst_width = dst->right - dst->left;
+ float dst_height = dst->bottom - dst->top;
+
+ const float &sci_left = scissor.left;
+ const float &sci_top = scissor.top;
+ const float &sci_right = scissor.right;
+ const float &sci_bottom = scissor.bottom;
+
+ float left_cut_ratio = 0.0, right_cut_ratio = 0.0, top_cut_ratio = 0.0, bottom_cut_ratio = 0.0;
+ bool need_cut = false;
+
+ if (dst_left < sci_left) {
+ left_cut_ratio = (sci_left - dst_left) / dst_width;
+ dst_left = sci_left;
+ need_cut = true;
+ }
+
+ if (dst_right > sci_right) {
+ right_cut_ratio = (dst_right - sci_right) / dst_width;
+ dst_right = sci_right;
+ need_cut = true;
+ }
+
+ if (dst_top < sci_top) {
+ top_cut_ratio = (sci_top - dst_top) / (dst_height);
+ dst_top = sci_top;
+ need_cut = true;
+ }
+
+ if (dst_bottom > sci_bottom) {
+ bottom_cut_ratio = (dst_bottom - sci_bottom) / (dst_height);
+ dst_bottom = sci_bottom;
+ need_cut = true;
+ }
+
+ if (!need_cut)
+ return true;
+
+ crop_left += crop_width * left_cut_ratio;
+ crop_top += crop_height * top_cut_ratio;
+ crop_right -= crop_width * right_cut_ratio;
+ crop_bottom -= crop_height * bottom_cut_ratio;
+ Normalize(1, 1, crop);
+ Normalize(1, 1, dst);
+ if (IsValid(*crop) && IsValid(*dst))
+ return true;
+ else
+ return false;
+}
+
+DisplayError ResourceDefault::ValidateLayerParams(const Layer *layer) {
+ const LayerRect &src = layer->src_rect;
+ const LayerRect &dst = layer->dst_rect;
+ const LayerBuffer &input_buffer = layer->input_buffer;
+
+ if (input_buffer.format == kFormatInvalid) {
+ DLOGV_IF(kTagResources, "Invalid input buffer format %d", input_buffer.format);
+ return kErrorNotSupported;
+ }
+
+ if (!IsValid(src) || !IsValid(dst)) {
+ Log(kTagResources, "input layer src_rect", src);
+ Log(kTagResources, "input layer dst_rect", dst);
+ return kErrorNotSupported;
+ }
+
+ // Make sure source in integral only if it is a non secure layer.
+ if (!input_buffer.flags.secure &&
+ ((src.left - roundf(src.left) != 0.0f) ||
+ (src.top - roundf(src.top) != 0.0f) ||
+ (src.right - roundf(src.right) != 0.0f) ||
+ (src.bottom - roundf(src.bottom) != 0.0f))) {
+ DLOGV_IF(kTagResources, "Input ROI is not integral");
+ return kErrorNotSupported;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateDimensions(const LayerRect &crop, const LayerRect &dst) {
+ if (!IsValid(crop)) {
+ Log(kTagResources, "Invalid crop rect", crop);
+ return kErrorNotSupported;
+ }
+
+ if (!IsValid(dst)) {
+ Log(kTagResources, "Invalid dst rect", dst);
+ return kErrorNotSupported;
+ }
+
+ float crop_width = crop.right - crop.left;
+ float crop_height = crop.bottom - crop.top;
+ float dst_width = dst.right - dst.left;
+ float dst_height = dst.bottom - dst.top;
+
+ 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;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format) {
+ DisplayError error = kErrorNone;
+
+ const LayerRect &src_rect = pipe_info->src_roi;
+ const LayerRect &dst_rect = pipe_info->dst_roi;
+
+ error = ValidateDimensions(src_rect, dst_rect);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ BufferLayout layout = GetBufferLayout(format);
+ error = ValidateScaling(src_rect, dst_rect, false /* rotated90 */, layout,
+ false /* use_rotator_downscale */);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
+ bool rotate90, BufferLayout layout,
+ bool use_rotator_downscale) {
+ DisplayError error = kErrorNone;
+
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
+
+ error = GetScaleFactor(crop, dst, &scale_x, &scale_y);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = ValidateDownScaling(scale_x, scale_y, (layout != kLinear));
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = ValidateUpScaling(scale_x, scale_y);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateDownScaling(float scale_x, float scale_y, bool ubwc_tiled) {
+ if ((UINT32(scale_x) > 1) || (UINT32(scale_y) > 1)) {
+ float max_scale_down = FLOAT(hw_res_info_.max_scale_down);
+
+ // MDP H/W cannot apply decimation on UBWC tiled framebuffer
+ if (!ubwc_tiled && hw_res_info_.has_decimation) {
+ 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: scale_x = %.0f, scale_y = %.0f, " \
+ "has_deci = %d", scale_x, scale_y, hw_res_info_.has_decimation);
+ return kErrorNotSupported;
+ }
+ }
+
+ DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f", scale_x, scale_y);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::ValidateUpScaling(float scale_x, float scale_y) {
+ 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 = %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 = %f", 1.0f / scale_y);
+ return kErrorNotSupported;
+ }
+ }
+
+ DLOGV_IF(kTagResources, "scale_x = %.4f, scale_y = %.4f", scale_x, scale_y);
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::GetScaleFactor(const LayerRect &crop, const LayerRect &dst,
+ float *scale_x, float *scale_y) {
+ float crop_width = crop.right - crop.left;
+ float crop_height = crop.bottom - crop.top;
+ float dst_width = dst.right - dst.left;
+ float dst_height = dst.bottom - dst.top;
+
+ *scale_x = crop_width / dst_width;
+ *scale_y = crop_height / dst_height;
+
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::SetDecimationFactor(HWPipeInfo *pipe) {
+ 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;
+
+ float src_w = pipe->src_roi.right - pipe->src_roi.left;
+ 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;
+
+ if (CalculateDecimation(down_scale_w, &pipe->horizontal_decimation) != kErrorNone) {
+ return kErrorNotSupported;
+ }
+
+ 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);
+
+ return kErrorNone;
+}
+
+void ResourceDefault::SplitRect(const LayerRect &src_rect, const LayerRect &dst_rect,
+ LayerRect *src_left, LayerRect *dst_left, LayerRect *src_right,
+ LayerRect *dst_right) {
+ // 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, 1);
+ dst_width = ROUND_UP_ALIGN_DOWN(dst_width * src_width / src_width_ori, 1);
+
+ src_left->left = src_rect.left;
+ src_left->right = src_rect.left + src_width;
+ src_right->left = src_left->right;
+ src_right->right = src_rect.right;
+
+ src_left->top = src_rect.top;
+ src_left->bottom = src_rect.bottom;
+ src_right->top = src_rect.top;
+ src_right->bottom = src_rect.bottom;
+
+ dst_left->top = dst_rect.top;
+ dst_left->bottom = dst_rect.bottom;
+ dst_right->top = dst_rect.top;
+ dst_right->bottom = dst_rect.bottom;
+
+ dst_left->left = dst_rect.left;
+ dst_left->right = dst_rect.left + dst_width;
+ dst_right->left = dst_left->right;
+ dst_right->right = dst_rect.right;
+}
+
+DisplayError ResourceDefault::AlignPipeConfig(const Layer *layer, HWPipeInfo *left_pipe,
+ HWPipeInfo *right_pipe) {
+ DisplayError error = kErrorNone;
+ if (!left_pipe->valid) {
+ DLOGE_IF(kTagResources, "left_pipe should not be invalid");
+ return kErrorNotSupported;
+ }
+
+ error = ValidatePipeParams(left_pipe, layer->input_buffer.format);
+ if (error != kErrorNone) {
+ goto PipeConfigExit;
+ }
+
+ if (right_pipe->valid) {
+ // Make sure the left and right ROI are conjunct
+ right_pipe->src_roi.left = left_pipe->src_roi.right;
+ right_pipe->dst_roi.left = left_pipe->dst_roi.right;
+ error = ValidatePipeParams(right_pipe, layer->input_buffer.format);
+ }
+
+PipeConfigExit:
+ if (error != kErrorNone) {
+ DLOGV_IF(kTagResources, "AlignPipeConfig failed");
+ }
+ return error;
+}
+
+DisplayError ResourceDefault::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;
+}
+
+DisplayError ResourceDefault::ValidateCursorConfig(Handle display_ctx, const Layer *layer,
+ bool is_top) {
+ return kErrorNotSupported;
+}
+
+DisplayError ResourceDefault::ValidateAndSetCursorPosition(Handle display_ctx, HWLayers *hw_layers,
+ int x, int y,
+ DisplayConfigVariableInfo *fb_config) {
+ return kErrorNotSupported;
+}
+
+DisplayError ResourceDefault::SetMaxBandwidthMode(HWBwModes mode) {
+ return kErrorNotSupported;
+}
+
+DisplayError ResourceDefault::GetScaleLutConfig(HWScaleLutInfo *lut_info) {
+ return kErrorNone;
+}
+
+DisplayError ResourceDefault::SetDetailEnhancerData(Handle display_ctx,
+ const DisplayDetailEnhancerData &de_data) {
+ return kErrorNotSupported;
+}
+
+} // namespace sdm