blob: 707dca9c357cbe903a1bf547840cbaa5247db184 [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_adf.h>
#include <inttypes.h>
#include <sstream>
#include <cstdlib>
#include <map>
#include <vector>
#include <array>
#include "hwc2.h"
uint64_t hwc2_display::display_cnt = 0;
hwc2_display::hwc2_display(hwc2_display_t id, int adf_intf_fd,
const struct adf_device &adf_dev, hwc2_connection_t connection,
hwc2_display_type_t type, hwc2_power_mode_t power_mode)
: id(id),
name(),
connection(connection),
type(type),
display_state(modified),
client_target_used(false),
windows(),
client_target(),
layers(),
vsync_enabled(HWC2_VSYNC_DISABLE),
changed_comp_types(),
configs(),
active_config(0),
power_mode(power_mode),
color_matrix(),
color_hint(HAL_COLOR_TRANSFORM_IDENTITY),
release_fence(-1),
adf_intf_fd(adf_intf_fd),
adf_dev(adf_dev)
{
init_name();
init_windows();
}
hwc2_display::~hwc2_display()
{
close(adf_intf_fd);
adf_device_close(&adf_dev);
}
std::string hwc2_display::dump() const
{
std::stringstream dmp;
dmp << "Display [" << id << "] " << getDisplayTypeName(type) << ":\n";
dmp << " Power Mode: " << getPowerModeName(power_mode) << "\n";
dmp << " Active Config:";
auto it = configs.begin();
if (configs.size() > 0 || it != configs.end())
dmp << "\n" << configs.at(active_config).dump();
else
dmp << " None\n";
if (power_mode == HWC2_POWER_MODE_OFF)
return dmp.str();
size_t idx = 0;
for (auto &win: windows) {
dmp << " Window [" << idx << "]:";
if (win.contains_layer()) {
dmp << " Layer\n";
dmp << layers.at(win.get_layer()).dump();
} else if (win.contains_client_target()) {
dmp << " Client Target\n";
dmp << client_target.dump();
} else
dmp << " Unused\n";
idx++;
}
return dmp.str();
}
hwc2_error_t hwc2_display::set_connection(hwc2_connection_t connection)
{
if (connection == HWC2_CONNECTION_INVALID) {
ALOGE("dpy %" PRIu64 ": invalid connection", id);
return HWC2_ERROR_BAD_PARAMETER;
}
display_state = modified;
this->connection = connection;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::get_name(uint32_t *out_size, char *out_name) const
{
if (!out_name) {
*out_size = name.size();
return HWC2_ERROR_NONE;
}
/* out_name does not require a NULL terminator so strncpy can truncate
* the output safely */
strncpy(out_name, name.c_str(), *out_size);
*out_size = (*out_size < name.size())? *out_size: name.size();
return HWC2_ERROR_NONE;
}
void hwc2_display::init_name()
{
name.append("dpy-");
if (HWC2_DISPLAY_TYPE_PHYSICAL)
name.append("phys-");
else
name.append("virt-");
name.append(std::to_string(id));
}
hwc2_error_t hwc2_display::set_power_mode(hwc2_power_mode_t mode)
{
int drm_mode;
switch (mode) {
case HWC2_POWER_MODE_ON:
drm_mode = DRM_MODE_DPMS_ON;
break;
case HWC2_POWER_MODE_OFF:
drm_mode = DRM_MODE_DPMS_OFF;
break;
case HWC2_POWER_MODE_DOZE:
case HWC2_POWER_MODE_DOZE_SUSPEND:
ALOGE("dpy %" PRIu64 ": unsupported power mode: %u", id, mode);
return HWC2_ERROR_UNSUPPORTED;
default:
ALOGE("dpy %" PRIu64 ": invalid power mode: %u", id, mode);
return HWC2_ERROR_BAD_PARAMETER;
}
adf_interface_blank(adf_intf_fd, drm_mode);
power_mode = mode;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::get_doze_support(int32_t *out_support) const
{
*out_support = 0;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_vsync_enabled(hwc2_vsync_t enabled)
{
if (enabled == HWC2_VSYNC_INVALID) {
ALOGE("dpy %" PRIu64 ": invalid vsync enabled", id);
return HWC2_ERROR_BAD_PARAMETER;
}
this->vsync_enabled = enabled;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::validate_display(uint32_t *out_num_types,
uint32_t *out_num_requests)
{
if (display_state == valid) {
*out_num_types = 0;
*out_num_requests = 0;
return HWC2_ERROR_NONE;
}
clear_windows();
changed_comp_types.clear();
if (color_hint != HAL_COLOR_TRANSFORM_IDENTITY)
force_client_composition();
else
assign_composition();
*out_num_requests = 0;
*out_num_types = changed_comp_types.size();
for (auto &lyr: layers)
lyr.second.set_modified(false);
if (*out_num_types > 0) {
display_state = invalid;
return HWC2_ERROR_HAS_CHANGES;
}
display_state = valid;
return HWC2_ERROR_NONE;
}
void hwc2_display::force_client_composition()
{
for (auto &lyr: layers) {
hwc2_composition_t comp_type = lyr.second.get_comp_type();
if (comp_type != HWC2_COMPOSITION_CLIENT)
changed_comp_types.emplace(lyr.second.get_id(), comp_type);
}
}
void hwc2_display::assign_composition()
{
hwc2_error_t ret;
std::map<uint32_t, hwc2_layer_t> ordered_layers;
for (auto &lyr: layers)
ordered_layers.emplace(lyr.second.get_z_order(), lyr.second.get_id());
bool client_target_assigned = false;
/* If there will definitely be a client target, assign it to the front most
* window */
if (layers.size() > windows.size()) {
ret = assign_client_target_window(0);
ALOG_ASSERT(ret == HWC2_ERROR_NONE, "No valid client target window");
client_target_assigned = true;
}
bool retry_assignment;
do {
retry_assignment = false;
/* The display controller uses a different z order than SurfaceFlinger */
uint32_t z_order = windows.size() - 1;
client_target_used = false;
/* Iterate over the layers from the back to the front.
* assign windows to device layers. Upon reaching a layer that must
* be composed by the client all subsequent layers will be assigned
* client composition */
for (auto &ordered_layer: ordered_layers) {
hwc2_layer_t lyr_id = ordered_layer.second;
hwc2_composition_t comp_type = layers.find(
lyr_id)->second.get_comp_type();
if (comp_type == HWC2_COMPOSITION_INVALID) {
ALOGW("dpy %" PRIu64 " lyr %" PRIu64 ": invalid composition"
" type %u", id, lyr_id, comp_type);
continue;
}
/* If the layer is not overlapped and can be assigned a window,
assign it and continue to the next layer */
if (comp_type == HWC2_COMPOSITION_DEVICE && !client_target_used
&& assign_layer_window(z_order, lyr_id) == HWC2_ERROR_NONE) {
z_order--;
continue;
}
/* The layer will be composited into a client target buffer so
* find a window for the client target */
if (!client_target_assigned) {
ret = assign_client_target_window(0);
if (ret != HWC2_ERROR_NONE) {
/* If no client target can be assigned, clear all the
* windows, assign a client target and retry assigning
* windows */
retry_assignment = true;
changed_comp_types.clear();
clear_windows();
ret = assign_client_target_window(0);
ALOG_ASSERT(ret == HWC2_ERROR_NONE, "No valid client target"
" window");
client_target_assigned = true;
break;
}
client_target_assigned = true;
}
/* Assign the layer to client composition */
if (comp_type != HWC2_COMPOSITION_CLIENT)
changed_comp_types.emplace(lyr_id, HWC2_COMPOSITION_CLIENT);
client_target_used = true;
}
} while (retry_assignment);
}
hwc2_error_t hwc2_display::get_changed_composition_types(
uint32_t *out_num_elements, hwc2_layer_t *out_layers,
hwc2_composition_t *out_types) const
{
if (display_state == modified) {
ALOGE("dpy %" PRIu64 ": display has been modified since last call to"
" validate_display", id);
return HWC2_ERROR_NOT_VALIDATED;
}
if (!out_layers || !out_types) {
*out_num_elements = changed_comp_types.size();
return HWC2_ERROR_NONE;
}
size_t idx = 0;
for (auto &changed: changed_comp_types) {
out_layers[idx] = changed.first;
out_types[idx] = changed.second;
idx++;
}
*out_num_elements = changed_comp_types.size();
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::get_display_requests(
hwc2_display_request_t *out_display_requests,
uint32_t *out_num_elements, hwc2_layer_t* /*out_layers*/,
hwc2_layer_request_t* /*out_layer_requests*/) const
{
if (display_state == modified) {
ALOGE("dpy %" PRIu64 ": display has been modified since last call to"
" validate_display", id);
return HWC2_ERROR_NOT_VALIDATED;
}
*out_display_requests = static_cast<hwc2_display_request_t>(0);
*out_num_elements = 0;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::accept_display_changes()
{
if (display_state == modified) {
ALOGE("dpy %" PRIu64 ": display has been modified since last call to"
" validate_display", id);
return HWC2_ERROR_NOT_VALIDATED;
}
for (auto &changed: changed_comp_types)
layers.find(changed.first)->second.set_comp_type(changed.second);
display_state = valid;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::present_display(int32_t *out_present_fence)
{
std::vector<struct adf_buffer_config> adf_bufs(windows.size());
std::array<adf_id_t, 1> interfaces = {{0}};
int new_release_fence = -1, err;
hwc2_error_t ret = prepare_present_display();
if (ret != HWC2_ERROR_NONE) {
ALOGE("dpy %" PRIu64 ": failed to prepare display for presenting", id);
*out_present_fence = -1;
return ret;
}
tegra_adf_flip *args;
size_t args_size = sizeof(*args) + windows.size() * sizeof(args->win[0]);
args = static_cast<tegra_adf_flip *>(calloc(1, args_size));
if (!args) {
ALOGE("dpy %" PRIu64 ": failed to alloc tegra_adf_flip", id);
*out_present_fence = -1;
return HWC2_ERROR_NO_RESOURCES;
}
args->win_num = windows.size();
size_t win_idx = 0, buf_idx = 0;
for (auto &win: windows) {
if (win.contains_client_target()) {
ret = client_target.get_adf_post_props(&args->win[win_idx],
&adf_bufs[buf_idx], win_idx, buf_idx, win.get_z_order());
if (ret != HWC2_ERROR_NONE) {
ALOGE("dpy %" PRIu64 ": failed to get client target adf props", id);
goto done;
}
buf_idx++;
} else if (win.contains_layer()) {
hwc2_layer_t lyr_id = win.get_layer();
ret = layers.find(lyr_id)->second.get_adf_post_props(
&args->win[win_idx], &adf_bufs[buf_idx], win_idx,
buf_idx, win.get_z_order());
if (ret != HWC2_ERROR_NONE) {
ALOGE("dpy %" PRIu64 " lyr %" PRIu64 ": failed to get layer adf"
" props", id, lyr_id);
goto done;
}
buf_idx++;
} else {
struct tegra_adf_flip_windowattr *win_attr = &args->win[win_idx];
win_attr->win_index = win_idx;
win_attr->buf_index = -1;
win_attr->z = win.get_z_order();
win_attr->blend = TEGRA_ADF_BLEND_NONE;
win_attr->flags = 0;
}
win_idx++;
}
err = adf_device_post_v2(&adf_dev, interfaces.data(), interfaces.size(),
adf_bufs.data(), buf_idx, args, args_size, ADF_COMPLETE_FENCE_PRESENT,
&new_release_fence);
if (err < 0) {
ALOGE("dpy %" PRIu64 ": adf_device_post_v2 failed %s", id, strerror(err));
err = HWC2_ERROR_NO_RESOURCES;
new_release_fence = -1;
}
release_fence.reset(new_release_fence);
close_acquire_fences();
for (size_t idx = 0; idx < buf_idx; idx++)
if (adf_bufs[idx].fd[0] >= 0)
close(adf_bufs[idx].fd[0]);
done:
free(args);
*out_present_fence = dup(release_fence.get());
return ret;
}
hwc2_error_t hwc2_display::prepare_present_display()
{
if (display_state != valid) {
ALOGE("dpy %" PRIu64 ": display not validated: %d", id, display_state);
return HWC2_ERROR_NOT_VALIDATED;
}
if (connection != HWC2_CONNECTION_CONNECTED) {
ALOGW("dpy %" PRIu64 ": invalid connection: %d", id, connection);
return HWC2_ERROR_BAD_DISPLAY;
}
if (power_mode == HWC2_POWER_MODE_OFF) {
ALOGW("dpy %" PRIu64 ": invalid power mode: %d", id, power_mode);
return HWC2_ERROR_BAD_DISPLAY;
}
hwc2_error_t ret = decompress_window_buffers();
if (ret != HWC2_ERROR_NONE) {
ALOGE("dpy %" PRIu64 ": failed to decompress buffers", id);
return ret;
}
return HWC2_ERROR_NONE;
}
void hwc2_display::close_acquire_fences()
{
for (auto &lyr: layers)
lyr.second.close_acquire_fence();
if (client_target_used)
client_target.close_acquire_fence();
}
hwc2_error_t hwc2_display::get_release_fences(uint32_t *out_num_elements,
hwc2_layer_t *out_layers, int32_t *out_fences) const
{
if (release_fence.get() < 0) {
*out_num_elements = 0;
return HWC2_ERROR_NONE;
}
size_t num = 0;
if (!out_layers || !out_fences) {
for (auto &window: windows)
if (window.contains_layer())
num++;
*out_num_elements = num;
return HWC2_ERROR_NONE;
}
for (auto it = windows.begin(); num < *out_num_elements,
it != windows.end(); it++) {
if (it->contains_layer()) {
out_layers[num] = it->get_layer();
out_fences[num] = dup(release_fence.get());
num++;
}
}
*out_num_elements = num;
return HWC2_ERROR_NONE;
}
void hwc2_display::init_windows()
{
for (auto it = windows.begin(); it != windows.end(); it++)
it->set_capabilities(window_capabilities[it - windows.begin()]);
}
void hwc2_display::clear_windows()
{
for (auto &window: windows)
window.clear();
}
hwc2_error_t hwc2_display::assign_client_target_window(uint32_t z_order)
{
for (auto &window: windows)
if (window.assign_client_target(z_order) == HWC2_ERROR_NONE)
return HWC2_ERROR_NONE;
return HWC2_ERROR_NO_RESOURCES;
}
hwc2_error_t hwc2_display::assign_layer_window(uint32_t z_order,
hwc2_layer_t lyr_id)
{
auto& lyr = layers.find(lyr_id)->second;
if (!hwc2_window::is_supported(lyr))
return HWC2_ERROR_UNSUPPORTED;
for (auto &window: windows)
if (window.assign_layer(z_order, lyr) == HWC2_ERROR_NONE)
return HWC2_ERROR_NONE;
return HWC2_ERROR_NO_RESOURCES;
}
hwc2_error_t hwc2_display::decompress_window_buffers()
{
hwc2_error_t ret;
for (auto &win: windows) {
if (win.contains_client_target()) {
ret = client_target.decompress();
if (ret != HWC2_ERROR_NONE) {
ALOGE("dpy %" PRIu64 ": failed to decompress client target"
" buffer", id);
return ret;
}
} else if (win.contains_layer()) {
ret = layers.at(win.get_layer()).decompress_buffer();
if (ret != HWC2_ERROR_NONE) {
ALOGE("dpy %" PRIu64 " lyr %" PRIu64 ": failed to decompress"
" layer buffer", id, win.get_layer());
return ret;
}
}
}
return HWC2_ERROR_NONE;
}
int hwc2_display::retrieve_display_configs(struct adf_hwc_helper *adf_helper)
{
size_t num_configs = 0;
int ret = adf_getDisplayConfigs(adf_helper, id, nullptr, &num_configs);
if (ret < 0 || num_configs == 0) {
ALOGE("dpy %" PRIu64 ": failed to get display configs: %s", id,
strerror(ret));
return ret;
}
std::vector<uint32_t> config_handles(num_configs);
ret = adf_getDisplayConfigs(adf_helper, id, config_handles.data(),
&num_configs);
if (ret < 0) {
ALOGE("dpy %" PRIu64 ": failed to get display configs: %s", id,
strerror(ret));
return ret;
}
active_config = config_handles[0];
std::array<uint32_t, 6> attributes = {{
HWC2_ATTRIBUTE_WIDTH,
HWC2_ATTRIBUTE_HEIGHT,
HWC2_ATTRIBUTE_VSYNC_PERIOD,
HWC2_ATTRIBUTE_DPI_X,
HWC2_ATTRIBUTE_DPI_Y,
HWC2_ATTRIBUTE_INVALID }};
std::array<int32_t, 5> values;
for (auto config_handle: config_handles) {
ret = adf_getDisplayAttributes_hwc2(adf_helper, id, config_handle,
attributes.data(), values.data());
if (ret < 0) {
ALOGW("dpy %" PRIu64 ": failed to get display attributes for config"
" %u: %s", id, config_handle, strerror(ret));
continue;
}
configs.emplace(config_handle, hwc2_config());
for (size_t attr = 0; attr < attributes.size() - 1; attr++) {
ret = configs[config_handle].set_attribute(
static_cast<hwc2_attribute_t>(attributes[attr]),
values[attr]);
if (ret < 0)
ALOGW("dpy %" PRIu64 ": failed to set attribute", id);
}
}
return ret;
}
hwc2_error_t hwc2_display::get_display_attribute(hwc2_config_t config,
hwc2_attribute_t attribute, int32_t *out_value) const
{
auto it = configs.find(config);
if (it == configs.end()) {
ALOGE("dpy %" PRIu64 ": bad config", id);
return HWC2_ERROR_BAD_CONFIG;
}
*out_value = it->second.get_attribute(attribute);
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::get_display_configs(uint32_t *out_num_configs,
hwc2_config_t *out_configs) const
{
if (!out_configs) {
*out_num_configs = configs.size();
return HWC2_ERROR_NONE;
}
size_t idx = 0;
for (auto it = configs.begin(); it != configs.end()
&& idx < *out_num_configs; it++, idx++)
out_configs[idx] = it->first;
*out_num_configs = idx;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::get_active_config(hwc2_config_t *out_config) const
{
if (!configs.size()) {
ALOGE("dpy %" PRIu64 ": no active config", id);
return HWC2_ERROR_BAD_CONFIG;
}
*out_config = active_config;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_active_config(
struct adf_hwc_helper *adf_helper, hwc2_config_t config)
{
if (config >= configs.size()) {
ALOGE("dpy %" PRIu64 ": bad config", id);
return HWC2_ERROR_BAD_CONFIG;
}
int ret = adf_set_active_config_hwc2(adf_helper, id, config);
if (ret < 0) {
ALOGE("dpy %" PRIu64 ": failed to set mode: %s", id, strerror(ret));
return HWC2_ERROR_BAD_CONFIG;
}
active_config = config;
set_client_target_properties();
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::get_color_modes(uint32_t *out_num_modes,
android_color_mode_t *out_modes) const
{
*out_num_modes = 1;
if (out_modes)
*out_modes = HAL_COLOR_MODE_NATIVE;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_color_mode(android_color_mode_t mode)
{
switch (mode) {
case HAL_COLOR_MODE_NATIVE:
return HWC2_ERROR_NONE;
case HAL_COLOR_MODE_STANDARD_BT601_625:
case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
case HAL_COLOR_MODE_STANDARD_BT601_525:
case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
case HAL_COLOR_MODE_STANDARD_BT709:
case HAL_COLOR_MODE_DCI_P3:
case HAL_COLOR_MODE_SRGB:
case HAL_COLOR_MODE_ADOBE_RGB:
ALOGE("dpy %" PRIu64 ": unsupported color mode", id);
return HWC2_ERROR_UNSUPPORTED;
default:
ALOGE("dpy %" PRIu64 ": invalid color mode", id);
return HWC2_ERROR_BAD_PARAMETER;
}
}
hwc2_error_t hwc2_display::get_hdr_capabilities(uint32_t *out_num_types,
android_hdr_t* /*out_types*/, float* /*out_max_luminance*/,
float* /*out_max_average_luminance*/,
float* /*out_min_luminance*/) const
{
*out_num_types = 0;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_color_transform(const float *color_matrix,
android_color_transform_t color_hint)
{
switch (color_hint) {
case HAL_COLOR_TRANSFORM_IDENTITY:
case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
case HAL_COLOR_TRANSFORM_VALUE_INVERSE:
case HAL_COLOR_TRANSFORM_GRAYSCALE:
case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA:
case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA:
case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA:
memcpy(this->color_matrix.data(), color_matrix,
this->color_matrix.size());
this->color_hint = color_hint;
return HWC2_ERROR_NONE;
default:
ALOGE("dpy %" PRIu64 ": invalid color transform hint", id);
return HWC2_ERROR_BAD_PARAMETER;
}
}
hwc2_error_t hwc2_display::get_client_target_support(uint32_t width,
uint32_t height, android_pixel_format_t format,
android_dataspace_t dataspace)
{
if (active_config >= configs.size()) {
ALOGE("dpy %" PRIu64 ": no active_config", id);
return HWC2_ERROR_UNSUPPORTED;
}
int32_t cnfg_width = configs[active_config].get_attribute(
HWC2_ATTRIBUTE_WIDTH);
int32_t cnfg_height = configs[active_config].get_attribute(
HWC2_ATTRIBUTE_HEIGHT);
if (cnfg_width < 0 || width != static_cast<uint32_t>(cnfg_width)) {
ALOGE("dpy %" PRIu64 ": unsupported client target width", id);
return HWC2_ERROR_UNSUPPORTED;
}
if (cnfg_height < 0 || height != static_cast<uint32_t>(cnfg_height)) {
ALOGE("dpy %" PRIu64 ": unsupported client target height", id);
return HWC2_ERROR_UNSUPPORTED;
}
if (format != HAL_PIXEL_FORMAT_RGBA_8888) {
ALOGE("dpy %" PRIu64 ": unsupported client target format", id);
return HWC2_ERROR_UNSUPPORTED;
}
if (dataspace != HAL_DATASPACE_UNKNOWN) {
ALOGE("dpy %" PRIu64 ": unsupported client target dataspace", id);
return HWC2_ERROR_UNSUPPORTED;
}
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_client_target(buffer_handle_t handle,
int32_t acquire_fence, android_dataspace_t dataspace,
const hwc_region_t &surface_damage)
{
hwc2_error_t ret = client_target.set_buffer(handle, acquire_fence);
if (ret != HWC2_ERROR_NONE)
return ret;
ret = client_target.set_dataspace(dataspace);
if (ret != HWC2_ERROR_NONE)
return ret;
return client_target.set_surface_damage(surface_damage);
}
hwc2_error_t hwc2_display::set_client_target_properties()
{
int32_t width = configs.at(active_config).get_attribute(HWC2_ATTRIBUTE_WIDTH);
int32_t height = configs.at(active_config).get_attribute(HWC2_ATTRIBUTE_HEIGHT);
hwc_rect_t frame;
frame.left = 0;
frame.top = 0;
frame.right = width;
frame.bottom = height;
client_target.set_display_frame(frame);
hwc_frect_t crop;
crop.left = 0.0;
crop.top = 0.0;
crop.right = static_cast<float>(width);
crop.bottom = static_cast<float>(height);
client_target.set_source_crop(crop);
client_target.set_blend_mode(HWC2_BLEND_MODE_PREMULTIPLIED);
client_target.set_z_order(UINT32_MAX);
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::create_layer(hwc2_layer_t *out_layer)
{
display_state = modified;
hwc2_layer_t lyr_id = hwc2_layer::get_next_id();
layers.emplace(std::piecewise_construct, std::forward_as_tuple(lyr_id),
std::forward_as_tuple(lyr_id));
*out_layer = lyr_id;
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::destroy_layer(hwc2_layer_t lyr_id)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
display_state = modified;
layers.erase(lyr_id);
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_layer_composition_type(hwc2_layer_t lyr_id,
hwc2_composition_t comp_type)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_comp_type(comp_type);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_buffer(hwc2_layer_t lyr_id,
buffer_handle_t handle, int32_t acquire_fence)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_buffer(handle, acquire_fence);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_dataspace(hwc2_layer_t lyr_id,
android_dataspace_t dataspace)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_dataspace(dataspace);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_display_frame(hwc2_layer_t lyr_id,
const hwc_rect_t &display_frame)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_display_frame(display_frame);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_source_crop(hwc2_layer_t lyr_id,
const hwc_frect_t &source_crop)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_source_crop(source_crop);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_z_order(hwc2_layer_t lyr_id, uint32_t z_order)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_z_order(z_order);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_surface_damage(hwc2_layer_t lyr_id,
const hwc_region_t &surface_damage)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
return it->second.set_surface_damage(surface_damage);
}
hwc2_error_t hwc2_display::set_layer_blend_mode(hwc2_layer_t lyr_id,
hwc2_blend_mode_t blend_mode)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_blend_mode(blend_mode);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_plane_alpha(hwc2_layer_t lyr_id, float plane_alpha)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_plane_alpha(plane_alpha);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_transform(hwc2_layer_t lyr_id,
const hwc_transform_t transform)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_transform(transform);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_visible_region(hwc2_layer_t lyr_id,
const hwc_region_t &visible_region)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
hwc2_error_t ret = it->second.set_visible_region(visible_region);
if (it->second.get_modified())
display_state = modified;
return ret;
}
hwc2_error_t hwc2_display::set_layer_color(hwc2_layer_t lyr_id,
const hwc_color_t& /*color*/)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
/* Layer colors are not supported on flounder. During validate, any layers
* marked HWC2_COMPOSITION_SOLID_COLOR will be changed to
* HWC2_COMPOSITION_CLIENT. No need to store the layer color. */
return HWC2_ERROR_NONE;
}
hwc2_error_t hwc2_display::set_cursor_position(hwc2_layer_t lyr_id,
int32_t /*x*/, int32_t /*y*/)
{
auto it = layers.find(lyr_id);
if (it == layers.end()) {
ALOGE("dpy %" PRIu64 ": lyr %" PRIu64 ": bad layer handle", id, lyr_id);
return HWC2_ERROR_BAD_LAYER;
}
/* Cursors are not supported on flounder. During validate, any layers marked
* HWC2_COMPOSITION_CURSOR will be changed to HWC2_COMPOSITION_CLIENT.
* No need to store the cursor position. */
return HWC2_ERROR_NONE;
}
hwc2_display_t hwc2_display::get_next_id()
{
return display_cnt++;
}