mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 05:56:34 +00:00
Merge "graphics: add libhwc2on{1,fb}adapter"
This commit is contained in:
76
graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
Normal file
76
graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
Normal file
@@ -0,0 +1,76 @@
|
||||
// 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: "libhwc2on1adapter",
|
||||
vendor: true,
|
||||
|
||||
clang: true,
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-Wno-user-defined-warnings",
|
||||
],
|
||||
cppflags: [
|
||||
"-Weverything",
|
||||
"-Wunused",
|
||||
"-Wunreachable-code",
|
||||
|
||||
// The static constructors and destructors in this library have not been noted to
|
||||
// introduce significant overheads
|
||||
"-Wno-exit-time-destructors",
|
||||
"-Wno-global-constructors",
|
||||
|
||||
// We only care about compiling as C++14
|
||||
"-Wno-c++98-compat-pedantic",
|
||||
|
||||
// android/sensors.h uses nested anonymous unions and anonymous structs
|
||||
"-Wno-nested-anon-types",
|
||||
"-Wno-gnu-anonymous-struct",
|
||||
|
||||
// Don't warn about struct padding
|
||||
"-Wno-padded",
|
||||
|
||||
// hwcomposer2.h features switch covering all cases.
|
||||
"-Wno-covered-switch-default",
|
||||
|
||||
// hwcomposer.h features zero size array.
|
||||
"-Wno-zero-length-array",
|
||||
|
||||
// Disabling warning specific to hwc2on1adapter code
|
||||
"-Wno-double-promotion",
|
||||
"-Wno-sign-conversion",
|
||||
"-Wno-switch-enum",
|
||||
"-Wno-float-equal",
|
||||
"-Wno-shorten-64-to-32",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-missing-prototypes",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"HWC2On1Adapter.cpp",
|
||||
"MiniFence.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libutils",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
"libhardware",
|
||||
],
|
||||
|
||||
export_include_dirs: ["include"],
|
||||
|
||||
export_shared_lib_headers: ["libutils"],
|
||||
}
|
||||
52
graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk
Normal file
52
graphics/composer/2.1/utils/hwc2on1adapter/CleanSpec.mk
Normal file
@@ -0,0 +1,52 @@
|
||||
# Copyright (C) 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.
|
||||
#
|
||||
|
||||
# If you don't need to do a full clean build but would like to touch
|
||||
# a file or delete some intermediate files, add a clean step to the end
|
||||
# of the list. These steps will only be run once, if they haven't been
|
||||
# run before.
|
||||
#
|
||||
# E.g.:
|
||||
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
|
||||
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
|
||||
#
|
||||
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
|
||||
# files that are missing or have been moved.
|
||||
#
|
||||
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
|
||||
# Use $(OUT_DIR) to refer to the "out" directory.
|
||||
#
|
||||
# If you need to re-do something that's already mentioned, just copy
|
||||
# the command and add it to the bottom of the list. E.g., if a change
|
||||
# that you made last week required touching a file and a change you
|
||||
# made today requires touching the same file, just copy the old
|
||||
# touch step and add it to the end of the list.
|
||||
#
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
# For example:
|
||||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
|
||||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
|
||||
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
|
||||
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so)
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so)
|
||||
2637
graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
Normal file
2637
graphics/composer/2.1/utils/hwc2on1adapter/HWC2On1Adapter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
42
graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp
Normal file
42
graphics/composer/2.1/utils/hwc2on1adapter/MiniFence.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#include "hwc2on1adapter/MiniFence.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
|
||||
|
||||
MiniFence::MiniFence() :
|
||||
mFenceFd(-1) {
|
||||
}
|
||||
|
||||
MiniFence::MiniFence(int fenceFd) :
|
||||
mFenceFd(fenceFd) {
|
||||
}
|
||||
|
||||
MiniFence::~MiniFence() {
|
||||
if (mFenceFd != -1) {
|
||||
close(mFenceFd);
|
||||
}
|
||||
}
|
||||
|
||||
int MiniFence::dup() const {
|
||||
return ::dup(mFenceFd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
* Copyright 2015 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_1_ADAPTER_H
|
||||
#define ANDROID_SF_HWC2_ON_1_ADAPTER_H
|
||||
|
||||
#define HWC2_INCLUDE_STRINGIFICATION
|
||||
#define HWC2_USE_CPP11
|
||||
#include <hardware/hwcomposer2.h>
|
||||
#undef HWC2_INCLUDE_STRINGIFICATION
|
||||
#undef HWC2_USE_CPP11
|
||||
|
||||
#include "MiniFence.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
struct hwc_composer_device_1;
|
||||
struct hwc_display_contents_1;
|
||||
struct hwc_layer_1;
|
||||
|
||||
namespace android {
|
||||
|
||||
// For devices unable to provide an implementation of HWC2 (see hwcomposer2.h),
|
||||
// we provide an adapter able to talk to HWC1 (see hwcomposer.h). It translates
|
||||
// streamed function calls ala HWC2 model to batched array of structs calls ala
|
||||
// HWC1 model.
|
||||
class HWC2On1Adapter : public hwc2_device_t
|
||||
{
|
||||
public:
|
||||
explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
|
||||
~HWC2On1Adapter();
|
||||
|
||||
struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
|
||||
uint8_t getHwc1MinorVersion() const { return mHwc1MinorVersion; }
|
||||
|
||||
private:
|
||||
static inline HWC2On1Adapter* getAdapter(hwc2_device_t* device) {
|
||||
return static_cast<HWC2On1Adapter*>(device);
|
||||
}
|
||||
|
||||
// getCapabilities
|
||||
|
||||
void doGetCapabilities(uint32_t* outCount,
|
||||
int32_t* /*hwc2_capability_t*/ outCapabilities);
|
||||
static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
|
||||
int32_t* /*hwc2_capability_t*/ outCapabilities) {
|
||||
getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
|
||||
}
|
||||
|
||||
bool supportsBackgroundColor() {
|
||||
return mHwc1SupportsBackgroundColor;
|
||||
}
|
||||
|
||||
// getFunction
|
||||
|
||||
hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
|
||||
static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
|
||||
int32_t intDesc) {
|
||||
auto descriptor = static_cast<HWC2::FunctionDescriptor>(intDesc);
|
||||
return getAdapter(device)->doGetFunction(descriptor);
|
||||
}
|
||||
|
||||
// Device functions
|
||||
|
||||
HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
|
||||
hwc2_display_t* outDisplay);
|
||||
static int32_t createVirtualDisplayHook(hwc2_device_t* device,
|
||||
uint32_t width, uint32_t height, int32_t* /*format*/,
|
||||
hwc2_display_t* outDisplay) {
|
||||
// HWC1 implementations cannot override the buffer format requested by
|
||||
// the consumer
|
||||
auto error = getAdapter(device)->createVirtualDisplay(width, height,
|
||||
outDisplay);
|
||||
return static_cast<int32_t>(error);
|
||||
}
|
||||
|
||||
HWC2::Error destroyVirtualDisplay(hwc2_display_t display);
|
||||
static int32_t destroyVirtualDisplayHook(hwc2_device_t* device,
|
||||
hwc2_display_t display) {
|
||||
auto error = getAdapter(device)->destroyVirtualDisplay(display);
|
||||
return static_cast<int32_t>(error);
|
||||
}
|
||||
|
||||
std::string mDumpString;
|
||||
void dump(uint32_t* outSize, char* outBuffer);
|
||||
static void dumpHook(hwc2_device_t* device, uint32_t* outSize,
|
||||
char* outBuffer) {
|
||||
getAdapter(device)->dump(outSize, outBuffer);
|
||||
}
|
||||
|
||||
uint32_t getMaxVirtualDisplayCount();
|
||||
static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
|
||||
return getAdapter(device)->getMaxVirtualDisplayCount();
|
||||
}
|
||||
|
||||
HWC2::Error registerCallback(HWC2::Callback descriptor,
|
||||
hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer);
|
||||
static int32_t registerCallbackHook(hwc2_device_t* device,
|
||||
int32_t intDesc, hwc2_callback_data_t callbackData,
|
||||
hwc2_function_pointer_t pointer) {
|
||||
auto descriptor = static_cast<HWC2::Callback>(intDesc);
|
||||
auto error = getAdapter(device)->registerCallback(descriptor,
|
||||
callbackData, pointer);
|
||||
return static_cast<int32_t>(error);
|
||||
}
|
||||
|
||||
// Display functions
|
||||
|
||||
class Layer;
|
||||
|
||||
class SortLayersByZ {
|
||||
public:
|
||||
bool operator()(const std::shared_ptr<Layer>& lhs,
|
||||
const std::shared_ptr<Layer>& rhs);
|
||||
};
|
||||
|
||||
// The semantics of the fences returned by the device differ between
|
||||
// hwc1.set() and hwc2.present(). Read hwcomposer.h and hwcomposer2.h
|
||||
// for more information.
|
||||
//
|
||||
// Release fences in hwc1 are obtained on set() for a frame n and signaled
|
||||
// when the layer buffer is not needed for read operations anymore
|
||||
// (typically on frame n+1). In HWC2, release fences are obtained with a
|
||||
// special call after present() for frame n. These fences signal
|
||||
// on frame n: More specifically, the fence for a given buffer provided in
|
||||
// frame n will signal when the prior buffer is no longer required.
|
||||
//
|
||||
// A retire fence (HWC1) is signaled when a composition is replaced
|
||||
// on the panel whereas a present fence (HWC2) is signaled when a
|
||||
// composition starts to be displayed on a panel.
|
||||
//
|
||||
// The HWC2to1Adapter emulates the new fence semantics for a frame
|
||||
// n by returning the fence from frame n-1. For frame 0, the adapter
|
||||
// returns NO_FENCE.
|
||||
class DeferredFence {
|
||||
public:
|
||||
DeferredFence()
|
||||
: mFences({MiniFence::NO_FENCE, MiniFence::NO_FENCE}) {}
|
||||
|
||||
void add(int32_t fenceFd) {
|
||||
mFences.emplace(new MiniFence(fenceFd));
|
||||
mFences.pop();
|
||||
}
|
||||
|
||||
const sp<MiniFence>& get() const {
|
||||
return mFences.front();
|
||||
}
|
||||
|
||||
private:
|
||||
// There are always two fences in this queue.
|
||||
std::queue<sp<MiniFence>> mFences;
|
||||
};
|
||||
|
||||
class FencedBuffer {
|
||||
public:
|
||||
FencedBuffer() : mBuffer(nullptr), mFence(MiniFence::NO_FENCE) {}
|
||||
|
||||
void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
|
||||
void setFence(int fenceFd) { mFence = new MiniFence(fenceFd); }
|
||||
|
||||
buffer_handle_t getBuffer() const { return mBuffer; }
|
||||
int getFence() const { return mFence->dup(); }
|
||||
|
||||
private:
|
||||
buffer_handle_t mBuffer;
|
||||
sp<MiniFence> mFence;
|
||||
};
|
||||
|
||||
class Display {
|
||||
public:
|
||||
Display(HWC2On1Adapter& device, HWC2::DisplayType type);
|
||||
|
||||
hwc2_display_t getId() const { return mId; }
|
||||
HWC2On1Adapter& getDevice() const { return mDevice; }
|
||||
|
||||
// Does not require locking because it is set before adding the
|
||||
// Displays to the Adapter's list of displays
|
||||
void setHwc1Id(int32_t id) { mHwc1Id = id; }
|
||||
int32_t getHwc1Id() const { return mHwc1Id; }
|
||||
|
||||
// HWC2 Display functions
|
||||
HWC2::Error acceptChanges();
|
||||
HWC2::Error createLayer(hwc2_layer_t* outLayerId);
|
||||
HWC2::Error destroyLayer(hwc2_layer_t layerId);
|
||||
HWC2::Error getActiveConfig(hwc2_config_t* outConfigId);
|
||||
HWC2::Error getAttribute(hwc2_config_t configId,
|
||||
HWC2::Attribute attribute, int32_t* outValue);
|
||||
HWC2::Error getChangedCompositionTypes(uint32_t* outNumElements,
|
||||
hwc2_layer_t* outLayers, int32_t* outTypes);
|
||||
HWC2::Error getColorModes(uint32_t* outNumModes, int32_t* outModes);
|
||||
HWC2::Error getConfigs(uint32_t* outNumConfigs,
|
||||
hwc2_config_t* outConfigIds);
|
||||
HWC2::Error getDozeSupport(int32_t* outSupport);
|
||||
HWC2::Error getHdrCapabilities(uint32_t* outNumTypes,
|
||||
int32_t* outTypes, float* outMaxLuminance,
|
||||
float* outMaxAverageLuminance, float* outMinLuminance);
|
||||
HWC2::Error getName(uint32_t* outSize, char* outName);
|
||||
HWC2::Error getReleaseFences(uint32_t* outNumElements,
|
||||
hwc2_layer_t* outLayers, int32_t* outFences);
|
||||
HWC2::Error getRequests(int32_t* outDisplayRequests,
|
||||
uint32_t* outNumElements, hwc2_layer_t* outLayers,
|
||||
int32_t* outLayerRequests);
|
||||
HWC2::Error getType(int32_t* outType);
|
||||
|
||||
// Since HWC1 "presents" (called "set" in HWC1) all Displays
|
||||
// at once, the first call to any Display::present will trigger
|
||||
// present() on all Displays in the Device. Subsequent calls without
|
||||
// first calling validate() are noop (except for duping/returning
|
||||
// the retire fence).
|
||||
HWC2::Error present(int32_t* outRetireFence);
|
||||
|
||||
HWC2::Error setActiveConfig(hwc2_config_t configId);
|
||||
HWC2::Error setClientTarget(buffer_handle_t target,
|
||||
int32_t acquireFence, int32_t dataspace,
|
||||
hwc_region_t damage);
|
||||
HWC2::Error setColorMode(android_color_mode_t mode);
|
||||
HWC2::Error setColorTransform(android_color_transform_t hint);
|
||||
HWC2::Error setOutputBuffer(buffer_handle_t buffer,
|
||||
int32_t releaseFence);
|
||||
HWC2::Error setPowerMode(HWC2::PowerMode mode);
|
||||
HWC2::Error setVsyncEnabled(HWC2::Vsync enabled);
|
||||
|
||||
// Since HWC1 "validates" (called "prepare" in HWC1) all Displays
|
||||
// at once, the first call to any Display::validate() will trigger
|
||||
// validate() on all other Displays in the Device.
|
||||
HWC2::Error validate(uint32_t* outNumTypes,
|
||||
uint32_t* outNumRequests);
|
||||
|
||||
HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
|
||||
|
||||
HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
|
||||
int32_t format, int32_t dataspace);
|
||||
|
||||
// Read configs from HWC1 device
|
||||
void populateConfigs();
|
||||
|
||||
// Set configs for a virtual display
|
||||
void populateConfigs(uint32_t width, uint32_t height);
|
||||
|
||||
bool prepare();
|
||||
|
||||
// Called after hwc.prepare() with responses from the device.
|
||||
void generateChanges();
|
||||
|
||||
bool hasChanges() const;
|
||||
HWC2::Error set(hwc_display_contents_1& hwcContents);
|
||||
void addRetireFence(int fenceFd);
|
||||
void addReleaseFences(const hwc_display_contents_1& hwcContents);
|
||||
|
||||
bool hasColorTransform() const;
|
||||
|
||||
std::string dump() const;
|
||||
|
||||
// Return a rect from the pool allocated during validate()
|
||||
hwc_rect_t* GetRects(size_t numRects);
|
||||
|
||||
hwc_display_contents_1* getDisplayContents();
|
||||
|
||||
void markGeometryChanged() { mGeometryChanged = true; }
|
||||
void resetGeometryMarker() { mGeometryChanged = false;}
|
||||
private:
|
||||
class Config {
|
||||
public:
|
||||
Config(Display& display)
|
||||
: mDisplay(display),
|
||||
mId(0),
|
||||
mAttributes() {}
|
||||
|
||||
bool isOnDisplay(const Display& display) const {
|
||||
return display.getId() == mDisplay.getId();
|
||||
}
|
||||
|
||||
void setAttribute(HWC2::Attribute attribute, int32_t value);
|
||||
int32_t getAttribute(HWC2::Attribute attribute) const;
|
||||
|
||||
void setHwc1Id(uint32_t id);
|
||||
bool hasHwc1Id(uint32_t id) const;
|
||||
HWC2::Error getColorModeForHwc1Id(uint32_t id,
|
||||
android_color_mode_t *outMode) const;
|
||||
HWC2::Error getHwc1IdForColorMode(android_color_mode_t mode,
|
||||
uint32_t* outId) const;
|
||||
|
||||
void setId(hwc2_config_t id) { mId = id; }
|
||||
hwc2_config_t getId() const { return mId; }
|
||||
|
||||
// Attempts to merge two configs that differ only in color
|
||||
// mode. Returns whether the merge was successful
|
||||
bool merge(const Config& other);
|
||||
|
||||
std::set<android_color_mode_t> getColorModes() const;
|
||||
|
||||
// splitLine divides the output into two lines suitable for
|
||||
// dumpsys SurfaceFlinger
|
||||
std::string toString(bool splitLine = false) const;
|
||||
|
||||
private:
|
||||
Display& mDisplay;
|
||||
hwc2_config_t mId;
|
||||
std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
|
||||
|
||||
// Maps from color transform to HWC1 config ID
|
||||
std::unordered_map<android_color_mode_t, uint32_t> mHwc1Ids;
|
||||
};
|
||||
|
||||
// Stores changes requested from the device upon calling prepare().
|
||||
// Handles change request to:
|
||||
// - Layer composition type.
|
||||
// - Layer hints.
|
||||
class Changes {
|
||||
public:
|
||||
uint32_t getNumTypes() const {
|
||||
return static_cast<uint32_t>(mTypeChanges.size());
|
||||
}
|
||||
|
||||
uint32_t getNumLayerRequests() const {
|
||||
return static_cast<uint32_t>(mLayerRequests.size());
|
||||
}
|
||||
|
||||
const std::unordered_map<hwc2_layer_t, HWC2::Composition>&
|
||||
getTypeChanges() const {
|
||||
return mTypeChanges;
|
||||
}
|
||||
|
||||
const std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>&
|
||||
getLayerRequests() const {
|
||||
return mLayerRequests;
|
||||
}
|
||||
|
||||
void addTypeChange(hwc2_layer_t layerId,
|
||||
HWC2::Composition type) {
|
||||
mTypeChanges.insert({layerId, type});
|
||||
}
|
||||
|
||||
void clearTypeChanges() { mTypeChanges.clear(); }
|
||||
|
||||
void addLayerRequest(hwc2_layer_t layerId,
|
||||
HWC2::LayerRequest request) {
|
||||
mLayerRequests.insert({layerId, request});
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<hwc2_layer_t, HWC2::Composition>
|
||||
mTypeChanges;
|
||||
std::unordered_map<hwc2_layer_t, HWC2::LayerRequest>
|
||||
mLayerRequests;
|
||||
};
|
||||
|
||||
std::shared_ptr<const Config>
|
||||
getConfig(hwc2_config_t configId) const;
|
||||
|
||||
void populateColorModes();
|
||||
void initializeActiveConfig();
|
||||
|
||||
// Creates a bi-directional mapping between index in HWC1
|
||||
// prepare/set array and Layer object. Stores mapping in
|
||||
// mHwc1LayerMap and also updates Layer's attribute mHwc1Id.
|
||||
void assignHwc1LayerIds();
|
||||
|
||||
// Called after a response to prepare() has been received:
|
||||
// Ingest composition type changes requested by the device.
|
||||
void updateTypeChanges(const struct hwc_layer_1& hwc1Layer,
|
||||
const Layer& layer);
|
||||
|
||||
// Called after a response to prepare() has been received:
|
||||
// Ingest layer hint changes requested by the device.
|
||||
void updateLayerRequests(const struct hwc_layer_1& hwc1Layer,
|
||||
const Layer& layer);
|
||||
|
||||
// Set all fields in HWC1 comm array for layer containing the
|
||||
// HWC_FRAMEBUFFER_TARGET (always the last layer).
|
||||
void prepareFramebufferTarget();
|
||||
|
||||
// Display ID generator.
|
||||
static std::atomic<hwc2_display_t> sNextId;
|
||||
const hwc2_display_t mId;
|
||||
|
||||
|
||||
HWC2On1Adapter& mDevice;
|
||||
|
||||
// The state of this display should only be modified from
|
||||
// SurfaceFlinger's main loop, with the exception of when dump is
|
||||
// called. To prevent a bad state from crashing us during a dump
|
||||
// call, all public calls into Display must acquire this mutex.
|
||||
//
|
||||
// It is recursive because we don't want to deadlock in validate
|
||||
// (or present) when we call HWC2On1Adapter::prepareAllDisplays
|
||||
// (or setAllDisplays), which calls back into Display functions
|
||||
// which require locking.
|
||||
mutable std::recursive_mutex mStateMutex;
|
||||
|
||||
// Allocate RAM able to store all layers and rects used for
|
||||
// communication with HWC1. Place allocated RAM in variable
|
||||
// mHwc1RequestedContents.
|
||||
void allocateRequestedContents();
|
||||
|
||||
// Array of structs exchanged between client and hwc1 device.
|
||||
// Sent to device upon calling prepare().
|
||||
std::unique_ptr<hwc_display_contents_1> mHwc1RequestedContents;
|
||||
private:
|
||||
DeferredFence mRetireFence;
|
||||
|
||||
// Will only be non-null after the Display has been validated and
|
||||
// before it has been presented
|
||||
std::unique_ptr<Changes> mChanges;
|
||||
|
||||
int32_t mHwc1Id;
|
||||
|
||||
std::vector<std::shared_ptr<Config>> mConfigs;
|
||||
std::shared_ptr<const Config> mActiveConfig;
|
||||
std::set<android_color_mode_t> mColorModes;
|
||||
android_color_mode_t mActiveColorMode;
|
||||
std::string mName;
|
||||
HWC2::DisplayType mType;
|
||||
HWC2::PowerMode mPowerMode;
|
||||
HWC2::Vsync mVsyncEnabled;
|
||||
|
||||
// Used to populate HWC1 HWC_FRAMEBUFFER_TARGET layer
|
||||
FencedBuffer mClientTarget;
|
||||
|
||||
|
||||
FencedBuffer mOutputBuffer;
|
||||
|
||||
bool mHasColorTransform;
|
||||
|
||||
// All layers this Display is aware of.
|
||||
std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
|
||||
|
||||
// Mapping between layer index in array of hwc_display_contents_1*
|
||||
// passed to HWC1 during validate/set and Layer object.
|
||||
std::unordered_map<size_t, std::shared_ptr<Layer>> mHwc1LayerMap;
|
||||
|
||||
// All communication with HWC1 via prepare/set is done with one
|
||||
// alloc. This pointer is pointing to a pool of hwc_rect_t.
|
||||
size_t mNumAvailableRects;
|
||||
hwc_rect_t* mNextAvailableRect;
|
||||
|
||||
// True if any of the Layers contained in this Display have been
|
||||
// updated with anything other than a buffer since last call to
|
||||
// Display::set()
|
||||
bool mGeometryChanged;
|
||||
};
|
||||
|
||||
// Utility template calling a Display object method directly based on the
|
||||
// hwc2_display_t displayId parameter.
|
||||
template <typename ...Args>
|
||||
static int32_t callDisplayFunction(hwc2_device_t* device,
|
||||
hwc2_display_t displayId, HWC2::Error (Display::*member)(Args...),
|
||||
Args... args) {
|
||||
auto display = getAdapter(device)->getDisplay(displayId);
|
||||
if (!display) {
|
||||
return static_cast<int32_t>(HWC2::Error::BadDisplay);
|
||||
}
|
||||
auto error = ((*display).*member)(std::forward<Args>(args)...);
|
||||
return static_cast<int32_t>(error);
|
||||
}
|
||||
|
||||
template <typename MF, MF memFunc, typename ...Args>
|
||||
static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
|
||||
Args... args) {
|
||||
return HWC2On1Adapter::callDisplayFunction(device, displayId, memFunc,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static int32_t getDisplayAttributeHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, hwc2_config_t config,
|
||||
int32_t intAttribute, int32_t* outValue) {
|
||||
auto attribute = static_cast<HWC2::Attribute>(intAttribute);
|
||||
return callDisplayFunction(device, display, &Display::getAttribute,
|
||||
config, attribute, outValue);
|
||||
}
|
||||
|
||||
static int32_t setColorTransformHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, const float* /*matrix*/,
|
||||
int32_t /*android_color_transform_t*/ intHint) {
|
||||
// We intentionally throw away the matrix, because if the hint is
|
||||
// anything other than IDENTITY, we have to fall back to client
|
||||
// composition anyway
|
||||
auto hint = static_cast<android_color_transform_t>(intHint);
|
||||
return callDisplayFunction(device, display, &Display::setColorTransform,
|
||||
hint);
|
||||
}
|
||||
|
||||
static int32_t setColorModeHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, int32_t /*android_color_mode_t*/ intMode) {
|
||||
auto mode = static_cast<android_color_mode_t>(intMode);
|
||||
return callDisplayFunction(device, display, &Display::setColorMode,
|
||||
mode);
|
||||
}
|
||||
|
||||
static int32_t setPowerModeHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, int32_t intMode) {
|
||||
auto mode = static_cast<HWC2::PowerMode>(intMode);
|
||||
return callDisplayFunction(device, display, &Display::setPowerMode,
|
||||
mode);
|
||||
}
|
||||
|
||||
static int32_t setVsyncEnabledHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, int32_t intEnabled) {
|
||||
auto enabled = static_cast<HWC2::Vsync>(intEnabled);
|
||||
return callDisplayFunction(device, display, &Display::setVsyncEnabled,
|
||||
enabled);
|
||||
}
|
||||
|
||||
class Layer {
|
||||
public:
|
||||
explicit Layer(Display& display);
|
||||
|
||||
bool operator==(const Layer& other) { return mId == other.mId; }
|
||||
bool operator!=(const Layer& other) { return !(*this == other); }
|
||||
|
||||
hwc2_layer_t getId() const { return mId; }
|
||||
Display& getDisplay() const { return mDisplay; }
|
||||
|
||||
// HWC2 Layer functions
|
||||
HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
|
||||
HWC2::Error setCursorPosition(int32_t x, int32_t y);
|
||||
HWC2::Error setSurfaceDamage(hwc_region_t damage);
|
||||
|
||||
// HWC2 Layer state functions
|
||||
HWC2::Error setBlendMode(HWC2::BlendMode mode);
|
||||
HWC2::Error setColor(hwc_color_t color);
|
||||
HWC2::Error setCompositionType(HWC2::Composition type);
|
||||
HWC2::Error setDataspace(android_dataspace_t dataspace);
|
||||
HWC2::Error setDisplayFrame(hwc_rect_t frame);
|
||||
HWC2::Error setPlaneAlpha(float alpha);
|
||||
HWC2::Error setSidebandStream(const native_handle_t* stream);
|
||||
HWC2::Error setSourceCrop(hwc_frect_t crop);
|
||||
HWC2::Error setTransform(HWC2::Transform transform);
|
||||
HWC2::Error setVisibleRegion(hwc_region_t visible);
|
||||
HWC2::Error setZ(uint32_t z);
|
||||
|
||||
HWC2::Composition getCompositionType() const {
|
||||
return mCompositionType;
|
||||
}
|
||||
uint32_t getZ() const { return mZ; }
|
||||
|
||||
void addReleaseFence(int fenceFd);
|
||||
const sp<MiniFence>& getReleaseFence() const;
|
||||
|
||||
void setHwc1Id(size_t id) { mHwc1Id = id; }
|
||||
size_t getHwc1Id() const { return mHwc1Id; }
|
||||
|
||||
// Write state to HWC1 communication struct.
|
||||
void applyState(struct hwc_layer_1& hwc1Layer);
|
||||
|
||||
std::string dump() const;
|
||||
|
||||
std::size_t getNumVisibleRegions() { return mVisibleRegion.size(); }
|
||||
|
||||
std::size_t getNumSurfaceDamages() { return mSurfaceDamage.size(); }
|
||||
|
||||
// True if a layer cannot be properly rendered by the device due
|
||||
// to usage of SolidColor (a.k.a BackgroundColor in HWC1).
|
||||
bool hasUnsupportedBackgroundColor() {
|
||||
return (mCompositionType == HWC2::Composition::SolidColor &&
|
||||
!mDisplay.getDevice().supportsBackgroundColor());
|
||||
}
|
||||
private:
|
||||
void applyCommonState(struct hwc_layer_1& hwc1Layer);
|
||||
void applySolidColorState(struct hwc_layer_1& hwc1Layer);
|
||||
void applySidebandState(struct hwc_layer_1& hwc1Layer);
|
||||
void applyBufferState(struct hwc_layer_1& hwc1Layer);
|
||||
void applyCompositionType(struct hwc_layer_1& hwc1Layer);
|
||||
|
||||
static std::atomic<hwc2_layer_t> sNextId;
|
||||
const hwc2_layer_t mId;
|
||||
Display& mDisplay;
|
||||
|
||||
FencedBuffer mBuffer;
|
||||
std::vector<hwc_rect_t> mSurfaceDamage;
|
||||
|
||||
HWC2::BlendMode mBlendMode;
|
||||
hwc_color_t mColor;
|
||||
HWC2::Composition mCompositionType;
|
||||
hwc_rect_t mDisplayFrame;
|
||||
float mPlaneAlpha;
|
||||
const native_handle_t* mSidebandStream;
|
||||
hwc_frect_t mSourceCrop;
|
||||
HWC2::Transform mTransform;
|
||||
std::vector<hwc_rect_t> mVisibleRegion;
|
||||
|
||||
uint32_t mZ;
|
||||
|
||||
DeferredFence mReleaseFence;
|
||||
|
||||
size_t mHwc1Id;
|
||||
bool mHasUnsupportedPlaneAlpha;
|
||||
};
|
||||
|
||||
// Utility tempate calling a Layer object method based on ID parameters:
|
||||
// hwc2_display_t displayId
|
||||
// and
|
||||
// hwc2_layer_t layerId
|
||||
template <typename ...Args>
|
||||
static int32_t callLayerFunction(hwc2_device_t* device,
|
||||
hwc2_display_t displayId, hwc2_layer_t layerId,
|
||||
HWC2::Error (Layer::*member)(Args...), Args... args) {
|
||||
auto result = getAdapter(device)->getLayer(displayId, layerId);
|
||||
auto error = std::get<HWC2::Error>(result);
|
||||
if (error == HWC2::Error::None) {
|
||||
auto layer = std::get<Layer*>(result);
|
||||
error = ((*layer).*member)(std::forward<Args>(args)...);
|
||||
}
|
||||
return static_cast<int32_t>(error);
|
||||
}
|
||||
|
||||
template <typename MF, MF memFunc, typename ...Args>
|
||||
static int32_t layerHook(hwc2_device_t* device, hwc2_display_t displayId,
|
||||
hwc2_layer_t layerId, Args... args) {
|
||||
return HWC2On1Adapter::callLayerFunction(device, displayId, layerId,
|
||||
memFunc, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Layer state functions
|
||||
|
||||
static int32_t setLayerBlendModeHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, hwc2_layer_t layer, int32_t intMode) {
|
||||
auto mode = static_cast<HWC2::BlendMode>(intMode);
|
||||
return callLayerFunction(device, display, layer,
|
||||
&Layer::setBlendMode, mode);
|
||||
}
|
||||
|
||||
static int32_t setLayerCompositionTypeHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, hwc2_layer_t layer, int32_t intType) {
|
||||
auto type = static_cast<HWC2::Composition>(intType);
|
||||
return callLayerFunction(device, display, layer,
|
||||
&Layer::setCompositionType, type);
|
||||
}
|
||||
|
||||
static int32_t setLayerDataspaceHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, hwc2_layer_t layer, int32_t intDataspace) {
|
||||
auto dataspace = static_cast<android_dataspace_t>(intDataspace);
|
||||
return callLayerFunction(device, display, layer, &Layer::setDataspace,
|
||||
dataspace);
|
||||
}
|
||||
|
||||
static int32_t setLayerTransformHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, hwc2_layer_t layer, int32_t intTransform) {
|
||||
auto transform = static_cast<HWC2::Transform>(intTransform);
|
||||
return callLayerFunction(device, display, layer, &Layer::setTransform,
|
||||
transform);
|
||||
}
|
||||
|
||||
static int32_t setLayerZOrderHook(hwc2_device_t* device,
|
||||
hwc2_display_t display, hwc2_layer_t layer, uint32_t z) {
|
||||
return callDisplayFunction(device, display, &Display::updateLayerZ,
|
||||
layer, z);
|
||||
}
|
||||
|
||||
// Adapter internals
|
||||
|
||||
void populateCapabilities();
|
||||
Display* getDisplay(hwc2_display_t id);
|
||||
std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
|
||||
hwc2_layer_t layerId);
|
||||
void populatePrimary();
|
||||
|
||||
bool prepareAllDisplays();
|
||||
std::vector<struct hwc_display_contents_1*> mHwc1Contents;
|
||||
HWC2::Error setAllDisplays();
|
||||
|
||||
// Callbacks
|
||||
void hwc1Invalidate();
|
||||
void hwc1Vsync(int hwc1DisplayId, int64_t timestamp);
|
||||
void hwc1Hotplug(int hwc1DisplayId, int connected);
|
||||
|
||||
// These are set in the constructor and before any asynchronous events are
|
||||
// possible
|
||||
|
||||
struct hwc_composer_device_1* const mHwc1Device;
|
||||
const uint8_t mHwc1MinorVersion;
|
||||
bool mHwc1SupportsVirtualDisplays;
|
||||
bool mHwc1SupportsBackgroundColor;
|
||||
|
||||
class Callbacks;
|
||||
const std::unique_ptr<Callbacks> mHwc1Callbacks;
|
||||
|
||||
std::unordered_set<HWC2::Capability> mCapabilities;
|
||||
|
||||
// These are only accessed from the main SurfaceFlinger thread (not from
|
||||
// callbacks or dump
|
||||
|
||||
std::map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
|
||||
|
||||
// A HWC1 supports only one virtual display.
|
||||
std::shared_ptr<Display> mHwc1VirtualDisplay;
|
||||
|
||||
// These are potentially accessed from multiple threads, and are protected
|
||||
// by this mutex. This needs to be recursive, since the HWC1 implementation
|
||||
// can call back into the invalidate callback on the same thread that is
|
||||
// calling prepare.
|
||||
std::recursive_timed_mutex mStateMutex;
|
||||
|
||||
struct CallbackInfo {
|
||||
hwc2_callback_data_t data;
|
||||
hwc2_function_pointer_t pointer;
|
||||
};
|
||||
std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
|
||||
bool mHasPendingInvalidate;
|
||||
|
||||
// There is a small gap between the time the HWC1 module is started and
|
||||
// when the callbacks for vsync and hotplugs are registered by the
|
||||
// HWC2on1Adapter. To prevent losing events they are stored in these arrays
|
||||
// and fed to the callback as soon as possible.
|
||||
std::vector<std::pair<int, int64_t>> mPendingVsyncs;
|
||||
std::vector<std::pair<int, int>> mPendingHotplugs;
|
||||
|
||||
// Mapping between HWC1 display id and Display objects.
|
||||
std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
|
||||
|
||||
// Map HWC1 display type (HWC_DISPLAY_PRIMARY, HWC_DISPLAY_EXTERNAL,
|
||||
// HWC_DISPLAY_VIRTUAL) to Display IDs generated by HWC2on1Adapter objects.
|
||||
std::unordered_map<int, hwc2_display_t> mHwc1DisplayMap;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 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 MINIFENCE_H
|
||||
#define MINIFENCE_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/* MiniFence is a minimal re-implementation of Fence from libui. It exists to
|
||||
* avoid linking the HWC2on1Adapter to libui and satisfy Treble requirements.
|
||||
*/
|
||||
class MiniFence : public LightRefBase<MiniFence> {
|
||||
public:
|
||||
static const sp<MiniFence> NO_FENCE;
|
||||
|
||||
// Construct a new MiniFence object with an invalid file descriptor.
|
||||
MiniFence();
|
||||
|
||||
// Construct a new MiniFence object to manage a given fence file descriptor.
|
||||
// When the new MiniFence object is destructed the file descriptor will be
|
||||
// closed.
|
||||
explicit MiniFence(int fenceFd);
|
||||
|
||||
// Not copyable or movable.
|
||||
MiniFence(const MiniFence& rhs) = delete;
|
||||
MiniFence& operator=(const MiniFence& rhs) = delete;
|
||||
MiniFence(MiniFence&& rhs) = delete;
|
||||
MiniFence& operator=(MiniFence&& rhs) = delete;
|
||||
|
||||
// Return a duplicate of the fence file descriptor. The caller is
|
||||
// responsible for closing the returned file descriptor. On error, -1 will
|
||||
// be returned and errno will indicate the problem.
|
||||
int dup() const;
|
||||
|
||||
private:
|
||||
// Only allow instantiation using ref counting.
|
||||
friend class LightRefBase<MiniFence>;
|
||||
~MiniFence();
|
||||
|
||||
int mFenceFd;
|
||||
|
||||
};
|
||||
}
|
||||
#endif //MINIFENCE_H
|
||||
33
graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
Normal file
33
graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
Normal file
@@ -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"],
|
||||
}
|
||||
887
graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
Normal file
887
graphics/composer/2.1/utils/hwc2onfbadapter/HWC2OnFbAdapter.cpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user