graphics: add a default implementation for IComposer
The default implementatoin is built on top of conventional hwcomposer2.
Test: make
Change-Id: Ia4f13b1d682462769056679fc0aae82a75cb53d2
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
new file mode 100644
index 0000000..f91c9a2
--- /dev/null
+++ b/graphics/composer/2.1/default/Android.bp
@@ -0,0 +1,16 @@
+cc_library_shared {
+ name: "android.hardware.graphics.composer@2.1-impl",
+ relative_install_path: "hw",
+ srcs: ["Hwc.cpp"],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "libbase",
+ "libcutils",
+ "libhardware",
+ "libhidl",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/graphics/composer/2.1/default/Hwc.cpp b/graphics/composer/2.1/default/Hwc.cpp
new file mode 100644
index 0000000..09c62f0
--- /dev/null
+++ b/graphics/composer/2.1/default/Hwc.cpp
@@ -0,0 +1,1292 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HwcPassthrough"
+
+#include <mutex>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <hardware/hwcomposer2.h>
+#include <log/log.h>
+
+#include "Hwc.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+using android::hardware::graphics::allocator::V2_0::PixelFormat;
+
+namespace {
+
+class HandleImporter {
+public:
+ HandleImporter() : mInitialized(false) {}
+
+ bool initialize()
+ {
+ // allow only one client
+ if (mInitialized) {
+ return false;
+ }
+
+ if (!openGralloc()) {
+ return false;
+ }
+
+ mInitialized = true;
+ return true;
+ }
+
+ void cleanup()
+ {
+ if (!mInitialized) {
+ return;
+ }
+
+ closeGralloc();
+ mInitialized = false;
+ }
+
+ // In IComposer, any buffer_handle_t is owned by the caller and we need to
+ // make a clone for hwcomposer2. We also need to translate empty handle
+ // to nullptr. This function does that, in-place.
+ bool importBuffer(buffer_handle_t& handle)
+ {
+ if (!handle->numFds && !handle->numInts) {
+ handle = nullptr;
+ return true;
+ }
+
+ buffer_handle_t clone = cloneBuffer(handle);
+ if (!clone) {
+ return false;
+ }
+
+ handle = clone;
+ return true;
+ }
+
+ void freeBuffer(buffer_handle_t handle)
+ {
+ if (!handle) {
+ return;
+ }
+
+ releaseBuffer(handle);
+ }
+
+ bool importFence(const native_handle_t* handle, int& fd)
+ {
+ if (handle->numFds == 0) {
+ fd = -1;
+ } else if (handle->numFds == 1) {
+ fd = dup(handle->data[0]);
+ if (fd < 0) {
+ ALOGE("failed to dup fence fd %d", handle->data[0]);
+ return false;
+ }
+ } else {
+ ALOGE("invalid fence handle with %d file descriptors",
+ handle->numFds);
+ return false;
+ }
+
+ return true;
+ }
+
+ void closeFence(int fd)
+ {
+ if (fd >= 0) {
+ close(fd);
+ }
+ }
+
+private:
+ bool mInitialized;
+
+ // Some existing gralloc drivers do not support retaining more than once,
+ // when we are in passthrough mode.
+#ifdef BINDERIZED
+ bool openGralloc()
+ {
+ const hw_module_t* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get gralloc module");
+ return false;
+ }
+
+ uint8_t major = (module->module_api_version >> 8) & 0xff;
+ if (major > 1) {
+ ALOGE("unknown gralloc module major version %d", major);
+ return false;
+ }
+
+ if (major == 1) {
+ err = gralloc1_open(module, &mDevice);
+ if (err) {
+ ALOGE("failed to open gralloc1 device");
+ return false;
+ }
+
+ mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN));
+ mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE));
+ if (!mRetain || !mRelease) {
+ ALOGE("invalid gralloc1 device");
+ gralloc1_close(mDevice);
+ return false;
+ }
+ } else {
+ mModule = reinterpret_cast<const gralloc_module_t*>(module);
+ }
+
+ return true;
+ }
+
+ void closeGralloc()
+ {
+ if (mDevice) {
+ gralloc1_close(mDevice);
+ }
+ }
+
+ buffer_handle_t cloneBuffer(buffer_handle_t handle)
+ {
+ native_handle_t* clone = native_handle_clone(handle);
+ if (!clone) {
+ ALOGE("failed to clone buffer %p", handle);
+ return nullptr;
+ }
+
+ bool err;
+ if (mDevice) {
+ err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE);
+ } else {
+ err = (mModule->registerBuffer(mModule, clone) != 0);
+ }
+
+ if (err) {
+ ALOGE("failed to retain/register buffer %p", clone);
+ native_handle_close(clone);
+ native_handle_delete(clone);
+ return nullptr;
+ }
+
+ return clone;
+ }
+
+ void releaseBuffer(buffer_handle_t handle)
+ {
+ if (mDevice) {
+ mRelease(mDevice, handle);
+ } else {
+ mModule->unregisterBuffer(mModule, handle);
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle_t*>(handle));
+ }
+ }
+
+ // gralloc1
+ gralloc1_device_t* mDevice;
+ GRALLOC1_PFN_RETAIN mRetain;
+ GRALLOC1_PFN_RELEASE mRelease;
+
+ // gralloc0
+ const gralloc_module_t* mModule;
+#else
+ bool openGralloc() { return true; }
+ void closeGralloc() {}
+ buffer_handle_t cloneBuffer(buffer_handle_t handle) { return handle; }
+ void releaseBuffer(buffer_handle_t) {}
+#endif
+};
+
+HandleImporter sHandleImporter;
+
+class BufferClone {
+public:
+ BufferClone() : mHandle(nullptr) {}
+
+ BufferClone(BufferClone&& other)
+ {
+ mHandle = other.mHandle;
+ other.mHandle = nullptr;
+ }
+
+ BufferClone(const BufferClone& other) = delete;
+ BufferClone& operator=(const BufferClone& other) = delete;
+
+ BufferClone& operator=(buffer_handle_t handle)
+ {
+ clear();
+ mHandle = handle;
+ return *this;
+ }
+
+ ~BufferClone()
+ {
+ clear();
+ }
+
+private:
+ void clear()
+ {
+ if (mHandle) {
+ sHandleImporter.freeBuffer(mHandle);
+ }
+ }
+
+ buffer_handle_t mHandle;
+};
+
+} // anonymous namespace
+
+class HwcHal : public IComposer {
+public:
+ HwcHal(const hw_module_t* module);
+ virtual ~HwcHal();
+
+ // IComposer interface
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
+ Return<uint32_t> getMaxVirtualDisplayCount() override;
+ Return<void> createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat formatHint, createVirtualDisplay_cb hidl_cb) override;
+ Return<Error> destroyVirtualDisplay(Display display) override;
+ Return<Error> acceptDisplayChanges(Display display) override;
+ Return<void> createLayer(Display display,
+ createLayer_cb hidl_cb) override;
+ Return<Error> destroyLayer(Display display, Layer layer) override;
+ Return<void> getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb) override;
+ Return<void> getChangedCompositionTypes(Display display,
+ getChangedCompositionTypes_cb hidl_cb) override;
+ Return<Error> getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace) override;
+ Return<void> getColorModes(Display display,
+ getColorModes_cb hidl_cb) override;
+ Return<void> getDisplayAttribute(Display display,
+ Config config, Attribute attribute,
+ getDisplayAttribute_cb hidl_cb) override;
+ Return<void> getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb) override;
+ Return<void> getDisplayName(Display display,
+ getDisplayName_cb hidl_cb) override;
+ Return<void> getDisplayRequests(Display display,
+ getDisplayRequests_cb hidl_cb) override;
+ Return<void> getDisplayType(Display display,
+ getDisplayType_cb hidl_cb) override;
+ Return<void> getDozeSupport(Display display,
+ getDozeSupport_cb hidl_cb) override;
+ Return<void> getHdrCapabilities(Display display,
+ getHdrCapabilities_cb hidl_cb) override;
+ Return<void> getReleaseFences(Display display,
+ getReleaseFences_cb hidl_cb) override;
+ Return<void> presentDisplay(Display display,
+ presentDisplay_cb hidl_cb) override;
+ Return<Error> setActiveConfig(Display display, Config config) override;
+ Return<Error> setClientTarget(Display display,
+ const native_handle_t* target,
+ const native_handle_t* acquireFence,
+ Dataspace dataspace, const hidl_vec<Rect>& damage) override;
+ Return<Error> setColorMode(Display display, ColorMode mode) override;
+ Return<Error> setColorTransform(Display display,
+ const hidl_vec<float>& matrix, ColorTransform hint) override;
+ Return<Error> setOutputBuffer(Display display,
+ const native_handle_t* buffer,
+ const native_handle_t* releaseFence) override;
+ Return<Error> setPowerMode(Display display, PowerMode mode) override;
+ Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
+ Return<void> validateDisplay(Display display,
+ validateDisplay_cb hidl_cb) override;
+ Return<Error> setCursorPosition(Display display,
+ Layer layer, int32_t x, int32_t y) override;
+ Return<Error> setLayerBuffer(Display display,
+ Layer layer, const native_handle_t* buffer,
+ const native_handle_t* acquireFence) override;
+ Return<Error> setLayerSurfaceDamage(Display display,
+ Layer layer, const hidl_vec<Rect>& damage) override;
+ Return<Error> setLayerBlendMode(Display display,
+ Layer layer, BlendMode mode) override;
+ Return<Error> setLayerColor(Display display,
+ Layer layer, const Color& color) override;
+ Return<Error> setLayerCompositionType(Display display,
+ Layer layer, Composition type) override;
+ Return<Error> setLayerDataspace(Display display,
+ Layer layer, Dataspace dataspace) override;
+ Return<Error> setLayerDisplayFrame(Display display,
+ Layer layer, const Rect& frame) override;
+ Return<Error> setLayerPlaneAlpha(Display display,
+ Layer layer, float alpha) override;
+ Return<Error> setLayerSidebandStream(Display display,
+ Layer layer, const native_handle_t* stream) override;
+ Return<Error> setLayerSourceCrop(Display display,
+ Layer layer, const FRect& crop) override;
+ Return<Error> setLayerTransform(Display display,
+ Layer layer, Transform transform) override;
+ Return<Error> setLayerVisibleRegion(Display display,
+ Layer layer, const hidl_vec<Rect>& visible) override;
+ Return<Error> setLayerZOrder(Display display,
+ Layer layer, uint32_t z) override;
+
+private:
+ void initCapabilities();
+
+ template<typename T>
+ void initDispatch(T& func, hwc2_function_descriptor_t desc);
+ void initDispatch();
+
+ bool hasCapability(Capability capability) const;
+
+ static void hotplugHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int32_t connected);
+ static void refreshHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display);
+ static void vsyncHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int64_t timestamp);
+
+ hwc2_device_t* mDevice;
+
+ std::unordered_set<Capability> mCapabilities;
+
+ struct {
+ HWC2_PFN_ACCEPT_DISPLAY_CHANGES acceptDisplayChanges;
+ HWC2_PFN_CREATE_LAYER createLayer;
+ HWC2_PFN_CREATE_VIRTUAL_DISPLAY createVirtualDisplay;
+ HWC2_PFN_DESTROY_LAYER destroyLayer;
+ HWC2_PFN_DESTROY_VIRTUAL_DISPLAY destroyVirtualDisplay;
+ HWC2_PFN_DUMP dump;
+ HWC2_PFN_GET_ACTIVE_CONFIG getActiveConfig;
+ HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES getChangedCompositionTypes;
+ HWC2_PFN_GET_CLIENT_TARGET_SUPPORT getClientTargetSupport;
+ HWC2_PFN_GET_COLOR_MODES getColorModes;
+ HWC2_PFN_GET_DISPLAY_ATTRIBUTE getDisplayAttribute;
+ HWC2_PFN_GET_DISPLAY_CONFIGS getDisplayConfigs;
+ HWC2_PFN_GET_DISPLAY_NAME getDisplayName;
+ HWC2_PFN_GET_DISPLAY_REQUESTS getDisplayRequests;
+ HWC2_PFN_GET_DISPLAY_TYPE getDisplayType;
+ HWC2_PFN_GET_DOZE_SUPPORT getDozeSupport;
+ HWC2_PFN_GET_HDR_CAPABILITIES getHdrCapabilities;
+ HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT getMaxVirtualDisplayCount;
+ HWC2_PFN_GET_RELEASE_FENCES getReleaseFences;
+ HWC2_PFN_PRESENT_DISPLAY presentDisplay;
+ HWC2_PFN_REGISTER_CALLBACK registerCallback;
+ HWC2_PFN_SET_ACTIVE_CONFIG setActiveConfig;
+ HWC2_PFN_SET_CLIENT_TARGET setClientTarget;
+ HWC2_PFN_SET_COLOR_MODE setColorMode;
+ HWC2_PFN_SET_COLOR_TRANSFORM setColorTransform;
+ HWC2_PFN_SET_CURSOR_POSITION setCursorPosition;
+ HWC2_PFN_SET_LAYER_BLEND_MODE setLayerBlendMode;
+ HWC2_PFN_SET_LAYER_BUFFER setLayerBuffer;
+ HWC2_PFN_SET_LAYER_COLOR setLayerColor;
+ HWC2_PFN_SET_LAYER_COMPOSITION_TYPE setLayerCompositionType;
+ HWC2_PFN_SET_LAYER_DATASPACE setLayerDataspace;
+ HWC2_PFN_SET_LAYER_DISPLAY_FRAME setLayerDisplayFrame;
+ HWC2_PFN_SET_LAYER_PLANE_ALPHA setLayerPlaneAlpha;
+ HWC2_PFN_SET_LAYER_SIDEBAND_STREAM setLayerSidebandStream;
+ HWC2_PFN_SET_LAYER_SOURCE_CROP setLayerSourceCrop;
+ HWC2_PFN_SET_LAYER_SURFACE_DAMAGE setLayerSurfaceDamage;
+ HWC2_PFN_SET_LAYER_TRANSFORM setLayerTransform;
+ HWC2_PFN_SET_LAYER_VISIBLE_REGION setLayerVisibleRegion;
+ HWC2_PFN_SET_LAYER_Z_ORDER setLayerZOrder;
+ HWC2_PFN_SET_OUTPUT_BUFFER setOutputBuffer;
+ HWC2_PFN_SET_POWER_MODE setPowerMode;
+ HWC2_PFN_SET_VSYNC_ENABLED setVsyncEnabled;
+ HWC2_PFN_VALIDATE_DISPLAY validateDisplay;
+ } mDispatch;
+
+ // cloned buffers for a display
+ struct DisplayBuffers {
+ BufferClone ClientTarget;
+ BufferClone OutputBuffer;
+
+ std::unordered_map<Layer, BufferClone> LayerBuffers;
+ std::unordered_map<Layer, BufferClone> LayerSidebandStreams;
+ };
+
+ std::mutex mCallbackMutex;
+ sp<IComposerCallback> mCallback;
+
+ std::mutex mDisplayMutex;
+ std::unordered_map<Display, DisplayBuffers> mDisplays;
+};
+
+HwcHal::HwcHal(const hw_module_t* module)
+ : mDevice(nullptr), mDispatch()
+{
+ if (!sHandleImporter.initialize()) {
+ LOG_ALWAYS_FATAL("failed to initialize handle importer");
+ }
+
+ int status = hwc2_open(module, &mDevice);
+ if (status) {
+ LOG_ALWAYS_FATAL("failed to open hwcomposer2 device: %s",
+ strerror(-status));
+ }
+
+ initCapabilities();
+ initDispatch();
+}
+
+HwcHal::~HwcHal()
+{
+ hwc2_close(mDevice);
+ mDisplays.clear();
+ sHandleImporter.cleanup();
+}
+
+void HwcHal::initCapabilities()
+{
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<Capability> caps(count);
+ mDevice->getCapabilities(mDevice, &count, reinterpret_cast<
+ std::underlying_type<Capability>::type*>(caps.data()));
+ caps.resize(count);
+
+ mCapabilities.insert(caps.cbegin(), caps.cend());
+}
+
+template<typename T>
+void HwcHal::initDispatch(T& func, hwc2_function_descriptor_t desc)
+{
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (!pfn) {
+ LOG_ALWAYS_FATAL("failed to get hwcomposer2 function %d", desc);
+ }
+
+ func = reinterpret_cast<T>(pfn);
+}
+
+void HwcHal::initDispatch()
+{
+ initDispatch(mDispatch.acceptDisplayChanges,
+ HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES);
+ initDispatch(mDispatch.createLayer, HWC2_FUNCTION_CREATE_LAYER);
+ initDispatch(mDispatch.createVirtualDisplay,
+ HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY);
+ initDispatch(mDispatch.destroyLayer, HWC2_FUNCTION_DESTROY_LAYER);
+ initDispatch(mDispatch.destroyVirtualDisplay,
+ HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY);
+ initDispatch(mDispatch.dump, HWC2_FUNCTION_DUMP);
+ initDispatch(mDispatch.getActiveConfig, HWC2_FUNCTION_GET_ACTIVE_CONFIG);
+ initDispatch(mDispatch.getChangedCompositionTypes,
+ HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES);
+ initDispatch(mDispatch.getClientTargetSupport,
+ HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT);
+ initDispatch(mDispatch.getColorModes, HWC2_FUNCTION_GET_COLOR_MODES);
+ initDispatch(mDispatch.getDisplayAttribute,
+ HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE);
+ initDispatch(mDispatch.getDisplayConfigs,
+ HWC2_FUNCTION_GET_DISPLAY_CONFIGS);
+ initDispatch(mDispatch.getDisplayName, HWC2_FUNCTION_GET_DISPLAY_NAME);
+ initDispatch(mDispatch.getDisplayRequests,
+ HWC2_FUNCTION_GET_DISPLAY_REQUESTS);
+ initDispatch(mDispatch.getDisplayType, HWC2_FUNCTION_GET_DISPLAY_TYPE);
+ initDispatch(mDispatch.getDozeSupport, HWC2_FUNCTION_GET_DOZE_SUPPORT);
+ initDispatch(mDispatch.getHdrCapabilities,
+ HWC2_FUNCTION_GET_HDR_CAPABILITIES);
+ initDispatch(mDispatch.getMaxVirtualDisplayCount,
+ HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT);
+ initDispatch(mDispatch.getReleaseFences,
+ HWC2_FUNCTION_GET_RELEASE_FENCES);
+ initDispatch(mDispatch.presentDisplay, HWC2_FUNCTION_PRESENT_DISPLAY);
+ initDispatch(mDispatch.registerCallback, HWC2_FUNCTION_REGISTER_CALLBACK);
+ initDispatch(mDispatch.setActiveConfig, HWC2_FUNCTION_SET_ACTIVE_CONFIG);
+ initDispatch(mDispatch.setClientTarget, HWC2_FUNCTION_SET_CLIENT_TARGET);
+ initDispatch(mDispatch.setColorMode, HWC2_FUNCTION_SET_COLOR_MODE);
+ initDispatch(mDispatch.setColorTransform,
+ HWC2_FUNCTION_SET_COLOR_TRANSFORM);
+ initDispatch(mDispatch.setCursorPosition,
+ HWC2_FUNCTION_SET_CURSOR_POSITION);
+ initDispatch(mDispatch.setLayerBlendMode,
+ HWC2_FUNCTION_SET_LAYER_BLEND_MODE);
+ initDispatch(mDispatch.setLayerBuffer, HWC2_FUNCTION_SET_LAYER_BUFFER);
+ initDispatch(mDispatch.setLayerColor, HWC2_FUNCTION_SET_LAYER_COLOR);
+ initDispatch(mDispatch.setLayerCompositionType,
+ HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE);
+ initDispatch(mDispatch.setLayerDataspace,
+ HWC2_FUNCTION_SET_LAYER_DATASPACE);
+ initDispatch(mDispatch.setLayerDisplayFrame,
+ HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME);
+ initDispatch(mDispatch.setLayerPlaneAlpha,
+ HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA);
+
+ if (hasCapability(Capability::SIDEBAND_STREAM)) {
+ initDispatch(mDispatch.setLayerSidebandStream,
+ HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM);
+ }
+
+ initDispatch(mDispatch.setLayerSourceCrop,
+ HWC2_FUNCTION_SET_LAYER_SOURCE_CROP);
+ initDispatch(mDispatch.setLayerSurfaceDamage,
+ HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE);
+ initDispatch(mDispatch.setLayerTransform,
+ HWC2_FUNCTION_SET_LAYER_TRANSFORM);
+ initDispatch(mDispatch.setLayerVisibleRegion,
+ HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION);
+ initDispatch(mDispatch.setLayerZOrder, HWC2_FUNCTION_SET_LAYER_Z_ORDER);
+ initDispatch(mDispatch.setOutputBuffer, HWC2_FUNCTION_SET_OUTPUT_BUFFER);
+ initDispatch(mDispatch.setPowerMode, HWC2_FUNCTION_SET_POWER_MODE);
+ initDispatch(mDispatch.setVsyncEnabled, HWC2_FUNCTION_SET_VSYNC_ENABLED);
+ initDispatch(mDispatch.validateDisplay, HWC2_FUNCTION_VALIDATE_DISPLAY);
+}
+
+bool HwcHal::hasCapability(Capability capability) const
+{
+ return (mCapabilities.count(capability) > 0);
+}
+
+Return<void> HwcHal::getCapabilities(getCapabilities_cb hidl_cb)
+{
+ std::vector<Capability> caps(
+ mCapabilities.cbegin(), mCapabilities.cend());
+
+ hidl_vec<Capability> caps_reply;
+ caps_reply.setToExternal(caps.data(), caps.size());
+ hidl_cb(caps_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb)
+{
+ uint32_t len;
+ mDispatch.dump(mDevice, &len, nullptr);
+
+ std::vector<char> buf(len + 1);
+ mDispatch.dump(mDevice, &len, buf.data());
+ buf.resize(len + 1);
+ buf[len] = '\0';
+
+ hidl_string buf_reply;
+ buf_reply.setToExternal(buf.data(), len);
+ hidl_cb(buf_reply);
+
+ return Void();
+}
+
+void HwcHal::hotplugHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int32_t connected)
+{
+ auto hal = reinterpret_cast<HwcHal*>(callbackData);
+
+ {
+ std::lock_guard<std::mutex> lock(hal->mDisplayMutex);
+
+ if (connected == HWC2_CONNECTION_CONNECTED) {
+ hal->mDisplays.emplace(display, DisplayBuffers());
+ } else if (connected == HWC2_CONNECTION_DISCONNECTED) {
+ hal->mDisplays.erase(display);
+ }
+ }
+
+ hal->mCallback->onHotplug(display,
+ static_cast<IComposerCallback::Connection>(connected));
+}
+
+void HwcHal::refreshHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display)
+{
+ auto hal = reinterpret_cast<HwcHal*>(callbackData);
+ hal->mCallback->onRefresh(display);
+}
+
+void HwcHal::vsyncHook(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int64_t timestamp)
+{
+ auto hal = reinterpret_cast<HwcHal*>(callbackData);
+ hal->mCallback->onVsync(display, timestamp);
+}
+
+Return<void> HwcHal::registerCallback(const sp<IComposerCallback>& callback)
+{
+ std::lock_guard<std::mutex> lock(mCallbackMutex);
+
+ mCallback = callback;
+
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
+ reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
+ reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
+
+ return Void();
+}
+
+Return<uint32_t> HwcHal::getMaxVirtualDisplayCount()
+{
+ return mDispatch.getMaxVirtualDisplayCount(mDevice);
+}
+
+Return<void> HwcHal::createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat formatHint, createVirtualDisplay_cb hidl_cb)
+{
+ int32_t format = static_cast<int32_t>(formatHint);
+ hwc2_display_t display;
+ auto error = mDispatch.createVirtualDisplay(mDevice, width, height,
+ &format, &display);
+ if (error == HWC2_ERROR_NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayMutex);
+
+ mDisplays.emplace(display, DisplayBuffers());
+ }
+
+ hidl_cb(static_cast<Error>(error), display,
+ static_cast<PixelFormat>(format));
+
+ return Void();
+}
+
+Return<Error> HwcHal::destroyVirtualDisplay(Display display)
+{
+ auto error = mDispatch.destroyVirtualDisplay(mDevice, display);
+ if (error == HWC2_ERROR_NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayMutex);
+
+ mDisplays.erase(display);
+ }
+
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::acceptDisplayChanges(Display display)
+{
+ auto error = mDispatch.acceptDisplayChanges(mDevice, display);
+ return static_cast<Error>(error);
+}
+
+Return<void> HwcHal::createLayer(Display display, createLayer_cb hidl_cb)
+{
+ hwc2_layer_t layer;
+ auto error = mDispatch.createLayer(mDevice, display, &layer);
+
+ hidl_cb(static_cast<Error>(error), layer);
+
+ return Void();
+}
+
+Return<Error> HwcHal::destroyLayer(Display display, Layer layer)
+{
+ auto error = mDispatch.destroyLayer(mDevice, display, layer);
+ return static_cast<Error>(error);
+}
+
+Return<void> HwcHal::getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb)
+{
+ hwc2_config_t config;
+ auto error = mDispatch.getActiveConfig(mDevice, display, &config);
+
+ hidl_cb(static_cast<Error>(error), config);
+
+ return Void();
+}
+
+Return<void> HwcHal::getChangedCompositionTypes(Display display,
+ getChangedCompositionTypes_cb hidl_cb)
+{
+ uint32_t count = 0;
+ auto error = mDispatch.getChangedCompositionTypes(mDevice, display,
+ &count, nullptr, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<hwc2_layer_t> layers(count);
+ std::vector<Composition> types(count);
+ error = mDispatch.getChangedCompositionTypes(mDevice, display,
+ &count, layers.data(),
+ reinterpret_cast<std::underlying_type<Composition>::type*>(
+ types.data()));
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ layers.resize(count);
+ types.resize(count);
+
+ hidl_vec<Layer> layers_reply;
+ layers_reply.setToExternal(layers.data(), layers.size());
+
+ hidl_vec<Composition> types_reply;
+ types_reply.setToExternal(types.data(), types.size());
+
+ hidl_cb(static_cast<Error>(error), layers_reply, types_reply);
+
+ return Void();
+}
+
+Return<Error> HwcHal::getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace)
+{
+ auto error = mDispatch.getClientTargetSupport(mDevice, display,
+ width, height, static_cast<int32_t>(format),
+ static_cast<int32_t>(dataspace));
+ return static_cast<Error>(error);
+}
+
+Return<void> HwcHal::getColorModes(Display display, getColorModes_cb hidl_cb)
+{
+ uint32_t count = 0;
+ auto error = mDispatch.getColorModes(mDevice, display, &count, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<ColorMode> modes(count);
+ error = mDispatch.getColorModes(mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<ColorMode>::type*>(
+ modes.data()));
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ modes.resize(count);
+
+ hidl_vec<ColorMode> modes_reply;
+ modes_reply.setToExternal(modes.data(), modes.size());
+ hidl_cb(static_cast<Error>(error), modes_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::getDisplayAttribute(Display display,
+ Config config, Attribute attribute,
+ getDisplayAttribute_cb hidl_cb)
+{
+ int32_t value;
+ auto error = mDispatch.getDisplayAttribute(mDevice, display, config,
+ static_cast<int32_t>(attribute), &value);
+
+ hidl_cb(static_cast<Error>(error), value);
+
+ return Void();
+}
+
+Return<void> HwcHal::getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb)
+{
+ uint32_t count = 0;
+ auto error = mDispatch.getDisplayConfigs(mDevice, display,
+ &count, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<hwc2_config_t> configs(count);
+ error = mDispatch.getDisplayConfigs(mDevice, display,
+ &count, configs.data());
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ configs.resize(count);
+
+ hidl_vec<Config> configs_reply;
+ configs_reply.setToExternal(configs.data(), configs.size());
+ hidl_cb(static_cast<Error>(error), configs_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::getDisplayName(Display display,
+ getDisplayName_cb hidl_cb)
+{
+ uint32_t count = 0;
+ auto error = mDispatch.getDisplayName(mDevice, display, &count, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<char> name(count + 1);
+ error = mDispatch.getDisplayName(mDevice, display, &count, name.data());
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ name.resize(count + 1);
+ name[count] = '\0';
+
+ hidl_string name_reply;
+ name_reply.setToExternal(name.data(), count);
+ hidl_cb(static_cast<Error>(error), name_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::getDisplayRequests(Display display,
+ getDisplayRequests_cb hidl_cb)
+{
+ int32_t display_reqs;
+ uint32_t count = 0;
+ auto error = mDispatch.getDisplayRequests(mDevice, display,
+ &display_reqs, &count, nullptr, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<hwc2_layer_t> layers(count);
+ std::vector<int32_t> layer_reqs(count);
+ error = mDispatch.getDisplayRequests(mDevice, display,
+ &display_reqs, &count, layers.data(), layer_reqs.data());
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ layers.resize(count);
+ layer_reqs.resize(count);
+
+ hidl_vec<Layer> layers_reply;
+ layers_reply.setToExternal(layers.data(), layers.size());
+
+ hidl_vec<uint32_t> layer_reqs_reply;
+ layer_reqs_reply.setToExternal(
+ reinterpret_cast<uint32_t*>(layer_reqs.data()),
+ layer_reqs.size());
+
+ hidl_cb(static_cast<Error>(error), display_reqs,
+ layers_reply, layer_reqs_reply);
+
+ return Void();
+}
+
+Return<void> HwcHal::getDisplayType(Display display,
+ getDisplayType_cb hidl_cb)
+{
+ int32_t type;
+ auto error = mDispatch.getDisplayType(mDevice, display, &type);
+
+ hidl_cb(static_cast<Error>(error), static_cast<DisplayType>(type));
+
+ return Void();
+}
+
+Return<void> HwcHal::getDozeSupport(Display display,
+ getDozeSupport_cb hidl_cb)
+{
+ int32_t support;
+ auto error = mDispatch.getDozeSupport(mDevice, display, &support);
+
+ hidl_cb(static_cast<Error>(error), support);
+
+ return Void();
+}
+
+Return<void> HwcHal::getHdrCapabilities(Display display,
+ getHdrCapabilities_cb hidl_cb)
+{
+ float max_lumi, max_avg_lumi, min_lumi;
+ uint32_t count = 0;
+ auto error = mDispatch.getHdrCapabilities(mDevice, display,
+ &count, nullptr, &max_lumi, &max_avg_lumi, &min_lumi);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<Hdr> types(count);
+ error = mDispatch.getHdrCapabilities(mDevice, display, &count,
+ reinterpret_cast<std::underlying_type<Hdr>::type*>(types.data()),
+ &max_lumi, &max_avg_lumi, &min_lumi);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ types.resize(count);
+
+ hidl_vec<Hdr> types_reply;
+ types_reply.setToExternal(types.data(), types.size());
+ hidl_cb(static_cast<Error>(error), types_reply,
+ max_lumi, max_avg_lumi, min_lumi);
+
+ return Void();
+}
+
+Return<void> HwcHal::getReleaseFences(Display display,
+ getReleaseFences_cb hidl_cb)
+{
+ uint32_t count = 0;
+ auto error = mDispatch.getReleaseFences(mDevice, display,
+ &count, nullptr, nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+
+ std::vector<hwc2_layer_t> layers(count);
+ std::vector<int32_t> fences(count);
+ error = mDispatch.getReleaseFences(mDevice, display,
+ &count, layers.data(), fences.data());
+ if (error != HWC2_ERROR_NONE) {
+ count = 0;
+ }
+ layers.resize(count);
+ fences.resize(count);
+
+ // filter out layers with release fence -1
+ std::vector<hwc2_layer_t> filtered_layers;
+ std::vector<int> filtered_fences;
+ for (size_t i = 0; i < layers.size(); i++) {
+ if (fences[i] >= 0) {
+ filtered_layers.push_back(layers[i]);
+ filtered_fences.push_back(fences[i]);
+ }
+ }
+
+ hidl_vec<Layer> layers_reply;
+ native_handle_t* fences_reply =
+ native_handle_create(filtered_fences.size(), 0);
+ if (fences_reply) {
+ layers_reply.setToExternal(filtered_layers.data(),
+ filtered_layers.size());
+ memcpy(fences_reply->data, filtered_fences.data(),
+ sizeof(int) * filtered_fences.size());
+
+ hidl_cb(static_cast<Error>(error), layers_reply, fences_reply);
+
+ native_handle_close(fences_reply);
+ native_handle_delete(fences_reply);
+ } else {
+ NATIVE_HANDLE_DECLARE_STORAGE(fences_storage, 0, 0);
+ fences_reply = native_handle_init(fences_storage, 0, 0);
+
+ hidl_cb(Error::NO_RESOURCES, layers_reply, fences_reply);
+
+ for (auto fence : filtered_fences) {
+ close(fence);
+ }
+ }
+
+ return Void();
+}
+
+Return<void> HwcHal::presentDisplay(Display display,
+ presentDisplay_cb hidl_cb)
+{
+ int32_t fence = -1;
+ auto error = mDispatch.presentDisplay(mDevice, display, &fence);
+
+ NATIVE_HANDLE_DECLARE_STORAGE(fence_storage, 1, 0);
+ native_handle_t* fence_reply;
+ if (fence >= 0) {
+ fence_reply = native_handle_init(fence_storage, 1, 0);
+ fence_reply->data[0] = fence;
+ } else {
+ fence_reply = native_handle_init(fence_storage, 0, 0);
+ }
+
+ hidl_cb(static_cast<Error>(error), fence_reply);
+
+ if (fence >= 0) {
+ close(fence);
+ }
+
+ return Void();
+}
+
+Return<Error> HwcHal::setActiveConfig(Display display, Config config)
+{
+ auto error = mDispatch.setActiveConfig(mDevice, display, config);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setClientTarget(Display display,
+ const native_handle_t* target,
+ const native_handle_t* acquireFence,
+ Dataspace dataspace, const hidl_vec<Rect>& damage)
+{
+ if (!sHandleImporter.importBuffer(target)) {
+ return Error::NO_RESOURCES;
+ }
+
+ int32_t fence;
+ if (!sHandleImporter.importFence(acquireFence, fence)) {
+ sHandleImporter.freeBuffer(target);
+ return Error::NO_RESOURCES;
+ }
+
+ hwc_region_t damage_region = { damage.size(),
+ reinterpret_cast<const hwc_rect_t*>(&damage[0]) };
+
+ int32_t error = mDispatch.setClientTarget(mDevice, display,
+ target, fence, static_cast<int32_t>(dataspace),
+ damage_region);
+ if (error == HWC2_ERROR_NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayMutex);
+
+ auto dpy = mDisplays.find(display);
+ dpy->second.ClientTarget = target;
+ } else {
+ sHandleImporter.freeBuffer(target);
+ sHandleImporter.closeFence(fence);
+ }
+
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setColorMode(Display display, ColorMode mode)
+{
+ auto error = mDispatch.setColorMode(mDevice, display,
+ static_cast<int32_t>(mode));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setColorTransform(Display display,
+ const hidl_vec<float>& matrix, ColorTransform hint)
+{
+ auto error = mDispatch.setColorTransform(mDevice, display,
+ &matrix[0], static_cast<int32_t>(hint));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setOutputBuffer(Display display,
+ const native_handle_t* buffer,
+ const native_handle_t* releaseFence)
+{
+ if (!sHandleImporter.importBuffer(buffer)) {
+ return Error::NO_RESOURCES;
+ }
+
+ int32_t fence;
+ if (!sHandleImporter.importFence(releaseFence, fence)) {
+ sHandleImporter.freeBuffer(buffer);
+ return Error::NO_RESOURCES;
+ }
+
+ int32_t error = mDispatch.setOutputBuffer(mDevice,
+ display, buffer, fence);
+ if (error == HWC2_ERROR_NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayMutex);
+
+ auto dpy = mDisplays.find(display);
+ dpy->second.OutputBuffer = buffer;
+ } else {
+ sHandleImporter.freeBuffer(buffer);
+ }
+
+ // unlike in setClientTarget, fence is owned by us and is always closed
+ sHandleImporter.closeFence(fence);
+
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setPowerMode(Display display, PowerMode mode)
+{
+ auto error = mDispatch.setPowerMode(mDevice, display,
+ static_cast<int32_t>(mode));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setVsyncEnabled(Display display,
+ Vsync enabled)
+{
+ auto error = mDispatch.setVsyncEnabled(mDevice, display,
+ static_cast<int32_t>(enabled));
+ return static_cast<Error>(error);
+}
+
+Return<void> HwcHal::validateDisplay(Display display,
+ validateDisplay_cb hidl_cb)
+{
+ uint32_t types_count = 0;
+ uint32_t reqs_count = 0;
+ auto error = mDispatch.validateDisplay(mDevice, display,
+ &types_count, &reqs_count);
+
+ hidl_cb(static_cast<Error>(error), types_count, reqs_count);
+
+ return Void();
+}
+
+Return<Error> HwcHal::setCursorPosition(Display display,
+ Layer layer, int32_t x, int32_t y)
+{
+ auto error = mDispatch.setCursorPosition(mDevice, display, layer, x, y);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerBuffer(Display display,
+ Layer layer, const native_handle_t* buffer,
+ const native_handle_t* acquireFence)
+{
+ if (!sHandleImporter.importBuffer(buffer)) {
+ return Error::NO_RESOURCES;
+ }
+
+ int32_t fence;
+ if (!sHandleImporter.importFence(acquireFence, fence)) {
+ sHandleImporter.freeBuffer(buffer);
+ return Error::NO_RESOURCES;
+ }
+
+ int32_t error = mDispatch.setLayerBuffer(mDevice,
+ display, layer, buffer, fence);
+ if (error == HWC2_ERROR_NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayMutex);
+
+ auto dpy = mDisplays.find(display);
+ dpy->second.LayerBuffers[layer] = buffer;
+ } else {
+ sHandleImporter.freeBuffer(buffer);
+ sHandleImporter.closeFence(fence);
+ }
+
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerSurfaceDamage(Display display,
+ Layer layer, const hidl_vec<Rect>& damage)
+{
+ hwc_region_t damage_region = { damage.size(),
+ reinterpret_cast<const hwc_rect_t*>(&damage[0]) };
+
+ auto error = mDispatch.setLayerSurfaceDamage(mDevice, display, layer,
+ damage_region);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerBlendMode(Display display,
+ Layer layer, BlendMode mode)
+{
+ auto error = mDispatch.setLayerBlendMode(mDevice, display, layer,
+ static_cast<int32_t>(mode));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerColor(Display display,
+ Layer layer, const Color& color)
+{
+ hwc_color_t hwc_color{color.r, color.g, color.b, color.a};
+ auto error = mDispatch.setLayerColor(mDevice, display, layer, hwc_color);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerCompositionType(Display display,
+ Layer layer, Composition type)
+{
+ auto error = mDispatch.setLayerCompositionType(mDevice, display, layer,
+ static_cast<int32_t>(type));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerDataspace(Display display,
+ Layer layer, Dataspace dataspace)
+{
+ auto error = mDispatch.setLayerDataspace(mDevice, display, layer,
+ static_cast<int32_t>(dataspace));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerDisplayFrame(Display display,
+ Layer layer, const Rect& frame)
+{
+ hwc_rect_t hwc_frame{frame.left, frame.top, frame.right, frame.bottom};
+ auto error = mDispatch.setLayerDisplayFrame(mDevice, display, layer,
+ hwc_frame);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerPlaneAlpha(Display display,
+ Layer layer, float alpha)
+{
+ auto error = mDispatch.setLayerPlaneAlpha(mDevice, display, layer, alpha);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerSidebandStream(Display display,
+ Layer layer, const native_handle_t* stream)
+{
+ if (!sHandleImporter.importBuffer(stream)) {
+ return Error::NO_RESOURCES;
+ }
+
+ int32_t error = mDispatch.setLayerSidebandStream(mDevice,
+ display, layer, stream);
+ if (error == HWC2_ERROR_NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayMutex);
+
+ auto dpy = mDisplays.find(display);
+ dpy->second.LayerSidebandStreams[layer] = stream;
+ } else {
+ sHandleImporter.freeBuffer(stream);
+ }
+
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerSourceCrop(Display display,
+ Layer layer, const FRect& crop)
+{
+ hwc_frect_t hwc_crop{crop.left, crop.top, crop.right, crop.bottom};
+ auto error = mDispatch.setLayerSourceCrop(mDevice, display, layer,
+ hwc_crop);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerTransform(Display display,
+ Layer layer, Transform transform)
+{
+ auto error = mDispatch.setLayerTransform(mDevice, display, layer,
+ static_cast<int32_t>(transform));
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerVisibleRegion(Display display,
+ Layer layer, const hidl_vec<Rect>& visible)
+{
+ hwc_region_t visible_region = { visible.size(),
+ reinterpret_cast<const hwc_rect_t*>(&visible[0]) };
+
+ auto error = mDispatch.setLayerVisibleRegion(mDevice, display, layer,
+ visible_region);
+ return static_cast<Error>(error);
+}
+
+Return<Error> HwcHal::setLayerZOrder(Display display,
+ Layer layer, uint32_t z)
+{
+ auto error = mDispatch.setLayerZOrder(mDevice, display, layer, z);
+ return static_cast<Error>(error);
+}
+
+IComposer* HIDL_FETCH_IComposer(const char*)
+{
+ const hw_module_t* module;
+ int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get hwcomposer module");
+ return nullptr;
+ }
+
+ return new HwcHal(module);
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/default/Hwc.h b/graphics/composer/2.1/default/Hwc.h
new file mode 100644
index 0000000..de69417
--- /dev/null
+++ b/graphics/composer/2.1/default/Hwc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 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_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
+#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+extern "C" IComposer* HIDL_FETCH_IComposer(const char* name);
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H