Introduce ComposerBase interface to allow custom Hwc implementations
Decouples the ComposerClient code which deals with parsing the command buffer
messages sent by SurfaceFlinger from the Hwc code that handles the
commands.
Bug: 33297270
Test: Compiled and verified on device that hwcomposer-2-1 service can
start correctly. SurfaceFlinger can connect to the service and the
system boots up. Also verified SurfaceFlinger runs correctly without
hwcomposer-2-1.
Change-Id: I43357306caea57d262735f4756c379ba9d0138cd
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp
new file mode 100644
index 0000000..49415ee
--- /dev/null
+++ b/graphics/composer/2.1/default/ComposerClient.cpp
@@ -0,0 +1,1127 @@
+/*
+ * 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 <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <log/log.h>
+
+#include "ComposerClient.h"
+#include "Hwc.h"
+#include "IComposerCommandBuffer.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace implementation {
+
+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) {
+ return true;
+ }
+
+ 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);
+ }
+
+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 = nullptr;
+ 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;
+
+} // anonymous namespace
+
+BufferClone::BufferClone()
+ : mHandle(nullptr)
+{
+}
+
+BufferClone::BufferClone(BufferClone&& other)
+{
+ mHandle = other.mHandle;
+ other.mHandle = nullptr;
+}
+
+BufferClone& BufferClone::operator=(buffer_handle_t handle)
+{
+ clear();
+ mHandle = handle;
+ return *this;
+}
+
+BufferClone::~BufferClone()
+{
+ clear();
+}
+
+void BufferClone::clear()
+{
+ if (mHandle) {
+ sHandleImporter.freeBuffer(mHandle);
+ }
+}
+
+ComposerClient::ComposerClient(ComposerBase& hal)
+ : mHal(hal), mWriter(kWriterInitialSize)
+{
+}
+
+ComposerClient::~ComposerClient()
+{
+ mHal.enableCallback(false);
+ mHal.removeClient();
+
+ // no need to grab the mutex as any in-flight hwbinder call should keep
+ // the client alive
+ for (const auto& dpy : mDisplayData) {
+ if (!dpy.second.Layers.empty()) {
+ ALOGW("client destroyed with valid layers");
+ }
+ for (const auto& ly : dpy.second.Layers) {
+ mHal.destroyLayer(dpy.first, ly.first);
+ }
+
+ if (dpy.second.IsVirtual) {
+ ALOGW("client destroyed with valid virtual display");
+ mHal.destroyVirtualDisplay(dpy.first);
+ }
+ }
+
+ mDisplayData.clear();
+
+ sHandleImporter.cleanup();
+}
+
+void ComposerClient::initialize()
+{
+ mReader = createCommandReader();
+ if (!sHandleImporter.initialize()) {
+ LOG_ALWAYS_FATAL("failed to initialize handle importer");
+ }
+}
+
+void ComposerClient::onHotplug(Display display,
+ IComposerCallback::Connection connected)
+{
+ {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ if (connected == IComposerCallback::Connection::CONNECTED) {
+ mDisplayData.emplace(display, DisplayData(false));
+ } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+ mDisplayData.erase(display);
+ }
+ }
+
+ mCallback->onHotplug(display, connected);
+}
+
+void ComposerClient::onRefresh(Display display)
+{
+ mCallback->onRefresh(display);
+}
+
+void ComposerClient::onVsync(Display display, int64_t timestamp)
+{
+ mCallback->onVsync(display, timestamp);
+}
+
+Return<void> ComposerClient::registerCallback(
+ const sp<IComposerCallback>& callback)
+{
+ // no locking as we require this function to be called only once
+ mCallback = callback;
+ mHal.enableCallback(callback != nullptr);
+
+ return Void();
+}
+
+Return<uint32_t> ComposerClient::getMaxVirtualDisplayCount()
+{
+ return mHal.getMaxVirtualDisplayCount();
+}
+
+Return<void> ComposerClient::createVirtualDisplay(uint32_t width,
+ uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
+ createVirtualDisplay_cb hidl_cb)
+{
+ Display display = 0;
+ Error err = mHal.createVirtualDisplay(width, height,
+ &formatHint, &display);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.emplace(display, DisplayData(true)).first;
+ dpy->second.OutputBuffers.resize(outputBufferSlotCount);
+ }
+
+ hidl_cb(err, display, formatHint);
+ return Void();
+}
+
+Return<Error> ComposerClient::destroyVirtualDisplay(Display display)
+{
+ Error err = mHal.destroyVirtualDisplay(display);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ mDisplayData.erase(display);
+ }
+
+ return err;
+}
+
+Return<void> ComposerClient::createLayer(Display display,
+ uint32_t bufferSlotCount, createLayer_cb hidl_cb)
+{
+ Layer layer = 0;
+ Error err = mHal.createLayer(display, &layer);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.find(display);
+ auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
+ ly->second.Buffers.resize(bufferSlotCount);
+ }
+
+ hidl_cb(err, layer);
+ return Void();
+}
+
+Return<Error> ComposerClient::destroyLayer(Display display, Layer layer)
+{
+ Error err = mHal.destroyLayer(display, layer);
+ if (err == Error::NONE) {
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.find(display);
+ dpy->second.Layers.erase(layer);
+ }
+
+ return err;
+}
+
+Return<void> ComposerClient::getActiveConfig(Display display,
+ getActiveConfig_cb hidl_cb)
+{
+ Config config = 0;
+ Error err = mHal.getActiveConfig(display, &config);
+
+ hidl_cb(err, config);
+ return Void();
+}
+
+Return<Error> ComposerClient::getClientTargetSupport(Display display,
+ uint32_t width, uint32_t height,
+ PixelFormat format, Dataspace dataspace)
+{
+ Error err = mHal.getClientTargetSupport(display,
+ width, height, format, dataspace);
+ return err;
+}
+
+Return<void> ComposerClient::getColorModes(Display display,
+ getColorModes_cb hidl_cb)
+{
+ hidl_vec<ColorMode> modes;
+ Error err = mHal.getColorModes(display, &modes);
+
+ hidl_cb(err, modes);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayAttribute(Display display,
+ Config config, Attribute attribute,
+ getDisplayAttribute_cb hidl_cb)
+{
+ int32_t value = 0;
+ Error err = mHal.getDisplayAttribute(display, config, attribute, &value);
+
+ hidl_cb(err, value);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayConfigs(Display display,
+ getDisplayConfigs_cb hidl_cb)
+{
+ hidl_vec<Config> configs;
+ Error err = mHal.getDisplayConfigs(display, &configs);
+
+ hidl_cb(err, configs);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayName(Display display,
+ getDisplayName_cb hidl_cb)
+{
+ hidl_string name;
+ Error err = mHal.getDisplayName(display, &name);
+
+ hidl_cb(err, name);
+ return Void();
+}
+
+Return<void> ComposerClient::getDisplayType(Display display,
+ getDisplayType_cb hidl_cb)
+{
+ DisplayType type = DisplayType::INVALID;
+ Error err = mHal.getDisplayType(display, &type);
+
+ hidl_cb(err, type);
+ return Void();
+}
+
+Return<void> ComposerClient::getDozeSupport(Display display,
+ getDozeSupport_cb hidl_cb)
+{
+ bool support = false;
+ Error err = mHal.getDozeSupport(display, &support);
+
+ hidl_cb(err, support);
+ return Void();
+}
+
+Return<void> ComposerClient::getHdrCapabilities(Display display,
+ getHdrCapabilities_cb hidl_cb)
+{
+ hidl_vec<Hdr> types;
+ float max_lumi = 0.0f;
+ float max_avg_lumi = 0.0f;
+ float min_lumi = 0.0f;
+ Error err = mHal.getHdrCapabilities(display, &types,
+ &max_lumi, &max_avg_lumi, &min_lumi);
+
+ hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi);
+ return Void();
+}
+
+Return<Error> ComposerClient::setClientTargetSlotCount(Display display,
+ uint32_t clientTargetSlotCount)
+{
+ std::lock_guard<std::mutex> lock(mDisplayDataMutex);
+
+ auto dpy = mDisplayData.find(display);
+ if (dpy == mDisplayData.end()) {
+ return Error::BAD_DISPLAY;
+ }
+
+ dpy->second.ClientTargets.resize(clientTargetSlotCount);
+
+ return Error::NONE;
+}
+
+Return<Error> ComposerClient::setActiveConfig(Display display, Config config)
+{
+ Error err = mHal.setActiveConfig(display, config);
+ return err;
+}
+
+Return<Error> ComposerClient::setColorMode(Display display, ColorMode mode)
+{
+ Error err = mHal.setColorMode(display, mode);
+ return err;
+}
+
+Return<Error> ComposerClient::setPowerMode(Display display, PowerMode mode)
+{
+ Error err = mHal.setPowerMode(display, mode);
+ return err;
+}
+
+Return<Error> ComposerClient::setVsyncEnabled(Display display, Vsync enabled)
+{
+ Error err = mHal.setVsyncEnabled(display, enabled);
+ return err;
+}
+
+Return<Error> ComposerClient::setInputCommandQueue(
+ const MQDescriptorSync<uint32_t>& descriptor)
+{
+ std::lock_guard<std::mutex> lock(mCommandMutex);
+ return mReader->setMQDescriptor(descriptor) ?
+ Error::NONE : Error::NO_RESOURCES;
+}
+
+Return<void> ComposerClient::getOutputCommandQueue(
+ getOutputCommandQueue_cb hidl_cb)
+{
+ // no locking as we require this function to be called inside
+ // executeCommands_cb
+
+ auto outDescriptor = mWriter.getMQDescriptor();
+ if (outDescriptor) {
+ hidl_cb(Error::NONE, *outDescriptor);
+ } else {
+ hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor());
+ }
+
+ return Void();
+}
+
+Return<void> ComposerClient::executeCommands(uint32_t inLength,
+ const hidl_vec<hidl_handle>& inHandles,
+ executeCommands_cb hidl_cb)
+{
+ std::lock_guard<std::mutex> lock(mCommandMutex);
+
+ bool outChanged = false;
+ uint32_t outLength = 0;
+ hidl_vec<hidl_handle> outHandles;
+
+ if (!mReader->readQueue(inLength, inHandles)) {
+ hidl_cb(Error::BAD_PARAMETER, outChanged, outLength, outHandles);
+ return Void();
+ }
+
+ Error err = mReader->parse();
+ if (err == Error::NONE &&
+ !mWriter.writeQueue(&outChanged, &outLength, &outHandles)) {
+ err = Error::NO_RESOURCES;
+ }
+
+ hidl_cb(err, outChanged, outLength, outHandles);
+
+ mReader->reset();
+ mWriter.reset();
+
+ return Void();
+}
+
+std::unique_ptr<ComposerClient::CommandReader>
+ComposerClient::createCommandReader()
+{
+ return std::unique_ptr<ComposerClient::CommandReader>(
+ new CommandReader(*this));
+}
+
+ComposerClient::CommandReader::CommandReader(ComposerClient& client)
+ : mClient(client), mHal(client.mHal), mWriter(client.mWriter)
+{
+}
+
+ComposerClient::CommandReader::~CommandReader()
+{
+}
+
+Error ComposerClient::CommandReader::parse()
+{
+ IComposerClient::Command command;
+ uint16_t length = 0;
+
+ while (!isEmpty()) {
+ if (!beginCommand(&command, &length)) {
+ break;
+ }
+
+ bool parsed = parseCommand(command, length);
+ endCommand();
+
+ if (!parsed) {
+ ALOGE("failed to parse command 0x%x, length %" PRIu16,
+ command, length);
+ break;
+ }
+ }
+
+ return (isEmpty()) ? Error::NONE : Error::BAD_PARAMETER;
+}
+
+bool ComposerClient::CommandReader::parseCommand(
+ IComposerClient::Command command, uint16_t length) {
+ switch (command) {
+ case IComposerClient::Command::SELECT_DISPLAY:
+ return parseSelectDisplay(length);
+ case IComposerClient::Command::SELECT_LAYER:
+ return parseSelectLayer(length);
+ case IComposerClient::Command::SET_COLOR_TRANSFORM:
+ return parseSetColorTransform(length);
+ case IComposerClient::Command::SET_CLIENT_TARGET:
+ return parseSetClientTarget(length);
+ case IComposerClient::Command::SET_OUTPUT_BUFFER:
+ return parseSetOutputBuffer(length);
+ case IComposerClient::Command::VALIDATE_DISPLAY:
+ return parseValidateDisplay(length);
+ case IComposerClient::Command::ACCEPT_DISPLAY_CHANGES:
+ return parseAcceptDisplayChanges(length);
+ case IComposerClient::Command::PRESENT_DISPLAY:
+ return parsePresentDisplay(length);
+ case IComposerClient::Command::SET_LAYER_CURSOR_POSITION:
+ return parseSetLayerCursorPosition(length);
+ case IComposerClient::Command::SET_LAYER_BUFFER:
+ return parseSetLayerBuffer(length);
+ case IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE:
+ return parseSetLayerSurfaceDamage(length);
+ case IComposerClient::Command::SET_LAYER_BLEND_MODE:
+ return parseSetLayerBlendMode(length);
+ case IComposerClient::Command::SET_LAYER_COLOR:
+ return parseSetLayerColor(length);
+ case IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE:
+ return parseSetLayerCompositionType(length);
+ case IComposerClient::Command::SET_LAYER_DATASPACE:
+ return parseSetLayerDataspace(length);
+ case IComposerClient::Command::SET_LAYER_DISPLAY_FRAME:
+ return parseSetLayerDisplayFrame(length);
+ case IComposerClient::Command::SET_LAYER_PLANE_ALPHA:
+ return parseSetLayerPlaneAlpha(length);
+ case IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM:
+ return parseSetLayerSidebandStream(length);
+ case IComposerClient::Command::SET_LAYER_SOURCE_CROP:
+ return parseSetLayerSourceCrop(length);
+ case IComposerClient::Command::SET_LAYER_TRANSFORM:
+ return parseSetLayerTransform(length);
+ case IComposerClient::Command::SET_LAYER_VISIBLE_REGION:
+ return parseSetLayerVisibleRegion(length);
+ case IComposerClient::Command::SET_LAYER_Z_ORDER:
+ return parseSetLayerZOrder(length);
+ default:
+ return false;
+ }
+}
+
+bool ComposerClient::CommandReader::parseSelectDisplay(uint16_t length)
+{
+ if (length != CommandWriterBase::kSelectDisplayLength) {
+ return false;
+ }
+
+ mDisplay = read64();
+ mWriter.selectDisplay(mDisplay);
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSelectLayer(uint16_t length)
+{
+ if (length != CommandWriterBase::kSelectLayerLength) {
+ return false;
+ }
+
+ mLayer = read64();
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetColorTransform(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetColorTransformLength) {
+ return false;
+ }
+
+ float matrix[16];
+ for (int i = 0; i < 16; i++) {
+ matrix[i] = readFloat();
+ }
+ auto transform = readSigned();
+
+ auto err = mHal.setColorTransform(mDisplay, matrix, transform);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetClientTarget(uint16_t length)
+{
+ // 4 parameters followed by N rectangles
+ if ((length - 4) % 4 != 0) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto clientTarget = readHandle(&useCache);
+ auto fence = readFence();
+ auto dataspace = readSigned();
+ auto damage = readRegion((length - 4) / 4);
+
+ auto err = lookupBuffer(BufferCache::CLIENT_TARGETS,
+ slot, useCache, clientTarget);
+ if (err == Error::NONE) {
+ err = mHal.setClientTarget(mDisplay, clientTarget, fence,
+ dataspace, damage);
+ }
+ if (err != Error::NONE) {
+ close(fence);
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetOutputBuffer(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetOutputBufferLength) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto outputBuffer = readHandle(&useCache);
+ auto fence = readFence();
+
+ auto err = lookupBuffer(BufferCache::OUTPUT_BUFFERS,
+ slot, useCache, outputBuffer);
+ if (err == Error::NONE) {
+ err = mHal.setOutputBuffer(mDisplay, outputBuffer, fence);
+ }
+ if (err != Error::NONE) {
+ close(fence);
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseValidateDisplay(uint16_t length)
+{
+ if (length != CommandWriterBase::kValidateDisplayLength) {
+ return false;
+ }
+
+ std::vector<Layer> changedLayers;
+ std::vector<IComposerClient::Composition> compositionTypes;
+ uint32_t displayRequestMask = 0x0;
+ std::vector<Layer> requestedLayers;
+ std::vector<uint32_t> requestMasks;
+
+ auto err = mHal.validateDisplay(mDisplay, &changedLayers,
+ &compositionTypes, &displayRequestMask,
+ &requestedLayers, &requestMasks);
+ if (err == Error::NONE) {
+ mWriter.setChangedCompositionTypes(changedLayers,
+ compositionTypes);
+ mWriter.setDisplayRequests(displayRequestMask,
+ requestedLayers, requestMasks);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseAcceptDisplayChanges(uint16_t length)
+{
+ if (length != CommandWriterBase::kAcceptDisplayChangesLength) {
+ return false;
+ }
+
+ auto err = mHal.acceptDisplayChanges(mDisplay);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parsePresentDisplay(uint16_t length)
+{
+ if (length != CommandWriterBase::kPresentDisplayLength) {
+ return false;
+ }
+
+ int presentFence = -1;
+ std::vector<Layer> layers;
+ std::vector<int> fences;
+ auto err = mHal.presentDisplay(mDisplay, &presentFence, &layers, &fences);
+ if (err == Error::NONE) {
+ mWriter.setPresentFence(presentFence);
+ mWriter.setReleaseFences(layers, fences);
+ } else {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerCursorPosition(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerCursorPositionLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerCursorPosition(mDisplay, mLayer,
+ readSigned(), readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerBuffer(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerBufferLength) {
+ return false;
+ }
+
+ bool useCache = false;
+ auto slot = read();
+ auto buffer = readHandle(&useCache);
+ auto fence = readFence();
+
+ auto err = lookupBuffer(BufferCache::LAYER_BUFFERS,
+ slot, useCache, buffer);
+ if (err == Error::NONE) {
+ err = mHal.setLayerBuffer(mDisplay, mLayer, buffer, fence);
+ }
+ if (err != Error::NONE) {
+ close(fence);
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerSurfaceDamage(uint16_t length)
+{
+ // N rectangles
+ if (length % 4 != 0) {
+ return false;
+ }
+
+ auto damage = readRegion(length / 4);
+ auto err = mHal.setLayerSurfaceDamage(mDisplay, mLayer, damage);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerBlendMode(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerBlendModeLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerBlendMode(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerColor(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerColorLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerColor(mDisplay, mLayer, readColor());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerCompositionType(
+ uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerCompositionTypeLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerCompositionType(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerDataspace(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerDataspaceLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerDataspace(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerDisplayFrame(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerDisplayFrameLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerDisplayFrame(mDisplay, mLayer, readRect());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerPlaneAlpha(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerPlaneAlphaLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerPlaneAlpha(mDisplay, mLayer, readFloat());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerSidebandStream(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerSidebandStreamLength) {
+ return false;
+ }
+
+ auto stream = readHandle();
+
+ auto err = lookupLayerSidebandStream(stream);
+ if (err == Error::NONE) {
+ err = mHal.setLayerSidebandStream(mDisplay, mLayer, stream);
+ }
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerSourceCrop(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerSourceCropLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerSourceCrop(mDisplay, mLayer, readFRect());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerTransform(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerTransformLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerTransform(mDisplay, mLayer, readSigned());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerVisibleRegion(uint16_t length)
+{
+ // N rectangles
+ if (length % 4 != 0) {
+ return false;
+ }
+
+ auto region = readRegion(length / 4);
+ auto err = mHal.setLayerVisibleRegion(mDisplay, mLayer, region);
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+bool ComposerClient::CommandReader::parseSetLayerZOrder(uint16_t length)
+{
+ if (length != CommandWriterBase::kSetLayerZOrderLength) {
+ return false;
+ }
+
+ auto err = mHal.setLayerZOrder(mDisplay, mLayer, read());
+ if (err != Error::NONE) {
+ mWriter.setError(getCommandLoc(), err);
+ }
+
+ return true;
+}
+
+hwc_rect_t ComposerClient::CommandReader::readRect()
+{
+ return hwc_rect_t{
+ readSigned(),
+ readSigned(),
+ readSigned(),
+ readSigned(),
+ };
+}
+
+std::vector<hwc_rect_t> ComposerClient::CommandReader::readRegion(size_t count)
+{
+ std::vector<hwc_rect_t> region;
+ region.reserve(count);
+ while (count > 0) {
+ region.emplace_back(readRect());
+ count--;
+ }
+
+ return region;
+}
+
+hwc_frect_t ComposerClient::CommandReader::readFRect()
+{
+ return hwc_frect_t{
+ readFloat(),
+ readFloat(),
+ readFloat(),
+ readFloat(),
+ };
+}
+
+Error ComposerClient::CommandReader::lookupBuffer(BufferCache cache,
+ uint32_t slot, bool useCache, buffer_handle_t& handle)
+{
+ std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex);
+
+ auto dpy = mClient.mDisplayData.find(mDisplay);
+ if (dpy == mClient.mDisplayData.end()) {
+ return Error::BAD_DISPLAY;
+ }
+
+ BufferClone* clone = nullptr;
+ switch (cache) {
+ case BufferCache::CLIENT_TARGETS:
+ if (slot < dpy->second.ClientTargets.size()) {
+ clone = &dpy->second.ClientTargets[slot];
+ }
+ break;
+ case BufferCache::OUTPUT_BUFFERS:
+ if (slot < dpy->second.OutputBuffers.size()) {
+ clone = &dpy->second.OutputBuffers[slot];
+ }
+ break;
+ case BufferCache::LAYER_BUFFERS:
+ {
+ auto ly = dpy->second.Layers.find(mLayer);
+ if (ly == dpy->second.Layers.end()) {
+ return Error::BAD_LAYER;
+ }
+ if (slot < ly->second.Buffers.size()) {
+ clone = &ly->second.Buffers[slot];
+ }
+ }
+ break;
+ case BufferCache::LAYER_SIDEBAND_STREAMS:
+ {
+ auto ly = dpy->second.Layers.find(mLayer);
+ if (ly == dpy->second.Layers.end()) {
+ return Error::BAD_LAYER;
+ }
+ if (slot == 0) {
+ clone = &ly->second.SidebandStream;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!clone) {
+ ALOGW("invalid buffer slot");
+ return Error::BAD_PARAMETER;
+ }
+
+ // use or update cache
+ if (useCache) {
+ handle = *clone;
+ } else {
+ if (!sHandleImporter.importBuffer(handle)) {
+ return Error::NO_RESOURCES;
+ }
+
+ *clone = handle;
+ }
+
+ return Error::NONE;
+}
+
+} // namespace implementation
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android