blob: 8ed16afdbad705a124c37518a29cb4f64b86024b [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cutils/log.h>
#include <tegra_dc_ext.h>
#include <tegrafb.h>
#include <tegra_adf.h>
#include <android-base/macros.h>
#include <sstream>
#include "hwc2.h"
static bool operator==(const hwc_rect_t &r1, const hwc_rect_t &r2)
{
return r1.left == r2.left && r1.top == r2.top && r1.right == r2.right
&& r1.bottom == r2.bottom;
}
static bool operator!=(const hwc_rect_t &r1, const hwc_rect_t &r2)
{
return !(r1 == r2);
}
static bool operator==(const hwc_frect_t &r1, const hwc_frect_t &r2)
{
return r1.left == r2.left && r1.top == r2.top && r1.right == r2.right
&& r1.bottom == r2.bottom;
}
static bool operator!=(const hwc_frect_t &r1, const hwc_frect_t &r2)
{
return !(r1 == r2);
}
static bool cmp_region(std::vector<hwc_rect_t> &r1, const hwc_region_t &r2)
{
if (r1.size() != r2.numRects)
return false;
return std::equal(r1.begin(), r1.end(), r2.rects);
}
hwc2_buffer::hwc2_buffer()
: handle(),
acquire_fence(-1),
dataspace(),
display_frame(),
source_crop(),
z_order(0),
surface_damage(),
blend_mode(HWC2_BLEND_MODE_NONE),
plane_alpha(1.0),
transform(),
visible_region(),
previous_format(0),
modified(true) { }
hwc2_buffer::~hwc2_buffer()
{
close_acquire_fence();
}
std::string hwc2_buffer::dump() const
{
std::stringstream dmp;
dmp << " Buffer: " << std::hex << handle << "/" << std::dec
<< acquire_fence << " Z: " << z_order << "\n";
dmp << " Display Frame: [" << display_frame.left << ", "
<< display_frame.top << ", " << display_frame.right << ", "
<< display_frame.bottom << "]\n";
dmp << " Source Crop: [" << source_crop.left << ", "
<< source_crop.top << ", " << source_crop.right << ", "
<< source_crop.bottom << "]\n";
dmp << " Transform: " << getTransformName(transform)
<< " Blend Mode: " << getBlendModeName(blend_mode);
if (plane_alpha != 1.0f)
dmp << " Alpha: " << plane_alpha;
dmp << "\n";
return dmp.str();
}
hwc2_error_t hwc2_buffer::decompress()
{
int ret = hwc2_gralloc::get_instance().decompress(handle, acquire_fence,
&acquire_fence);
if (ret < 0) {
ALOGE("failed to decompress buffer: %s", strerror(ret));
return HWC2_ERROR_NO_RESOURCES;
}
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::get_adf_post_props(
struct tegra_adf_flip_windowattr *win_attr,
struct adf_buffer_config *adf_buf, size_t win_idx,
size_t buf_idx, uint32_t z_order) const
{
if (!hwc2_gralloc::get_instance().is_valid(handle)) {
ALOGE("invalid buffer handle");
return HWC2_ERROR_NO_RESOURCES;
}
hwc2_error_t ret = get_adf_buf_config(adf_buf);
if (ret != HWC2_ERROR_NONE) {
ALOGE("failed to set adf buf configs");
return ret;
}
ret = get_adf_win_attr(win_attr, win_idx, buf_idx, z_order);
if (ret != HWC2_ERROR_NONE) {
ALOGE("failed to set win attr");
return ret;
}
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::get_adf_buf_config(
struct adf_buffer_config *adf_buf) const
{
const hwc2_gralloc& gralloc = hwc2_gralloc::get_instance();
adf_buf->overlay_engine = 0;
adf_buf->w = (uint32_t) (ceil(source_crop.right) - ceil(source_crop.left));
adf_buf->h = (uint32_t) (ceil(source_crop.bottom) - ceil(source_crop.top));
adf_buf->format = gralloc.get_format(handle);
const void *surf;
size_t surf_cnt;
gralloc.get_surfaces(handle, &surf, &surf_cnt);
if (!surf || surf_cnt == 0) {
ALOGE("failed to get surfaces");
return HWC2_ERROR_NO_RESOURCES;
}
adf_buf->n_planes = surf_cnt;
int fd;
gralloc.get_dma_buf(surf, 0, &fd);
for (size_t idx = 0; idx < arraysize(adf_buf->fd); idx++) {
if (idx < adf_buf->n_planes)
adf_buf->fd[idx] = fd;
else
adf_buf->fd[idx] = -1;
}
adf_buf->pitch[0] = gralloc.get_pitch(surf, 0);
adf_buf->offset[0] = gralloc.get_offset(surf, 0);
if (surf_cnt == 1) {
adf_buf->pitch[1] = 0;
adf_buf->pitch[2] = 0;
adf_buf->offset[1] = 0;
adf_buf->offset[2] = 0;
} else {
switch (surf_cnt) {
case 2:
adf_buf->pitch[1] = gralloc.get_pitch(surf, 1);
adf_buf->pitch[2] = gralloc.get_pitch(surf, 1);
adf_buf->offset[1] = gralloc.get_offset(surf, 1);
adf_buf->offset[2] = 0;
break;
case 3:
adf_buf->pitch[1] = gralloc.get_pitch(surf, 1);
adf_buf->pitch[2] = gralloc.get_pitch(surf, 1);
adf_buf->offset[1] = gralloc.get_offset(surf, 1);
adf_buf->offset[2] = gralloc.get_offset(surf, 2);
break;
default:
LOG_ALWAYS_FATAL("Invalid surface count. There must be between 1 to"
" 3 surfaces per buffer.");
break;
}
}
adf_buf->acquire_fence = acquire_fence;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::get_adf_win_attr(
struct tegra_adf_flip_windowattr *win_attr, size_t win_idx,
size_t buf_idx, uint32_t z_order) const
{
const hwc2_gralloc& gralloc = hwc2_gralloc::get_instance();
const void *surf;
size_t surf_cnt;
uint32_t layout;
win_attr->win_index = win_idx;
win_attr->buf_index = buf_idx;
switch (blend_mode) {
case HWC2_BLEND_MODE_PREMULTIPLIED:
win_attr->blend = TEGRA_ADF_BLEND_PREMULT;
break;
case HWC2_BLEND_MODE_COVERAGE:
win_attr->blend = TEGRA_ADF_BLEND_COVERAGE;
break;
case HWC2_BLEND_MODE_NONE:
win_attr->blend = TEGRA_ADF_BLEND_NONE;
break;
default:
ALOGW("invalid blend mode %d", blend_mode);
win_attr->blend = TEGRA_ADF_BLEND_NONE;
}
win_attr->x = ((uint32_t) ceil(source_crop.left)) << 12;
win_attr->y = ((uint32_t) ceil(source_crop.top)) << 12;
win_attr->out_x = display_frame.left;
win_attr->out_y = display_frame.top;
win_attr->out_w = display_frame.right - display_frame.left;
win_attr->out_h = display_frame.bottom - display_frame.top;
win_attr->z = z_order;
win_attr->flags = 0;
gralloc.get_surfaces(handle, &surf, &surf_cnt);
if (!surf || surf_cnt == 0) {
ALOGE("failed to get surfaces");
return HWC2_ERROR_NO_RESOURCES;
}
layout = gralloc.get_layout(surf, 0);
if (layout == HWC2_WINDOW_CAP_TILED)
win_attr->flags |= TEGRA_FB_WIN_FLAG_TILED;
if (layout == HWC2_WINDOW_CAP_BLOCK_LINEAR) {
win_attr->flags |= TEGRA_DC_EXT_FLIP_FLAG_BLOCKLINEAR;
win_attr->block_height_log2 = gralloc.get_block_height_log2(surf, 0);
}
win_attr->flags |= TEGRA_DC_EXT_FLIP_FLAG_GLOBAL_ALPHA;
win_attr->global_alpha = (uint8_t) (plane_alpha * 0xFF);
if (transform & HWC_TRANSFORM_FLIP_H)
win_attr->flags |= TEGRA_DC_EXT_FLIP_FLAG_INVERT_H;
if (transform & HWC_TRANSFORM_FLIP_V)
win_attr->flags |= TEGRA_DC_EXT_FLIP_FLAG_INVERT_V;
if (transform & HWC_TRANSFORM_ROT_90) {
win_attr->flags |= TEGRA_DC_EXT_FLIP_FLAG_SCAN_COLUMN;
win_attr->flags ^= TEGRA_DC_EXT_FLIP_FLAG_INVERT_V;
}
return HWC2_ERROR_NONE;
}
void hwc2_buffer::close_acquire_fence()
{
if (acquire_fence >= 0) {
close(acquire_fence);
acquire_fence = -1;
}
}
uint32_t hwc2_buffer::get_adf_buffer_format() const
{
if (!handle)
return 0;
return hwc2_gralloc::get_instance().get_format(handle);
}
uint32_t hwc2_buffer::get_layout() const
{
const hwc2_gralloc &gralloc = hwc2_gralloc::get_instance();
const void *surf;
size_t surf_cnt;
if (!handle)
return 0;
gralloc.get_surfaces(handle, &surf, &surf_cnt);
return gralloc.get_layout(surf, 0);
}
int hwc2_buffer::get_display_frame_width() const
{
return display_frame.right - display_frame.left;
}
int hwc2_buffer::get_display_frame_height() const
{
return display_frame.bottom - display_frame.top;
}
float hwc2_buffer::get_source_crop_width() const
{
return source_crop.right - source_crop.left;
}
float hwc2_buffer::get_source_crop_height() const
{
return source_crop.bottom - source_crop.top;
}
float hwc2_buffer::get_scale_width() const
{
float source_crop_width = get_source_crop_width();
if (source_crop_width == 0)
return -1.0;
return get_display_frame_width() / source_crop_width;
}
float hwc2_buffer::get_scale_height() const
{
float source_crop_height = get_source_crop_height();
if (source_crop_height == 0)
return -1.0;
return get_display_frame_height() / source_crop_height;
}
void hwc2_buffer::get_surfaces(const void **surf, size_t *surf_cnt) const
{
if (!handle)
*surf_cnt = 0;
else
hwc2_gralloc::get_instance().get_surfaces(handle, surf, surf_cnt);
}
bool hwc2_buffer::is_source_crop_int_aligned() const
{
return (source_crop.left == ceil(source_crop.left)
&& source_crop.top == ceil(source_crop.top)
&& source_crop.right == ceil(source_crop.right)
&& source_crop.bottom == ceil(source_crop.bottom));
}
bool hwc2_buffer::is_stereo() const
{
if (!handle)
return false;
return hwc2_gralloc::get_instance().is_stereo(handle);
}
bool hwc2_buffer::is_yuv() const
{
if (!handle)
return false;
return hwc2_gralloc::get_instance().is_yuv(handle);
}
bool hwc2_buffer::is_overlapped() const
{
if (visible_region.size() != 1)
return true;
if (visible_region.at(0).left != display_frame.left
|| visible_region.at(0).top != display_frame.top
|| visible_region.at(0).right != display_frame.right
|| visible_region.at(0).bottom != display_frame.bottom)
return true;
return false;
}
hwc2_error_t hwc2_buffer::set_buffer(buffer_handle_t handle,
int32_t acquire_fence)
{
/* Only check if non-null buffers are valid. Layer buffers are determined to
* be non-null in hwc2_layer. Client target buffers can be null and should
* not produce an error. */
if (handle && !hwc2_gralloc::get_instance().is_valid(handle)) {
ALOGE("invalid buffer handle");
return HWC2_ERROR_BAD_PARAMETER;
}
close_acquire_fence();
this->handle = handle;
this->acquire_fence = acquire_fence;
uint32_t format = get_adf_buffer_format();
modified = modified || format != previous_format;
previous_format = format;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_dataspace(android_dataspace_t dataspace)
{
modified = modified || dataspace != this->dataspace;
this->dataspace = dataspace;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_display_frame(const hwc_rect_t &display_frame)
{
modified = modified || display_frame != this->display_frame;
this->display_frame = display_frame;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_source_crop(const hwc_frect_t &source_crop)
{
modified = modified || source_crop != this->source_crop;
this->source_crop = source_crop;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_z_order(uint32_t z_order)
{
modified = modified || z_order != this->z_order;
this->z_order = z_order;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_surface_damage(const hwc_region_t &surface_damage)
{
this->surface_damage.clear();
for (size_t idx = 0; idx < surface_damage.numRects; idx++)
this->surface_damage.push_back(surface_damage.rects[idx]);
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_blend_mode(hwc2_blend_mode_t blend_mode)
{
if (blend_mode == HWC2_BLEND_MODE_INVALID) {
ALOGE("invalid blend mode");
return HWC2_ERROR_BAD_PARAMETER;
}
modified = modified || blend_mode != this->blend_mode;
this->blend_mode = blend_mode;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_plane_alpha(float plane_alpha)
{
modified = modified || plane_alpha != this->plane_alpha;
this->plane_alpha = plane_alpha;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_transform(const hwc_transform_t transform)
{
modified = modified || transform != this->transform;
this->transform = transform;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_buffer::set_visible_region(const hwc_region_t &visible_region)
{
modified = modified || !cmp_region(this->visible_region, visible_region);
this->visible_region.clear();
for (size_t idx = 0; idx < visible_region.numRects; idx++)
this->visible_region.push_back(visible_region.rects[idx]);
return HWC2_ERROR_NONE;
}