diff options
author | Chia-I Wu <olv@google.com> | 2017-11-07 18:01:54 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-11-07 18:01:54 +0000 |
commit | 5be02d66ed26c2938cf179ed625057d225ab38c8 (patch) | |
tree | 5f18169f4aed5e72b33d92d3d7f23b18600497d0 /libs | |
parent | 7938fa4bb0bb5e0aadae456ff8b1269d0a337026 (diff) | |
parent | e771093f4bb8b5a77984d741c3bab936f0c9f40c (diff) | |
download | native-5be02d66ed26c2938cf179ed625057d225ab38c8.tar.gz |
Merge "libhwc2onfbadapter: add a new adatper for FB HAL"
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwc2onfbadapter/Android.bp | 33 | ||||
-rw-r--r-- | libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp | 887 | ||||
-rw-r--r-- | libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h | 123 |
3 files changed, 1043 insertions, 0 deletions
diff --git a/libs/hwc2onfbadapter/Android.bp b/libs/hwc2onfbadapter/Android.bp new file mode 100644 index 0000000000..73a41f7ff4 --- /dev/null +++ b/libs/hwc2onfbadapter/Android.bp @@ -0,0 +1,33 @@ +// Copyright 2010 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. + +cc_library_shared { + name: "libhwc2onfbadapter", + vendor: true, + + clang: true, + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + + srcs: [ + "HWC2OnFbAdapter.cpp", + ], + + header_libs: ["libhardware_headers"], + shared_libs: ["liblog", "libsync"], + export_include_dirs: ["include"], +} diff --git a/libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp b/libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp new file mode 100644 index 0000000000..7c9e6518b7 --- /dev/null +++ b/libs/hwc2onfbadapter/HWC2OnFbAdapter.cpp @@ -0,0 +1,887 @@ +/* + * Copyright 2017 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. + */ + +#define LOG_TAG "HWC2OnFbAdapter" + +//#define LOG_NDEBUG 0 + +#include "hwc2onfbadapter/HWC2OnFbAdapter.h" + +#include <algorithm> +#include <type_traits> + +#include <inttypes.h> +#include <time.h> +#include <sys/prctl.h> +#include <unistd.h> // for close + +#include <hardware/fb.h> +#include <log/log.h> +#include <sync/sync.h> + +namespace android { + +namespace { + +void dumpHook(hwc2_device_t* device, uint32_t* outSize, char* outBuffer) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (outBuffer) { + *outSize = adapter.getDebugString().copy(outBuffer, *outSize); + } else { + adapter.updateDebugString(); + *outSize = adapter.getDebugString().size(); + } +} + +int32_t registerCallbackHook(hwc2_device_t* device, int32_t descriptor, + hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) { + auto& adapter = HWC2OnFbAdapter::cast(device); + switch (descriptor) { + case HWC2_CALLBACK_HOTPLUG: + if (pointer) { + reinterpret_cast<HWC2_PFN_HOTPLUG>(pointer)(callbackData, adapter.getDisplayId(), + HWC2_CONNECTION_CONNECTED); + } + break; + case HWC2_CALLBACK_REFRESH: + break; + case HWC2_CALLBACK_VSYNC: + adapter.setVsyncCallback(reinterpret_cast<HWC2_PFN_VSYNC>(pointer), callbackData); + break; + default: + return HWC2_ERROR_BAD_PARAMETER; + } + + return HWC2_ERROR_NONE; +} + +uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* /*device*/) { + return 0; +} + +int32_t createVirtualDisplayHook(hwc2_device_t* /*device*/, uint32_t /*width*/, uint32_t /*height*/, + int32_t* /*format*/, hwc2_display_t* /*outDisplay*/) { + return HWC2_ERROR_NO_RESOURCES; +} + +int32_t destroyVirtualDisplayHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/) { + return HWC2_ERROR_BAD_DISPLAY; +} + +int32_t setOutputBufferHook(hwc2_device_t* /*device*/, hwc2_display_t /*display*/, + buffer_handle_t /*buffer*/, int32_t /*releaseFence*/) { + return HWC2_ERROR_BAD_DISPLAY; +} + +int32_t getDisplayNameHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outSize, + char* outName) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + const auto& info = adapter.getInfo(); + if (outName) { + *outSize = info.name.copy(outName, *outSize); + } else { + *outSize = info.name.size(); + } + + return HWC2_ERROR_NONE; +} + +int32_t getDisplayTypeHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outType) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + *outType = HWC2_DISPLAY_TYPE_PHYSICAL; + return HWC2_ERROR_NONE; +} + +int32_t getDozeSupportHook(hwc2_device_t* device, hwc2_display_t display, int32_t* outSupport) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + *outSupport = 0; + return HWC2_ERROR_NONE; +} + +int32_t getHdrCapabilitiesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes, + int32_t* /*outTypes*/, float* /*outMaxLuminance*/, + float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + *outNumTypes = 0; + return HWC2_ERROR_NONE; +} + +int32_t setPowerModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t /*mode*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + // pretend that it works + return HWC2_ERROR_NONE; +} + +int32_t setVsyncEnabledHook(hwc2_device_t* device, hwc2_display_t display, int32_t enabled) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + adapter.enableVsync(enabled == HWC2_VSYNC_ENABLE); + return HWC2_ERROR_NONE; +} + +int32_t getColorModesHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumModes, + int32_t* outModes) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + if (outModes) { + if (*outNumModes > 0) { + outModes[0] = HAL_COLOR_MODE_NATIVE; + *outNumModes = 1; + } + } else { + *outNumModes = 1; + } + + return HWC2_ERROR_NONE; +} + +int32_t setColorModeHook(hwc2_device_t* device, hwc2_display_t display, int32_t mode) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (mode != HAL_COLOR_MODE_NATIVE) { + return HWC2_ERROR_BAD_PARAMETER; + } + + return HWC2_ERROR_NONE; +} + +int32_t setColorTransformHook(hwc2_device_t* device, hwc2_display_t display, + const float* /*matrix*/, int32_t /*hint*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + // we always force client composition + adapter.setState(HWC2OnFbAdapter::State::MODIFIED); + return HWC2_ERROR_NONE; +} + +int32_t getClientTargetSupportHook(hwc2_device_t* device, hwc2_display_t display, uint32_t width, + uint32_t height, int32_t format, int32_t dataspace) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (dataspace != HAL_DATASPACE_UNKNOWN) { + return HWC2_ERROR_UNSUPPORTED; + } + + const auto& info = adapter.getInfo(); + return (info.width == width && info.height == height && info.format == format) + ? HWC2_ERROR_NONE + : HWC2_ERROR_UNSUPPORTED; +} + +int32_t setClientTargetHook(hwc2_device_t* device, hwc2_display_t display, buffer_handle_t target, + int32_t acquireFence, int32_t dataspace, hwc_region_t /*damage*/) { + if (acquireFence >= 0) { + sync_wait(acquireFence, -1); + close(acquireFence); + } + + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (dataspace != HAL_DATASPACE_UNKNOWN) { + return HWC2_ERROR_BAD_PARAMETER; + } + + // no state change + adapter.setBuffer(target); + return HWC2_ERROR_NONE; +} + +int32_t getDisplayConfigsHook(hwc2_device_t* device, hwc2_display_t display, + uint32_t* outNumConfigs, hwc2_config_t* outConfigs) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + if (outConfigs) { + if (*outNumConfigs > 0) { + outConfigs[0] = adapter.getConfigId(); + *outNumConfigs = 1; + } + } else { + *outNumConfigs = 1; + } + + return HWC2_ERROR_NONE; +} + +int32_t getDisplayAttributeHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config, + int32_t attribute, int32_t* outValue) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (adapter.getConfigId() != config) { + return HWC2_ERROR_BAD_CONFIG; + } + + const auto& info = adapter.getInfo(); + switch (attribute) { + case HWC2_ATTRIBUTE_WIDTH: + *outValue = int32_t(info.width); + break; + case HWC2_ATTRIBUTE_HEIGHT: + *outValue = int32_t(info.height); + break; + case HWC2_ATTRIBUTE_VSYNC_PERIOD: + *outValue = int32_t(info.vsync_period_ns); + break; + case HWC2_ATTRIBUTE_DPI_X: + *outValue = int32_t(info.xdpi_scaled); + break; + case HWC2_ATTRIBUTE_DPI_Y: + *outValue = int32_t(info.ydpi_scaled); + break; + default: + return HWC2_ERROR_BAD_PARAMETER; + } + + return HWC2_ERROR_NONE; +} + +int32_t getActiveConfigHook(hwc2_device_t* device, hwc2_display_t display, + hwc2_config_t* outConfig) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + *outConfig = adapter.getConfigId(); + return HWC2_ERROR_NONE; +} + +int32_t setActiveConfigHook(hwc2_device_t* device, hwc2_display_t display, hwc2_config_t config) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (adapter.getConfigId() != config) { + return HWC2_ERROR_BAD_CONFIG; + } + + return HWC2_ERROR_NONE; +} + +int32_t validateDisplayHook(hwc2_device_t* device, hwc2_display_t display, uint32_t* outNumTypes, + uint32_t* outNumRequests) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + const auto& dirtyLayers = adapter.getDirtyLayers(); + *outNumTypes = dirtyLayers.size(); + *outNumRequests = 0; + + if (*outNumTypes > 0) { + adapter.setState(HWC2OnFbAdapter::State::VALIDATED_WITH_CHANGES); + return HWC2_ERROR_HAS_CHANGES; + } else { + adapter.setState(HWC2OnFbAdapter::State::VALIDATED); + return HWC2_ERROR_NONE; + } +} + +int32_t getChangedCompositionTypesHook(hwc2_device_t* device, hwc2_display_t display, + uint32_t* outNumElements, hwc2_layer_t* outLayers, + int32_t* outTypes) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) { + return HWC2_ERROR_NOT_VALIDATED; + } + + // request client composition for all layers + const auto& dirtyLayers = adapter.getDirtyLayers(); + if (outLayers && outTypes) { + *outNumElements = std::min(*outNumElements, uint32_t(dirtyLayers.size())); + auto iter = dirtyLayers.cbegin(); + for (uint32_t i = 0; i < *outNumElements; i++) { + outLayers[i] = *iter++; + outTypes[i] = HWC2_COMPOSITION_CLIENT; + } + } else { + *outNumElements = dirtyLayers.size(); + } + + return HWC2_ERROR_NONE; +} + +int32_t getDisplayRequestsHook(hwc2_device_t* device, hwc2_display_t display, + int32_t* outDisplayRequests, uint32_t* outNumElements, + hwc2_layer_t* /*outLayers*/, int32_t* /*outLayerRequests*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) { + return HWC2_ERROR_NOT_VALIDATED; + } + + *outDisplayRequests = 0; + *outNumElements = 0; + return HWC2_ERROR_NONE; +} + +int32_t acceptDisplayChangesHook(hwc2_device_t* device, hwc2_display_t display) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (adapter.getState() == HWC2OnFbAdapter::State::MODIFIED) { + return HWC2_ERROR_NOT_VALIDATED; + } + + adapter.clearDirtyLayers(); + adapter.setState(HWC2OnFbAdapter::State::VALIDATED); + return HWC2_ERROR_NONE; +} + +int32_t presentDisplayHook(hwc2_device_t* device, hwc2_display_t display, + int32_t* outPresentFence) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (adapter.getState() != HWC2OnFbAdapter::State::VALIDATED) { + return HWC2_ERROR_NOT_VALIDATED; + } + + adapter.postBuffer(); + *outPresentFence = -1; + + return HWC2_ERROR_NONE; +} + +int32_t getReleaseFencesHook(hwc2_device_t* device, hwc2_display_t display, + uint32_t* outNumElements, hwc2_layer_t* /*outLayers*/, + int32_t* /*outFences*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + *outNumElements = 0; + return HWC2_ERROR_NONE; +} + +int32_t createLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t* outLayer) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + *outLayer = adapter.addLayer(); + adapter.setState(HWC2OnFbAdapter::State::MODIFIED); + return HWC2_ERROR_NONE; +} + +int32_t destroyLayerHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + if (adapter.removeLayer(layer)) { + adapter.setState(HWC2OnFbAdapter::State::MODIFIED); + return HWC2_ERROR_NONE; + } else { + return HWC2_ERROR_BAD_LAYER; + } +} + +int32_t setCursorPositionHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t /*layer*/, + int32_t /*x*/, int32_t /*y*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + + // always an error + return HWC2_ERROR_BAD_LAYER; +} + +int32_t setLayerBufferHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, + buffer_handle_t /*buffer*/, int32_t acquireFence) { + if (acquireFence >= 0) { + sync_wait(acquireFence, -1); + close(acquireFence); + } + + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (!adapter.hasLayer(layer)) { + return HWC2_ERROR_BAD_LAYER; + } + + // no state change + return HWC2_ERROR_NONE; +} + +int32_t setLayerSurfaceDamageHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, + hwc_region_t /*damage*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (!adapter.hasLayer(layer)) { + return HWC2_ERROR_BAD_LAYER; + } + + // no state change + return HWC2_ERROR_NONE; +} + +int32_t setLayerCompositionTypeHook(hwc2_device_t* device, hwc2_display_t display, + hwc2_layer_t layer, int32_t type) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (!adapter.markLayerDirty(layer, type != HWC2_COMPOSITION_CLIENT)) { + return HWC2_ERROR_BAD_LAYER; + } + + adapter.setState(HWC2OnFbAdapter::State::MODIFIED); + return HWC2_ERROR_NONE; +} + +template <typename... Args> +int32_t setLayerStateHook(hwc2_device_t* device, hwc2_display_t display, hwc2_layer_t layer, + Args... /*args*/) { + auto& adapter = HWC2OnFbAdapter::cast(device); + if (adapter.getDisplayId() != display) { + return HWC2_ERROR_BAD_DISPLAY; + } + if (!adapter.hasLayer(layer)) { + return HWC2_ERROR_BAD_LAYER; + } + + adapter.setState(HWC2OnFbAdapter::State::MODIFIED); + return HWC2_ERROR_NONE; +} + +template <typename PFN, typename T> +static hwc2_function_pointer_t asFP(T function) { + static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer"); + return reinterpret_cast<hwc2_function_pointer_t>(function); +} + +hwc2_function_pointer_t getFunctionHook(hwc2_device_t* /*device*/, int32_t descriptor) { + switch (descriptor) { + // global functions + case HWC2_FUNCTION_DUMP: + return asFP<HWC2_PFN_DUMP>(dumpHook); + case HWC2_FUNCTION_REGISTER_CALLBACK: + return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook); + + // virtual display functions + case HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT: + return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(getMaxVirtualDisplayCountHook); + case HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY: + return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(createVirtualDisplayHook); + case HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY: + return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(destroyVirtualDisplayHook); + case HWC2_FUNCTION_SET_OUTPUT_BUFFER: + return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(setOutputBufferHook); + + // display functions + case HWC2_FUNCTION_GET_DISPLAY_NAME: + return asFP<HWC2_PFN_GET_DISPLAY_NAME>(getDisplayNameHook); + case HWC2_FUNCTION_GET_DISPLAY_TYPE: + return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(getDisplayTypeHook); + case HWC2_FUNCTION_GET_DOZE_SUPPORT: + return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(getDozeSupportHook); + case HWC2_FUNCTION_GET_HDR_CAPABILITIES: + return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(getHdrCapabilitiesHook); + case HWC2_FUNCTION_SET_POWER_MODE: + return asFP<HWC2_PFN_SET_POWER_MODE>(setPowerModeHook); + case HWC2_FUNCTION_SET_VSYNC_ENABLED: + return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(setVsyncEnabledHook); + case HWC2_FUNCTION_GET_COLOR_MODES: + return asFP<HWC2_PFN_GET_COLOR_MODES>(getColorModesHook); + case HWC2_FUNCTION_SET_COLOR_MODE: + return asFP<HWC2_PFN_SET_COLOR_MODE>(setColorModeHook); + case HWC2_FUNCTION_SET_COLOR_TRANSFORM: + return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(setColorTransformHook); + case HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT: + return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(getClientTargetSupportHook); + case HWC2_FUNCTION_SET_CLIENT_TARGET: + return asFP<HWC2_PFN_SET_CLIENT_TARGET>(setClientTargetHook); + + // config functions + case HWC2_FUNCTION_GET_DISPLAY_CONFIGS: + return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(getDisplayConfigsHook); + case HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE: + return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(getDisplayAttributeHook); + case HWC2_FUNCTION_GET_ACTIVE_CONFIG: + return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(getActiveConfigHook); + case HWC2_FUNCTION_SET_ACTIVE_CONFIG: + return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(setActiveConfigHook); + + // validate/present functions + case HWC2_FUNCTION_VALIDATE_DISPLAY: + return asFP<HWC2_PFN_VALIDATE_DISPLAY>(validateDisplayHook); + case HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES: + return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(getChangedCompositionTypesHook); + case HWC2_FUNCTION_GET_DISPLAY_REQUESTS: + return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(getDisplayRequestsHook); + case HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES: + return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(acceptDisplayChangesHook); + case HWC2_FUNCTION_PRESENT_DISPLAY: + return asFP<HWC2_PFN_PRESENT_DISPLAY>(presentDisplayHook); + case HWC2_FUNCTION_GET_RELEASE_FENCES: + return asFP<HWC2_PFN_GET_RELEASE_FENCES>(getReleaseFencesHook); + + // layer create/destroy + case HWC2_FUNCTION_CREATE_LAYER: + return asFP<HWC2_PFN_CREATE_LAYER>(createLayerHook); + case HWC2_FUNCTION_DESTROY_LAYER: + return asFP<HWC2_PFN_DESTROY_LAYER>(destroyLayerHook); + + // layer functions; validateDisplay not required + case HWC2_FUNCTION_SET_CURSOR_POSITION: + return asFP<HWC2_PFN_SET_CURSOR_POSITION>(setCursorPositionHook); + case HWC2_FUNCTION_SET_LAYER_BUFFER: + return asFP<HWC2_PFN_SET_LAYER_BUFFER>(setLayerBufferHook); + case HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE: + return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(setLayerSurfaceDamageHook); + + // layer state functions; validateDisplay required + case HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE: + return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(setLayerCompositionTypeHook); + case HWC2_FUNCTION_SET_LAYER_BLEND_MODE: + return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(setLayerStateHook<int32_t>); + case HWC2_FUNCTION_SET_LAYER_COLOR: + return asFP<HWC2_PFN_SET_LAYER_COLOR>(setLayerStateHook<hwc_color_t>); + case HWC2_FUNCTION_SET_LAYER_DATASPACE: + return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(setLayerStateHook<int32_t>); + case HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME: + return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(setLayerStateHook<hwc_rect_t>); + case HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA: + return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(setLayerStateHook<float>); + case HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM: + return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(setLayerStateHook<buffer_handle_t>); + case HWC2_FUNCTION_SET_LAYER_SOURCE_CROP: + return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(setLayerStateHook<hwc_frect_t>); + case HWC2_FUNCTION_SET_LAYER_TRANSFORM: + return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(setLayerStateHook<int32_t>); + case HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION: + return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(setLayerStateHook<hwc_region_t>); + case HWC2_FUNCTION_SET_LAYER_Z_ORDER: + return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(setLayerStateHook<uint32_t>); + + default: + ALOGE("unknown function descriptor %d", descriptor); + return nullptr; + } +} + +void getCapabilitiesHook(hwc2_device_t* /*device*/, uint32_t* outCount, + int32_t* /*outCapabilities*/) { + *outCount = 0; +} + +int closeHook(hw_device_t* device) { + auto& adapter = HWC2OnFbAdapter::cast(device); + adapter.close(); + return 0; +} + +} // anonymous namespace + +HWC2OnFbAdapter::HWC2OnFbAdapter(framebuffer_device_t* fbDevice) + : hwc2_device_t(), mFbDevice(fbDevice) { + common.close = closeHook; + hwc2_device::getCapabilities = getCapabilitiesHook; + hwc2_device::getFunction = getFunctionHook; + + mFbInfo.name = "fbdev"; + mFbInfo.width = mFbDevice->width; + mFbInfo.height = mFbDevice->height; + mFbInfo.format = mFbDevice->format; + mFbInfo.vsync_period_ns = int(1e9 / mFbDevice->fps); + mFbInfo.xdpi_scaled = int(mFbDevice->xdpi * 1000.0f); + mFbInfo.ydpi_scaled = int(mFbDevice->ydpi * 1000.0f); + + mVsyncThread.start(0, mFbInfo.vsync_period_ns); +} + +HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hw_device_t* device) { + return *reinterpret_cast<HWC2OnFbAdapter*>(device); +} + +HWC2OnFbAdapter& HWC2OnFbAdapter::cast(hwc2_device_t* device) { + return *reinterpret_cast<HWC2OnFbAdapter*>(device); +} + +hwc2_display_t HWC2OnFbAdapter::getDisplayId() { + return 0; +} + +hwc2_config_t HWC2OnFbAdapter::getConfigId() { + return 0; +} + +void HWC2OnFbAdapter::close() { + mVsyncThread.stop(); + framebuffer_close(mFbDevice); +} + +const HWC2OnFbAdapter::Info& HWC2OnFbAdapter::getInfo() const { + return mFbInfo; +} + +void HWC2OnFbAdapter::updateDebugString() { + if (mFbDevice->common.version >= 1 && mFbDevice->dump) { + char buffer[4096]; + mFbDevice->dump(mFbDevice, buffer, sizeof(buffer)); + buffer[sizeof(buffer) - 1] = '\0'; + + mDebugString = buffer; + } +} + +const std::string& HWC2OnFbAdapter::getDebugString() const { + return mDebugString; +} + +void HWC2OnFbAdapter::setState(State state) { + mState = state; +} + +HWC2OnFbAdapter::State HWC2OnFbAdapter::getState() const { + return mState; +} + +hwc2_layer_t HWC2OnFbAdapter::addLayer() { + hwc2_layer_t id = ++mNextLayerId; + + mLayers.insert(id); + mDirtyLayers.insert(id); + + return id; +} + +bool HWC2OnFbAdapter::removeLayer(hwc2_layer_t layer) { + mDirtyLayers.erase(layer); + return mLayers.erase(layer); +} + +bool HWC2OnFbAdapter::hasLayer(hwc2_layer_t layer) const { + return mLayers.count(layer) > 0; +} + +bool HWC2OnFbAdapter::markLayerDirty(hwc2_layer_t layer, bool dirty) { + if (mLayers.count(layer) == 0) { + return false; + } + + if (dirty) { + mDirtyLayers.insert(layer); + } else { + mDirtyLayers.erase(layer); + } + + return true; +} + +const std::unordered_set<hwc2_layer_t>& HWC2OnFbAdapter::getDirtyLayers() const { + return mDirtyLayers; +} + +void HWC2OnFbAdapter::clearDirtyLayers() { + mDirtyLayers.clear(); +} + +/* + * For each frame, SurfaceFlinger + * + * - peforms GLES composition + * - calls eglSwapBuffers + * - calls setClientTarget, which maps to setBuffer below + * - calls presentDisplay, which maps to postBuffer below + * + * setBuffer should be a good place to call compositionComplete. + * + * As for post, it + * + * - schedules the buffer for presentation on the next vsync + * - locks the buffer and blocks all other users trying to lock it + * + * It does not give us a way to return a present fence, and we need to live + * with that. The implication is that, when we are double-buffered, + * SurfaceFlinger assumes the front buffer is available for rendering again + * immediately after the back buffer is posted. The locking semantics + * hopefully are strong enough that the rendering will be blocked. + */ +void HWC2OnFbAdapter::setBuffer(buffer_handle_t buffer) { + if (mFbDevice->compositionComplete) { + mFbDevice->compositionComplete(mFbDevice); + } + mBuffer = buffer; +} + +bool HWC2OnFbAdapter::postBuffer() { + int error = 0; + if (mBuffer) { + error = mFbDevice->post(mFbDevice, mBuffer); + } + + return error == 0; +} + +void HWC2OnFbAdapter::setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) { + mVsyncThread.setCallback(callback, data); +} + +void HWC2OnFbAdapter::enableVsync(bool enable) { + mVsyncThread.enableCallback(enable); +} + +int64_t HWC2OnFbAdapter::VsyncThread::now() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + + return int64_t(ts.tv_sec) * 1'000'000'000 + ts.tv_nsec; +} + +bool HWC2OnFbAdapter::VsyncThread::sleepUntil(int64_t t) { + struct timespec ts; + ts.tv_sec = t / 1'000'000'000; + ts.tv_nsec = t % 1'000'000'000; + + while (true) { + int error = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, nullptr); + if (error) { + if (error == EINTR) { + continue; + } + return false; + } else { + return true; + } + } +} + +void HWC2OnFbAdapter::VsyncThread::start(int64_t firstVsync, int64_t period) { + mNextVsync = firstVsync; + mPeriod = period; + mStarted = true; + mThread = std::thread(&VsyncThread::vsyncLoop, this); +} + +void HWC2OnFbAdapter::VsyncThread::stop() { + { + std::lock_guard<std::mutex> lock(mMutex); + mStarted = false; + } + mCondition.notify_all(); + mThread.join(); +} + +void HWC2OnFbAdapter::VsyncThread::setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data) { + std::lock_guard<std::mutex> lock(mMutex); + mCallback = callback; + mCallbackData = data; +} + +void HWC2OnFbAdapter::VsyncThread::enableCallback(bool enable) { + { + std::lock_guard<std::mutex> lock(mMutex); + mCallbackEnabled = enable; + } + mCondition.notify_all(); +} + +void HWC2OnFbAdapter::VsyncThread::vsyncLoop() { + prctl(PR_SET_NAME, "VsyncThread", 0, 0, 0); + + std::unique_lock<std::mutex> lock(mMutex); + if (!mStarted) { + return; + } + + while (true) { + if (!mCallbackEnabled) { + mCondition.wait(lock, [this] { return mCallbackEnabled || !mStarted; }); + if (!mStarted) { + break; + } + } + + lock.unlock(); + + // adjust mNextVsync if necessary + int64_t t = now(); + if (mNextVsync < t) { + int64_t n = (t - mNextVsync + mPeriod - 1) / mPeriod; + mNextVsync += mPeriod * n; + } + bool fire = sleepUntil(mNextVsync); + + lock.lock(); + + if (fire) { + ALOGV("VsyncThread(%" PRId64 ")", mNextVsync); + if (mCallback) { + mCallback(mCallbackData, getDisplayId(), mNextVsync); + } + mNextVsync += mPeriod; + } + } +} + +} // namespace android diff --git a/libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h b/libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h new file mode 100644 index 0000000000..d6272fdb17 --- /dev/null +++ b/libs/hwc2onfbadapter/include/hwc2onfbadapter/HWC2OnFbAdapter.h @@ -0,0 +1,123 @@ +/* + * Copyright 2017 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. + */ + +#ifndef ANDROID_SF_HWC2_ON_FB_ADAPTER_H +#define ANDROID_SF_HWC2_ON_FB_ADAPTER_H + +#include <condition_variable> +#include <mutex> +#include <string> +#include <thread> +#include <unordered_set> + +#include <hardware/hwcomposer2.h> + +struct framebuffer_device_t; + +namespace android { + +class HWC2OnFbAdapter : public hwc2_device_t { +public: + HWC2OnFbAdapter(framebuffer_device_t* fbDevice); + + static HWC2OnFbAdapter& cast(hw_device_t* device); + static HWC2OnFbAdapter& cast(hwc2_device_t* device); + + static hwc2_display_t getDisplayId(); + static hwc2_config_t getConfigId(); + + void close(); + + struct Info { + std::string name; + uint32_t width; + uint32_t height; + int format; + int vsync_period_ns; + int xdpi_scaled; + int ydpi_scaled; + }; + const Info& getInfo() const; + + void updateDebugString(); + const std::string& getDebugString() const; + + enum class State { + MODIFIED, + VALIDATED_WITH_CHANGES, + VALIDATED, + }; + void setState(State state); + State getState() const; + + hwc2_layer_t addLayer(); + bool removeLayer(hwc2_layer_t layer); + bool hasLayer(hwc2_layer_t layer) const; + bool markLayerDirty(hwc2_layer_t layer, bool dirty); + const std::unordered_set<hwc2_layer_t>& getDirtyLayers() const; + void clearDirtyLayers(); + + void setBuffer(buffer_handle_t buffer); + bool postBuffer(); + + void setVsyncCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data); + void enableVsync(bool enable); + +private: + framebuffer_device_t* mFbDevice{nullptr}; + Info mFbInfo{}; + + std::string mDebugString; + + State mState{State::MODIFIED}; + + uint64_t mNextLayerId{0}; + std::unordered_set<hwc2_layer_t> mLayers; + std::unordered_set<hwc2_layer_t> mDirtyLayers; + + buffer_handle_t mBuffer{nullptr}; + + class VsyncThread { + public: + static int64_t now(); + static bool sleepUntil(int64_t t); + + void start(int64_t first, int64_t period); + void stop(); + void setCallback(HWC2_PFN_VSYNC callback, hwc2_callback_data_t data); + void enableCallback(bool enable); + + private: + void vsyncLoop(); + bool waitUntilNextVsync(); + + std::thread mThread; + int64_t mNextVsync{0}; + int64_t mPeriod{0}; + + std::mutex mMutex; + std::condition_variable mCondition; + bool mStarted{false}; + HWC2_PFN_VSYNC mCallback{nullptr}; + hwc2_callback_data_t mCallbackData{nullptr}; + bool mCallbackEnabled{false}; + }; + VsyncThread mVsyncThread; +}; + +} // namespace android + +#endif // ANDROID_SF_HWC2_ON_FB_ADAPTER_H |