/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ComposerCommandEngine.h" #include <hardware/hwcomposer2.h> #include <map> #include <set> #include "Util.h" namespace aidl::android::hardware::graphics::composer3::impl { #define DISPATCH_LAYER_COMMAND(display, layerCmd, field, funcName) \ do { \ if (layerCmd.field) { \ executeSetLayer##funcName(display, layerCmd.layer, *layerCmd.field); \ } \ } while (0) #define DISPATCH_LAYER_COMMAND_SIMPLE(display, layerCmd, field, funcName) \ do { \ dispatchLayerCommand(display, layerCmd.layer, #field, layerCmd.field, \ &IComposerHal::setLayer##funcName); \ } while (0) #define DISPATCH_DISPLAY_COMMAND(displayCmd, field, funcName) \ do { \ if (displayCmd.field) { \ execute##funcName(displayCmd.display, *displayCmd.field); \ } \ } while (0) #define DISPATCH_DISPLAY_BOOL_COMMAND(displayCmd, field, funcName) \ do { \ if (displayCmd.field) { \ execute##funcName(displayCmd.display); \ } \ } while (0) #define DISPATCH_DISPLAY_COMMAND_AND_TWO_DATA(displayCmd, field, data_1, data_2, funcName) \ do { \ if (displayCmd.field) { \ execute##funcName(displayCmd.display, displayCmd.data_1, displayCmd.data_2); \ } \ } while (0) int32_t ComposerCommandEngine::init() { mWriter = std::make_unique<ComposerServiceWriter>(); return (mWriter != nullptr) ? ::android::NO_ERROR : ::android::NO_MEMORY; } int32_t ComposerCommandEngine::execute(const std::vector<DisplayCommand>& commands, std::vector<CommandResultPayload>* result) { std::set<int64_t> displaysPendingBrightenssChange; mCommandIndex = 0; for (const auto& command : commands) { dispatchDisplayCommand(command); ++mCommandIndex; // The input commands could have 2+ commands for the same display. // If the first has pending brightness change, the second presentDisplay will apply it. if (command.validateDisplay || command.presentDisplay || command.presentOrValidateDisplay) { displaysPendingBrightenssChange.erase(command.display); } else if (command.brightness) { displaysPendingBrightenssChange.insert(command.display); } } *result = mWriter->getPendingCommandResults(); mWriter->reset(); // standalone display brightness command shouldn't wait for next present or validate for (auto display : displaysPendingBrightenssChange) { auto err = mHal->flushDisplayBrightnessChange(display); if (err) { return err; } } return ::android::NO_ERROR; } void ComposerCommandEngine::dispatchBatchCreateDestroyLayerCommand(int64_t display, const LayerCommand& layerCmd) { auto cmdType = layerCmd.layerLifecycleBatchCommandType; if ((cmdType != LayerLifecycleBatchCommandType::CREATE) && (cmdType != LayerLifecycleBatchCommandType::DESTROY)) { return; } auto err = mHal->batchedCreateDestroyLayer(display, layerCmd.layer, cmdType); if (err) { mWriter->setError(mCommandIndex, err); return; } if (cmdType == LayerLifecycleBatchCommandType::CREATE) { err = mResources->addLayer(display, layerCmd.layer, layerCmd.newBufferSlotCount); } else { err = mResources->removeLayer(display, layerCmd.layer); } if (err) { mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::dispatchDisplayCommand(const DisplayCommand& command) { // place batched createLayer and destroyLayer commands before any other commands, so layers are // properly created to operate on. for (const auto& layerCmd : command.layers) { if (layerCmd.layerLifecycleBatchCommandType == LayerLifecycleBatchCommandType::CREATE || layerCmd.layerLifecycleBatchCommandType == LayerLifecycleBatchCommandType::DESTROY) { dispatchBatchCreateDestroyLayerCommand(command.display, layerCmd); } } // place SetDisplayBrightness before SetLayerWhitePointNits since current // display brightness is used to validate the layer white point nits. DISPATCH_DISPLAY_COMMAND(command, brightness, SetDisplayBrightness); for (const auto& layerCmd : command.layers) { // ignore layer data update if command is DESTROY if (layerCmd.layerLifecycleBatchCommandType != LayerLifecycleBatchCommandType::DESTROY) { dispatchLayerCommand(command.display, layerCmd); } } DISPATCH_DISPLAY_COMMAND(command, colorTransformMatrix, SetColorTransform); DISPATCH_DISPLAY_COMMAND(command, clientTarget, SetClientTarget); DISPATCH_DISPLAY_COMMAND(command, virtualDisplayOutputBuffer, SetOutputBuffer); DISPATCH_DISPLAY_COMMAND_AND_TWO_DATA(command, validateDisplay, expectedPresentTime, frameIntervalNs, ValidateDisplay); DISPATCH_DISPLAY_BOOL_COMMAND(command, acceptDisplayChanges, AcceptDisplayChanges); DISPATCH_DISPLAY_BOOL_COMMAND(command, presentDisplay, PresentDisplay); DISPATCH_DISPLAY_COMMAND_AND_TWO_DATA(command, presentOrValidateDisplay, expectedPresentTime, frameIntervalNs, PresentOrValidateDisplay); } void ComposerCommandEngine::dispatchLayerCommand(int64_t display, const LayerCommand& command) { DISPATCH_LAYER_COMMAND(display, command, cursorPosition, CursorPosition); DISPATCH_LAYER_COMMAND(display, command, buffer, Buffer); DISPATCH_LAYER_COMMAND(display, command, damage, SurfaceDamage); DISPATCH_LAYER_COMMAND(display, command, blendMode, BlendMode); DISPATCH_LAYER_COMMAND(display, command, color, Color); DISPATCH_LAYER_COMMAND(display, command, composition, Composition); DISPATCH_LAYER_COMMAND(display, command, dataspace, Dataspace); DISPATCH_LAYER_COMMAND(display, command, displayFrame, DisplayFrame); DISPATCH_LAYER_COMMAND(display, command, planeAlpha, PlaneAlpha); DISPATCH_LAYER_COMMAND(display, command, sidebandStream, SidebandStream); DISPATCH_LAYER_COMMAND(display, command, sourceCrop, SourceCrop); DISPATCH_LAYER_COMMAND(display, command, transform, Transform); DISPATCH_LAYER_COMMAND(display, command, visibleRegion, VisibleRegion); DISPATCH_LAYER_COMMAND(display, command, z, ZOrder); DISPATCH_LAYER_COMMAND(display, command, colorTransform, ColorTransform); DISPATCH_LAYER_COMMAND(display, command, brightness, Brightness); DISPATCH_LAYER_COMMAND(display, command, perFrameMetadata, PerFrameMetadata); DISPATCH_LAYER_COMMAND(display, command, perFrameMetadataBlob, PerFrameMetadataBlobs); DISPATCH_LAYER_COMMAND_SIMPLE(display, command, blockingRegion, BlockingRegion); DISPATCH_LAYER_COMMAND(display, command, bufferSlotsToClear, BufferSlotsToClear); } int32_t ComposerCommandEngine::executeValidateDisplayInternal(int64_t display) { std::vector<int64_t> changedLayers; std::vector<Composition> compositionTypes; uint32_t displayRequestMask = 0x0; std::vector<int64_t> requestedLayers; std::vector<int32_t> requestMasks; ClientTargetProperty clientTargetProperty{common::PixelFormat::RGBA_8888, common::Dataspace::UNKNOWN}; DimmingStage dimmingStage; auto err = mHal->validateDisplay(display, &changedLayers, &compositionTypes, &displayRequestMask, &requestedLayers, &requestMasks, &clientTargetProperty, &dimmingStage); mResources->setDisplayMustValidateState(display, false); if (err == HWC2_ERROR_NONE || err == HWC2_ERROR_HAS_CHANGES) { mWriter->setChangedCompositionTypes(display, changedLayers, compositionTypes); mWriter->setDisplayRequests(display, displayRequestMask, requestedLayers, requestMasks); static constexpr float kBrightness = 1.f; mWriter->setClientTargetProperty(display, clientTargetProperty, kBrightness, dimmingStage); } else { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } return err; } void ComposerCommandEngine::executeSetColorTransform(int64_t display, const std::vector<float>& matrix) { auto err = mHal->setColorTransform(display, matrix); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetClientTarget(int64_t display, const ClientTarget& command) { bool useCache = !command.buffer.handle; buffer_handle_t handle = useCache ? nullptr : ::android::makeFromAidl(*command.buffer.handle); buffer_handle_t clientTarget; auto bufferReleaser = mResources->createReleaser(true); auto err = mResources->getDisplayClientTarget(display, command.buffer.slot, useCache, handle, clientTarget, bufferReleaser.get()); if (!err) { err = mHal->setClientTarget(display, clientTarget, command.buffer.fence, command.dataspace, command.damage); if (err) { LOG(ERROR) << __func__ << " setClientTarget: err " << err; mWriter->setError(mCommandIndex, err); } } else { LOG(ERROR) << __func__ << " getDisplayClientTarget : err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetOutputBuffer(uint64_t display, const Buffer& buffer) { bool useCache = !buffer.handle; buffer_handle_t handle = useCache ? nullptr : ::android::makeFromAidl(*buffer.handle); buffer_handle_t outputBuffer; auto bufferReleaser = mResources->createReleaser(true); auto err = mResources->getDisplayOutputBuffer(display, buffer.slot, useCache, handle, outputBuffer, bufferReleaser.get()); if (!err) { err = mHal->setOutputBuffer(display, outputBuffer, buffer.fence); if (err) { LOG(ERROR) << __func__ << " setOutputBuffer: err " << err; mWriter->setError(mCommandIndex, err); } } else { LOG(ERROR) << __func__ << " getDisplayOutputBuffer: err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetExpectedPresentTimeInternal( int64_t display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime, int frameIntervalNs) { mHal->setExpectedPresentTime(display, expectedPresentTime, frameIntervalNs); } void ComposerCommandEngine::executeValidateDisplay( int64_t display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime, int frameIntervalNs) { executeSetExpectedPresentTimeInternal(display, expectedPresentTime, frameIntervalNs); executeValidateDisplayInternal(display); } void ComposerCommandEngine::executeSetDisplayBrightness(uint64_t display, const DisplayBrightness& command) { auto err = mHal->setDisplayBrightness(display, command.brightness); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executePresentOrValidateDisplay( int64_t display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime, int frameIntervalNs) { executeSetExpectedPresentTimeInternal(display, expectedPresentTime, frameIntervalNs); // First try to Present as is. auto presentErr = mResources->mustValidateDisplay(display) ? IComposerClient::EX_NOT_VALIDATED : executePresentDisplay(display); if (!presentErr) { mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented); return; } // Fallback to validate auto validateErr = executeValidateDisplayInternal(display); if (validateErr != HWC2_ERROR_NONE && validateErr != HWC2_ERROR_HAS_CHANGES) return; bool hasClientComp = false; bool cannotPresentDirectly = (validateErr == HWC2_ERROR_HAS_CHANGES) || (mHal->getHasClientComposition(display, hasClientComp) == HWC2_ERROR_NONE && hasClientComp); if (cannotPresentDirectly) { mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Validated); return; } // Try to call present again executeAcceptDisplayChanges(display); presentErr = executePresentDisplay(display); if (!presentErr) { mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented); } } void ComposerCommandEngine::executeAcceptDisplayChanges(int64_t display) { auto err = mHal->acceptDisplayChanges(display); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } int ComposerCommandEngine::executePresentDisplay(int64_t display) { ndk::ScopedFileDescriptor presentFence; std::vector<int64_t> layers; std::vector<ndk::ScopedFileDescriptor> fences; auto err = mHal->presentDisplay(display, presentFence, &layers, &fences); if (!err) { mWriter->setPresentFence(display, std::move(presentFence)); mWriter->setReleaseFences(display, layers, std::move(fences)); } return err; } void ComposerCommandEngine::executeSetLayerCursorPosition(int64_t display, int64_t layer, const common::Point& cursorPosition) { auto err = mHal->setLayerCursorPosition(display, layer, cursorPosition.x, cursorPosition.y); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerBuffer(int64_t display, int64_t layer, const Buffer& buffer) { bool useCache = !buffer.handle; buffer_handle_t handle = useCache ? nullptr : ::android::makeFromAidl(*buffer.handle); buffer_handle_t hwcBuffer; auto bufferReleaser = mResources->createReleaser(true); auto err = mResources->getLayerBuffer(display, layer, buffer.slot, useCache, handle, hwcBuffer, bufferReleaser.get()); if (!err) { err = mHal->setLayerBuffer(display, layer, hwcBuffer, buffer.fence); if (err) { LOG(ERROR) << __func__ << ": setLayerBuffer err " << err; mWriter->setError(mCommandIndex, err); } } else { LOG(ERROR) << __func__ << ": getLayerBuffer err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerSurfaceDamage(int64_t display, int64_t layer, const std::vector<std::optional<common::Rect>>& damage) { auto err = mHal->setLayerSurfaceDamage(display, layer, damage); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerBlendMode(int64_t display, int64_t layer, const ParcelableBlendMode& blendMode) { auto err = mHal->setLayerBlendMode(display, layer, blendMode.blendMode); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerColor(int64_t display, int64_t layer, const Color& color) { auto err = mHal->setLayerColor(display, layer, color); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerComposition(int64_t display, int64_t layer, const ParcelableComposition& composition) { auto err = mHal->setLayerCompositionType(display, layer, composition.composition); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerDataspace(int64_t display, int64_t layer, const ParcelableDataspace& dataspace) { auto err = mHal->setLayerDataspace(display, layer, dataspace.dataspace); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerDisplayFrame(int64_t display, int64_t layer, const common::Rect& rect) { auto err = mHal->setLayerDisplayFrame(display, layer, rect); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerPlaneAlpha(int64_t display, int64_t layer, const PlaneAlpha& planeAlpha) { auto err = mHal->setLayerPlaneAlpha(display, layer, planeAlpha.alpha); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerSidebandStream(int64_t display, int64_t layer, const AidlNativeHandle& sidebandStream) { buffer_handle_t handle = ::android::makeFromAidl(sidebandStream); buffer_handle_t stream; auto bufferReleaser = mResources->createReleaser(false); auto err = mResources->getLayerSidebandStream(display, layer, handle, stream, bufferReleaser.get()); if (err) { err = mHal->setLayerSidebandStream(display, layer, stream); } if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerSourceCrop(int64_t display, int64_t layer, const common::FRect& sourceCrop) { auto err = mHal->setLayerSourceCrop(display, layer, sourceCrop); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerTransform(int64_t display, int64_t layer, const ParcelableTransform& transform) { auto err = mHal->setLayerTransform(display, layer, transform.transform); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerVisibleRegion(int64_t display, int64_t layer, const std::vector<std::optional<common::Rect>>& visibleRegion) { auto err = mHal->setLayerVisibleRegion(display, layer, visibleRegion); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerZOrder(int64_t display, int64_t layer, const ZOrder& zOrder) { auto err = mHal->setLayerZOrder(display, layer, zOrder.z); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerPerFrameMetadata(int64_t display, int64_t layer, const std::vector<std::optional<PerFrameMetadata>>& perFrameMetadata) { auto err = mHal->setLayerPerFrameMetadata(display, layer, perFrameMetadata); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerColorTransform(int64_t display, int64_t layer, const std::vector<float>& matrix) { auto err = mHal->setLayerColorTransform(display, layer, matrix); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerBrightness(int64_t display, int64_t layer, const LayerBrightness& brightness) { auto err = mHal->setLayerBrightness(display, layer, brightness.brightness); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerPerFrameMetadataBlobs(int64_t display, int64_t layer, const std::vector<std::optional<PerFrameMetadataBlob>>& metadata) { auto err = mHal->setLayerPerFrameMetadataBlobs(display, layer, metadata); if (err) { LOG(ERROR) << __func__ << ": err " << err; mWriter->setError(mCommandIndex, err); } } void ComposerCommandEngine::executeSetLayerBufferSlotsToClear( int64_t display, int64_t layer, const std::vector<int32_t>& bufferSlotsToClear) { std::optional<PowerMode> powerMode; mHal->getPowerMode(display, powerMode); if (!powerMode.has_value() || powerMode.value() != PowerMode::OFF) { return; } buffer_handle_t cachedBuffer = nullptr; std::unique_ptr<IBufferReleaser> bufferReleaser = mResources->createReleaser(true); // get all cached buffers std::vector<buffer_handle_t> cachedBuffers; std::map<buffer_handle_t, int32_t> handle2Slots; for (int32_t slot : bufferSlotsToClear) { auto err = mResources->getLayerBuffer(display, layer, slot, /*fromCache=*/true, nullptr, cachedBuffer, bufferReleaser.get()); if (cachedBuffer) { cachedBuffers.push_back(cachedBuffer); handle2Slots[cachedBuffer] = slot; } else { LOG(ERROR) << __func__ << ": Buffer slot " << slot << " is null"; } if (err) { LOG(ERROR) << __func__ << ": failed to getLayerBuffer err " << err; mWriter->setError(mCommandIndex, err); return; } } // clear any other cache in composer std::vector<buffer_handle_t> clearableBuffers; mHal->uncacheLayerBuffers(display, layer, cachedBuffers, clearableBuffers); for (auto buffer : clearableBuffers) { auto slot = handle2Slots[buffer]; // replace the slot with nullptr and release the buffer by bufferReleaser auto err = mResources->getLayerBuffer(display, layer, slot, /*fromCache=*/false, nullptr, cachedBuffer, bufferReleaser.get()); if (err) { LOG(ERROR) << __func__ << ": failed to clear buffer cache err " << err; mWriter->setError(mCommandIndex, err); return; } } } } // namespace aidl::android::hardware::graphics::composer3::impl