blob: 4ab09e1e8ee356815c36eb88488715e1b1a92d76 [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HW_EMU_HWC2_H
#define ANDROID_HW_EMU_HWC2_H
#define HWC2_INCLUDE_STRINGIFICATION
#define HWC2_USE_CPP11
#include <hardware/hwcomposer2.h>
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
#include <utils/Thread.h>
#include <android-base/unique_fd.h>
#include <atomic>
#include <map>
#include <memory>
#include <mutex>
#include <numeric>
#include <sstream>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include <set>
#include <cutils/native_handle.h>
#include "HostConnection.h"
namespace android {
class EmuHWC2 : public hwc2_device_t {
public:
EmuHWC2();
int populatePrimary();
int populateSecondaryDisplays();
private:
static inline EmuHWC2* getHWC2(hwc2_device_t* device) {
return static_cast<EmuHWC2*>(device);
}
static int closeHook(hw_device_t* device) {
EmuHWC2 *ctx = reinterpret_cast<EmuHWC2*>(device);
delete ctx;
return 0;
}
// getCapabilities
void doGetCapabilities(uint32_t* outCount, int32_t* outCapabilities);
static void getCapabilitiesHook(hwc2_device_t* device, uint32_t* outCount,
int32_t* outCapabilities) {
getHWC2(device)->doGetCapabilities(outCount, outCapabilities);
}
// getFunction
hwc2_function_pointer_t doGetFunction(HWC2::FunctionDescriptor descriptor);
static hwc2_function_pointer_t getFunctionHook(hwc2_device_t* device,
int32_t desc) {
auto descriptor = static_cast<HWC2::FunctionDescriptor>(desc);
return getHWC2(device)->doGetFunction(descriptor);
}
// Device functions
HWC2::Error createVirtualDisplay(uint32_t width, uint32_t height,
int32_t* format, 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) {
auto error = getHWC2(device)->createVirtualDisplay(width, height,
format, 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 = getHWC2(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) {
getHWC2(device)->dump(outSize, outBuffer);
}
uint32_t getMaxVirtualDisplayCount();
static uint32_t getMaxVirtualDisplayCountHook(hwc2_device_t* device) {
return getHWC2(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 = getHWC2(device)->registerCallback(descriptor,
callbackData, pointer);
return static_cast<int32_t>(error);
}
class Layer;
class SortLayersByZ {
public:
bool operator()(const std::shared_ptr<Layer>& lhs,
const std::shared_ptr<Layer>& rhs) const;
};
// SurfaceFlinger sets the ColorBuffer and its Fence handler for each
// layer. This class is a container for these two.
class FencedBuffer {
public:
FencedBuffer() : mBuffer(nullptr) {}
void setBuffer(buffer_handle_t buffer) { mBuffer = buffer; }
void setFence(int fenceFd) {
mFence = std::make_shared<base::unique_fd>(fenceFd);
}
buffer_handle_t getBuffer() const { return mBuffer; }
int getFence() const { return mFence ? dup(mFence->get()) : -1; }
private:
buffer_handle_t mBuffer;
std::shared_ptr<base::unique_fd> mFence;
};
typedef struct compose_layer {
uint32_t cbHandle;
hwc2_composition_t composeMode;
hwc_rect_t displayFrame;
hwc_frect_t crop;
int32_t blendMode;
float alpha;
hwc_color_t color;
hwc_transform_t transform;
} ComposeLayer;
typedef struct compose_device {
uint32_t version;
uint32_t targetHandle;
uint32_t numLayers;
struct compose_layer layer[0];
} ComposeDevice;
typedef struct compose_device_v2 {
uint32_t version;
uint32_t displayId;
uint32_t targetHandle;
uint32_t numLayers;
struct compose_layer layer[0];
} ComposeDevice_v2;
class ComposeMsg {
public:
ComposeMsg(uint32_t layerCnt = 0) :
mData(sizeof(ComposeDevice) + layerCnt * sizeof(ComposeLayer))
{
mComposeDevice = reinterpret_cast<ComposeDevice*>(mData.data());
mLayerCnt = layerCnt;
}
ComposeDevice* get() { return mComposeDevice; }
uint32_t getLayerCnt() { return mLayerCnt; }
private:
std::vector<uint8_t> mData;
uint32_t mLayerCnt;
ComposeDevice* mComposeDevice;
};
class ComposeMsg_v2 {
public:
ComposeMsg_v2(uint32_t layerCnt = 0) :
mData(sizeof(ComposeDevice_v2) + layerCnt * sizeof(ComposeLayer))
{
mComposeDevice = reinterpret_cast<ComposeDevice_v2*>(mData.data());
mLayerCnt = layerCnt;
}
ComposeDevice_v2* get() { return mComposeDevice; }
uint32_t getLayerCnt() { return mLayerCnt; }
private:
std::vector<uint8_t> mData;
uint32_t mLayerCnt;
ComposeDevice_v2* mComposeDevice;
};
class Display {
public:
Display(EmuHWC2& device, HWC2::DisplayType type, int width, int height);
~Display();
hwc2_display_t getId() const {return mId;}
// 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 getDisplayAttribute(hwc2_config_t configId,
int32_t 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);
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(int32_t mode);
HWC2::Error setColorTransform(const float* matrix,
int32_t hint);
HWC2::Error setOutputBuffer(buffer_handle_t buffer,
int32_t releaseFence);
HWC2::Error setPowerMode(int32_t mode);
HWC2::Error setVsyncEnabled(int32_t enabled);
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);
// 2.3 required functions
HWC2::Error getDisplayIdentificationData(uint8_t* outPort,
uint32_t* outDataSize, uint8_t* outData);
HWC2::Error getDisplayCapabilities(uint32_t* outNumCapabilities,
uint32_t* outCapabilities);
HWC2::Error getDisplayBrightnessSupport(bool *out_support);
HWC2::Error setDisplayBrightness(float brightness);
// Read configs from PRIMARY Display
int populatePrimaryConfigs(int width, int height, int dpiX, int dpiY);
HWC2::Error populateSecondaryConfigs(uint32_t width, uint32_t height,
uint32_t dpi, uint32_t idx);
private:
void post(HostConnection *hostCon, ExtendedRCEncoderContext *rcEnc,
buffer_handle_t h);
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 setId(hwc2_config_t id) {mId = id; }
hwc2_config_t getId() const {return mId; }
std::string toString() const;
private:
Display& mDisplay;
hwc2_config_t mId;
std::unordered_map<HWC2::Attribute, int32_t> mAttributes;
};
// 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;
};
// Generate sw vsync signal
class VsyncThread : public Thread {
public:
VsyncThread(Display& display)
: mDisplay(display) {}
virtual ~VsyncThread() {}
private:
Display& mDisplay;
bool threadLoop() final;
};
private:
EmuHWC2& mDevice;
// Display ID generator.
static std::atomic<hwc2_display_t> sNextId;
static const uint32_t hostDisplayIdStart = 6;
const hwc2_display_t mId;
// emulator side displayId
uint32_t mHostDisplayId;
std::string mName;
HWC2::DisplayType mType;
HWC2::PowerMode mPowerMode;
HWC2::Vsync mVsyncEnabled;
uint32_t mVsyncPeriod;
VsyncThread mVsyncThread;
FencedBuffer mClientTarget;
// Will only be non-null after the Display has been validated and
// before it has been presented
std::unique_ptr<Changes> mChanges;
// All layers this Display is aware of.
std::multiset<std::shared_ptr<Layer>, SortLayersByZ> mLayers;
std::vector<hwc2_display_t> mReleaseLayerIds;
std::vector<int32_t> mReleaseFences;
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;
bool mSetColorTransform;
// 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.
mutable std::mutex mStateMutex;
std::unique_ptr<ComposeMsg> mComposeMsg;
std::unique_ptr<ComposeMsg_v2> mComposeMsg_v2;
int mSyncDeviceFd;
const native_handle_t* mTargetCb;
};
template<typename MF, MF memFunc, typename ...Args>
static int32_t displayHook(hwc2_device_t* device, hwc2_display_t displayId,
Args... args) {
auto display = getHWC2(device)->getDisplay(displayId);
if (!display) {
return static_cast<int32_t>(HWC2::Error::BadDisplay);
}
auto error = ((*display).*memFunc)(std::forward<Args>(args)...);
return static_cast<int32_t>(error);
}
class Layer {
public:
explicit Layer(Display& display);
Display& getDisplay() const {return mDisplay;}
hwc2_layer_t getId() const {return mId;}
bool operator==(const Layer& other) { return mId == other.mId; }
bool operator!=(const Layer& other) { return !(*this == other); }
// 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(int32_t mode);
HWC2::Error setColor(hwc_color_t color);
HWC2::Error setCompositionType(int32_t type);
HWC2::Error setDataspace(int32_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(int32_t transform);
HWC2::Error setVisibleRegion(hwc_region_t visible);
HWC2::Error setZ(uint32_t z);
HWC2::Composition getCompositionType() const {
return mCompositionType;
}
hwc_color_t getColor() {return mColor; }
uint32_t getZ() {return mZ; }
std::size_t getNumVisibleRegions() {return mVisibleRegion.size(); }
FencedBuffer& getLayerBuffer() {return mBuffer; }
int32_t getBlendMode() {return (int32_t)mBlendMode; }
float getPlaneAlpha() {return mPlaneAlpha; }
hwc_frect_t getSourceCrop() {return mSourceCrop; }
hwc_rect_t getDisplayFrame() {return mDisplayFrame; }
hwc_transform_t getTransform() {return (hwc_transform_t)mTransform; }
private:
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;
};
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) {
auto result = getHWC2(device)->getLayer(displayId, layerId);
auto error = std::get<HWC2::Error>(result);
if (error == HWC2::Error::None) {
auto layer = std::get<Layer*>(result);
error = ((*layer).*memFunc)(std::forward<Args>(args)...);
}
return static_cast<int32_t>(error);
}
// helpers
void populateCapabilities();
Display* getDisplay(hwc2_display_t id);
std::tuple<Layer*, HWC2::Error> getLayer(hwc2_display_t displayId,
hwc2_layer_t layerId);
HWC2::Error initDisplayParameters();
const native_handle_t* allocateDisplayColorBuffer(int width, int height);
void freeDisplayColorBuffer(const native_handle_t* h);
std::unordered_set<HWC2::Capability> mCapabilities;
// These are potentially accessed from multiple threads, and are protected
// by this mutex.
std::mutex mStateMutex;
struct CallbackInfo {
hwc2_callback_data_t data;
hwc2_function_pointer_t pointer;
};
std::unordered_map<HWC2::Callback, CallbackInfo> mCallbacks;
// use map so displays can be pluged in by order of ID, 0, 1, 2, 3, etc.
std::map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
std::unordered_map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
int mDisplayWidth;
int mDisplayHeight;
int mDisplayDpiX;
int mDisplayDpiY;
};
}
#endif