/* * 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 #include #include "ComposerClient.h" #include "ComposerBase.h" #include "IComposerCommandBuffer.h" namespace android { namespace hardware { namespace graphics { namespace composer { namespace V2_1 { namespace implementation { namespace { using MapperError = android::hardware::graphics::mapper::V2_0::Error; using android::hardware::graphics::mapper::V2_0::IMapper; class HandleImporter { public: bool initialize() { // allow only one client if (mInitialized) { return false; } mMapper = IMapper::getService(); mInitialized = true; return true; } void cleanup() { mMapper.clear(); 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; } MapperError error; buffer_handle_t importedHandle; mMapper->importBuffer( hidl_handle(handle), [&](const auto& tmpError, const auto& tmpBufferHandle) { error = tmpError; importedHandle = static_cast(tmpBufferHandle); }); if (error != MapperError::NONE) { return false; } handle = importedHandle; return true; } void freeBuffer(buffer_handle_t handle) { if (!handle) { return; } mMapper->freeBuffer(const_cast(handle)); } private: bool mInitialized = false; sp mMapper; }; HandleImporter sHandleImporter; } // anonymous namespace BufferCacheEntry::BufferCacheEntry() : mHandle(nullptr) { } BufferCacheEntry::BufferCacheEntry(BufferCacheEntry&& other) { mHandle = other.mHandle; other.mHandle = nullptr; } BufferCacheEntry& BufferCacheEntry::operator=(buffer_handle_t handle) { clear(); mHandle = handle; return *this; } BufferCacheEntry::~BufferCacheEntry() { clear(); } void BufferCacheEntry::clear() { if (mHandle) { sHandleImporter.freeBuffer(mHandle); } } ComposerClient::ComposerClient(ComposerBase& hal) : mHal(hal), mWriter(kWriterInitialSize) { } ComposerClient::~ComposerClient() { // We want to call hwc2_close here (and move hwc2_open to the // constructor), with the assumption that hwc2_close would // // - clean up all resources owned by the client // - make sure all displays are blank (since there is no layer) // // But since SF used to crash at this point, different hwcomposer2 // implementations behave differently on hwc2_close. Our only portable // choice really is to abort(). But that is not an option anymore // because we might also have VTS or VR as clients that can come and go. // // Below we manually clean all resources (layers and virtual // displays), and perform a presentDisplay afterwards. ALOGW("destroying composer client"); mHal.enableCallback(false); // no need to grab the mutex as any in-flight hwbinder call would have // kept the client alive for (const auto& dpy : mDisplayData) { ALOGW("destroying client resources for display %" PRIu64, dpy.first); for (const auto& ly : dpy.second.Layers) { mHal.destroyLayer(dpy.first, ly.first); } if (dpy.second.IsVirtual) { mHal.destroyVirtualDisplay(dpy.first); } else { ALOGW("performing a final presentDisplay"); std::vector changedLayers; std::vector compositionTypes; uint32_t displayRequestMask = 0; std::vector requestedLayers; std::vector requestMasks; mHal.validateDisplay(dpy.first, &changedLayers, &compositionTypes, &displayRequestMask, &requestedLayers, &requestMasks); mHal.acceptDisplayChanges(dpy.first); int32_t presentFence = -1; std::vector releasedLayers; std::vector releaseFences; mHal.presentDisplay(dpy.first, &presentFence, &releasedLayers, &releaseFences); if (presentFence >= 0) { close(presentFence); } for (auto fence : releaseFences) { if (fence >= 0) { close(fence); } } } } mDisplayData.clear(); sHandleImporter.cleanup(); mHal.removeClient(); ALOGW("removed composer client"); } 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 lock(mDisplayDataMutex); if (connected == IComposerCallback::Connection::CONNECTED) { mDisplayData.emplace(display, DisplayData(false)); } else if (connected == IComposerCallback::Connection::DISCONNECTED) { mDisplayData.erase(display); } } auto ret = mCallback->onHotplug(display, connected); ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str()); } void ComposerClient::onRefresh(Display display) { auto ret = mCallback->onRefresh(display); ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str()); } void ComposerClient::onVsync(Display display, int64_t timestamp) { auto ret = mCallback->onVsync(display, timestamp); ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str()); } Return ComposerClient::registerCallback( const sp& callback) { // no locking as we require this function to be called only once mCallback = callback; mHal.enableCallback(callback != nullptr); return Void(); } Return ComposerClient::getMaxVirtualDisplayCount() { return mHal.getMaxVirtualDisplayCount(); } Return 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 lock(mDisplayDataMutex); auto dpy = mDisplayData.emplace(display, DisplayData(true)).first; dpy->second.OutputBuffers.resize(outputBufferSlotCount); } hidl_cb(err, display, formatHint); return Void(); } Return ComposerClient::destroyVirtualDisplay(Display display) { Error err = mHal.destroyVirtualDisplay(display); if (err == Error::NONE) { std::lock_guard lock(mDisplayDataMutex); mDisplayData.erase(display); } return err; } Return 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 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 ComposerClient::destroyLayer(Display display, Layer layer) { Error err = mHal.destroyLayer(display, layer); if (err == Error::NONE) { std::lock_guard lock(mDisplayDataMutex); auto dpy = mDisplayData.find(display); dpy->second.Layers.erase(layer); } return err; } Return ComposerClient::getActiveConfig(Display display, getActiveConfig_cb hidl_cb) { Config config = 0; Error err = mHal.getActiveConfig(display, &config); hidl_cb(err, config); return Void(); } Return 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 ComposerClient::getColorModes(Display display, getColorModes_cb hidl_cb) { hidl_vec modes; Error err = mHal.getColorModes(display, &modes); hidl_cb(err, modes); return Void(); } Return 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 ComposerClient::getDisplayConfigs(Display display, getDisplayConfigs_cb hidl_cb) { hidl_vec configs; Error err = mHal.getDisplayConfigs(display, &configs); hidl_cb(err, configs); return Void(); } Return ComposerClient::getDisplayName(Display display, getDisplayName_cb hidl_cb) { hidl_string name; Error err = mHal.getDisplayName(display, &name); hidl_cb(err, name); return Void(); } Return 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 ComposerClient::getDozeSupport(Display display, getDozeSupport_cb hidl_cb) { bool support = false; Error err = mHal.getDozeSupport(display, &support); hidl_cb(err, support); return Void(); } Return ComposerClient::getHdrCapabilities(Display display, getHdrCapabilities_cb hidl_cb) { hidl_vec 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 ComposerClient::setClientTargetSlotCount(Display display, uint32_t clientTargetSlotCount) { std::lock_guard lock(mDisplayDataMutex); auto dpy = mDisplayData.find(display); if (dpy == mDisplayData.end()) { return Error::BAD_DISPLAY; } dpy->second.ClientTargets.resize(clientTargetSlotCount); return Error::NONE; } Return ComposerClient::setActiveConfig(Display display, Config config) { Error err = mHal.setActiveConfig(display, config); return err; } Return ComposerClient::setColorMode(Display display, ColorMode mode) { Error err = mHal.setColorMode(display, mode); return err; } Return ComposerClient::setPowerMode(Display display, PowerMode mode) { Error err = mHal.setPowerMode(display, mode); return err; } Return ComposerClient::setVsyncEnabled(Display display, Vsync enabled) { Error err = mHal.setVsyncEnabled(display, enabled); return err; } Return ComposerClient::setInputCommandQueue( const MQDescriptorSync& descriptor) { std::lock_guard lock(mCommandMutex); return mReader->setMQDescriptor(descriptor) ? Error::NONE : Error::NO_RESOURCES; } Return 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 ComposerClient::executeCommands(uint32_t inLength, const hidl_vec& inHandles, executeCommands_cb hidl_cb) { std::lock_guard lock(mCommandMutex); bool outChanged = false; uint32_t outLength = 0; hidl_vec 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::createCommandReader() { return std::unique_ptr( 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::PRESENT_OR_VALIDATE_DISPLAY: return parsePresentOrValidateDisplay(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); bool closeFence = true; auto err = lookupBuffer(BufferCache::CLIENT_TARGETS, slot, useCache, clientTarget, &clientTarget); if (err == Error::NONE) { err = mHal.setClientTarget(mDisplay, clientTarget, fence, dataspace, damage); auto updateBufErr = updateBuffer(BufferCache::CLIENT_TARGETS, slot, useCache, clientTarget); if (err == Error::NONE) { closeFence = false; err = updateBufErr; } } if (closeFence) { close(fence); } if (err != Error::NONE) { 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(); bool closeFence = true; auto err = lookupBuffer(BufferCache::OUTPUT_BUFFERS, slot, useCache, outputBuffer, &outputBuffer); if (err == Error::NONE) { err = mHal.setOutputBuffer(mDisplay, outputBuffer, fence); auto updateBufErr = updateBuffer(BufferCache::OUTPUT_BUFFERS, slot, useCache, outputBuffer); if (err == Error::NONE) { closeFence = false; err = updateBufErr; } } if (closeFence) { close(fence); } if (err != Error::NONE) { mWriter.setError(getCommandLoc(), err); } return true; } bool ComposerClient::CommandReader::parseValidateDisplay(uint16_t length) { if (length != CommandWriterBase::kValidateDisplayLength) { return false; } std::vector changedLayers; std::vector compositionTypes; uint32_t displayRequestMask = 0x0; std::vector requestedLayers; std::vector 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::parsePresentOrValidateDisplay(uint16_t length) { if (length != CommandWriterBase::kPresentOrValidateDisplayLength) { return false; } // First try to Present as is. int presentFence = -1; std::vector layers; std::vector fences; auto err = mHal.presentDisplay(mDisplay, &presentFence, &layers, &fences); if (err == Error::NONE) { mWriter.setPresentOrValidateResult(1); mWriter.setPresentFence(presentFence); mWriter.setReleaseFences(layers, fences); return true; } // Present has failed. We need to fallback to validate std::vector changedLayers; std::vector compositionTypes; uint32_t displayRequestMask = 0x0; std::vector requestedLayers; std::vector requestMasks; err = mHal.validateDisplay(mDisplay, &changedLayers, &compositionTypes, &displayRequestMask, &requestedLayers, &requestMasks); if (err == Error::NONE) { mWriter.setPresentOrValidateResult(0); 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 layers; std::vector 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(); bool closeFence = true; auto err = lookupBuffer(BufferCache::LAYER_BUFFERS, slot, useCache, buffer, &buffer); if (err == Error::NONE) { err = mHal.setLayerBuffer(mDisplay, mLayer, buffer, fence); auto updateBufErr = updateBuffer(BufferCache::LAYER_BUFFERS, slot, useCache, buffer); if (err == Error::NONE) { closeFence = false; err = updateBufErr; } } if (closeFence) { close(fence); } if (err != Error::NONE) { 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, &stream); if (err == Error::NONE) { err = mHal.setLayerSidebandStream(mDisplay, mLayer, stream); auto updateErr = updateLayerSidebandStream(stream); if (err == Error::NONE) { err = updateErr; } } 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 ComposerClient::CommandReader::readRegion(size_t count) { std::vector 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::lookupBufferCacheEntryLocked( BufferCache cache, uint32_t slot, BufferCacheEntry** outEntry) { auto dpy = mClient.mDisplayData.find(mDisplay); if (dpy == mClient.mDisplayData.end()) { return Error::BAD_DISPLAY; } BufferCacheEntry* entry = nullptr; switch (cache) { case BufferCache::CLIENT_TARGETS: if (slot < dpy->second.ClientTargets.size()) { entry = &dpy->second.ClientTargets[slot]; } break; case BufferCache::OUTPUT_BUFFERS: if (slot < dpy->second.OutputBuffers.size()) { entry = &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()) { entry = &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) { entry = &ly->second.SidebandStream; } } break; default: break; } if (!entry) { ALOGW("invalid buffer slot %" PRIu32, slot); return Error::BAD_PARAMETER; } *outEntry = entry; return Error::NONE; } Error ComposerClient::CommandReader::lookupBuffer(BufferCache cache, uint32_t slot, bool useCache, buffer_handle_t handle, buffer_handle_t* outHandle) { if (useCache) { std::lock_guard lock(mClient.mDisplayDataMutex); BufferCacheEntry* entry; Error error = lookupBufferCacheEntryLocked(cache, slot, &entry); if (error != Error::NONE) { return error; } // input handle is ignored *outHandle = entry->getHandle(); } else { if (!sHandleImporter.importBuffer(handle)) { return Error::NO_RESOURCES; } *outHandle = handle; } return Error::NONE; } Error ComposerClient::CommandReader::updateBuffer(BufferCache cache, uint32_t slot, bool useCache, buffer_handle_t handle) { // handle was looked up from cache if (useCache) { return Error::NONE; } std::lock_guard lock(mClient.mDisplayDataMutex); BufferCacheEntry* entry = nullptr; Error error = lookupBufferCacheEntryLocked(cache, slot, &entry); if (error != Error::NONE) { return error; } *entry = handle; return Error::NONE; } } // namespace implementation } // namespace V2_1 } // namespace composer } // namespace graphics } // namespace hardware } // namespace android