blob: 1d032bf3b530091836af051414796bbbb340953b [file] [log] [blame]
/*
* 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/constants.h>
#include <utils/debug.h>
#include "display_base.h"
#define __CLASS__ "DisplayBase"
namespace sde {
DisplayBase::DisplayBase(DisplayType display_type, DisplayEventHandler *event_handler,
HWDeviceType hw_device_type, HWInterface *hw_intf, CompManager *comp_manager)
: display_type_(display_type), event_handler_(event_handler), hw_device_type_(hw_device_type),
hw_intf_(hw_intf), comp_manager_(comp_manager), state_(kStateOff), hw_device_(0),
display_comp_ctx_(0), display_attributes_(NULL), num_modes_(0), active_mode_index_(0),
pending_commit_(false), vsync_enable_(false) {
}
DisplayError DisplayBase::Init() {
SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
error = hw_intf_->Open(hw_device_type_, &hw_device_, this);
if (error != kErrorNone) {
return error;
}
error = hw_intf_->GetNumDisplayAttributes(hw_device_, &num_modes_);
if (error != kErrorNone) {
goto CleanupOnError;
}
display_attributes_ = new HWDisplayAttributes[num_modes_];
if (!display_attributes_) {
error = kErrorMemory;
goto CleanupOnError;
}
for (uint32_t i = 0; i < num_modes_; i++) {
error = hw_intf_->GetDisplayAttributes(hw_device_, &display_attributes_[i], i);
if (error != kErrorNone) {
goto CleanupOnError;
}
}
active_mode_index_ = GetBestConfig();
error = hw_intf_->SetDisplayAttributes(hw_device_, active_mode_index_);
if (error != kErrorNone) {
goto CleanupOnError;
}
error = comp_manager_->RegisterDisplay(display_type_, display_attributes_[active_mode_index_],
&display_comp_ctx_);
if (error != kErrorNone) {
goto CleanupOnError;
}
return kErrorNone;
CleanupOnError:
comp_manager_->UnregisterDisplay(display_comp_ctx_);
if (display_attributes_) {
delete[] display_attributes_;
}
hw_intf_->Close(hw_device_);
return error;
}
DisplayError DisplayBase::Deinit() {
SCOPE_LOCK(locker_);
comp_manager_->UnregisterDisplay(display_comp_ctx_);
delete[] display_attributes_;
hw_intf_->Close(hw_device_);
return kErrorNone;
}
DisplayError DisplayBase::Prepare(LayerStack *layer_stack) {
SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
if (!layer_stack) {
return kErrorParameters;
}
pending_commit_ = false;
if ((state_ == kStateOn)) {
// Clean hw layers for reuse.
hw_layers_.info.Reset();
hw_layers_.info.stack = layer_stack;
while (true) {
error = comp_manager_->Prepare(display_comp_ctx_, &hw_layers_);
if (error != kErrorNone) {
break;
}
error = hw_intf_->Validate(hw_device_, &hw_layers_);
if (error == kErrorNone) {
// Strategy is successful now, wait for Commit().
comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
pending_commit_ = true;
break;
}
}
}
return error;
}
DisplayError DisplayBase::Commit(LayerStack *layer_stack) {
SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
if (!layer_stack) {
return kErrorParameters;
}
if (!pending_commit_) {
DLOGE("Commit: Corresponding Prepare() is not called.");
return kErrorUndefined;
}
if (state_ == kStateOn) {
error = hw_intf_->Commit(hw_device_, &hw_layers_);
if (error == kErrorNone) {
comp_manager_->PostCommit(display_comp_ctx_, &hw_layers_);
} else {
DLOGE("Unexpected error. Commit failed on driver.");
}
}
pending_commit_ = false;
return kErrorNone;
}
DisplayError DisplayBase::GetDisplayState(DisplayState *state) {
SCOPE_LOCK(locker_);
if (!state) {
return kErrorParameters;
}
*state = state_;
return kErrorNone;
}
DisplayError DisplayBase::GetNumVariableInfoConfigs(uint32_t *count) {
SCOPE_LOCK(locker_);
if (!count) {
return kErrorParameters;
}
*count = num_modes_;
return kErrorNone;
}
DisplayError DisplayBase::GetConfig(DisplayConfigFixedInfo *fixed_info) {
SCOPE_LOCK(locker_);
if (!fixed_info) {
return kErrorParameters;
}
return kErrorNone;
}
DisplayError DisplayBase::GetConfig(DisplayConfigVariableInfo *variable_info, uint32_t mode) {
SCOPE_LOCK(locker_);
if (!variable_info || mode >= num_modes_) {
return kErrorParameters;
}
*variable_info = display_attributes_[mode];
return kErrorNone;
}
DisplayError DisplayBase::GetVSyncState(bool *enabled) {
SCOPE_LOCK(locker_);
if (!enabled) {
return kErrorParameters;
}
return kErrorNone;
}
DisplayError DisplayBase::SetDisplayState(DisplayState state) {
SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
DLOGI("Set state = %d", state);
if (state == state_) {
DLOGI("Same state transition is requested.");
return kErrorNone;
}
switch (state) {
case kStateOff:
hw_layers_.info.count = 0;
comp_manager_->Purge(display_comp_ctx_);
error = hw_intf_->PowerOff(hw_device_);
break;
case kStateOn:
error = hw_intf_->PowerOn(hw_device_);
break;
case kStateDoze:
error = hw_intf_->Doze(hw_device_);
break;
case kStateStandby:
error = hw_intf_->Standby(hw_device_);
break;
default:
DLOGE("Spurious state = %d transition requested.", state);
break;
}
if (error == kErrorNone) {
state_ = state;
}
return error;
}
DisplayError DisplayBase::SetConfig(uint32_t mode) {
SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
if (mode >= num_modes_) {
return kErrorParameters;
}
error = hw_intf_->SetDisplayAttributes(hw_device_, mode);
return error;
}
DisplayError DisplayBase::SetVSyncState(bool enable) {
SCOPE_LOCK(locker_);
DisplayError error = kErrorNone;
if (vsync_enable_ != enable) {
error = hw_intf_->SetVSyncState(hw_device_, enable);
if (error == kErrorNone) {
vsync_enable_ = enable;
}
}
return error;
}
DisplayError DisplayBase::VSync(int64_t timestamp) {
if (vsync_enable_) {
DisplayEventVSync vsync;
vsync.timestamp = timestamp;
event_handler_->VSync(vsync);
}
return kErrorNone;
}
DisplayError DisplayBase::Blank(bool blank) {
return kErrorNone;
}
void DisplayBase::AppendDump(char *buffer, uint32_t length) {
SCOPE_LOCK(locker_);
AppendString(buffer, length, "\n-----------------------");
AppendString(buffer, length, "\ndevice type: %u", display_type_);
AppendString(buffer, length, "\nstate: %u, vsync on: %u", state_, INT(vsync_enable_));
AppendString(buffer, length, "\nnum configs: %u, active config index: %u",
num_modes_, active_mode_index_);
DisplayConfigVariableInfo &info = display_attributes_[active_mode_index_];
AppendString(buffer, length, "\nres:%ux%u, dpi:%.2fx%.2f, fps:%.2f, vsync period: %u",
info.x_pixels, info.y_pixels, info.x_dpi, info.y_dpi, info.fps, info.vsync_period_ns);
uint32_t num_layers = 0;
uint32_t num_hw_layers = 0;
if (hw_layers_.info.stack) {
num_layers = hw_layers_.info.stack->layer_count;
num_hw_layers = hw_layers_.info.count;
}
AppendString(buffer, length, "\n\nnum actual layers: %u, num sde layers: %u",
num_layers, num_hw_layers);
for (uint32_t i = 0; i < num_hw_layers; i++) {
Layer &layer = hw_layers_.info.stack->layers[i];
LayerBuffer *input_buffer = layer.input_buffer;
HWLayerConfig &layer_config = hw_layers_.config[i];
HWPipeInfo &left_pipe = hw_layers_.config[i].left_pipe;
HWPipeInfo &right_pipe = hw_layers_.config[i].right_pipe;
AppendString(buffer, length, "\n\nsde idx: %u, actual idx: %u", i, hw_layers_.info.index[i]);
AppendString(buffer, length, "\nw: %u, h: %u, fmt: %u",
input_buffer->width, input_buffer->height, input_buffer->format);
AppendRect(buffer, length, "\nsrc_rect:", &layer.src_rect);
AppendRect(buffer, length, "\ndst_rect:", &layer.dst_rect);
AppendString(buffer, length, "\n\tleft split =>");
AppendString(buffer, length, "\n\t pipe id: 0x%x", left_pipe.pipe_id);
AppendRect(buffer, length, "\n\t src_roi:", &left_pipe.src_roi);
AppendRect(buffer, length, "\n\t dst_roi:", &left_pipe.dst_roi);
if (layer_config.is_right_pipe) {
AppendString(buffer, length, "\n\tright split =>");
AppendString(buffer, length, "\n\t pipe id: 0x%x", right_pipe.pipe_id);
AppendRect(buffer, length, "\n\t src_roi:", &right_pipe.src_roi);
AppendRect(buffer, length, "\n\t dst_roi:", &right_pipe.dst_roi);
}
}
}
void DisplayBase::AppendRect(char *buffer, uint32_t length, const char *rect_name,
LayerRect *rect) {
AppendString(buffer, length, "%s %.1f, %.1f, %.1f, %.1f",
rect_name, rect->left, rect->top, rect->right, rect->bottom);
}
int DisplayBase::GetBestConfig() {
return (num_modes_ == 1) ? 0 : -1;
}
} // namespace sde