SF: HWC2 C++ shim

Provides an object-based C++ interface to the HWC 2.0 HAL

Change-Id: Ie1a7bfd2f6faa548bc45da845a4f50f1915b5806
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index fe39768..3d71aa8 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -19,6 +19,7 @@
     SurfaceFlingerConsumer.cpp \
     Transform.cpp \
     DisplayHardware/FramebufferSurface.cpp \
+    DisplayHardware/HWC2.cpp \
     DisplayHardware/HWC2On1Adapter.cpp \
     DisplayHardware/HWComposer.cpp \
     DisplayHardware/PowerHAL.cpp \
diff --git a/services/surfaceflinger/DisplayHardware/FloatRect.h b/services/surfaceflinger/DisplayHardware/FloatRect.h
index 3b75cc0..9ad1040 100644
--- a/services/surfaceflinger/DisplayHardware/FloatRect.h
+++ b/services/surfaceflinger/DisplayHardware/FloatRect.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SF_FLOAT_RECT
 #define ANDROID_SF_FLOAT_RECT
 
+#include <ui/Rect.h>
 #include <utils/TypeHelpers.h>
 
 namespace android {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
new file mode 100644
index 0000000..0e97a53
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -0,0 +1,992 @@
+/*
+ * 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.
+ */
+
+// #define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "HWC2"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "HWC2.h"
+
+#include "FloatRect.h"
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+
+#include <android/configuration.h>
+
+#include <inttypes.h>
+
+extern "C" {
+    static void hotplug_hook(hwc2_callback_data_t callbackData,
+            hwc2_display_t displayId, int32_t intConnected) {
+        auto device = static_cast<HWC2::Device*>(callbackData);
+        auto display = device->getDisplayById(displayId);
+        if (display) {
+            auto connected = static_cast<HWC2::Connection>(intConnected);
+            device->callHotplug(std::move(display), connected);
+        } else {
+            ALOGE("Hotplug callback called with unknown display %" PRIu64,
+                    displayId);
+        }
+    }
+
+    static void refresh_hook(hwc2_callback_data_t callbackData,
+            hwc2_display_t displayId) {
+        auto device = static_cast<HWC2::Device*>(callbackData);
+        auto display = device->getDisplayById(displayId);
+        if (display) {
+            device->callRefresh(std::move(display));
+        } else {
+            ALOGE("Refresh callback called with unknown display %" PRIu64,
+                    displayId);
+        }
+    }
+
+    static void vsync_hook(hwc2_callback_data_t callbackData,
+            hwc2_display_t displayId, int64_t timestamp) {
+        auto device = static_cast<HWC2::Device*>(callbackData);
+        auto display = device->getDisplayById(displayId);
+        if (display) {
+            device->callVsync(std::move(display), timestamp);
+        } else {
+            ALOGE("Vsync callback called with unknown display %" PRIu64,
+                    displayId);
+        }
+    }
+}
+
+using android::Fence;
+using android::FloatRect;
+using android::GraphicBuffer;
+using android::Rect;
+using android::Region;
+using android::sp;
+
+namespace HWC2 {
+
+// Device methods
+
+Device::Device(hwc2_device_t* device)
+  : mHwcDevice(device),
+    mCreateVirtualDisplay(nullptr),
+    mDestroyVirtualDisplay(nullptr),
+    mDump(nullptr),
+    mGetMaxVirtualDisplayCount(nullptr),
+    mRegisterCallback(nullptr),
+    mAcceptDisplayChanges(nullptr),
+    mCreateLayer(nullptr),
+    mDestroyLayer(nullptr),
+    mGetActiveConfig(nullptr),
+    mGetChangedCompositionTypes(nullptr),
+    mGetDisplayAttribute(nullptr),
+    mGetDisplayConfigs(nullptr),
+    mGetDisplayName(nullptr),
+    mGetDisplayRequests(nullptr),
+    mGetDisplayType(nullptr),
+    mGetDozeSupport(nullptr),
+    mGetReleaseFences(nullptr),
+    mPresentDisplay(nullptr),
+    mSetActiveConfig(nullptr),
+    mSetClientTarget(nullptr),
+    mSetOutputBuffer(nullptr),
+    mSetPowerMode(nullptr),
+    mSetVsyncEnabled(nullptr),
+    mValidateDisplay(nullptr),
+    mSetCursorPosition(nullptr),
+    mSetLayerBuffer(nullptr),
+    mSetLayerSurfaceDamage(nullptr),
+    mSetLayerBlendMode(nullptr),
+    mSetLayerColor(nullptr),
+    mSetLayerCompositionType(nullptr),
+    mSetLayerDisplayFrame(nullptr),
+    mSetLayerPlaneAlpha(nullptr),
+    mSetLayerSidebandStream(nullptr),
+    mSetLayerSourceCrop(nullptr),
+    mSetLayerTransform(nullptr),
+    mSetLayerVisibleRegion(nullptr),
+    mSetLayerZOrder(nullptr),
+    mCapabilities(),
+    mDisplays(),
+    mHotplug(),
+    mPendingHotplugs(),
+    mRefresh(),
+    mPendingRefreshes(),
+    mVsync(),
+    mPendingVsyncs()
+{
+    loadCapabilities();
+    loadFunctionPointers();
+    registerCallbacks();
+}
+
+Device::~Device()
+{
+    if (mHwcDevice == nullptr) {
+        return;
+    }
+
+    for (auto element : mDisplays) {
+        auto display = element.second;
+
+        DisplayType displayType = HWC2::DisplayType::Invalid;
+        auto error = display->getType(&displayType);
+        if (error != Error::None) {
+            ALOGE("~Device: Failed to determine type of display %" PRIu64
+                    ": %s (%d)", display->getId(), to_string(error).c_str(),
+                    static_cast<int32_t>(error));
+            continue;
+        }
+
+        if (displayType == HWC2::DisplayType::Physical) {
+            error = display->setVsyncEnabled(HWC2::Vsync::Disable);
+            if (error != Error::None) {
+                ALOGE("~Device: Failed to disable vsync for display %" PRIu64
+                        ": %s (%d)", display->getId(), to_string(error).c_str(),
+                        static_cast<int32_t>(error));
+            }
+        }
+    }
+
+    hwc2_close(mHwcDevice);
+}
+
+// Required by HWC2 device
+
+std::string Device::dump() const
+{
+    uint32_t numBytes = 0;
+    mDump(mHwcDevice, &numBytes, nullptr);
+
+    std::vector<char> buffer(numBytes);
+    mDump(mHwcDevice, &numBytes, buffer.data());
+
+    return std::string(buffer.data(), buffer.size());
+}
+
+uint32_t Device::getMaxVirtualDisplayCount() const
+{
+    return mGetMaxVirtualDisplayCount(mHwcDevice);
+}
+
+Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
+        std::shared_ptr<Display>* outDisplay)
+{
+    ALOGI("Creating virtual display");
+
+    hwc2_display_t displayId = 0;
+    int32_t intError = mCreateVirtualDisplay(mHwcDevice, width, height,
+            &displayId);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    ALOGI("Created virtual display");
+    *outDisplay = getDisplayById(displayId);
+    (*outDisplay)->setVirtual();
+    return Error::None;
+}
+
+void Device::registerHotplugCallback(HotplugCallback hotplug)
+{
+    ALOGV("registerHotplugCallback");
+    mHotplug = hotplug;
+    for (auto& pending : mPendingHotplugs) {
+        auto& display = pending.first;
+        auto connected = pending.second;
+        ALOGV("Sending pending hotplug(%" PRIu64 ", %s)", display->getId(),
+                to_string(connected).c_str());
+        mHotplug(std::move(display), connected);
+    }
+}
+
+void Device::registerRefreshCallback(RefreshCallback refresh)
+{
+    mRefresh = refresh;
+    for (auto& pending : mPendingRefreshes) {
+        mRefresh(std::move(pending));
+    }
+}
+
+void Device::registerVsyncCallback(VsyncCallback vsync)
+{
+    mVsync = vsync;
+    for (auto& pending : mPendingVsyncs) {
+        auto& display = pending.first;
+        auto timestamp = pending.second;
+        mVsync(std::move(display), timestamp);
+    }
+}
+
+// For use by Device callbacks
+
+void Device::callHotplug(std::shared_ptr<Display> display, Connection connected)
+{
+    if (connected == Connection::Connected) {
+        if (!display->isConnected()) {
+            display->loadConfigs();
+            display->setConnected(true);
+        }
+    } else {
+        display->setConnected(false);
+        mDisplays.erase(display->getId());
+    }
+
+    if (mHotplug) {
+        mHotplug(std::move(display), connected);
+    } else {
+        ALOGV("callHotplug called, but no valid callback registered, storing");
+        mPendingHotplugs.emplace_back(std::move(display), connected);
+    }
+}
+
+void Device::callRefresh(std::shared_ptr<Display> display)
+{
+    if (mRefresh) {
+        mRefresh(std::move(display));
+    } else {
+        ALOGV("callRefresh called, but no valid callback registered, storing");
+        mPendingRefreshes.emplace_back(std::move(display));
+    }
+}
+
+void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp)
+{
+    if (mVsync) {
+        mVsync(std::move(display), timestamp);
+    } else {
+        ALOGV("callVsync called, but no valid callback registered, storing");
+        mPendingVsyncs.emplace_back(std::move(display), timestamp);
+    }
+}
+
+// Other Device methods
+
+std::shared_ptr<Display> Device::getDisplayById(hwc2_display_t id) {
+    if (mDisplays.count(id) != 0) {
+        return mDisplays.at(id);
+    }
+
+    auto display = std::make_shared<Display>(*this, id);
+    mDisplays.emplace(id, display);
+    return display;
+}
+
+// Device initialization methods
+
+void Device::loadCapabilities()
+{
+    static_assert(sizeof(Capability) == sizeof(int32_t),
+            "Capability size has changed");
+    uint32_t numCapabilities = 0;
+    mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr);
+    mCapabilities.resize(numCapabilities);
+    auto asInt = reinterpret_cast<int32_t*>(mCapabilities.data());
+    mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, asInt);
+}
+
+void Device::loadFunctionPointers()
+{
+    // For all of these early returns, we log an error message inside
+    // loadFunctionPointer specifying which function failed to load
+
+    // Display function pointers
+    if(!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
+            mCreateVirtualDisplay)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
+            mDestroyVirtualDisplay)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
+            mGetMaxVirtualDisplayCount)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
+            mRegisterCallback)) return;
+
+    // Device function pointers
+    if(!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
+            mAcceptDisplayChanges)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::CreateLayer,
+            mCreateLayer)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
+            mDestroyLayer)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
+            mGetActiveConfig)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
+            mGetChangedCompositionTypes)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
+            mGetDisplayAttribute)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
+            mGetDisplayConfigs)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
+            mGetDisplayName)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
+            mGetDisplayRequests)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
+            mGetDisplayType)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
+            mGetDozeSupport)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
+            mGetReleaseFences)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
+            mPresentDisplay)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
+            mSetActiveConfig)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
+            mSetClientTarget)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
+            mSetOutputBuffer)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
+            mSetPowerMode)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
+            mSetVsyncEnabled)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
+            mValidateDisplay)) return;
+
+    // Layer function pointers
+    if(!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
+            mSetCursorPosition)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
+            mSetLayerBuffer)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
+            mSetLayerSurfaceDamage)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
+            mSetLayerBlendMode)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
+            mSetLayerColor)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
+            mSetLayerCompositionType)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
+            mSetLayerDisplayFrame)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
+            mSetLayerPlaneAlpha)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
+            mSetLayerSidebandStream)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
+            mSetLayerSourceCrop)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
+            mSetLayerTransform)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
+            mSetLayerVisibleRegion)) return;
+    if(!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
+            mSetLayerZOrder)) return;
+}
+
+void Device::registerCallbacks()
+{
+    registerCallback<HWC2_PFN_HOTPLUG>(Callback::Hotplug, hotplug_hook);
+    registerCallback<HWC2_PFN_REFRESH>(Callback::Refresh, refresh_hook);
+    registerCallback<HWC2_PFN_VSYNC>(Callback::Vsync, vsync_hook);
+}
+
+
+// For use by Display
+
+void Device::destroyVirtualDisplay(hwc2_display_t display)
+{
+    ALOGI("Destroying virtual display");
+    int32_t intError = mDestroyVirtualDisplay(mHwcDevice, display);
+    auto error = static_cast<Error>(intError);
+    ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
+            " %s (%d)", display, to_string(error).c_str(), intError);
+}
+
+// Display methods
+
+Display::Display(Device& device, hwc2_display_t id)
+  : mDevice(device),
+    mId(id),
+    mIsConnected(false),
+    mIsVirtual(false)
+{
+    ALOGV("Created display %" PRIu64, id);
+}
+
+Display::~Display()
+{
+    ALOGV("Destroyed display %" PRIu64, mId);
+    if (mIsVirtual) {
+        mDevice.destroyVirtualDisplay(mId);
+    }
+}
+
+Display::Config::Config(Display& display, hwc2_config_t id)
+  : mDisplay(display),
+    mId(id),
+    mWidth(-1),
+    mHeight(-1),
+    mVsyncPeriod(-1),
+    mDpiX(-1),
+    mDpiY(-1) {}
+
+Display::Config::Builder::Builder(Display& display, hwc2_config_t id)
+  : mConfig(new Config(display, id)) {}
+
+float Display::Config::Builder::getDefaultDensity() {
+    // Default density is based on TVs: 1080p displays get XHIGH density, lower-
+    // resolution displays get TV density. Maybe eventually we'll need to update
+    // it for 4k displays, though hopefully those will just report accurate DPI
+    // information to begin with. This is also used for virtual displays and
+    // older HWC implementations, so be careful about orientation.
+
+    auto longDimension = std::max(mConfig->mWidth, mConfig->mHeight);
+    if (longDimension >= 1080) {
+        return ACONFIGURATION_DENSITY_XHIGH;
+    } else {
+        return ACONFIGURATION_DENSITY_TV;
+    }
+}
+
+// Required by HWC2 display
+
+Error Display::acceptChanges()
+{
+    int32_t intError = mDevice.mAcceptDisplayChanges(mDevice.mHwcDevice, mId);
+    return static_cast<Error>(intError);
+}
+
+Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
+{
+    hwc2_layer_t layerId = 0;
+    int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    auto layer = std::make_shared<Layer>(shared_from_this(), layerId);
+    mLayers.emplace(layerId, layer);
+    *outLayer = std::move(layer);
+    return Error::None;
+}
+
+Error Display::getActiveConfig(
+        std::shared_ptr<const Display::Config>* outConfig) const
+{
+    ALOGV("[%" PRIu64 "] getActiveConfig", mId);
+    hwc2_config_t configId = 0;
+    int32_t intError = mDevice.mGetActiveConfig(mDevice.mHwcDevice, mId,
+            &configId);
+    auto error = static_cast<Error>(intError);
+
+    if (error != Error::None) {
+        return error;
+    }
+
+    if (mConfigs.count(configId) != 0) {
+        *outConfig = mConfigs.at(configId);
+    } else {
+        ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId,
+                configId);
+        // Return no error, but the caller needs to check for a null pointer to
+        // detect this case
+        *outConfig = nullptr;
+    }
+
+    return Error::None;
+}
+
+Error Display::getChangedCompositionTypes(
+        std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes)
+{
+    uint32_t numElements = 0;
+    int32_t intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice,
+            mId, &numElements, nullptr, nullptr);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::vector<hwc2_layer_t> layerIds(numElements);
+    std::vector<int32_t> types(numElements);
+    intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId,
+            &numElements, layerIds.data(), types.data());
+    error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    outTypes->clear();
+    outTypes->reserve(numElements);
+    for (uint32_t element = 0; element < numElements; ++element) {
+        auto layer = getLayerById(layerIds[element]);
+        if (layer) {
+            auto type = static_cast<Composition>(types[element]);
+            ALOGV("getChangedCompositionTypes: adding %" PRIu64 " %s",
+                    layer->getId(), to_string(type).c_str());
+            outTypes->emplace(layer, type);
+        } else {
+            ALOGE("getChangedCompositionTypes: invalid layer %" PRIu64 " found"
+                    " on display %" PRIu64, layerIds[element], mId);
+        }
+    }
+
+    return Error::None;
+}
+
+std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const
+{
+    std::vector<std::shared_ptr<const Config>> configs;
+    for (const auto& element : mConfigs) {
+        configs.emplace_back(element.second);
+    }
+    return configs;
+}
+
+Error Display::getName(std::string* outName) const
+{
+    uint32_t size;
+    int32_t intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
+            nullptr);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::vector<char> rawName(size);
+    intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
+            rawName.data());
+    error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outName = std::string(rawName.cbegin(), rawName.cend());
+    return Error::None;
+}
+
+Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
+        std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
+                outLayerRequests)
+{
+    int32_t intDisplayRequests = 0;
+    uint32_t numElements = 0;
+    int32_t intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
+            &intDisplayRequests, &numElements, nullptr, nullptr);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::vector<hwc2_layer_t> layerIds(numElements);
+    std::vector<int32_t> layerRequests(numElements);
+    intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
+            &intDisplayRequests, &numElements, layerIds.data(),
+            layerRequests.data());
+    error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outDisplayRequests = static_cast<DisplayRequest>(intDisplayRequests);
+    outLayerRequests->clear();
+    outLayerRequests->reserve(numElements);
+    for (uint32_t element = 0; element < numElements; ++element) {
+        auto layer = getLayerById(layerIds[element]);
+        if (layer) {
+            auto layerRequest =
+                    static_cast<LayerRequest>(layerRequests[element]);
+            outLayerRequests->emplace(layer, layerRequest);
+        } else {
+            ALOGE("getRequests: invalid layer %" PRIu64 " found on display %"
+                    PRIu64, layerIds[element], mId);
+        }
+    }
+
+    return Error::None;
+}
+
+Error Display::getType(DisplayType* outType) const
+{
+    int32_t intType = 0;
+    int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId,
+            &intType);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outType = static_cast<DisplayType>(intType);
+    return Error::None;
+}
+
+Error Display::supportsDoze(bool* outSupport) const
+{
+    int32_t intSupport = 0;
+    int32_t intError = mDevice.mGetDozeSupport(mDevice.mHwcDevice, mId,
+            &intSupport);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+    *outSupport = static_cast<bool>(intSupport);
+    return Error::None;
+}
+
+Error Display::getReleaseFences(
+        std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
+{
+    uint32_t numElements = 0;
+    int32_t intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId,
+            &numElements, nullptr, nullptr);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::vector<hwc2_layer_t> layerIds(numElements);
+    std::vector<int32_t> fenceFds(numElements);
+    intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements,
+            layerIds.data(), fenceFds.data());
+    error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    std::unordered_map<std::shared_ptr<Layer>, sp<Fence>> releaseFences;
+    releaseFences.reserve(numElements);
+    for (uint32_t element = 0; element < numElements; ++element) {
+        auto layer = getLayerById(layerIds[element]);
+        if (layer) {
+            sp<Fence> fence(new Fence(fenceFds[element]));
+            releaseFences.emplace(std::move(layer), fence);
+        } else {
+            ALOGE("getReleaseFences: invalid layer %" PRIu64
+                    " found on display %" PRIu64, layerIds[element], mId);
+            return Error::BadLayer;
+        }
+    }
+
+    *outFences = std::move(releaseFences);
+    return Error::None;
+}
+
+Error Display::present(sp<Fence>* outRetireFence)
+{
+    int32_t retireFenceFd = 0;
+    int32_t intError = mDevice.mPresentDisplay(mDevice.mHwcDevice, mId,
+            &retireFenceFd);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        return error;
+    }
+
+    *outRetireFence = new Fence(retireFenceFd);
+    return Error::None;
+}
+
+Error Display::setActiveConfig(const std::shared_ptr<const Config>& config)
+{
+    if (config->getDisplayId() != mId) {
+        ALOGE("setActiveConfig received config %u for the wrong display %"
+                PRIu64 " (expected %" PRIu64 ")", config->getId(),
+                config->getDisplayId(), mId);
+        return Error::BadConfig;
+    }
+    int32_t intError = mDevice.mSetActiveConfig(mDevice.mHwcDevice, mId,
+            config->getId());
+    return static_cast<Error>(intError);
+}
+
+Error Display::setClientTarget(buffer_handle_t target,
+        const sp<Fence>& acquireFence, android_dataspace_t dataspace)
+{
+    int32_t fenceFd = acquireFence->dup();
+    int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, target,
+            fenceFd, static_cast<int32_t>(dataspace));
+    return static_cast<Error>(intError);
+}
+
+Error Display::setOutputBuffer(const sp<GraphicBuffer>& buffer,
+        const sp<Fence>& releaseFence)
+{
+    int32_t fenceFd = releaseFence->dup();
+    auto handle = buffer->getNativeBuffer()->handle;
+    int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle,
+            fenceFd);
+    return static_cast<Error>(intError);
+}
+
+Error Display::setPowerMode(PowerMode mode)
+{
+    auto intMode = static_cast<int32_t>(mode);
+    int32_t intError = mDevice.mSetPowerMode(mDevice.mHwcDevice, mId, intMode);
+    return static_cast<Error>(intError);
+}
+
+Error Display::setVsyncEnabled(Vsync enabled)
+{
+    auto intEnabled = static_cast<int32_t>(enabled);
+    int32_t intError = mDevice.mSetVsyncEnabled(mDevice.mHwcDevice, mId,
+            intEnabled);
+    return static_cast<Error>(intError);
+}
+
+Error Display::validate(uint32_t* outNumTypes, uint32_t* outNumRequests)
+{
+    uint32_t numTypes = 0;
+    uint32_t numRequests = 0;
+    int32_t intError = mDevice.mValidateDisplay(mDevice.mHwcDevice, mId,
+            &numTypes, &numRequests);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None && error != Error::HasChanges) {
+        return error;
+    }
+
+    *outNumTypes = numTypes;
+    *outNumRequests = numRequests;
+    return error;
+}
+
+// For use by Device
+
+int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
+{
+    int32_t value = 0;
+    int32_t intError = mDevice.mGetDisplayAttribute(mDevice.mHwcDevice, mId,
+            configId, static_cast<int32_t>(attribute), &value);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId,
+                configId, to_string(attribute).c_str(),
+                to_string(error).c_str(), intError);
+        return -1;
+    }
+    return value;
+}
+
+void Display::loadConfig(hwc2_config_t configId)
+{
+    ALOGV("[%" PRIu64 "] loadConfig(%u)", mId, configId);
+
+    auto config = Config::Builder(*this, configId)
+            .setWidth(getAttribute(configId, Attribute::Width))
+            .setHeight(getAttribute(configId, Attribute::Height))
+            .setVsyncPeriod(getAttribute(configId, Attribute::VsyncPeriod))
+            .setDpiX(getAttribute(configId, Attribute::DpiX))
+            .setDpiY(getAttribute(configId, Attribute::DpiY))
+            .build();
+    mConfigs.emplace(configId, std::move(config));
+}
+
+void Display::loadConfigs()
+{
+    ALOGV("[%" PRIu64 "] loadConfigs", mId);
+
+    uint32_t numConfigs = 0;
+    int32_t intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId,
+            &numConfigs, nullptr);
+    auto error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        ALOGE("[%" PRIu64 "] getDisplayConfigs [1] failed: %s (%d)", mId,
+                to_string(error).c_str(), intError);
+        return;
+    }
+
+    std::vector<hwc2_config_t> configIds(numConfigs);
+    intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs,
+            configIds.data());
+    error = static_cast<Error>(intError);
+    if (error != Error::None) {
+        ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
+                to_string(error).c_str(), intError);
+        return;
+    }
+
+    for (auto configId : configIds) {
+        loadConfig(configId);
+    }
+}
+
+// For use by Layer
+
+void Display::destroyLayer(hwc2_layer_t layerId)
+{
+    int32_t intError = mDevice.mDestroyLayer(mDevice.mHwcDevice, mId, layerId);
+    auto error = static_cast<Error>(intError);
+    ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
+            " failed: %s (%d)", mId, layerId, to_string(error).c_str(),
+            intError);
+    mLayers.erase(layerId);
+}
+
+// Other Display methods
+
+std::shared_ptr<Layer> Display::getLayerById(hwc2_layer_t id) const
+{
+    if (mLayers.count(id) == 0) {
+        return nullptr;
+    }
+
+    auto layer = mLayers.at(id).lock();
+    return layer;
+}
+
+// Layer methods
+
+Layer::Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id)
+  : mDisplay(display),
+    mDisplayId(display->getId()),
+    mDevice(display->getDevice()),
+    mId(id)
+{
+    ALOGV("Created layer %" PRIu64 " on display %" PRIu64, id,
+            display->getId());
+}
+
+Layer::~Layer()
+{
+    auto display = mDisplay.lock();
+    if (display) {
+        display->destroyLayer(mId);
+    }
+}
+
+Error Layer::setCursorPosition(int32_t x, int32_t y)
+{
+    int32_t intError = mDevice.mSetCursorPosition(mDevice.mHwcDevice,
+            mDisplayId, mId, x, y);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setBuffer(buffer_handle_t buffer,
+        const sp<Fence>& acquireFence)
+{
+    int32_t fenceFd = acquireFence->dup();
+    int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId,
+            mId, buffer, fenceFd);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setSurfaceDamage(const Region& damage)
+{
+    // We encode default full-screen damage as INVALID_RECT upstream, but as 0
+    // rects for HWC
+    int32_t intError = 0;
+    if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) {
+        intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
+                mDisplayId, mId, {0, nullptr});
+    } else {
+        size_t rectCount = 0;
+        auto rectArray = damage.getArray(&rectCount);
+
+        std::vector<hwc_rect_t> hwcRects;
+        for (size_t rect = 0; rect < rectCount; ++rect) {
+            hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
+                    rectArray[rect].right, rectArray[rect].bottom});
+        }
+
+        hwc_region_t hwcRegion = {};
+        hwcRegion.numRects = rectCount;
+        hwcRegion.rects = hwcRects.data();
+
+        intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
+                mDisplayId, mId, hwcRegion);
+    }
+
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setBlendMode(BlendMode mode)
+{
+    auto intMode = static_cast<int32_t>(mode);
+    int32_t intError = mDevice.mSetLayerBlendMode(mDevice.mHwcDevice,
+            mDisplayId, mId, intMode);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setColor(hwc_color_t color)
+{
+    int32_t intError = mDevice.mSetLayerColor(mDevice.mHwcDevice, mDisplayId,
+            mId, color);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setCompositionType(Composition type)
+{
+    auto intType = static_cast<int32_t>(type);
+    int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice,
+            mDisplayId, mId, intType);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setDisplayFrame(const Rect& frame)
+{
+    hwc_rect_t hwcRect{frame.left, frame.top, frame.right, frame.bottom};
+    int32_t intError = mDevice.mSetLayerDisplayFrame(mDevice.mHwcDevice,
+            mDisplayId, mId, hwcRect);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setPlaneAlpha(float alpha)
+{
+    int32_t intError = mDevice.mSetLayerPlaneAlpha(mDevice.mHwcDevice,
+            mDisplayId, mId, alpha);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setSidebandStream(const native_handle_t* stream)
+{
+    int32_t intError = mDevice.mSetLayerSidebandStream(mDevice.mHwcDevice,
+            mDisplayId, mId, stream);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setSourceCrop(const FloatRect& crop)
+{
+    hwc_frect_t hwcRect{crop.left, crop.top, crop.right, crop.bottom};
+    int32_t intError = mDevice.mSetLayerSourceCrop(mDevice.mHwcDevice,
+            mDisplayId, mId, hwcRect);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setTransform(Transform transform)
+{
+    auto intTransform = static_cast<int32_t>(transform);
+    int32_t intError = mDevice.mSetLayerTransform(mDevice.mHwcDevice,
+            mDisplayId, mId, intTransform);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setVisibleRegion(const Region& region)
+{
+    size_t rectCount = 0;
+    auto rectArray = region.getArray(&rectCount);
+
+    std::vector<hwc_rect_t> hwcRects;
+    for (size_t rect = 0; rect < rectCount; ++rect) {
+        hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
+                rectArray[rect].right, rectArray[rect].bottom});
+    }
+
+    hwc_region_t hwcRegion = {};
+    hwcRegion.numRects = rectCount;
+    hwcRegion.rects = hwcRects.data();
+
+    int32_t intError = mDevice.mSetLayerVisibleRegion(mDevice.mHwcDevice,
+            mDisplayId, mId, hwcRegion);
+    return static_cast<Error>(intError);
+}
+
+Error Layer::setZOrder(uint32_t z)
+{
+    int32_t intError = mDevice.mSetLayerZOrder(mDevice.mHwcDevice, mDisplayId,
+            mId, z);
+    return static_cast<Error>(intError);
+}
+
+} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
new file mode 100644
index 0000000..a7bd28c
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -0,0 +1,377 @@
+/*
+ * 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_H
+#define ANDROID_SF_HWC2_H
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <functional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+    class Fence;
+    class FloatRect;
+    class GraphicBuffer;
+    class Rect;
+    class Region;
+}
+
+namespace HWC2 {
+
+class Display;
+class Layer;
+
+typedef std::function<void(std::shared_ptr<Display>, Connection)>
+        HotplugCallback;
+typedef std::function<void(std::shared_ptr<Display>)> RefreshCallback;
+typedef std::function<void(std::shared_ptr<Display>, nsecs_t)> VsyncCallback;
+
+class Device
+{
+public:
+    Device(hwc2_device_t* device);
+    ~Device();
+
+    friend class HWC2::Display;
+    friend class HWC2::Layer;
+
+    // Required by HWC2
+
+    std::string dump() const;
+
+    const std::vector<Capability>& getCapabilities() const {
+        return mCapabilities;
+    };
+
+    uint32_t getMaxVirtualDisplayCount() const;
+    Error createVirtualDisplay(uint32_t width, uint32_t height,
+            std::shared_ptr<Display>* outDisplay);
+
+    void registerHotplugCallback(HotplugCallback hotplug);
+    void registerRefreshCallback(RefreshCallback refresh);
+    void registerVsyncCallback(VsyncCallback vsync);
+
+    // For use by callbacks
+
+    void callHotplug(std::shared_ptr<Display> display, Connection connected);
+    void callRefresh(std::shared_ptr<Display> display);
+    void callVsync(std::shared_ptr<Display> display, nsecs_t timestamp);
+
+    // Other Device methods
+
+    // This will create a Display if one is not found, but it will not be marked
+    // as connected
+    std::shared_ptr<Display> getDisplayById(hwc2_display_t id);
+
+private:
+    // Initialization methods
+
+    template <typename PFN>
+    [[clang::warn_unused_result]] bool loadFunctionPointer(
+            FunctionDescriptor desc, PFN& outPFN) {
+        auto intDesc = static_cast<int32_t>(desc);
+        auto pfn = mHwcDevice->getFunction(mHwcDevice, intDesc);
+        if (pfn != nullptr) {
+            outPFN = reinterpret_cast<PFN>(pfn);
+            return true;
+        } else {
+            ALOGE("Failed to load function %s", to_string(desc).c_str());
+            return false;
+        }
+    }
+
+    template <typename PFN, typename HOOK>
+    void registerCallback(Callback callback, HOOK hook) {
+        static_assert(std::is_same<PFN, HOOK>::value,
+                "Incompatible function pointer");
+        auto intCallback = static_cast<int32_t>(callback);
+        auto callbackData = static_cast<hwc2_callback_data_t>(this);
+        auto pfn = reinterpret_cast<hwc2_function_pointer_t>(hook);
+        mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn);
+    }
+
+    void loadCapabilities();
+    void loadFunctionPointers();
+    void registerCallbacks();
+
+    // For use by Display
+
+    void destroyVirtualDisplay(hwc2_display_t display);
+
+    // Member variables
+
+    hwc2_device_t* mHwcDevice;
+
+    // Device function pointers
+    HWC2_PFN_CREATE_VIRTUAL_DISPLAY mCreateVirtualDisplay;
+    HWC2_PFN_DESTROY_VIRTUAL_DISPLAY mDestroyVirtualDisplay;
+    HWC2_PFN_DUMP mDump;
+    HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT mGetMaxVirtualDisplayCount;
+    HWC2_PFN_REGISTER_CALLBACK mRegisterCallback;
+
+    // Display function pointers
+    HWC2_PFN_ACCEPT_DISPLAY_CHANGES mAcceptDisplayChanges;
+    HWC2_PFN_CREATE_LAYER mCreateLayer;
+    HWC2_PFN_DESTROY_LAYER mDestroyLayer;
+    HWC2_PFN_GET_ACTIVE_CONFIG mGetActiveConfig;
+    HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES mGetChangedCompositionTypes;
+    HWC2_PFN_GET_DISPLAY_ATTRIBUTE mGetDisplayAttribute;
+    HWC2_PFN_GET_DISPLAY_CONFIGS mGetDisplayConfigs;
+    HWC2_PFN_GET_DISPLAY_NAME mGetDisplayName;
+    HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests;
+    HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType;
+    HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport;
+    HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences;
+    HWC2_PFN_PRESENT_DISPLAY mPresentDisplay;
+    HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig;
+    HWC2_PFN_SET_CLIENT_TARGET mSetClientTarget;
+    HWC2_PFN_SET_OUTPUT_BUFFER mSetOutputBuffer;
+    HWC2_PFN_SET_POWER_MODE mSetPowerMode;
+    HWC2_PFN_SET_VSYNC_ENABLED mSetVsyncEnabled;
+    HWC2_PFN_VALIDATE_DISPLAY mValidateDisplay;
+
+    // Layer function pointers
+    HWC2_PFN_SET_CURSOR_POSITION mSetCursorPosition;
+    HWC2_PFN_SET_LAYER_BUFFER mSetLayerBuffer;
+    HWC2_PFN_SET_LAYER_SURFACE_DAMAGE mSetLayerSurfaceDamage;
+    HWC2_PFN_SET_LAYER_BLEND_MODE mSetLayerBlendMode;
+    HWC2_PFN_SET_LAYER_COLOR mSetLayerColor;
+    HWC2_PFN_SET_LAYER_COMPOSITION_TYPE mSetLayerCompositionType;
+    HWC2_PFN_SET_LAYER_DISPLAY_FRAME mSetLayerDisplayFrame;
+    HWC2_PFN_SET_LAYER_PLANE_ALPHA mSetLayerPlaneAlpha;
+    HWC2_PFN_SET_LAYER_SIDEBAND_STREAM mSetLayerSidebandStream;
+    HWC2_PFN_SET_LAYER_SOURCE_CROP mSetLayerSourceCrop;
+    HWC2_PFN_SET_LAYER_TRANSFORM mSetLayerTransform;
+    HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion;
+    HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder;
+
+    std::vector<Capability> mCapabilities;
+    std::unordered_map<hwc2_display_t, std::shared_ptr<Display>> mDisplays;
+
+    HotplugCallback mHotplug;
+    std::vector<std::pair<std::shared_ptr<Display>, Connection>>
+            mPendingHotplugs;
+    RefreshCallback mRefresh;
+    std::vector<std::shared_ptr<Display>> mPendingRefreshes;
+    VsyncCallback mVsync;
+    std::vector<std::pair<std::shared_ptr<Display>, nsecs_t>> mPendingVsyncs;
+};
+
+class Display : public std::enable_shared_from_this<Display>
+{
+public:
+    Display(Device& device, hwc2_display_t id);
+    ~Display();
+
+    friend class HWC2::Device;
+    friend class HWC2::Layer;
+
+    class Config
+    {
+    public:
+        class Builder
+        {
+        public:
+            Builder(Display& display, hwc2_config_t id);
+
+            std::shared_ptr<const Config> build() {
+                return std::const_pointer_cast<const Config>(
+                        std::move(mConfig));
+            }
+
+            Builder& setWidth(int32_t width) {
+                mConfig->mWidth = width;
+                return *this;
+            }
+            Builder& setHeight(int32_t height) {
+                mConfig->mHeight = height;
+                return *this;
+            }
+            Builder& setVsyncPeriod(int32_t vsyncPeriod) {
+                mConfig->mVsyncPeriod = vsyncPeriod;
+                return *this;
+            }
+            Builder& setDpiX(int32_t dpiX) {
+                if (dpiX == -1) {
+                    mConfig->mDpiX = getDefaultDensity();
+                } else {
+                    mConfig->mDpiX = dpiX / 1000.0f;
+                }
+                return *this;
+            }
+            Builder& setDpiY(int32_t dpiY) {
+                if (dpiY == -1) {
+                    mConfig->mDpiY = getDefaultDensity();
+                } else {
+                    mConfig->mDpiY = dpiY / 1000.0f;
+                }
+                return *this;
+            }
+
+        private:
+            float getDefaultDensity();
+            std::shared_ptr<Config> mConfig;
+        };
+
+        hwc2_display_t getDisplayId() const { return mDisplay.getId(); }
+        hwc2_config_t getId() const { return mId; }
+
+        int32_t getWidth() const { return mWidth; }
+        int32_t getHeight() const { return mHeight; }
+        nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+        float getDpiX() const { return mDpiX; }
+        float getDpiY() const { return mDpiY; }
+
+    private:
+        Config(Display& display, hwc2_config_t id);
+
+        Display& mDisplay;
+        hwc2_config_t mId;
+
+        int32_t mWidth;
+        int32_t mHeight;
+        nsecs_t mVsyncPeriod;
+        float mDpiX;
+        float mDpiY;
+    };
+
+    // Required by HWC2
+
+    [[clang::warn_unused_result]] Error acceptChanges();
+    [[clang::warn_unused_result]] Error createLayer(
+            std::shared_ptr<Layer>* outLayer);
+    [[clang::warn_unused_result]] Error getActiveConfig(
+            std::shared_ptr<const Config>* outConfig) const;
+    [[clang::warn_unused_result]] Error getChangedCompositionTypes(
+            std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes);
+
+    // Doesn't call into the HWC2 device, so no errors are possible
+    std::vector<std::shared_ptr<const Config>> getConfigs() const;
+
+    [[clang::warn_unused_result]] Error getName(std::string* outName) const;
+    [[clang::warn_unused_result]] Error getRequests(
+            DisplayRequest* outDisplayRequests,
+            std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
+                    outLayerRequests);
+    [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
+    [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
+    [[clang::warn_unused_result]] Error getReleaseFences(
+            std::unordered_map<std::shared_ptr<Layer>,
+                    android::sp<android::Fence>>* outFences) const;
+    [[clang::warn_unused_result]] Error present(
+            android::sp<android::Fence>* outRetireFence);
+    [[clang::warn_unused_result]] Error setActiveConfig(
+            const std::shared_ptr<const Config>& config);
+    [[clang::warn_unused_result]] Error setClientTarget(
+            buffer_handle_t target,
+            const android::sp<android::Fence>& acquireFence,
+            android_dataspace_t dataspace);
+    [[clang::warn_unused_result]] Error setOutputBuffer(
+            const android::sp<android::GraphicBuffer>& buffer,
+            const android::sp<android::Fence>& releaseFence);
+    [[clang::warn_unused_result]] Error setPowerMode(PowerMode mode);
+    [[clang::warn_unused_result]] Error setVsyncEnabled(Vsync enabled);
+    [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
+            uint32_t* outNumRequests);
+
+    // Other Display methods
+
+    Device& getDevice() const { return mDevice; }
+    hwc2_display_t getId() const { return mId; }
+    bool isConnected() const { return mIsConnected; }
+
+private:
+    // For use by Device
+
+    // Virtual displays are always connected
+    void setVirtual() {
+        mIsVirtual = true;
+        mIsConnected = true;
+    }
+
+    void setConnected(bool connected) { mIsConnected = connected; }
+    int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
+    void loadConfig(hwc2_config_t configId);
+    void loadConfigs();
+
+    // For use by Layer
+    void destroyLayer(hwc2_layer_t layerId);
+
+    // This may fail (and return a null pointer) if no layer with this ID exists
+    // on this display
+    std::shared_ptr<Layer> getLayerById(hwc2_layer_t id) const;
+
+    // Member variables
+
+    Device& mDevice;
+    hwc2_display_t mId;
+    bool mIsConnected;
+    bool mIsVirtual;
+    std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers;
+    std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+};
+
+class Layer
+{
+public:
+    Layer(const std::shared_ptr<Display>& display, hwc2_layer_t id);
+    ~Layer();
+
+    bool isAbandoned() const { return mDisplay.expired(); }
+    hwc2_layer_t getId() const { return mId; }
+
+    [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
+    [[clang::warn_unused_result]] Error setBuffer(buffer_handle_t buffer,
+            const android::sp<android::Fence>& acquireFence);
+    [[clang::warn_unused_result]] Error setSurfaceDamage(
+            const android::Region& damage);
+
+    [[clang::warn_unused_result]] Error setBlendMode(BlendMode mode);
+    [[clang::warn_unused_result]] Error setColor(hwc_color_t color);
+    [[clang::warn_unused_result]] Error setCompositionType(Composition type);
+    [[clang::warn_unused_result]] Error setDisplayFrame(
+            const android::Rect& frame);
+    [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha);
+    [[clang::warn_unused_result]] Error setSidebandStream(
+            const native_handle_t* stream);
+    [[clang::warn_unused_result]] Error setSourceCrop(
+            const android::FloatRect& crop);
+    [[clang::warn_unused_result]] Error setTransform(Transform transform);
+    [[clang::warn_unused_result]] Error setVisibleRegion(
+            const android::Region& region);
+    [[clang::warn_unused_result]] Error setZOrder(uint32_t z);
+
+private:
+    std::weak_ptr<Display> mDisplay;
+    hwc2_display_t mDisplayId;
+    Device& mDevice;
+    hwc2_layer_t mId;
+};
+
+} // namespace HWC2
+
+#endif // ANDROID_SF_HWC2_H