blob: 5e7a637a2c0fab4d8ee248c3d1976f5cd52ae95d [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 <errno.h>
#include <gralloc_priv.h>
#include <utils/constants.h>
#include "hwc_display.h"
#include "hwc_logger.h"
#define __CLASS__ "HWCDisplay"
namespace sde {
HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
int id)
: core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL) {
}
int HWCDisplay::Init() {
DisplayError error = core_intf_->CreateDisplay(type_, this, &display_intf_);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("Display create failed. Error = %d", error);
return -EINVAL;
}
return 0;
}
int HWCDisplay::Deinit() {
DisplayError error = core_intf_->DestroyDisplay(display_intf_);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("Display destroy failed. Error = %d", error);
return -EINVAL;
}
if (LIKELY(layer_stack_memory_.raw)) {
delete[] layer_stack_memory_.raw;
}
return 0;
}
int HWCDisplay::EventControl(int event, int enable) {
DisplayError error = kErrorNone;
switch (event) {
case HWC_EVENT_VSYNC:
error = display_intf_->SetVSyncState(enable);
break;
case HWC_EVENT_ORIENTATION:
// TODO(user): Need to handle this case
break;
default:
DLOGW("Unsupported event = %d", event);
}
if (UNLIKELY(error != kErrorNone)) {
DLOGE("Failed. event = %d, enable = %d, error = %d", event, enable, error);
return -EINVAL;
}
return 0;
}
int HWCDisplay::Blank(int blank) {
DLOGI("blank = %d, display = %d", blank, id_);
DisplayState state = blank ? kStateOff : kStateOn;
return SetState(state);
}
int HWCDisplay::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
if (*num_configs > 0) {
configs[0] = 0;
*num_configs = 1;
}
return 0;
}
int HWCDisplay::GetDisplayAttributes(uint32_t config, const uint32_t *attributes, int32_t *values) {
DisplayError error = kErrorNone;
DisplayConfigVariableInfo variable_config;
error = display_intf_->GetConfig(&variable_config, config);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("GetConfig variable info failed. Error = %d", error);
return -EINVAL;
}
for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
switch (attributes[i]) {
case HWC_DISPLAY_VSYNC_PERIOD:
values[i] = variable_config.vsync_period_ns;
break;
case HWC_DISPLAY_WIDTH:
values[i] = variable_config.x_pixels;
break;
case HWC_DISPLAY_HEIGHT:
values[i] = variable_config.y_pixels;
break;
case HWC_DISPLAY_DPI_X:
values[i] = INT32(variable_config.x_dpi * 1000.0f);
break;
case HWC_DISPLAY_DPI_Y:
values[i] = INT32(variable_config.y_dpi * 1000.0f);
break;
case HWC_DISPLAY_SECURE:
values[i] = INT32(true); // For backward compatibility. All Physical displays are secure
break;
default:
DLOGW("Spurious attribute type = %d", attributes[i]);
return -EINVAL;
}
}
return 0;
}
int HWCDisplay::SetState(DisplayState state) {
DisplayError error = display_intf_->SetDisplayState(state);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("Set state failed. Error = %d", error);
return -EINVAL;
}
return 0;
}
DisplayError HWCDisplay::VSync(const DisplayEventVSync &vsync) {
if (*hwc_procs_) {
(*hwc_procs_)->vsync(*hwc_procs_, id_, vsync.timestamp);
}
return kErrorNone;
}
DisplayError HWCDisplay::Refresh() {
if (*hwc_procs_) {
(*hwc_procs_)->invalidate(*hwc_procs_);
}
return kErrorNone;
}
int HWCDisplay::AllocateLayerStack(hwc_display_contents_1_t *content_list) {
if (!content_list || !content_list->numHwLayers) {
DLOGW("Invalid content list");
return -EINVAL;
}
size_t num_hw_layers = content_list->numHwLayers;
// Allocate memory for a) total number of layers b) buffer handle for each layer c) number of
// visible rectangles in each layer d) dirty rectangle for each layer
size_t required_size = num_hw_layers * (sizeof(Layer) + sizeof(LayerBuffer));
for (size_t i = 0; i < num_hw_layers; i++) {
// visible rectangles + 1 dirty rectangle
size_t num_rects = content_list->hwLayers[i].visibleRegionScreen.numRects + 1;
required_size += num_rects * sizeof(LayerRect);
}
// Layer array may be large enough to hold current number of layers.
// If not, re-allocate it now.
if (UNLIKELY(layer_stack_memory_.size < required_size)) {
if (LIKELY(layer_stack_memory_.raw)) {
delete[] layer_stack_memory_.raw;
layer_stack_memory_.size = 0;
}
// Allocate in multiple of kSizeSteps.
required_size = ROUND_UP(required_size, layer_stack_memory_.kSizeSteps);
layer_stack_memory_.raw = new uint8_t[required_size];
if (UNLIKELY(!layer_stack_memory_.raw)) {
return -ENOMEM;
}
layer_stack_memory_.size = required_size;
}
// Assign memory addresses now.
uint8_t *current_address = layer_stack_memory_.raw;
// Layer array address
layer_stack_ = LayerStack();
layer_stack_.layers = reinterpret_cast<Layer *>(current_address);
layer_stack_.layer_count = static_cast<uint32_t>(num_hw_layers);
current_address += num_hw_layers * sizeof(Layer);
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer &layer = layer_stack_.layers[i];
layer = Layer();
// Layer buffer handle address
layer.input_buffer = reinterpret_cast<LayerBuffer *>(current_address);
*layer.input_buffer = LayerBuffer();
current_address += sizeof(LayerBuffer);
// Visible rectangle address
layer.visible_regions.rect = reinterpret_cast<LayerRect *>(current_address);
layer.visible_regions.count = static_cast<uint32_t>(hwc_layer.visibleRegionScreen.numRects);
for (size_t i = 0; i < layer.visible_regions.count; i++) {
*layer.visible_regions.rect = LayerRect();
}
current_address += hwc_layer.visibleRegionScreen.numRects * sizeof(LayerRect);
// Dirty rectangle address
layer.dirty_regions.rect = reinterpret_cast<LayerRect *>(current_address);
layer.dirty_regions.count = 1;
*layer.dirty_regions.rect = LayerRect();
current_address += sizeof(LayerRect);
}
return 0;
}
int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) {
if (!content_list || !content_list->numHwLayers) {
DLOGW("Invalid content list");
return -EINVAL;
}
size_t num_hw_layers = content_list->numHwLayers;
if (num_hw_layers <= 1) {
return 0;
}
// Configure each layer
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
Layer &layer = layer_stack_.layers[i];
LayerBuffer *layer_buffer = layer.input_buffer;
if (pvt_handle) {
if (SetFormat(pvt_handle->format, &layer_buffer->format)) {
return -EINVAL;
}
layer_buffer->width = pvt_handle->width;
layer_buffer->height = pvt_handle->height;
if (pvt_handle->bufferType == BUFFER_TYPE_VIDEO) {
layer_stack_.flags.video_present = true;
}
if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
layer_stack_.flags.secure_present = true;
}
}
SetRect(hwc_layer.displayFrame, &layer.dst_rect);
SetRect(hwc_layer.sourceCropf, &layer.src_rect);
for (size_t j = 0; j < hwc_layer.visibleRegionScreen.numRects; j++) {
SetRect(hwc_layer.visibleRegionScreen.rects[j], &layer.visible_regions.rect[j]);
}
SetRect(hwc_layer.dirtyRect, &layer.dirty_regions.rect[0]);
SetComposition(hwc_layer.compositionType, &layer.composition);
SetBlending(hwc_layer.blending, &layer.blending);
LayerTransform &layer_transform = layer.transform;
uint32_t &hwc_transform = hwc_layer.transform;
layer_transform.flip_horizontal = ((hwc_transform & HWC_TRANSFORM_FLIP_H) > 0);
layer_transform.flip_vertical = ((hwc_transform & HWC_TRANSFORM_FLIP_V) > 0);
layer_transform.rotation = ((hwc_transform & HWC_TRANSFORM_ROT_90) ? 90.0f : 0.0f);
layer.plane_alpha = hwc_layer.planeAlpha;
layer.flags.skip = ((hwc_layer.flags & HWC_SKIP_LAYER) > 0);
layer.flags.updating = (layer_stack_cache_.layer_cache[i].handle != hwc_layer.handle);
if (layer.flags.skip) {
layer_stack_.flags.skip_present = true;
}
}
// Configure layer stack
layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0);
DisplayError error = display_intf_->Prepare(&layer_stack_);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("Prepare failed. Error = %d", error);
return -EINVAL;
}
bool needs_fb_refresh = NeedsFrameBufferRefresh(content_list);
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer &layer = layer_stack_.layers[i];
LayerComposition composition = layer.composition;
// If current layer does not need frame buffer redraw, then mark it as HWC_OVERLAY
if (!needs_fb_refresh && (composition != kCompositionGPUTarget)) {
composition = kCompositionSDE;
}
SetComposition(composition, &hwc_layer.compositionType);
}
// Cache the current layer stack information like layer_count, composition type and layer handle
// for the future.
CacheLayerStackInfo(content_list);
return 0;
}
int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) {
if (!content_list || !content_list->numHwLayers) {
DLOGW("Invalid content list");
return -EINVAL;
}
size_t num_hw_layers = content_list->numHwLayers;
if (num_hw_layers <= 1) {
if (!num_hw_layers) {
return 0;
}
// TODO(user): handle if only 1 layer(fb target) is received.
int &acquireFenceFd = content_list->hwLayers[0].acquireFenceFd;
if (acquireFenceFd >= 0) {
close(acquireFenceFd);
}
return 0;
}
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
if (pvt_handle) {
layer_buffer->planes[0].fd = pvt_handle->fd;
layer_buffer->planes[0].offset = pvt_handle->offset;
layer_buffer->planes[0].stride = pvt_handle->width;
}
layer_buffer->acquire_fence_fd = hwc_layer.acquireFenceFd;
}
DisplayError error = display_intf_->Commit(&layer_stack_);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("Commit failed. Error = %d", error);
return -EINVAL;
}
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer &layer = layer_stack_.layers[i];
LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
if (layer.composition == kCompositionSDE || layer.composition == kCompositionGPUTarget) {
hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
}
if (hwc_layer.acquireFenceFd >= 0) {
close(hwc_layer.acquireFenceFd);
}
}
return 0;
}
bool HWCDisplay::NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list) {
uint32_t layer_count = layer_stack_.layer_count;
// Frame buffer needs to be refreshed for the following reasons:
// 1. Any layer is marked skip in the current layer stack.
// 2. Any layer is added/removed/layer properties changes in the current layer stack.
// 3. Any layer handle is changed and it is marked for GPU composition
// 4. Any layer's current composition is different from previous composition.
if ((layer_stack_cache_.layer_count != layer_count) || layer_stack_.flags.skip_present ||
layer_stack_.flags.geometry_changed) {
return true;
}
for (uint32_t i = 0; i < layer_count; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer &layer = layer_stack_.layers[i];
LayerCache &layer_cache = layer_stack_cache_.layer_cache[i];
if (layer.composition == kCompositionGPUTarget) {
continue;
}
if (layer_cache.composition != layer.composition) {
return true;
}
if ((layer.composition == kCompositionGPU) && (layer_cache.handle != hwc_layer.handle)) {
return true;
}
}
return false;
}
void HWCDisplay::CacheLayerStackInfo(hwc_display_contents_1_t *content_list) {
uint32_t layer_count = layer_stack_.layer_count;
for (uint32_t i = 0; i < layer_count; i++) {
Layer &layer = layer_stack_.layers[i];
if (layer.composition == kCompositionGPUTarget) {
continue;
}
layer_stack_cache_.layer_cache[i].handle = content_list->hwLayers[i].handle;
layer_stack_cache_.layer_cache[i].composition = layer.composition;
}
layer_stack_cache_.layer_count = layer_count;
}
void HWCDisplay::SetRect(const hwc_rect_t &source, LayerRect *target) {
target->left = FLOAT(source.left);
target->top = FLOAT(source.top);
target->right = FLOAT(source.right);
target->bottom = FLOAT(source.bottom);
}
void HWCDisplay::SetRect(const hwc_frect_t &source, LayerRect *target) {
target->left = source.left;
target->top = source.top;
target->right = source.right;
target->bottom = source.bottom;
}
void HWCDisplay::SetComposition(const int32_t &source, LayerComposition *target) {
switch (source) {
case HWC_FRAMEBUFFER_TARGET: *target = kCompositionGPUTarget; break;
default: *target = kCompositionSDE; break;
}
}
void HWCDisplay::SetComposition(const int32_t &source, int32_t *target) {
switch (source) {
case kCompositionGPUTarget: *target = HWC_FRAMEBUFFER_TARGET; break;
case kCompositionSDE: *target = HWC_OVERLAY; break;
default: *target = HWC_FRAMEBUFFER; break;
}
}
void HWCDisplay::SetBlending(const int32_t &source, LayerBlending *target) {
switch (source) {
case HWC_BLENDING_PREMULT: *target = kBlendingPremultiplied; break;
case HWC_BLENDING_COVERAGE: *target = kBlendingCoverage; break;
default: *target = kBlendingNone; break;
}
}
int HWCDisplay::SetFormat(const int32_t &source, LayerBufferFormat *target) {
switch (source) {
case HAL_PIXEL_FORMAT_RGBA_8888: *target = kFormatRGBA8888; break;
case HAL_PIXEL_FORMAT_BGRA_8888: *target = kFormatBGRA8888; break;
case HAL_PIXEL_FORMAT_RGBX_8888: *target = kFormatRGBX8888; break;
case HAL_PIXEL_FORMAT_BGRX_8888: *target = kFormatBGRX8888; break;
case HAL_PIXEL_FORMAT_RGB_888: *target = kFormatRGB888; break;
case HAL_PIXEL_FORMAT_RGB_565: *target = kFormatRGB565; break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: *target = kFormatYCbCr420SemiPlanarVenus; break;
default:
DLOGW("Unsupported format type = %d", source);
return -EINVAL;
}
return 0;
}
} // namespace sde