You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

977 lines
29 KiB

/*
* Copyright 2018 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 <stdint.h>
#include <string.h>
#include <time.h>
#include <utils/Thread.h>
#include <map>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <cutils/log.h>
#include <sys/resource.h>
#include <system/graphics.h>
#include <hardware/hwcomposer2.h>
extern hw_module_t HAL_MODULE_INFO_SYM;
namespace {
const int32_t kNumColorModes = 9;
const hwc2_config_t kDummyConfig = 0;
// We're arbitrarily choosing these values to make the fake display not look
// suspicious.
const int32_t kDummyVSyncPeriod = 16666667; // 60Hz
const int32_t kDummyDpiX = 160;
const int32_t kDummyDpiY = 160;
class DummyDisplay;
hwc2_display_t nextId = 1;
std::map<hwc2_display_t, DummyDisplay> displays;
HWC2_PFN_VSYNC vsync_callback = nullptr;
hwc2_callback_data_t vsync_data = nullptr;
HWC2_PFN_HOTPLUG hotplug_callback = nullptr;
hwc2_callback_data_t hotplug_data = nullptr;
class DummyDisplay;
DummyDisplay* physical_display = nullptr;
class DummyDisplay {
public:
DummyDisplay(hwc2_display_t id, uint32_t width, uint32_t height)
: id_(id), width_(width), height_(height) {}
hwc2_display_t GetId() { return id_; }
bool IsPhysical() { return physical_display == this; }
bool IsConfigured() { return configured_; }
void Configure() { configured_ = true; }
uint32_t GetWidth() { return width_; }
uint32_t GetHeight() { return height_; }
void MakePhysical() {
if (physical_display != nullptr) {
ALOGE("Dummy composer does not support multiple physical displays.");
} else {
physical_display = this;
}
}
hwc2_layer_t CreateLayer() {
hwc2_layer_t layer = nextLayer_++;
layers_.insert(layer);
return layer;
}
bool IsValidLayer(hwc2_layer_t layer) {
return layers_.find(layer) != layers_.end();
}
void DestroyLayer(hwc2_layer_t layer) {
isClientComposed_.erase(layer);
layers_.erase(layer);
}
bool SetClientComposed(hwc2_layer_t layer, bool value) {
if (layers_.find(layer) == layers_.end()) {
return false;
}
isClientComposed_[layer] = value;
return true;
}
uint32_t NumNotClientComposed() {
uint32_t ret = 0;
for (const auto& layer : layers_) {
if (!isClientComposed_[layer]) {
ret++;
}
}
return ret;
}
void GetNonClientComposedIDs(hwc2_layer_t* layers, uint32_t size) {
if (!layers) {
return;
}
for (const auto& layer : layers_) {
if (size == 0) {
break;
}
if (!isClientComposed_[layer]) {
*(layers++) = layer;
size--;
}
}
}
private:
hwc2_display_t id_;
uint32_t width_;
uint32_t height_;
bool configured_ = false;
hwc2_layer_t nextLayer_ = 1;
std::set<hwc2_layer_t> layers_;
std::map<hwc2_layer_t, bool> isClientComposed_;
};
class VSyncThread : public android::Thread {
public:
VSyncThread() : Thread(false) {}
private:
bool threadLoop() override {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_nsec += kDummyVSyncPeriod;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
ts.tv_sec += 1;
}
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr))
;
int64_t timestamp = ts.tv_sec * 1000000000 + ts.tv_nsec;
if (vsync_callback == nullptr) {
return true;
}
vsync_callback(vsync_data, physical_display->GetId(), timestamp);
return true;
}
};
android::sp<VSyncThread> vsyncThread;
const uint32_t kPhysicalDummyWidth = 640;
const uint32_t kPhysicalDummyHeight = 480;
int32_t Hwc2ImplCreateVirtualDisplay(hwc2_device_t* /*device*/, uint32_t width,
uint32_t height, int32_t* /*format*/,
hwc2_display_t* out_display) {
hwc2_display_t id = nextId++;
*out_display = id;
displays.emplace(std::piecewise_construct, std::forward_as_tuple(id),
std::forward_as_tuple(id, width, height));
if (hotplug_callback != nullptr) {
hotplug_callback(hotplug_data, id, HWC2_CONNECTION_CONNECTED);
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplDestroyVirtualDisplay(hwc2_device_t* /*device*/,
hwc2_display_t display) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (iter->second.IsPhysical()) {
return HWC2_ERROR_BAD_PARAMETER;
}
if (hotplug_callback != nullptr) {
hotplug_callback(hotplug_data, display, HWC2_CONNECTION_DISCONNECTED);
}
displays.erase(iter);
return HWC2_ERROR_NONE;
}
void Hwc2ImplDump(hwc2_device_t* /*device*/, uint32_t* out_size,
char* out_buffer) {
const char* dump_data = u8"hwcomposer is a dummy";
if (out_buffer) {
strncpy(out_buffer, dump_data, *out_size);
}
*out_size = static_cast<uint32_t>(strlen(dump_data));
}
uint32_t Hwc2ImplGetMaxVirtualDisplayCount(hwc2_device_t* /*device*/) {
return UINT32_MAX;
}
int32_t Hwc2ImplRegisterCallback(hwc2_device_t* /*device*/, int32_t descriptor,
hwc2_callback_data_t callback_data,
hwc2_function_pointer_t pointer) {
switch (descriptor) {
case HWC2_CALLBACK_HOTPLUG:
hotplug_callback = reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer);
hotplug_data = callback_data;
for (const auto& disp : displays) {
hotplug_callback(hotplug_data, disp.first, HWC2_CONNECTION_CONNECTED);
}
return HWC2_ERROR_NONE;
case HWC2_CALLBACK_VSYNC:
vsync_callback = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
vsync_data = callback_data;
return HWC2_ERROR_NONE;
case HWC2_CALLBACK_REFRESH:
return HWC2_ERROR_NONE;
default:
return HWC2_ERROR_BAD_PARAMETER;
}
}
int32_t Hwc2ImplAcceptDisplayChanges(hwc2_device_t* /*device*/,
hwc2_display_t display) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplCreateLayer(hwc2_device_t* /*device*/, hwc2_display_t display,
hwc2_layer_t* out_layer) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
*out_layer = iter->second.CreateLayer();
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplDestroyLayer(hwc2_device_t* /*device*/, hwc2_display_t display,
hwc2_layer_t layer) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
iter->second.DestroyLayer(layer);
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetActiveConfig(hwc2_device_t* /*device*/,
hwc2_display_t display,
hwc2_config_t* out_config) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (!iter->second.IsConfigured()) {
return HWC2_ERROR_BAD_CONFIG;
}
*out_config = kDummyConfig;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetChangedCompositionTypes(hwc2_device_t* /*device*/,
hwc2_display_t display,
uint32_t* out_num_elements,
hwc2_layer_t* out_layers,
int32_t* out_types) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
uint32_t out_size = *out_num_elements;
uint32_t not_composed = iter->second.NumNotClientComposed();
if (iter->second.IsPhysical()) {
*out_num_elements = 0;
return HWC2_ERROR_NONE;
}
if (out_layers == nullptr || out_types == nullptr) {
*out_num_elements = not_composed;
return HWC2_ERROR_NONE;
}
iter->second.GetNonClientComposedIDs(out_layers, out_size);
for (uint32_t i = 0; i < out_size; i++) {
out_types[i] = HWC2_COMPOSITION_CLIENT;
}
if (not_composed < out_size) {
*out_num_elements = not_composed;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetClientTargetSupport(hwc2_device_t* /*device*/,
hwc2_display_t /*display*/,
uint32_t /*width*/, uint32_t /*height*/,
int32_t /*format*/,
int32_t /*dataspace*/) {
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetColorModes(hwc2_device_t* /*device*/, hwc2_display_t display,
uint32_t* out_num_modes, int32_t* out_modes) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (*out_num_modes > kNumColorModes) {
*out_num_modes = kNumColorModes;
}
if (!out_modes) {
return HWC2_ERROR_NONE;
}
for (uint32_t i = 0; i < *out_num_modes; i++) {
*(out_modes++) = static_cast<int32_t>(i);
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetDisplayAttribute(hwc2_device_t* /*device*/,
hwc2_display_t display,
hwc2_config_t config, int32_t attribute,
int32_t* out_value) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (config != kDummyConfig) {
return HWC2_ERROR_BAD_CONFIG;
}
switch (attribute) {
case HWC2_ATTRIBUTE_WIDTH:
*out_value = 720;//static_cast<int32_t>(iter->second.GetWidth());
return HWC2_ERROR_NONE;
case HWC2_ATTRIBUTE_HEIGHT:
*out_value = 1280;//static_cast<int32_t>(iter->second.GetHeight());
return HWC2_ERROR_NONE;
case HWC2_ATTRIBUTE_VSYNC_PERIOD:
*out_value = kDummyVSyncPeriod;
return HWC2_ERROR_NONE;
case HWC2_ATTRIBUTE_DPI_X:
*out_value = kDummyDpiX;
return HWC2_ERROR_NONE;
case HWC2_ATTRIBUTE_DPI_Y:
*out_value = kDummyDpiY;
return HWC2_ERROR_NONE;
default:
*out_value = -1;
return HWC2_ERROR_NONE;
}
}
int32_t Hwc2ImplGetDisplayConfigs(hwc2_device_t* /*device*/,
hwc2_display_t display,
uint32_t* out_num_configs,
hwc2_config_t* out_configs) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (out_configs) {
if (*out_num_configs >= 1) {
out_configs[0] = kDummyConfig;
} else {
return HWC2_ERROR_NONE;
}
}
*out_num_configs = 1;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetDisplayName(hwc2_device_t* /*device*/,
hwc2_display_t display, uint32_t* out_size,
char* out_name) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
auto str = std::to_string(display);
if (out_name) {
strncpy(out_name, str.c_str(), *out_size);
}
if (*out_size > (str.size() + 1)) {
*out_size = static_cast<uint32_t>( str.size() + 1);
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetDisplayRequests(hwc2_device_t* /*device*/,
hwc2_display_t display,
int32_t* out_display_requests,
uint32_t* out_num_elements,
hwc2_layer_t* /*out_layers*/,
int32_t* /*out_layer_requests*/) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
*out_num_elements = 0;
*out_display_requests = 0;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetDisplayType(hwc2_device_t* /*device*/,
hwc2_display_t display, int32_t* out_type) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (iter->second.IsPhysical()) {
*out_type = HWC2_DISPLAY_TYPE_PHYSICAL;
} else {
*out_type = HWC2_DISPLAY_TYPE_VIRTUAL;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetDozeSupport(hwc2_device_t* /*device*/,
hwc2_display_t display, int32_t* out_support) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
*out_support = 0;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetHdrCapabilities(
hwc2_device_t* /*device*/, hwc2_display_t display, uint32_t* out_num_types,
int32_t* /*out_types*/, float* /*out_max_luminance*/,
float* /*out_max_average_luminance*/, float* /*out_min_luminance*/) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
*out_num_types = 0;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplGetReleaseFences(hwc2_device_t* /*device*/,
hwc2_display_t display,
uint32_t* out_num_elements,
hwc2_layer_t* /*out_layers*/,
int32_t* /*out_fences*/) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
*out_num_elements = 0;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplPresentDisplay(hwc2_device_t* /*device*/,
hwc2_display_t display,
int32_t* out_retire_fence) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
/* Hope this works... */
*out_retire_fence = -1;
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetActiveConfig(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_config_t config) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (config != kDummyConfig) {
return HWC2_ERROR_BAD_CONFIG;
}
iter->second.Configure();
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetClientTarget(hwc2_device_t* /*device*/,
hwc2_display_t display,
buffer_handle_t /*target*/,
int32_t /*acquire_fence*/,
int32_t /*dataspace*/,
hwc_region_t /*damage*/) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetColorMode(hwc2_device_t* /*device*/, hwc2_display_t display,
int32_t mode) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (mode < 0 || mode >= kNumColorModes) {
return HWC2_ERROR_BAD_PARAMETER;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetColorTransform(hwc2_device_t* /*device*/,
hwc2_display_t display,
const float* /*matrix*/, int32_t /*hint*/) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
/* A bad hint value should yield HWC2_ERROR_BAD_PARAMETER but the
* documentation is incomplete and inaccurate as to what is and is not a
* valid hint value.
*/
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetOutputBuffer(hwc2_device_t* /*device*/,
hwc2_display_t display,
buffer_handle_t /*buffer*/,
int32_t /*release_fence*/) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (iter->second.IsPhysical()) {
return HWC2_ERROR_UNSUPPORTED;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetPowerMode(hwc2_device_t* /*device*/, hwc2_display_t display,
int32_t mode) {
if (displays.find(display) == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
switch (mode) {
case HWC2_POWER_MODE_OFF:
case HWC2_POWER_MODE_ON:
return HWC2_ERROR_NONE;
case HWC2_POWER_MODE_DOZE:
case HWC2_POWER_MODE_DOZE_SUSPEND:
return HWC2_ERROR_UNSUPPORTED;
default:
return HWC2_ERROR_BAD_PARAMETER;
}
}
int32_t Hwc2ImplSetVsyncEnabled(hwc2_device_t* /*device*/,
hwc2_display_t display, int32_t enabled) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (!iter->second.IsPhysical()) {
return HWC2_ERROR_NONE;
}
if (enabled == HWC2_VSYNC_ENABLE) {
if (vsyncThread.get() != nullptr) {
return HWC2_ERROR_NONE;
}
vsyncThread = new VSyncThread();
android::status_t ret =
vsyncThread->run("dummy_vsync", HAL_PRIORITY_URGENT_DISPLAY);
if (ret != android::OK) {
ALOGE("Could not create vsync thread (%d)", ret);
}
return HWC2_ERROR_NONE;
}
if (enabled != HWC2_VSYNC_DISABLE) {
return HWC2_ERROR_BAD_PARAMETER;
}
vsyncThread->requestExit();
vsyncThread.clear();
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplValidateDisplay(hwc2_device_t* /*device*/,
hwc2_display_t display, uint32_t* out_num_types,
uint32_t* out_num_requests) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
*out_num_requests = 0;
if (iter->second.IsPhysical()) {
*out_num_types = 0;
} else {
*out_num_types = iter->second.NumNotClientComposed();
}
return HWC2_ERROR_NONE;
}
int32_t validateLayer(hwc2_display_t display, hwc2_layer_t layer) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (!iter->second.IsValidLayer(layer)) {
return HWC2_ERROR_BAD_LAYER;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetCursorPosition(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
int32_t /*x*/, int32_t /*y*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerBuffer(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
buffer_handle_t /*buffer*/,
int32_t /*acquireFence*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerSurfaceDamage(hwc2_device_t* /*device*/,
hwc2_display_t display,
hwc2_layer_t layer,
hwc_region_t /*damage*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerBlendMode(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
int32_t /*mode*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerColor(hwc2_device_t* /*device*/, hwc2_display_t display,
hwc2_layer_t layer, hwc_color_t /*color*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerCompositionType(hwc2_device_t* /*device*/,
hwc2_display_t display,
hwc2_layer_t layer, int32_t type) {
auto iter = displays.find(display);
if (iter == displays.end()) {
return HWC2_ERROR_BAD_DISPLAY;
}
if (type == HWC2_COMPOSITION_SIDEBAND) {
return HWC2_ERROR_UNSUPPORTED;
}
if (!iter->second.SetClientComposed(layer, type == HWC2_COMPOSITION_CLIENT)) {
return HWC2_ERROR_BAD_LAYER;
}
return HWC2_ERROR_NONE;
}
int32_t Hwc2ImplSetLayerDataspace(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
int32_t /*dataspace*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerDisplayFrame(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
hwc_rect_t /*frame*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerPlaneAlpha(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
float /*alpha*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerSidebandStream(hwc2_device_t* /*device*/,
hwc2_display_t display,
hwc2_layer_t layer,
const native_handle_t* /*stream*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerSourceCrop(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
hwc_frect_t /*crop*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerTransform(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
int32_t /*transform*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayerVisibleRegion(hwc2_device_t* /*device*/,
hwc2_display_t display,
hwc2_layer_t layer,
hwc_region_t /*visible*/) {
return validateLayer(display, layer);
}
int32_t Hwc2ImplSetLayer_z_order(hwc2_device_t* /*device*/,
hwc2_display_t display, hwc2_layer_t layer,
uint32_t /*z*/) {
return validateLayer(display, layer);
}
int Hwc2DeviceClose(struct hw_device_t* /*dev*/) { return 0; }
void Hwc2GetCapabilities(struct hwc2_device* /*device*/, uint32_t* out_count,
int32_t* /*out_capabilities*/) {
*out_count = 0;
}
hwc2_function_pointer_t Hwc2GetFunction(struct hwc2_device* /*device*/,
int32_t descriptor) {
switch (descriptor) {
case HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplAcceptDisplayChanges);
case HWC2_FUNCTION_CREATE_LAYER:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplCreateLayer);
case HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplCreateVirtualDisplay);
case HWC2_FUNCTION_DESTROY_LAYER:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplDestroyLayer);
case HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplDestroyVirtualDisplay);
case HWC2_FUNCTION_DUMP:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplDump);
case HWC2_FUNCTION_GET_ACTIVE_CONFIG:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplGetActiveConfig);
case HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetChangedCompositionTypes);
case HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetClientTargetSupport);
case HWC2_FUNCTION_GET_COLOR_MODES:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplGetColorModes);
case HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetDisplayAttribute);
case HWC2_FUNCTION_GET_DISPLAY_CONFIGS:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetDisplayConfigs);
case HWC2_FUNCTION_GET_DISPLAY_NAME:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplGetDisplayName);
case HWC2_FUNCTION_GET_DISPLAY_REQUESTS:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetDisplayRequests);
case HWC2_FUNCTION_GET_DISPLAY_TYPE:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplGetDisplayType);
case HWC2_FUNCTION_GET_DOZE_SUPPORT:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplGetDozeSupport);
case HWC2_FUNCTION_GET_HDR_CAPABILITIES:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetHdrCapabilities);
case HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetMaxVirtualDisplayCount);
case HWC2_FUNCTION_GET_RELEASE_FENCES:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplGetReleaseFences);
case HWC2_FUNCTION_PRESENT_DISPLAY:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplPresentDisplay);
case HWC2_FUNCTION_REGISTER_CALLBACK:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplRegisterCallback);
case HWC2_FUNCTION_SET_ACTIVE_CONFIG:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetActiveConfig);
case HWC2_FUNCTION_SET_CLIENT_TARGET:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetClientTarget);
case HWC2_FUNCTION_SET_COLOR_MODE:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetColorMode);
case HWC2_FUNCTION_SET_COLOR_TRANSFORM:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetColorTransform);
case HWC2_FUNCTION_SET_CURSOR_POSITION:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetCursorPosition);
case HWC2_FUNCTION_SET_LAYER_BLEND_MODE:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerBlendMode);
case HWC2_FUNCTION_SET_LAYER_BUFFER:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetLayerBuffer);
case HWC2_FUNCTION_SET_LAYER_COLOR:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetLayerColor);
case HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerCompositionType);
case HWC2_FUNCTION_SET_LAYER_DATASPACE:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerDataspace);
case HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerDisplayFrame);
case HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerPlaneAlpha);
case HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerSidebandStream);
case HWC2_FUNCTION_SET_LAYER_SOURCE_CROP:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerSourceCrop);
case HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerSurfaceDamage);
case HWC2_FUNCTION_SET_LAYER_TRANSFORM:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerTransform);
case HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayerVisibleRegion);
case HWC2_FUNCTION_SET_LAYER_Z_ORDER:
return reinterpret_cast<hwc2_function_pointer_t>(
Hwc2ImplSetLayer_z_order);
case HWC2_FUNCTION_SET_OUTPUT_BUFFER:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetOutputBuffer);
case HWC2_FUNCTION_SET_POWER_MODE:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetPowerMode);
case HWC2_FUNCTION_SET_VSYNC_ENABLED:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplSetVsyncEnabled);
case HWC2_FUNCTION_VALIDATE_DISPLAY:
return reinterpret_cast<hwc2_function_pointer_t>(Hwc2ImplValidateDisplay);
default:
return nullptr;
}
}
hwc2_device_t dummy_device = {
.common = {.tag = HARDWARE_DEVICE_TAG,
.version = HWC_DEVICE_API_VERSION_2_0,
.module = &HAL_MODULE_INFO_SYM,
.close = Hwc2DeviceClose},
.getCapabilities = Hwc2GetCapabilities,
.getFunction = Hwc2GetFunction,
};
int Hwc2DeviceOpen(const struct hw_module_t* /*module*/, const char* name,
struct hw_device_t** device) {
if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
return -EINVAL;
}
if (physical_display == nullptr) {
hwc2_display_t physical_dummy;
Hwc2ImplCreateVirtualDisplay(&dummy_device, kPhysicalDummyWidth,
kPhysicalDummyHeight, nullptr,
&physical_dummy);
displays.find(physical_dummy)->second.MakePhysical();
Hwc2ImplSetActiveConfig(&dummy_device, physical_dummy, kDummyConfig);
}
*device = &dummy_device.common;
return 0;
}
struct hw_module_methods_t Hwc2ModuleMethods = {
.open = Hwc2DeviceOpen,
};
} // namespace
hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 2,
.version_minor = 0,
.id = HWC_HARDWARE_MODULE_ID,
.name = "Dummy hwcomposer module",
.author = "The Android Open Source Project",
.methods = &Hwc2ModuleMethods,
};