Emulator HWC2 HAL implementation
Test: go/emu-hwc2
Bug: 78773713
Change-Id: I4023803c8c91d18c658a751c2cc48c244af1c75d
diff --git a/Android.mk b/Android.mk
index 39b8144..c9eae70 100644
--- a/Android.mk
+++ b/Android.mk
@@ -137,4 +137,9 @@
include $(GOLDFISH_OPENGL_PATH)/system/vulkan/Android.mk
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 28 -o $(IS_AT_LEAST_QPR1) = true && echo isApi29OrHigher),isApi29OrHigher)
+ # HWC2 enabled after P
+ include $(GOLDFISH_OPENGL_PATH)/system/hwc2/Android.mk
+endif
+
endif
diff --git a/system/OpenglSystemCommon/HostConnection.cpp b/system/OpenglSystemCommon/HostConnection.cpp
index b3788fa..790994e 100644
--- a/system/OpenglSystemCommon/HostConnection.cpp
+++ b/system/OpenglSystemCommon/HostConnection.cpp
@@ -226,6 +226,7 @@
queryAndSetDmaImpl(m_rcEnc);
queryAndSetGLESMaxVersion(m_rcEnc);
queryAndSetNoErrorState(m_rcEnc);
+ queryAndSetHostCompositionImpl(m_rcEnc);
if (m_processPipe) {
m_processPipe->processPipeInit(m_rcEnc);
}
@@ -279,6 +280,17 @@
return m_glExtensions;
}
+void HostConnection::queryAndSetHostCompositionImpl(ExtendedRCEncoderContext *rcEnc) {
+ const std::string& glExtensions = queryGLExtensions(rcEnc);
+ ALOGD("HostComposition ext %s", glExtensions.c_str());
+ if (glExtensions.find(kHostCompositionV1) != std::string::npos) {
+ rcEnc->setHostComposition(HOST_COMPOSITION_V1);
+ }
+ else {
+ rcEnc->setHostComposition(HOST_COMPOSITION_NONE);
+ }
+}
+
void HostConnection::setChecksumHelper(ExtendedRCEncoderContext *rcEnc) {
const std::string& glExtensions = queryGLExtensions(rcEnc);
// check the host supported version
diff --git a/system/OpenglSystemCommon/HostConnection.h b/system/OpenglSystemCommon/HostConnection.h
index 9c0d2b0..c19693c 100644
--- a/system/OpenglSystemCommon/HostConnection.h
+++ b/system/OpenglSystemCommon/HostConnection.h
@@ -72,6 +72,12 @@
static const char kGLESMaxVersion_3_1[] = "ANDROID_EMU_gles_max_version_3_1";
static const char kGLESMaxVersion_3_2[] = "ANDROID_EMU_gles_max_version_3_2";
+enum HostComposition {
+ HOST_COMPOSITION_NONE = 0,
+ HOST_COMPOSITION_V1,
+};
+static const char kHostCompositionV1[] = "ANDROID_EMU_host_composition_v1";
+
// No querying errors from host extension
static const char kGLESNoHostError[] = "ANDROID_EMU_gles_no_host_error";
@@ -85,8 +91,12 @@
}
void setSyncImpl(SyncImpl syncImpl) { m_syncImpl = syncImpl; }
void setDmaImpl(DmaImpl dmaImpl) { m_dmaImpl = dmaImpl; }
+ void setHostComposition(HostComposition hostComposition) {
+ m_hostComposition = hostComposition; }
bool hasNativeSync() const { return m_syncImpl >= SYNC_IMPL_NATIVE_SYNC_V2; }
bool hasNativeSyncV3() const { return m_syncImpl >= SYNC_IMPL_NATIVE_SYNC_V3; }
+ bool hasHostCompositionV1() const {
+ return m_hostComposition == HOST_COMPOSITION_V1; }
DmaImpl getDmaVersion() const { return m_dmaImpl; }
void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
virtual uint64_t lockAndWriteDma(void* data, uint32_t size) {
@@ -107,6 +117,7 @@
private:
SyncImpl m_syncImpl;
DmaImpl m_dmaImpl;
+ HostComposition m_hostComposition;
struct goldfish_dma_context* m_dmaCxt;
GLESMaxVersion m_glesMaxVersion;
};
@@ -167,6 +178,7 @@
void queryAndSetDmaImpl(ExtendedRCEncoderContext *rcEnc);
void queryAndSetGLESMaxVersion(ExtendedRCEncoderContext *rcEnc);
void queryAndSetNoErrorState(ExtendedRCEncoderContext *rcEnc);
+ void queryAndSetHostCompositionImpl(ExtendedRCEncoderContext *rcEnc);
private:
IOStream *m_stream;
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
new file mode 100644
index 0000000..a3bf20f
--- /dev/null
+++ b/system/hwc2/Android.mk
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_VENDOR_MODULE := true
+emulator_hwcomposer_shared_libraries := \
+ liblog \
+ libutils \
+ libcutils \
+ libEGL \
+ libutils \
+ libhardware \
+ libsync \
+ libui \
+
+emulator_hwcomposer_cflags += \
+ -DLOG_TAG=\"hwc2\"
+
+emulator_hwcomposer_c_includes += \
+ system/core/libsync \
+ system/core/libsync/include \
+ device/generic/goldfish-opengl/system/include \
+ device/generic/goldfish-opengl/system/OpenglSystemCommon \
+ device/generic/goldfish-opengl/host/include/libOpenglRender \
+ device/generic/goldfish-opengl/shared/OpenglCodecCommon \
+ device/generic/goldfish-opengl/system/renderControl_enc
+
+emulator_hwcomposer_relative_path := hw
+
+emulator_hwcomposer2_src_files := \
+ EmuHWC2.cpp \
+ MiniFence.cpp
+
+include $(CLEAR_VARS)
+
+LOCAL_VENDOR_MODULE := true
+LOCAL_SHARED_LIBRARIES := $(emulator_hwcomposer_shared_libraries)
+LOCAL_SHARED_LIBRARIES += libOpenglSystemCommon lib_renderControl_enc
+LOCAL_SRC_FILES := $(emulator_hwcomposer2_src_files)
+LOCAL_C_INCLUDES := $(emulator_hwcomposer_c_includes)
+LOCAL_MODULE_RELATIVE_PATH := $(emulator_hwcomposer_relative_path)
+
+LOCAL_MODULE := hwcomposer.ranchu
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/system/hwc2/EmuHWC2.cpp b/system/hwc2/EmuHWC2.cpp
new file mode 100644
index 0000000..37466a1
--- /dev/null
+++ b/system/hwc2/EmuHWC2.cpp
@@ -0,0 +1,1336 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EmuHWC2.h"
+#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "EmuHWC2"
+
+#include <errno.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#if defined(LOG_NNDEBUG) && LOG_NNDEBUG == 0
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+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);
+}
+
+#define DEFINE_AND_VALIDATE_HOST_CONNECTION \
+ HostConnection *hostCon = HostConnection::get(); \
+ if (!hostCon) { \
+ ALOGE("EmuHWC2: Failed to get host connection\n"); \
+ return Error::NoResources; \
+ } \
+ ExtendedRCEncoderContext *rcEnc = hostCon->rcEncoder(); \
+ if (!rcEnc) { \
+ ALOGE("EmuHWC2: Failed to get renderControl encoder context\n"); \
+ return Error::NoResources; \
+ }
+
+
+using namespace HWC2;
+
+namespace android {
+
+EmuHWC2::EmuHWC2()
+ : mStateMutex()
+{
+ common.tag = HARDWARE_DEVICE_TAG;
+ common.version = HWC_DEVICE_API_VERSION_2_0;
+ common.close = closeHook;
+ getCapabilities = getCapabilitiesHook;
+ getFunction = getFunctionHook;
+ populateCapabilities();
+}
+
+void EmuHWC2::doGetCapabilities(uint32_t* outCount, int32_t* outCapabilities) {
+ if (outCapabilities == nullptr) {
+ *outCount = mCapabilities.size();
+ return;
+ }
+
+ auto capabilityIter = mCapabilities.cbegin();
+ for (size_t i = 0; i < *outCount; ++i) {
+ if (capabilityIter == mCapabilities.cend()) {
+ return;
+ }
+ outCapabilities[i] = static_cast<int32_t>(*capabilityIter);
+ ++capabilityIter;
+ }
+}
+
+hwc2_function_pointer_t EmuHWC2::doGetFunction(
+ FunctionDescriptor descriptor) {
+ switch(descriptor) {
+ case FunctionDescriptor::CreateVirtualDisplay:
+ return asFP<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+ createVirtualDisplayHook);
+ case FunctionDescriptor::DestroyVirtualDisplay:
+ return asFP<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+ destroyVirtualDisplayHook);
+ case FunctionDescriptor::Dump:
+ return asFP<HWC2_PFN_DUMP>(dumpHook);
+ case FunctionDescriptor::GetMaxVirtualDisplayCount:
+ return asFP<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+ getMaxVirtualDisplayCountHook);
+ case FunctionDescriptor::RegisterCallback:
+ return asFP<HWC2_PFN_REGISTER_CALLBACK>(registerCallbackHook);
+
+ // Display functions
+ case FunctionDescriptor::AcceptDisplayChanges:
+ return asFP<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+ displayHook<decltype(&Display::acceptChanges),
+ &Display::acceptChanges>);
+ case FunctionDescriptor::CreateLayer:
+ return asFP<HWC2_PFN_CREATE_LAYER>(
+ displayHook<decltype(&Display::createLayer),
+ &Display::createLayer, hwc2_layer_t*>);
+ case FunctionDescriptor::DestroyLayer:
+ return asFP<HWC2_PFN_DESTROY_LAYER>(
+ displayHook<decltype(&Display::destroyLayer),
+ &Display::destroyLayer, hwc2_layer_t>);
+ case FunctionDescriptor::GetActiveConfig:
+ return asFP<HWC2_PFN_GET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::getActiveConfig),
+ &Display::getActiveConfig, hwc2_config_t*>);
+ case FunctionDescriptor::GetChangedCompositionTypes:
+ return asFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+ displayHook<decltype(&Display::getChangedCompositionTypes),
+ &Display::getChangedCompositionTypes, uint32_t*,
+ hwc2_layer_t*, int32_t*>);
+ case FunctionDescriptor::GetColorModes:
+ return asFP<HWC2_PFN_GET_COLOR_MODES>(
+ displayHook<decltype(&Display::getColorModes),
+ &Display::getColorModes, uint32_t*, int32_t*>);
+ case FunctionDescriptor::GetDisplayAttribute:
+ return asFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+ displayHook<decltype(&Display::getDisplayAttribute),
+ &Display::getDisplayAttribute, hwc2_config_t,
+ int32_t, int32_t*>);
+ case FunctionDescriptor::GetDisplayConfigs:
+ return asFP<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+ displayHook<decltype(&Display::getConfigs),
+ &Display::getConfigs, uint32_t*, hwc2_config_t*>);
+ case FunctionDescriptor::GetDisplayName:
+ return asFP<HWC2_PFN_GET_DISPLAY_NAME>(
+ displayHook<decltype(&Display::getName),
+ &Display::getName, uint32_t*, char*>);
+ case FunctionDescriptor::GetDisplayRequests:
+ return asFP<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+ displayHook<decltype(&Display::getRequests),
+ &Display::getRequests, int32_t*, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::GetDisplayType:
+ return asFP<HWC2_PFN_GET_DISPLAY_TYPE>(
+ displayHook<decltype(&Display::getType),
+ &Display::getType, int32_t*>);
+ case FunctionDescriptor::GetDozeSupport:
+ return asFP<HWC2_PFN_GET_DOZE_SUPPORT>(
+ displayHook<decltype(&Display::getDozeSupport),
+ &Display::getDozeSupport, int32_t*>);
+ case FunctionDescriptor::GetHdrCapabilities:
+ return asFP<HWC2_PFN_GET_HDR_CAPABILITIES>(
+ displayHook<decltype(&Display::getHdrCapabilities),
+ &Display::getHdrCapabilities, uint32_t*, int32_t*, float*,
+ float*, float*>);
+ case FunctionDescriptor::GetReleaseFences:
+ return asFP<HWC2_PFN_GET_RELEASE_FENCES>(
+ displayHook<decltype(&Display::getReleaseFences),
+ &Display::getReleaseFences, uint32_t*, hwc2_layer_t*,
+ int32_t*>);
+ case FunctionDescriptor::PresentDisplay:
+ return asFP<HWC2_PFN_PRESENT_DISPLAY>(
+ displayHook<decltype(&Display::present),
+ &Display::present, int32_t*>);
+ case FunctionDescriptor::SetActiveConfig:
+ return asFP<HWC2_PFN_SET_ACTIVE_CONFIG>(
+ displayHook<decltype(&Display::setActiveConfig),
+ &Display::setActiveConfig, hwc2_config_t>);
+ case FunctionDescriptor::SetClientTarget:
+ return asFP<HWC2_PFN_SET_CLIENT_TARGET>(
+ displayHook<decltype(&Display::setClientTarget),
+ &Display::setClientTarget, buffer_handle_t, int32_t,
+ int32_t, hwc_region_t>);
+ case FunctionDescriptor::SetColorMode:
+ return asFP<HWC2_PFN_SET_COLOR_MODE>(
+ displayHook<decltype(&Display::setColorMode),
+ &Display::setColorMode, int32_t>);
+ case FunctionDescriptor::SetColorTransform:
+ return asFP<HWC2_PFN_SET_COLOR_TRANSFORM>(
+ displayHook<decltype(&Display::setColorTransform),
+ &Display::setColorTransform, const float*, int32_t>);
+ case FunctionDescriptor::SetOutputBuffer:
+ return asFP<HWC2_PFN_SET_OUTPUT_BUFFER>(
+ displayHook<decltype(&Display::setOutputBuffer),
+ &Display::setOutputBuffer, buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetPowerMode:
+ return asFP<HWC2_PFN_SET_POWER_MODE>(
+ displayHook<decltype(&Display::setPowerMode),
+ &Display::setPowerMode, int32_t>);
+ case FunctionDescriptor::SetVsyncEnabled:
+ return asFP<HWC2_PFN_SET_VSYNC_ENABLED>(
+ displayHook<decltype(&Display::setVsyncEnabled),
+ &Display::setVsyncEnabled, int32_t>);
+ case FunctionDescriptor::ValidateDisplay:
+ return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
+ displayHook<decltype(&Display::validate),
+ &Display::validate, uint32_t*, uint32_t*>);
+ case FunctionDescriptor::GetClientTargetSupport:
+ return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+ displayHook<decltype(&Display::getClientTargetSupport),
+ &Display::getClientTargetSupport, uint32_t, uint32_t,
+ int32_t, int32_t>);
+ // Layer functions
+ case FunctionDescriptor::SetCursorPosition:
+ return asFP<HWC2_PFN_SET_CURSOR_POSITION>(
+ layerHook<decltype(&Layer::setCursorPosition),
+ &Layer::setCursorPosition, int32_t, int32_t>);
+ case FunctionDescriptor::SetLayerBuffer:
+ return asFP<HWC2_PFN_SET_LAYER_BUFFER>(
+ layerHook<decltype(&Layer::setBuffer), &Layer::setBuffer,
+ buffer_handle_t, int32_t>);
+ case FunctionDescriptor::SetLayerSurfaceDamage:
+ return asFP<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+ layerHook<decltype(&Layer::setSurfaceDamage),
+ &Layer::setSurfaceDamage, hwc_region_t>);
+
+ // Layer state functions
+ case FunctionDescriptor::SetLayerBlendMode:
+ return asFP<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+ layerHook<decltype(&Layer::setBlendMode),
+ &Layer::setBlendMode, int32_t>);
+ case FunctionDescriptor::SetLayerColor:
+ return asFP<HWC2_PFN_SET_LAYER_COLOR>(
+ layerHook<decltype(&Layer::setColor), &Layer::setColor,
+ hwc_color_t>);
+ case FunctionDescriptor::SetLayerCompositionType:
+ return asFP<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+ layerHook<decltype(&Layer::setCompositionType),
+ &Layer::setCompositionType, int32_t>);
+ case FunctionDescriptor::SetLayerDataspace:
+ return asFP<HWC2_PFN_SET_LAYER_DATASPACE>(
+ layerHook<decltype(&Layer::setDataspace),
+ &Layer::setDataspace, int32_t>);
+ case FunctionDescriptor::SetLayerDisplayFrame:
+ return asFP<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+ layerHook<decltype(&Layer::setDisplayFrame),
+ &Layer::setDisplayFrame, hwc_rect_t>);
+ case FunctionDescriptor::SetLayerPlaneAlpha:
+ return asFP<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+ layerHook<decltype(&Layer::setPlaneAlpha),
+ &Layer::setPlaneAlpha, float>);
+ case FunctionDescriptor::SetLayerSidebandStream:
+ return asFP<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+ layerHook<decltype(&Layer::setSidebandStream),
+ &Layer::setSidebandStream, const native_handle_t*>);
+ case FunctionDescriptor::SetLayerSourceCrop:
+ return asFP<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+ layerHook<decltype(&Layer::setSourceCrop),
+ &Layer::setSourceCrop, hwc_frect_t>);
+ case FunctionDescriptor::SetLayerTransform:
+ return asFP<HWC2_PFN_SET_LAYER_TRANSFORM>(
+ layerHook<decltype(&Layer::setTransform),
+ &Layer::setTransform, int32_t>);
+ case FunctionDescriptor::SetLayerVisibleRegion:
+ return asFP<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+ layerHook<decltype(&Layer::setVisibleRegion),
+ &Layer::setVisibleRegion, hwc_region_t>);
+ case FunctionDescriptor::SetLayerZOrder:
+ return asFP<HWC2_PFN_SET_LAYER_Z_ORDER>(
+ displayHook<decltype(&Display::updateLayerZ),
+ &Display::updateLayerZ, hwc2_layer_t, uint32_t>);
+
+ default:
+ ALOGE("doGetFunction: Unknown function descriptor: %d (%s)",
+ static_cast<int32_t>(descriptor),
+ to_string(descriptor).c_str());
+ return nullptr;
+ }
+}
+
+
+// Device functions
+
+Error EmuHWC2::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
+ int32_t* /*format*/, hwc2_display_t* /*outDisplay*/) {
+ ALOGVV("%s", __FUNCTION__);
+ //TODO: VirtualDisplay support
+ return Error::None;
+}
+
+Error EmuHWC2::destroyVirtualDisplay(hwc2_display_t /*displayId*/) {
+ ALOGVV("%s", __FUNCTION__);
+ //TODO: VirtualDisplay support
+ return Error::None;
+}
+
+void EmuHWC2::dump(uint32_t* /*outSize*/, char* /*outBuffer*/) {
+ ALOGVV("%s", __FUNCTION__);
+ //TODO:
+ return;
+}
+
+uint32_t EmuHWC2::getMaxVirtualDisplayCount() {
+ ALOGVV("%s", __FUNCTION__);
+ //TODO: VirtualDisplay support
+ return 0;
+}
+
+static bool isValid(Callback descriptor) {
+ switch (descriptor) {
+ case Callback::Hotplug: // Fall-through
+ case Callback::Refresh: // Fall-through
+ case Callback::Vsync: return true;
+ default: return false;
+ }
+}
+
+Error EmuHWC2::registerCallback(Callback descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer) {
+ ALOGVV("%s", __FUNCTION__);
+ if (!isValid(descriptor)) {
+ ALOGE("registerCallback: Unkown function descriptor: %d",
+ static_cast<int32_t>(descriptor));
+ return Error::BadParameter;
+ }
+ ALOGV("registerCallback(%s, %p, %p)", to_string(descriptor).c_str(),
+ callbackData, pointer);
+
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (pointer != nullptr) {
+ mCallbacks[descriptor] = {callbackData, pointer};
+ }
+ else {
+ ALOGV("unregisterCallback(%s)", to_string(descriptor).c_str());
+ mCallbacks.erase(descriptor);
+ return Error::None;
+ }
+
+ // Callback without the state lock held
+ if (descriptor == Callback::Hotplug) {
+ lock.unlock();
+ auto hotplug = reinterpret_cast<HWC2_PFN_VSYNC>(pointer);
+ hotplug(callbackData, 0, static_cast<int32_t>(Connection::Connected));
+ }
+
+ return Error::None;
+}
+
+//Gralloc Functions
+EmuHWC2::GrallocModule::GrallocModule() {
+ int ret;
+
+ ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mHw);
+ assert(ret == 0 && "Gralloc moudle not found");
+ mGralloc = reinterpret_cast<const gralloc_module_t*>(mHw);
+
+ ret = framebuffer_open(mHw, &mFbDev);
+ assert(ret == 0 && "Fail to open FrameBuffer device");
+}
+
+EmuHWC2::GrallocModule::~GrallocModule() {
+ if (mHandle != nullptr) {
+ mGralloc->unregisterBuffer(mGralloc, mHandle);
+ mAllocDev->free(mAllocDev, mHandle);
+ ALOGI("free targetCb %d", ((cb_handle_t*)(mHandle))->hostHandle);
+ }
+}
+
+uint32_t EmuHWC2::GrallocModule::getTargetCb() {
+ if (mHandle == nullptr) {
+ int ret, stride;
+ ret = gralloc_open(mHw, &mAllocDev);
+ assert(ret == 0 && "Fail to open GPU device");
+ ret = mAllocDev->alloc(mAllocDev,
+ mFbDev->width, mFbDev->height, mFbDev->format,
+ GRALLOC_USAGE_HW_COMPOSER|GRALLOC_USAGE_HW_RENDER,
+ &mHandle, &stride);
+ assert(ret == 0 && "Fail to allocate target ColorBuffer");
+ mGralloc->registerBuffer(mGralloc, mHandle);
+ ALOGI("targetCb %d", reinterpret_cast<const cb_handle_t*>(mHandle)
+ ->hostHandle);
+ }
+ return reinterpret_cast<const cb_handle_t*>(mHandle)->hostHandle;
+}
+
+// Display functions
+
+std::atomic<hwc2_display_t> EmuHWC2::Display::sNextId(0);
+
+EmuHWC2::Display::Display(EmuHWC2& device, DisplayType type)
+ : mDevice(device),
+ mId(sNextId++),
+ mName(),
+ mType(type),
+ mPowerMode(PowerMode::Off),
+ mVsyncEnabled(Vsync::Invalid),
+ mVsyncPeriod(1000*1000*1000/60), // vsync is 60 hz
+ mVsyncThread(*this),
+ mClientTarget(),
+ mChanges(),
+ mLayers(),
+ mConfigs(),
+ mActiveConfig(nullptr),
+ mColorModes(),
+ mSetColorTransform(false),
+ mStateMutex()
+ {
+ mVsyncThread.run("", HAL_PRIORITY_URGENT_DISPLAY);
+ }
+
+Error EmuHWC2::Display::acceptChanges() {
+ ALOGVV("%s: displayId %u", __FUNCTION__, (uint32_t)mId);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGW("%s: displayId %u acceptChanges failed, not validated",
+ __FUNCTION__, (uint32_t)mId);
+ return Error::NotValidated;
+ }
+
+
+ for (auto& change : mChanges->getTypeChanges()) {
+ auto layerId = change.first;
+ auto type = change.second;
+ if (mDevice.mLayers.count(layerId) == 0) {
+ // This should never happen but somehow does.
+ ALOGW("Cannot accept change for unknown layer %u",
+ (uint32_t)layerId);
+ continue;
+ }
+ auto layer = mDevice.mLayers[layerId];
+ layer->setCompositionType((int32_t)type);
+ }
+
+ mChanges->clearTypeChanges();
+ return Error::None;
+}
+
+Error EmuHWC2::Display::createLayer(hwc2_layer_t* outLayerId) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ auto layer = *mLayers.emplace(std::make_shared<Layer>(*this));
+ mDevice.mLayers.emplace(std::make_pair(layer->getId(), layer));
+ *outLayerId = layer->getId();
+ ALOGV("%s: Display %u created layer %u", __FUNCTION__, (uint32_t)mId,
+ (uint32_t)(*outLayerId));
+ return Error::None;
+}
+
+Error EmuHWC2::Display::destroyLayer(hwc2_layer_t layerId) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGW("%s failed: no such layer, displayId %u layerId %u",
+ __FUNCTION__, (uint32_t)mId, (uint32_t)layerId);
+ return Error::BadLayer;
+ }
+ const auto layer = mapLayer->second;
+ mDevice.mLayers.erase(mapLayer);
+ const auto zRange = mLayers.equal_range(layer);
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ current = mLayers.erase(current);
+ break;
+ }
+ }
+ ALOGV("%s: displayId %d layerId %d", __FUNCTION__, (uint32_t)mId,
+ (uint32_t)layerId);
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getActiveConfig(hwc2_config_t* outConfig) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!mActiveConfig) {
+ ALOGW("%s: displayId %d %s", __FUNCTION__, (uint32_t)mId,
+ to_string(Error::BadConfig).c_str());
+ return Error::BadConfig;
+ }
+ auto configId = mActiveConfig->getId();
+ ALOGV("%s: displayId %d configId %d", __FUNCTION__,
+ (uint32_t)mId, (uint32_t)configId);
+ *outConfig = configId;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getDisplayAttribute(hwc2_config_t configId,
+ int32_t attribute, int32_t* outValue) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ ALOGW("%s: bad config (%u %u)", __FUNCTION__, (uint32_t)mId, configId);
+ return Error::BadConfig;
+ }
+ *outValue = mConfigs[configId]->getAttribute((Attribute)attribute);
+ ALOGV("%s: (%d %d) %s --> %d", __FUNCTION__,
+ (uint32_t)mId, (uint32_t)configId,
+ to_string((Attribute)attribute).c_str(), *outValue);
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getChangedCompositionTypes(
+ uint32_t* outNumElements, hwc2_layer_t* outLayers, int32_t* outTypes) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ ALOGW("display %u getChangedCompositionTypes failed: not validated",
+ (uint32_t)mId);
+ return Error::NotValidated;
+ }
+
+ if ((outLayers == nullptr) || (outTypes == nullptr)) {
+ *outNumElements = mChanges->getTypeChanges().size();
+ return Error::None;
+ }
+
+ uint32_t numWritten = 0;
+ for (const auto& element : mChanges->getTypeChanges()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ auto layerId = element.first;
+ auto intType = static_cast<int32_t>(element.second);
+ ALOGV("%s: Adding layer %u %s", __FUNCTION__, (uint32_t)layerId,
+ to_string(element.second).c_str());
+ outLayers[numWritten] = layerId;
+ outTypes[numWritten] = intType;
+ ++numWritten;
+ }
+ *outNumElements = numWritten;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getColorModes(uint32_t* outNumModes,
+ int32_t* outModes) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!outModes) {
+ *outNumModes = mColorModes.size();
+ return Error::None;
+ }
+
+ // we only support HAL_COLOR_MODE_NATIVE so far
+ uint32_t numModes = std::min(*outNumModes,
+ static_cast<uint32_t>(mColorModes.size()));
+ std::copy_n(mColorModes.cbegin(), numModes, outModes);
+ *outNumModes = numModes;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getConfigs(uint32_t* outNumConfigs,
+ hwc2_config_t* outConfigs) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!outConfigs) {
+ *outNumConfigs = mConfigs.size();
+ return Error::None;
+ }
+ uint32_t numWritten = 0;
+ for (const auto config : mConfigs) {
+ if (numWritten == *outNumConfigs) {
+ break;
+ }
+ outConfigs[numWritten] = config->getId();
+ ++numWritten;
+ }
+ *outNumConfigs = numWritten;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getDozeSupport(int32_t* outSupport) {
+ ALOGVV("%s", __FUNCTION__);
+ // We don't support so far
+ *outSupport = 0;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getHdrCapabilities(uint32_t* outNumTypes,
+ int32_t* /*outTypes*/, float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ ALOGVV("%s", __FUNCTION__);
+ // We don't support so far
+ *outNumTypes = 0;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getName(uint32_t* outSize, char* outName) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!outName) {
+ *outSize = mName.size();
+ return Error::None;
+ }
+ auto numCopied = mName.copy(outName, *outSize);
+ *outSize = numCopied;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getReleaseFences(uint32_t* outNumElements,
+ hwc2_layer_t* /*outLayers*/, int32_t* /*outFences*/) {
+ ALOGVV("%s", __FUNCTION__);
+
+ *outNumElements = 0;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getRequests(int32_t* outDisplayRequests,
+ uint32_t* outNumElements, hwc2_layer_t* outLayers,
+ int32_t* outLayerRequests) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ return Error::NotValidated;
+ }
+
+ if (outLayers == nullptr || outLayerRequests == nullptr) {
+ *outNumElements = mChanges->getNumLayerRequests();
+ return Error::None;
+ }
+
+ //TODO
+ // Display requests (HWC2::DisplayRequest) are not supported so far:
+ *outDisplayRequests = 0;
+
+ uint32_t numWritten = 0;
+ for (const auto& request : mChanges->getLayerRequests()) {
+ if (numWritten == *outNumElements) {
+ break;
+ }
+ outLayers[numWritten] = request.first;
+ outLayerRequests[numWritten] = static_cast<int32_t>(request.second);
+ ++numWritten;
+ }
+
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getType(int32_t* outType) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ *outType = (int32_t)mType;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::present(int32_t* outRetireFence) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!mChanges || (mChanges->getNumTypes() > 0)) {
+ ALOGE("%s display(%u) set failed: not validated", __FUNCTION__,
+ (uint32_t)mId);
+ return Error::NotValidated;
+ }
+ mChanges.reset();
+
+ DEFINE_AND_VALIDATE_HOST_CONNECTION
+ if (rcEnc->hasHostCompositionV1()) {
+ uint32_t numLayer = 0;
+ for (auto layer: mLayers) {
+ if (layer->getCompositionType() == Composition::Device ||
+ layer->getCompositionType() == Composition::SolidColor) {
+ numLayer++;
+ }
+ }
+ ALOGV("present %d layers total %u layers", numLayer,
+ (uint32_t)mLayers.size());
+ if (numLayer == 0) {
+ mGralloc->getFb()->post(mGralloc->getFb(), mClientTarget.getBuffer());
+ *outRetireFence = mClientTarget.getFence();
+ return Error::None;
+ }
+
+ if (mComposeMsg == nullptr || mComposeMsg->getLayerCnt() < numLayer) {
+ mComposeMsg.reset(new ComposeMsg(numLayer));
+ }
+
+ // Handle the composition
+ ComposeDevice* p = mComposeMsg->get();
+ ComposeLayer* l = p->layer;
+ for (auto layer: mLayers) {
+ if (layer->getCompositionType() != Composition::Device &&
+ layer->getCompositionType() != Composition::SolidColor) {
+ ALOGE("%s: Unsupported composition types %d",
+ __FUNCTION__, layer->getCompositionType());
+ continue;
+ }
+ // send layer composition command to host
+ if (layer->getCompositionType() == Composition::Device) {
+ int fence = layer->getLayerBuffer().getFence();
+ if (fence != -1) {
+ int err = sync_wait(fence, 3000);
+ if (err < 0 && errno == ETIME) {
+ ALOGE("%s waited on fence %d for 3000 ms",
+ __FUNCTION__, fence);
+ }
+ }
+ else {
+ ALOGV("%s: aquiredFence not set for layer %u",
+ __FUNCTION__, (uint32_t)layer->getId());
+ }
+ cb_handle_t *cb =
+ (cb_handle_t *)layer->getLayerBuffer().getBuffer();
+ if (cb != nullptr) {
+ l->cbHandle = cb->hostHandle;
+ }
+ else {
+ ALOGE("%s null buffer for layer %d", __FUNCTION__,
+ (uint32_t)layer->getId());
+ }
+ }
+ else {
+ // solidcolor has no buffer
+ l->cbHandle = 0;
+ }
+ l->composeMode = (hwc2_composition_t)layer->getCompositionType();
+ l->displayFrame = layer->getDisplayFrame();
+ l->crop = layer->getSourceCrop();
+ l->blendMode = layer->getBlendMode();
+ l->alpha = layer->getPlaneAlpha();
+ l->color = layer->getColor();
+ l->transform = layer->getTransform();
+ ALOGV(" cb %d blendmode %d alpha %f %d %d %d %d z %d"
+ " composeMode %d, transform %d",
+ l->cbHandle, l->blendMode, l->alpha,
+ l->displayFrame.left, l->displayFrame.top,
+ l->displayFrame.right, l->displayFrame.bottom,
+ layer->getZ(), l->composeMode, l->transform);
+ l++;
+ }
+ p->version = 1;
+ p->targetHandle = mGralloc->getTargetCb();
+ p->numLayers = numLayer;
+
+ rcEnc->rcCompose(rcEnc,
+ sizeof(ComposeDevice) + numLayer * sizeof(ComposeLayer),
+ (void *)p);
+ // not set retireFence should be fine, because the rcCompose is a
+ // sync call, it returns until the host call eglswapbuffers
+ *outRetireFence = -1;
+ }
+ else {
+ // we set all layers Composition::Client, so do nothing.
+ mGralloc->getFb()->post(mGralloc->getFb(), mClientTarget.getBuffer());
+ *outRetireFence = mClientTarget.getFence();
+ ALOGV("%s fallback to post, returns outRetireFence %d",
+ __FUNCTION__, *outRetireFence);
+ }
+
+ return Error::None;
+}
+
+Error EmuHWC2::Display::setActiveConfig(hwc2_config_t configId) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (configId > mConfigs.size() || !mConfigs[configId]->isOnDisplay(*this)) {
+ ALOGW("%s: bad config (%u %u)", __FUNCTION__, (uint32_t)mId,
+ (uint32_t)configId);
+ return Error::BadConfig;
+ }
+ auto config = mConfigs[configId];
+ if (config == mActiveConfig) {
+ return Error::None;
+ }
+
+ mActiveConfig = config;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::setClientTarget(buffer_handle_t target,
+ int32_t acquireFence, int32_t /*dataspace*/, hwc_region_t /*damage*/) {
+ ALOGVV("%s", __FUNCTION__);
+
+ cb_handle_t *cb =
+ (cb_handle_t *)target;
+ ALOGV("%s: display(%u) buffer handle %p cb %d, acquireFence %d", __FUNCTION__,
+ (uint32_t)mId, target, cb->hostHandle, acquireFence);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+ mClientTarget.setBuffer(target);
+ mClientTarget.setFence(acquireFence);
+ return Error::None;
+}
+
+Error EmuHWC2::Display::setColorMode(int32_t intMode) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ auto mode = static_cast<android_color_mode_t>(intMode);
+ ALOGV("%s: (display %u mode %d)", __FUNCTION__, (uint32_t)mId, intMode);
+ if (mode == mActiveColorMode) {
+ return Error::None;
+ }
+ if (mColorModes.count(mode) == 0) {
+ ALOGE("%s: display %d Mode %d not found in mColorModes",
+ __FUNCTION__, (uint32_t)mId, intMode);
+ return Error::Unsupported;
+ }
+ mActiveColorMode = mode;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::setColorTransform(const float* /*matrix*/,
+ int32_t hint) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+ //we force client composition if this is set
+ if (hint == 0 ) {
+ mSetColorTransform = false;
+ }
+ else {
+ mSetColorTransform = true;
+ }
+ return Error::None;
+}
+
+Error EmuHWC2::Display::setOutputBuffer(buffer_handle_t /*buffer*/,
+ int32_t /*releaseFence*/) {
+ ALOGVV("%s", __FUNCTION__);
+ //TODO: for virtual display
+ return Error::None;
+}
+
+static bool isValid(PowerMode mode) {
+ switch (mode) {
+ case PowerMode::Off: // Fall-through
+ case PowerMode::DozeSuspend: // Fall-through
+ case PowerMode::Doze: // Fall-through
+ case PowerMode::On: return true;
+ default: return false;
+ }
+}
+
+Error EmuHWC2::Display::setPowerMode(int32_t intMode) {
+ ALOGVV("%s", __FUNCTION__);
+ // Emulator always set screen ON
+ PowerMode mode = static_cast<PowerMode>(intMode);
+ if (!isValid(mode)) {
+ return Error::BadParameter;
+ }
+ if (mode == mPowerMode) {
+ return Error::None;
+ }
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ ALOGV("%s: (display %u mode %s)", __FUNCTION__,
+ (uint32_t)mId, to_string(mode).c_str());
+ mPowerMode = mode;
+ return Error::None;
+}
+
+static bool isValid(Vsync enable) {
+ switch (enable) {
+ case Vsync::Enable: // Fall-through
+ case Vsync::Disable: return true;
+ case Vsync::Invalid: return false;
+ }
+}
+
+Error EmuHWC2::Display::setVsyncEnabled(int32_t intEnable) {
+ ALOGVV("%s", __FUNCTION__);
+ Vsync enable = static_cast<Vsync>(intEnable);
+ if (!isValid(enable)) {
+ return Error::BadParameter;
+ }
+ if (enable == mVsyncEnabled) {
+ return Error::None;
+ }
+
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ mVsyncEnabled = enable;
+ return Error::None;
+}
+
+Error EmuHWC2::Display::validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (!mChanges) {
+ mChanges.reset(new Changes);
+ DEFINE_AND_VALIDATE_HOST_CONNECTION
+ if (rcEnc->hasHostCompositionV1()) {
+ // Support Device and SolidColor, otherwise, fallback all layers
+ // to Client
+ bool fallBack = false;
+ for (auto& layer : mLayers) {
+ if (layer->getCompositionType() == Composition::Client ||
+ layer->getCompositionType() == Composition::Cursor ||
+ layer->getCompositionType() == Composition::Sideband) {
+ ALOGV("%s: layer %u CompositionType %d\n", __FUNCTION__,
+ (uint32_t)layer->getId(), layer->getCompositionType());
+ fallBack = true;
+ break;
+ }
+ }
+ if (mSetColorTransform) {
+ fallBack = true;
+ }
+ if (fallBack) {
+ for (auto& layer : mLayers) {
+ if (layer->getCompositionType() != Composition::Client) {
+ mChanges->addTypeChange(layer->getId(),
+ Composition::Client);
+ }
+ }
+ }
+ }
+ else {
+ for (auto& layer : mLayers) {
+ if (layer->getCompositionType() != Composition::Client) {
+ mChanges->addTypeChange(layer->getId(),
+ Composition::Client);
+ }
+ }
+ }
+ }
+ else {
+ ALOGE("Validate was called more than once!");
+ }
+
+ *outNumTypes = mChanges->getNumTypes();
+ *outNumRequests = mChanges->getNumLayerRequests();
+ ALOGV("%s: displayId %u types %u, requests %u", __FUNCTION__,
+ (uint32_t)mId, *outNumTypes, *outNumRequests);
+ return *outNumTypes > 0 ? Error::HasChanges : Error::None;
+}
+
+Error EmuHWC2::Display::updateLayerZ(hwc2_layer_t layerId, uint32_t z) {
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ const auto mapLayer = mDevice.mLayers.find(layerId);
+ if (mapLayer == mDevice.mLayers.end()) {
+ ALOGE("%s failed to find layer %u", __FUNCTION__, (uint32_t)mId);
+ return Error::BadLayer;
+ }
+
+ const auto layer = mapLayer->second;
+ const auto zRange = mLayers.equal_range(layer);
+ bool layerOnDisplay = false;
+ for (auto current = zRange.first; current != zRange.second; ++current) {
+ if (**current == *layer) {
+ if ((*current)->getZ() == z) {
+ // Don't change anything if the Z hasn't changed
+ return Error::None;
+ }
+ current = mLayers.erase(current);
+ layerOnDisplay = true;
+ break;
+ }
+ }
+
+ if (!layerOnDisplay) {
+ ALOGE("%s failed to find layer %u on display", __FUNCTION__,
+ (uint32_t)mId);
+ return Error::BadLayer;
+ }
+
+ layer->setZ(z);
+ mLayers.emplace(std::move(layer));
+ return Error::None;
+}
+
+Error EmuHWC2::Display::getClientTargetSupport(uint32_t width, uint32_t height,
+ int32_t format, int32_t dataspace){
+ ALOGVV("%s", __FUNCTION__);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ if (mActiveConfig == nullptr) {
+ return Error::Unsupported;
+ }
+
+ if (width == (uint32_t)mActiveConfig->getAttribute(Attribute::Width) &&
+ height == (uint32_t)mActiveConfig->getAttribute(Attribute::Height) &&
+ format == HAL_PIXEL_FORMAT_RGBA_8888 &&
+ dataspace == HAL_DATASPACE_UNKNOWN) {
+ return Error::None;
+ }
+
+ return Error::None;
+}
+
+
+int EmuHWC2::Display::populatePrimaryConfigs() {
+ ALOGVV("%s DisplayId %u", __FUNCTION__, (uint32_t)mId);
+ std::unique_lock<std::mutex> lock(mStateMutex);
+
+ mGralloc.reset(new GrallocModule());
+ auto newConfig = std::make_shared<Config>(*this);
+ // vsync is 60 hz;
+ newConfig->setAttribute(Attribute::VsyncPeriod, mVsyncPeriod);
+ newConfig->setAttribute(Attribute::Width, mGralloc->getFb()->width);
+ newConfig->setAttribute(Attribute::Height, mGralloc->getFb()->height);
+ newConfig->setAttribute(Attribute::DpiX, mGralloc->getFb()->xdpi*1000);
+ newConfig->setAttribute(Attribute::DpiY, mGralloc->getFb()->ydpi*1000);
+
+ newConfig->setId(static_cast<hwc2_config_t>(mConfigs.size()));
+ ALOGV("Found new config %d: %s", (uint32_t)newConfig->getId(),
+ newConfig->toString().c_str());
+ mConfigs.emplace_back(std::move(newConfig));
+
+ // Only have single config so far, it is activeConfig
+ mActiveConfig = mConfigs[0];
+ mActiveColorMode = HAL_COLOR_MODE_NATIVE;
+ mColorModes.emplace((android_color_mode_t)HAL_COLOR_MODE_NATIVE);
+
+ return 0;
+}
+
+
+// Config functions
+
+void EmuHWC2::Display::Config::setAttribute(Attribute attribute,
+ int32_t value) {
+ mAttributes[attribute] = value;
+}
+
+int32_t EmuHWC2::Display::Config::getAttribute(Attribute attribute) const {
+ if (mAttributes.count(attribute) == 0) {
+ return -1;
+ }
+ return mAttributes.at(attribute);
+}
+
+std::string EmuHWC2::Display::Config::toString() const {
+ std::string output;
+
+ const size_t BUFFER_SIZE = 100;
+ char buffer[BUFFER_SIZE] = {};
+ auto writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ "%u x %u", mAttributes.at(HWC2::Attribute::Width),
+ mAttributes.at(HWC2::Attribute::Height));
+ output.append(buffer, writtenBytes);
+
+ if (mAttributes.count(HWC2::Attribute::VsyncPeriod) != 0) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE, " @ %.1f Hz",
+ 1e9 / mAttributes.at(HWC2::Attribute::VsyncPeriod));
+ output.append(buffer, writtenBytes);
+ }
+
+ if (mAttributes.count(HWC2::Attribute::DpiX) != 0 &&
+ mAttributes.at(HWC2::Attribute::DpiX) != -1) {
+ std::memset(buffer, 0, BUFFER_SIZE);
+ writtenBytes = snprintf(buffer, BUFFER_SIZE,
+ ", DPI: %.1f x %.1f",
+ mAttributes.at(HWC2::Attribute::DpiX) / 1000.0f,
+ mAttributes.at(HWC2::Attribute::DpiY) / 1000.0f);
+ output.append(buffer, writtenBytes);
+ }
+
+ return output;
+}
+
+
+// VsyncThread function
+bool EmuHWC2::Display::VsyncThread::threadLoop() {
+ struct timespec rt;
+ if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
+ ALOGE("%s: error in vsync thread clock_gettime: %s",
+ __FUNCTION__, strerror(errno));
+ return true;
+ }
+ const int logInterval = 60;
+ int64_t lastLogged = rt.tv_sec;
+ int sent = 0;
+ int lastSent = 0;
+ bool vsyncEnabled = false;
+ struct timespec wait_time;
+ wait_time.tv_sec = 0;
+ wait_time.tv_nsec = mDisplay.mVsyncPeriod;
+
+ while (true) {
+ int err = nanosleep(&wait_time, NULL);
+ if (err == -1) {
+ if (errno == EINTR) {
+ break;
+ }
+ ALOGE("%s: error in vsync thread: %s", __FUNCTION__, strerror(errno));
+ }
+
+ std::unique_lock<std::mutex> lock(mDisplay.mStateMutex);
+ vsyncEnabled = (mDisplay.mVsyncEnabled == Vsync::Enable);
+ lock.unlock();
+
+ if (!vsyncEnabled) {
+ continue;
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
+ ALOGE("%s: error in vsync thread clock_gettime: %s",
+ __FUNCTION__, strerror(errno));
+ }
+
+ int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
+
+ lock.lock();
+ const auto& callbackInfo = mDisplay.mDevice.mCallbacks[Callback::Vsync];
+ auto vsync = reinterpret_cast<HWC2_PFN_VSYNC>(callbackInfo.pointer);
+ lock.unlock();
+
+ if (vsync) {
+ vsync(callbackInfo.data, mDisplay.mId, timestamp);
+ }
+
+ if (rt.tv_sec - lastLogged >= logInterval) {
+ ALOGVV("sent %d syncs in %ds", sent - lastSent, rt.tv_sec - lastLogged);
+ lastLogged = rt.tv_sec;
+ lastSent = sent;
+ }
+ ++sent;
+ }
+ return false;
+}
+
+
+// Layer functions
+bool EmuHWC2::SortLayersByZ::operator()(
+ const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs) {
+ return lhs->getZ() < rhs->getZ();
+}
+
+std::atomic<hwc2_layer_t> EmuHWC2::Layer::sNextId(1);
+
+EmuHWC2::Layer::Layer(Display& display)
+ : mId(sNextId++),
+ mDisplay(display),
+ mBuffer(),
+ mSurfaceDamage(),
+ mBlendMode(BlendMode::None),
+ mColor({0, 0, 0, 0}),
+ mCompositionType(Composition::Invalid),
+ mDisplayFrame({0, 0, -1, -1}),
+ mPlaneAlpha(0.0f),
+ mSidebandStream(nullptr),
+ mSourceCrop({0.0f, 0.0f, -1.0f, -1.0f}),
+ mTransform(Transform::None),
+ mVisibleRegion(),
+ mZ(0)
+ {}
+
+Error EmuHWC2::Layer::setBuffer(buffer_handle_t buffer,
+ int32_t acquireFence) {
+ ALOGVV("%s: Setting acquireFence %d for layer %u", __FUNCTION__,
+ acquireFence, (uint32_t)mId);
+ mBuffer.setBuffer(buffer);
+ mBuffer.setFence(acquireFence);
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setCursorPosition(int32_t /*x*/,
+ int32_t /*y*/) {
+ ALOGVV("%s", __FUNCTION__);
+ if (mCompositionType != Composition::Cursor) {
+ return Error::BadLayer;
+ }
+ //TODO
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setSurfaceDamage(hwc_region_t /*damage*/) {
+ // Emulator redraw whole layer per frame, so ignore this.
+ return Error::None;
+}
+
+// Layer state functions
+
+Error EmuHWC2::Layer::setBlendMode(int32_t mode) {
+ ALOGVV("%s %d for layer %u", __FUNCTION__, mode, (uint32_t)mId);
+ mBlendMode = static_cast<BlendMode>(mode);
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setColor(hwc_color_t color) {
+ ALOGVV("%s", __FUNCTION__);
+ mColor = color;
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setCompositionType(int32_t type) {
+ ALOGVV("%s", __FUNCTION__);
+ mCompositionType = static_cast<Composition>(type);
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setDataspace(int32_t) {
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setDisplayFrame(hwc_rect_t frame) {
+ mDisplayFrame = frame;
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setPlaneAlpha(float alpha) {
+ mPlaneAlpha = alpha;
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setSidebandStream(const native_handle_t* stream) {
+ mSidebandStream = stream;
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setSourceCrop(hwc_frect_t crop) {
+ mSourceCrop = crop;
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setTransform(int32_t transform) {
+ mTransform = static_cast<Transform>(transform);
+ return Error::None;
+}
+
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ return rect1.left == rect2.left &&
+ rect1.right == rect2.right &&
+ rect1.top == rect2.top &&
+ rect1.bottom == rect2.bottom;
+}
+
+Error EmuHWC2::Layer::setVisibleRegion(hwc_region_t visible) {
+ ALOGVV("%s", __FUNCTION__);
+ if ((getNumVisibleRegions() != visible.numRects) ||
+ !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+ compareRects)) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ }
+ return Error::None;
+}
+
+Error EmuHWC2::Layer::setZ(uint32_t z) {
+ ALOGVV("%s %d", __FUNCTION__, z);
+ mZ = z;
+ return Error::None;
+}
+
+// Adaptor Helpers
+
+void EmuHWC2::populateCapabilities() {
+ //TODO: add Capabilities
+ // support virtualDisplay
+ // support sideBandStream
+ // support backGroundColor
+ // we should not set this for HWC2, TODO: remove
+ // mCapabilities.insert(Capability::PresentFenceIsNotReliable);
+}
+
+int EmuHWC2::populatePrimary() {
+ int ret = 0;
+ auto display = std::make_shared<Display>(*this, HWC2::DisplayType::Physical);
+ ret = display->populatePrimaryConfigs();
+ if (ret != 0) {
+ return ret;
+ }
+ mDisplays.emplace(display->getId(), std::move(display));
+ return ret;
+}
+
+EmuHWC2::Display* EmuHWC2::getDisplay(hwc2_display_t id) {
+ auto display = mDisplays.find(id);
+ if (display == mDisplays.end()) {
+ return nullptr;
+ }
+ return display->second.get();
+}
+
+std::tuple<EmuHWC2::Layer*, Error> EmuHWC2::getLayer(
+ hwc2_display_t displayId, hwc2_layer_t layerId) {
+ auto display = getDisplay(displayId);
+ if (!display) {
+ ALOGE("%s: Fail to find display %d", __FUNCTION__, (uint32_t)displayId);
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadDisplay);
+ }
+
+ auto layerEntry = mLayers.find(layerId);
+ if (layerEntry == mLayers.end()) {
+ ALOGE("%s: Fail to find layer %d", __FUNCTION__, (uint32_t)layerId);
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+
+ auto layer = layerEntry->second;
+ if (layer->getDisplay().getId() != displayId) {
+ ALOGE("%s: layer %d not belongs to display %d", __FUNCTION__,
+ (uint32_t)layerId, (uint32_t)displayId);
+ return std::make_tuple(static_cast<Layer*>(nullptr), Error::BadLayer);
+ }
+ return std::make_tuple(layer.get(), Error::None);
+}
+
+static int hwc2DevOpen(const struct hw_module_t *module, const char *name,
+ struct hw_device_t **dev) {
+ ALOGV("%s ", __FUNCTION__);
+ if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
+ ALOGE("Invalid module name- %s", name);
+ return -EINVAL;
+ }
+
+ EmuHWC2* ctx = new EmuHWC2();
+ if (!ctx) {
+ ALOGE("Failed to allocate EmuHWC2");
+ return -ENOMEM;
+ }
+ int ret = ctx->populatePrimary();
+ if (ret != 0) {
+ ALOGE("Failed to populate primary display");
+ return ret;
+ }
+
+ ctx->common.module = const_cast<hw_module_t *>(module);
+ *dev = &ctx->common;
+ return 0;
+}
+}
+
+static struct hw_module_methods_t hwc2_module_methods = {
+ .open = android::hwc2DevOpen
+};
+
+hw_module_t HAL_MODULE_INFO_SYM = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 2,
+ .version_minor = 0,
+ .id = HWC_HARDWARE_MODULE_ID,
+ .name = "goldfish HWC2 module",
+ .author = "The Android Open Source Project",
+ .methods = &hwc2_module_methods,
+ .dso = NULL,
+ .reserved = {0},
+};
diff --git a/system/hwc2/EmuHWC2.h b/system/hwc2/EmuHWC2.h
new file mode 100644
index 0000000..0d768dd
--- /dev/null
+++ b/system/hwc2/EmuHWC2.h
@@ -0,0 +1,448 @@
+/*
+ * 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 <atomic>
+#include <map>
+#include <mutex>
+#include <vector>
+#include <unordered_set>
+#include <unordered_map>
+#include <set>
+
+#include "gralloc_cb.h"
+#include "MiniFence.h"
+#include "HostConnection.h"
+
+namespace android {
+
+class EmuHWC2 : public hwc2_device_t {
+public:
+ EmuHWC2();
+ int populatePrimary();
+
+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);
+ };
+
+ // 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), 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 GrallocModule {
+ public:
+ GrallocModule();
+ ~GrallocModule();
+ framebuffer_device_t* getFb() { return mFbDev; }
+ uint32_t getTargetCb();
+ private:
+ const hw_module_t* mHw = nullptr;
+ const gralloc_module_t* mGralloc = nullptr;
+ alloc_device_t* mAllocDev = nullptr;
+ framebuffer_device_t* mFbDev = nullptr;
+ buffer_handle_t mHandle = nullptr;
+ };
+
+ 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;
+
+ 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 Display {
+ public:
+ Display(EmuHWC2& device, HWC2::DisplayType type);
+ 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);
+
+ // Read configs from PRIMARY Display
+ int populatePrimaryConfigs();
+
+ 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 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;
+ const hwc2_display_t mId;
+ 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<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<GrallocModule> mGralloc;
+ std::unique_ptr<ComposeMsg> mComposeMsg;
+ };
+
+ 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);
+
+ 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;
+
+ std::unordered_map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+ std::unordered_map<hwc2_layer_t, std::shared_ptr<Layer>> mLayers;
+
+};
+
+}
+#endif
diff --git a/system/hwc2/MiniFence.cpp b/system/hwc2/MiniFence.cpp
new file mode 100644
index 0000000..ecfb063
--- /dev/null
+++ b/system/hwc2/MiniFence.cpp
@@ -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 "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);
+}
+}
diff --git a/system/hwc2/MiniFence.h b/system/hwc2/MiniFence.h
new file mode 100644
index 0000000..31c9536
--- /dev/null
+++ b/system/hwc2/MiniFence.h
@@ -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 EMU_HWC2_MINIFENCE_H
+#define EMU_HWC2_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 //EMU_HWC2_MINIFENCE_H
diff --git a/system/renderControl_enc/renderControl_client_context.cpp b/system/renderControl_enc/renderControl_client_context.cpp
index 4a86244..fb5ead1 100644
--- a/system/renderControl_enc/renderControl_client_context.cpp
+++ b/system/renderControl_enc/renderControl_client_context.cpp
@@ -47,6 +47,7 @@
rcUpdateColorBufferDMA = (rcUpdateColorBufferDMA_client_proc_t) getProc("rcUpdateColorBufferDMA", userData);
rcCreateColorBufferDMA = (rcCreateColorBufferDMA_client_proc_t) getProc("rcCreateColorBufferDMA", userData);
rcWaitSyncKHR = (rcWaitSyncKHR_client_proc_t) getProc("rcWaitSyncKHR", userData);
+ rcCompose = (rcCompose_client_proc_t) getProc("rcCompose", userData);
return 0;
}
diff --git a/system/renderControl_enc/renderControl_client_context.h b/system/renderControl_enc/renderControl_client_context.h
index 1e5594b..5d3878c 100644
--- a/system/renderControl_enc/renderControl_client_context.h
+++ b/system/renderControl_enc/renderControl_client_context.h
@@ -47,6 +47,7 @@
rcUpdateColorBufferDMA_client_proc_t rcUpdateColorBufferDMA;
rcCreateColorBufferDMA_client_proc_t rcCreateColorBufferDMA;
rcWaitSyncKHR_client_proc_t rcWaitSyncKHR;
+ rcCompose_client_proc_t rcCompose;
virtual ~renderControl_client_context_t() {}
typedef renderControl_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
diff --git a/system/renderControl_enc/renderControl_client_proc.h b/system/renderControl_enc/renderControl_client_proc.h
index 3f1e5bb..24708dd 100644
--- a/system/renderControl_enc/renderControl_client_proc.h
+++ b/system/renderControl_enc/renderControl_client_proc.h
@@ -46,6 +46,7 @@
typedef int (renderControl_APIENTRY *rcUpdateColorBufferDMA_client_proc_t) (void * ctx, uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*, uint32_t);
typedef uint32_t (renderControl_APIENTRY *rcCreateColorBufferDMA_client_proc_t) (void * ctx, uint32_t, uint32_t, GLenum, int);
typedef void (renderControl_APIENTRY *rcWaitSyncKHR_client_proc_t) (void * ctx, uint64_t, EGLint);
+typedef GLint (renderControl_APIENTRY *rcCompose_client_proc_t) (void * ctx, uint32_t, void*);
#endif
diff --git a/system/renderControl_enc/renderControl_enc.cpp b/system/renderControl_enc/renderControl_enc.cpp
index f250926..905b6a9 100644
--- a/system/renderControl_enc/renderControl_enc.cpp
+++ b/system/renderControl_enc/renderControl_enc.cpp
@@ -1393,6 +1393,49 @@
}
+GLint rcCompose_enc(void *self , uint32_t bufferSize, void* buffer)
+{
+
+ renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+ IOStream *stream = ctx->m_stream;
+ ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+ bool useChecksum = checksumCalculator->getVersion() > 0;
+
+ const unsigned int __size_buffer = bufferSize;
+ unsigned char *ptr;
+ unsigned char *buf;
+ const size_t sizeWithoutChecksum = 8 + 4 + __size_buffer + 1*4;
+ const size_t checksumSize = checksumCalculator->checksumByteSize();
+ const size_t totalSize = sizeWithoutChecksum + checksumSize;
+ buf = stream->alloc(totalSize);
+ ptr = buf;
+ int tmp = OP_rcCompose;memcpy(ptr, &tmp, 4); ptr += 4;
+ memcpy(ptr, &totalSize, 4); ptr += 4;
+
+ memcpy(ptr, &bufferSize, 4); ptr += 4;
+ *(unsigned int *)(ptr) = __size_buffer; ptr += 4;
+ memcpy(ptr, buffer, __size_buffer);ptr += __size_buffer;
+
+ if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+ if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+ GLint retval;
+ stream->readback(&retval, 4);
+ if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+ if (useChecksum) {
+ unsigned char *checksumBufPtr = NULL;
+ unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+ if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+ stream->readback(checksumBufPtr, checksumSize);
+ if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+ ALOGE("rcCompose: GL communication error, please report this issue to b.android.com.\n");
+ abort();
+ }
+ }
+ return retval;
+}
+
} // namespace
renderControl_encoder_context_t::renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -1437,5 +1480,6 @@
this->rcUpdateColorBufferDMA = &rcUpdateColorBufferDMA_enc;
this->rcCreateColorBufferDMA = &rcCreateColorBufferDMA_enc;
this->rcWaitSyncKHR = &rcWaitSyncKHR_enc;
+ this->rcCompose = &rcCompose_enc;
}
diff --git a/system/renderControl_enc/renderControl_entry.cpp b/system/renderControl_enc/renderControl_entry.cpp
index 9a47dd3..4296940 100644
--- a/system/renderControl_enc/renderControl_entry.cpp
+++ b/system/renderControl_enc/renderControl_entry.cpp
@@ -42,6 +42,7 @@
int rcUpdateColorBufferDMA(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void* pixels, uint32_t pixels_size);
uint32_t rcCreateColorBufferDMA(uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat);
void rcWaitSyncKHR(uint64_t sync, EGLint flags);
+ GLint rcCompose(uint32_t bufferSize, void* buffer);
};
#ifndef GET_CONTEXT
@@ -272,3 +273,9 @@
ctx->rcWaitSyncKHR(ctx, sync, flags);
}
+GLint rcCompose(uint32_t bufferSize, void* buffer)
+{
+ GET_CONTEXT;
+ return ctx->rcCompose(ctx, bufferSize, buffer);
+}
+
diff --git a/system/renderControl_enc/renderControl_ftable.h b/system/renderControl_enc/renderControl_ftable.h
index 7bfc7c5..ab75bb0 100644
--- a/system/renderControl_enc/renderControl_ftable.h
+++ b/system/renderControl_enc/renderControl_ftable.h
@@ -45,6 +45,7 @@
{"rcUpdateColorBufferDMA", (void*)rcUpdateColorBufferDMA},
{"rcCreateColorBufferDMA", (void*)rcCreateColorBufferDMA},
{"rcWaitSyncKHR", (void*)rcWaitSyncKHR},
+ {"rcCompose", (void*)rcCompose},
};
static const int renderControl_num_funcs = sizeof(renderControl_funcs_by_name) / sizeof(struct _renderControl_funcs_by_name);
diff --git a/system/renderControl_enc/renderControl_opcodes.h b/system/renderControl_enc/renderControl_opcodes.h
index 146164f..100faaa 100644
--- a/system/renderControl_enc/renderControl_opcodes.h
+++ b/system/renderControl_enc/renderControl_opcodes.h
@@ -40,7 +40,8 @@
#define OP_rcUpdateColorBufferDMA 10034
#define OP_rcCreateColorBufferDMA 10035
#define OP_rcWaitSyncKHR 10036
-#define OP_last 10037
+#define OP_rcCompose 10037
+#define OP_last 10038
#endif