/* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2017 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 __QTICOMPOSERCOMMANDBUFFER_H__ #define __QTICOMPOSERCOMMANDBUFFER_H__ #include #include #include #include #include #include #include #include #include namespace vendor { namespace qti { namespace hardware { namespace display { namespace composer { namespace V3_0 { using ::android::hardware::graphics::common::V1_0::ColorTransform; using ::android::hardware::graphics::common::V1_0::Dataspace; using ::android::hardware::graphics::common::V1_0::Transform; using ::android::hardware::graphics::composer::V2_1::Error; using ::android::hardware::graphics::composer::V2_1::Display; using ::android::hardware::graphics::composer::V2_1::Layer; using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; using ::android::hardware::hidl_vec; using ::android::hardware::hidl_handle; using CommandQueueType = MessageQueue; using std::shared_ptr; using std::string; using sdm::Fence; // This class helps build a command queue. Note that all sizes/lengths are in units of uint32_t's. class CommandWriter { public: explicit CommandWriter(uint32_t initialMaxSize) : mDataMaxSize(initialMaxSize) { mData = std::make_unique(mDataMaxSize); reset(); } ~CommandWriter() { reset(); } void reset() { mDataWritten = 0; mCommandEnd = 0; // handles in mDataHandles are owned by the caller mDataHandles.clear(); // handles in mTemporaryHandles are owned by the writer for (auto handle : mTemporaryHandles) { native_handle_close(handle); native_handle_delete(handle); } mTemporaryHandles.clear(); } IQtiComposerClient::Command getCommand(uint32_t offset) { uint32_t val = (offset < mDataWritten) ? mData[offset] : 0; return static_cast(val & static_cast(IQtiComposerClient::Command::OPCODE_MASK)); } bool writeQueue(bool& queueChanged, uint32_t& commandLength, hidl_vec& commandHandles) { if (mDataWritten == 0) { queueChanged = false; commandLength = 0; commandHandles.setToExternal(nullptr, 0); return true; } // After data are written to the queue, it may not be read by the // remote reader when // // - the writer does not send them (because of other errors) // - the hwbinder transaction fails // - the reader does not read them (because of other errors) // // Discard the stale data here. size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0; if (staleDataSize > 0) { ALOGW("discarding stale data from message queue"); CommandQueueType::MemTransaction tx; if (mQueue->beginRead(staleDataSize, &tx)) { mQueue->commitRead(staleDataSize); } } // write data to queue, optionally resizing it if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) { if (!mQueue->write(mData.get(), mDataWritten)) { ALOGE("failed to write commands to message queue"); return false; } queueChanged = false; } else { auto newQueue = std::make_unique(mDataMaxSize); if (!newQueue->isValid() || !newQueue->write(mData.get(), mDataWritten)) { ALOGE("failed to prepare a new message queue "); return false; } mQueue = std::move(newQueue); queueChanged = true; } commandLength = mDataWritten; commandHandles.setToExternal(const_cast(mDataHandles.data()), mDataHandles.size()); return true; } const MQDescriptorSync* getMQDescriptor() const { return (mQueue) ? mQueue->getDesc() : nullptr; } // Commands from ::android::hardware::graphics::composer::V2_1::IComposerClient follow. static constexpr uint16_t kSelectDisplayLength = 2; void selectDisplay(Display display) { beginCommand(IQtiComposerClient::Command::SELECT_DISPLAY, kSelectDisplayLength); write64(display); endCommand(); } static constexpr uint16_t kSelectLayerLength = 2; void selectLayer(Layer layer) { beginCommand(IQtiComposerClient::Command::SELECT_LAYER, kSelectLayerLength); write64(layer); endCommand(); } static constexpr uint16_t kSetErrorLength = 2; void setError(uint32_t location, Error error) { beginCommand(IQtiComposerClient::Command::SET_ERROR, kSetErrorLength); write(location); writeSigned(static_cast(error)); endCommand(); } static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1; void setPresentOrValidateResult(uint32_t state) { beginCommand(IQtiComposerClient::Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT, kPresentOrValidateDisplayResultLength); write(state); endCommand(); } void setChangedCompositionTypes(const std::vector& layers, const std::vector& types) { size_t totalLayers = std::min(layers.size(), types.size()); size_t currentLayer = 0; while (currentLayer < totalLayers) { size_t count = std::min(totalLayers - currentLayer, static_cast(kMaxLength) / 3); beginCommand(IQtiComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES, count * 3); for (size_t i = 0; i < count; i++) { write64(layers[currentLayer + i]); writeSigned(static_cast(types[currentLayer + i])); } endCommand(); currentLayer += count; } } void setDisplayRequests(uint32_t displayRequestMask, const std::vector& layers, const std::vector& layerRequestMasks) { size_t totalLayers = std::min(layers.size(), layerRequestMasks.size()); size_t currentLayer = 0; while (currentLayer < totalLayers) { size_t count = std::min(totalLayers - currentLayer, static_cast(kMaxLength - 1) / 3); beginCommand(IQtiComposerClient::Command::SET_DISPLAY_REQUESTS, 1 + count * 3); write(displayRequestMask); for (size_t i = 0; i < count; i++) { write64(layers[currentLayer + i]); write(static_cast(layerRequestMasks[currentLayer + i])); } endCommand(); currentLayer += count; } } static constexpr uint16_t kSetPresentFenceLength = 1; void setPresentFence(const shared_ptr &presentFence) { beginCommand(IQtiComposerClient::Command::SET_PRESENT_FENCE, kSetPresentFenceLength); writeFence(presentFence); endCommand(); } void setReleaseFences(const std::vector& layers, const std::vector>& releaseFences) { size_t totalLayers = std::min(layers.size(), releaseFences.size()); size_t currentLayer = 0; while (currentLayer < totalLayers) { size_t count = std::min(totalLayers - currentLayer, static_cast(kMaxLength) / 3); beginCommand(IQtiComposerClient::Command::SET_RELEASE_FENCES, count * 3); for (size_t i = 0; i < count; i++) { write64(layers[currentLayer + i]); writeFence(releaseFences[currentLayer + i]); } endCommand(); currentLayer += count; } } static constexpr uint16_t kSetColorTransformLength = 17; void setColorTransform(const float* matrix, ColorTransform hint) { beginCommand(IQtiComposerClient::Command::SET_COLOR_TRANSFORM, kSetColorTransformLength); for (int i = 0; i < 16; i++) { writeFloat(matrix[i]); } writeSigned(static_cast(hint)); endCommand(); } void setClientTarget(uint32_t slot, const native_handle_t* target, const shared_ptr& acquireFence, Dataspace dataspace, const std::vector& damage) { bool doWrite = (damage.size() <= (kMaxLength - 4) / 4); size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0); beginCommand(IQtiComposerClient::Command::SET_CLIENT_TARGET, length); write(slot); writeHandle(target, true); writeFence(acquireFence); writeSigned(static_cast(dataspace)); // When there are too many rectangles in the damage region and doWrite // is false, we write no rectangle at all which means the entire // client target is damaged. if (doWrite) { writeRegion(damage); } endCommand(); } static constexpr uint16_t kSetOutputBufferLength = 3; void setOutputBuffer(uint32_t slot, const native_handle_t* buffer, const shared_ptr& releaseFence) { beginCommand(IQtiComposerClient::Command::SET_OUTPUT_BUFFER, kSetOutputBufferLength); write(slot); writeHandle(buffer, true); writeFence(releaseFence); endCommand(); } static constexpr uint16_t kValidateDisplayLength = 0; void validateDisplay() { beginCommand(IQtiComposerClient::Command::VALIDATE_DISPLAY, kValidateDisplayLength); endCommand(); } static constexpr uint16_t kPresentOrValidateDisplayLength = 0; void presentOrvalidateDisplay() { beginCommand(IQtiComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY, kPresentOrValidateDisplayLength); endCommand(); } static constexpr uint16_t kAcceptDisplayChangesLength = 0; void acceptDisplayChanges() { beginCommand(IQtiComposerClient::Command::ACCEPT_DISPLAY_CHANGES, kAcceptDisplayChangesLength); endCommand(); } static constexpr uint16_t kPresentDisplayLength = 0; void presentDisplay() { beginCommand(IQtiComposerClient::Command::PRESENT_DISPLAY, kPresentDisplayLength); endCommand(); } static constexpr uint16_t kSetLayerCursorPositionLength = 2; void setLayerCursorPosition(int32_t x, int32_t y) { beginCommand(IQtiComposerClient::Command::SET_LAYER_CURSOR_POSITION, kSetLayerCursorPositionLength); writeSigned(x); writeSigned(y); endCommand(); } static constexpr uint16_t kSetLayerBufferLength = 3; void setLayerBuffer(uint32_t slot, const native_handle_t* buffer, const shared_ptr& acquireFence) { beginCommand(IQtiComposerClient::Command::SET_LAYER_BUFFER, kSetLayerBufferLength); write(slot); writeHandle(buffer, true); writeFence(acquireFence); endCommand(); } void setLayerSurfaceDamage(const std::vector& damage) { bool doWrite = (damage.size() <= kMaxLength / 4); size_t length = (doWrite) ? damage.size() * 4 : 0; beginCommand(IQtiComposerClient::Command::SET_LAYER_SURFACE_DAMAGE, length); // When there are too many rectangles in the damage region and doWrite // is false, we write no rectangle at all which means the entire // layer is damaged. if (doWrite) { writeRegion(damage); } endCommand(); } static constexpr uint16_t kSetLayerBlendModeLength = 1; void setLayerBlendMode(IQtiComposerClient::BlendMode mode) { beginCommand(IQtiComposerClient::Command::SET_LAYER_BLEND_MODE, kSetLayerBlendModeLength); writeSigned(static_cast(mode)); endCommand(); } static constexpr uint16_t kSetLayerColorLength = 1; void setLayerColor(IQtiComposerClient::Color color) { beginCommand(IQtiComposerClient::Command::SET_LAYER_COLOR, kSetLayerColorLength); writeColor(color); endCommand(); } static constexpr uint16_t kSetLayerCompositionTypeLength = 1; void setLayerCompositionType(IQtiComposerClient::Composition type) { beginCommand(IQtiComposerClient::Command::SET_LAYER_COMPOSITION_TYPE, kSetLayerCompositionTypeLength); writeSigned(static_cast(type)); endCommand(); } static constexpr uint16_t kSetLayerDataspaceLength = 1; void setLayerDataspace(Dataspace dataspace) { beginCommand(IQtiComposerClient::Command::SET_LAYER_DATASPACE, kSetLayerDataspaceLength); writeSigned(static_cast(dataspace)); endCommand(); } static constexpr uint16_t kSetLayerDisplayFrameLength = 4; void setLayerDisplayFrame(const IQtiComposerClient::Rect& frame) { beginCommand(IQtiComposerClient::Command::SET_LAYER_DISPLAY_FRAME, kSetLayerDisplayFrameLength); writeRect(frame); endCommand(); } static constexpr uint16_t kSetLayerPlaneAlphaLength = 1; void setLayerPlaneAlpha(float alpha) { beginCommand(IQtiComposerClient::Command::SET_LAYER_PLANE_ALPHA, kSetLayerPlaneAlphaLength); writeFloat(alpha); endCommand(); } static constexpr uint16_t kSetLayerSidebandStreamLength = 1; void setLayerSidebandStream(const native_handle_t* stream) { beginCommand(IQtiComposerClient::Command::SET_LAYER_SIDEBAND_STREAM, kSetLayerSidebandStreamLength); writeHandle(stream); endCommand(); } static constexpr uint16_t kSetLayerSourceCropLength = 4; void setLayerSourceCrop(const IQtiComposerClient::FRect& crop) { beginCommand(IQtiComposerClient::Command::SET_LAYER_SOURCE_CROP, kSetLayerSourceCropLength); writeFRect(crop); endCommand(); } static constexpr uint16_t kSetLayerTransformLength = 1; void setLayerTransform(Transform transform) { beginCommand(IQtiComposerClient::Command::SET_LAYER_TRANSFORM, kSetLayerTransformLength); writeSigned(static_cast(transform)); endCommand(); } void setLayerVisibleRegion(const std::vector& visible) { bool doWrite = (visible.size() <= kMaxLength / 4); size_t length = (doWrite) ? visible.size() * 4 : 0; beginCommand(IQtiComposerClient::Command::SET_LAYER_VISIBLE_REGION, length); // When there are too many rectangles in the visible region and // doWrite is false, we write no rectangle at all which means the // entire layer is visible. if (doWrite) { writeRegion(visible); } endCommand(); } static constexpr uint16_t kSetLayerZOrderLength = 1; void setLayerZOrder(uint32_t z) { beginCommand(IQtiComposerClient::Command::SET_LAYER_Z_ORDER, kSetLayerZOrderLength); write(z); endCommand(); } static constexpr uint16_t kSetLayerTypeLength = 1; void setLayerType(uint32_t z) { beginCommand(IQtiComposerClient::Command::SET_LAYER_TYPE, kSetLayerTypeLength); write(z); endCommand(); } // Commands from ::android::hardware::graphics::composer::V2_2::IComposerClient follow. static constexpr uint16_t kSetLayerFloatColorLength = 4; void setLayerFloatColor(IQtiComposerClient::FloatColor color) { beginCommand(IQtiComposerClient::Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength); writeFloatColor(color); endCommand(); } void setLayerPerFrameMetadata(const hidl_vec& metadataVec) { beginCommand(IQtiComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, metadataVec.size() * 2); for (const auto& metadata : metadataVec) { writeSigned(static_cast(metadata.key)); writeFloat(metadata.value); } endCommand(); } // Commands from ::android::hardware::graphics::composer::V2_3::IComposerClient follow. static constexpr uint16_t kSetLayerColorTransformLength = 16; void setLayerColorTransform(const float* matrix) { beginCommand(IQtiComposerClient::Command::SET_LAYER_COLOR_TRANSFORM, kSetLayerColorTransformLength); for (int i = 0; i < 16; i++) { writeFloat(matrix[i]); } endCommand(); } void setLayerPerFrameMetadataBlobs( const hidl_vec& metadata) { size_t commandLength = 0; if (metadata.size() > std::numeric_limits::max()) { LOG_FATAL("too many metadata blobs - dynamic metadata size is too large"); return; } // number of blobs commandLength += metadata.size(); for (auto metadataBlob : metadata) { commandLength += sizeof(int32_t); // key of metadata blob commandLength += 1; // size information of metadata blob // metadata content size size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t); commandLength += metadataSize; commandLength += (metadataBlob.blob.size() - (metadataSize * sizeof(uint32_t)) > 0) ? 1 : 0; } if (commandLength > std::numeric_limits::max()) { LOG_FATAL("dynamic metadata size is too large"); return; } // Blobs are written as: // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...} uint16_t length = static_cast(commandLength); beginCommand(IQtiComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length); write(static_cast(metadata.size())); for (auto metadataBlob : metadata) { writeSigned(static_cast(metadataBlob.key)); write(static_cast(metadataBlob.blob.size())); writeBlob(static_cast(metadataBlob.blob.size()), metadataBlob.blob.data()); } endCommand(); } static constexpr uint16_t kSetDisplayElapseTime = 2; void setDisplayElapseTime(uint64_t time) { beginCommand(IQtiComposerClient::Command::SET_DISPLAY_ELAPSE_TIME, kSetDisplayElapseTime); write64(time); endCommand(); } protected: // Commands from ::android::hardware::graphics::composer::V2_1::IComposerClient follow. void beginCommand(IQtiComposerClient::Command command, uint16_t length) { if (mCommandEnd) { LOG_FATAL("endCommand was not called before command 0x%x", command); } growData(1 + length); write(static_cast(command) | length); mCommandEnd = mDataWritten + length; } void endCommand() { if (!mCommandEnd) { LOG_FATAL("beginCommand was not called"); } else if (mDataWritten > mCommandEnd) { LOG_FATAL("too much data written"); mDataWritten = mCommandEnd; } else if (mDataWritten < mCommandEnd) { LOG_FATAL("too little data written"); while (mDataWritten < mCommandEnd) { write(0); } } mCommandEnd = 0; } void write(uint32_t val) { mData[mDataWritten++] = val; } void writeSigned(int32_t val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); } void writeFloat(float val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); } void write64(uint64_t val) { uint32_t lo = static_cast(val & 0xffffffff); uint32_t hi = static_cast(val >> 32); write(lo); write(hi); } void writeRect(const IQtiComposerClient::Rect& rect) { writeSigned(rect.left); writeSigned(rect.top); writeSigned(rect.right); writeSigned(rect.bottom); } void writeRegion(const std::vector& region) { for (const auto& rect : region) { writeRect(rect); } } void writeFRect(const IQtiComposerClient::FRect& rect) { writeFloat(rect.left); writeFloat(rect.top); writeFloat(rect.right); writeFloat(rect.bottom); } void writeColor(const IQtiComposerClient::Color& color) { write((color.r << 0) | (color.g << 8) | (color.b << 16) | (color.a << 24)); } // ownership of handle is not transferred void writeHandle(const native_handle_t* handle, bool useCache) { if (!handle) { writeSigned(static_cast((useCache) ? IQtiComposerClient::HandleIndex::CACHED : IQtiComposerClient::HandleIndex::EMPTY)); return; } mDataHandles.push_back(handle); writeSigned(mDataHandles.size() - 1); } void writeHandle(const native_handle_t* handle) { writeHandle(handle, false); } // Handle would own fence hereafter. Hence provide a dupped fd. void writeFence(const shared_ptr& fence) { native_handle_t* handle = nullptr; if (fence) { handle = getTemporaryHandle(1, 0); if (handle) { handle->data[0] = Fence::Dup(fence); } else { ALOGW("failed to get temporary handle for fence %s", Fence::GetStr(fence).c_str()); Fence::Wait(fence); } } writeHandle(handle); } native_handle_t* getTemporaryHandle(int numFds, int numInts) { native_handle_t* handle = native_handle_create(numFds, numInts); if (handle) { mTemporaryHandles.push_back(handle); } return handle; } static constexpr uint16_t kMaxLength = std::numeric_limits::max(); // Commands from ::android::hardware::graphics::composer::V2_2::IComposerClient follow. void writeFloatColor(const IQtiComposerClient::FloatColor& color) { writeFloat(color.r); writeFloat(color.g); writeFloat(color.b); writeFloat(color.a); } // Commands from ::android::hardware::graphics::composer::V2_3::IComposerClient follow. void writeBlob(uint32_t length, const unsigned char* blob) { memcpy(&mData[mDataWritten], blob, length); uint32_t numElements = length / 4; mDataWritten += numElements; mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0; } private: void growData(uint32_t grow) { uint32_t newWritten = mDataWritten + grow; if (newWritten < mDataWritten) { LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32 ", growing by %" PRIu32, mDataWritten, grow); } if (newWritten <= mDataMaxSize) { return; } uint32_t newMaxSize = mDataMaxSize << 1; if (newMaxSize < newWritten) { newMaxSize = newWritten; } auto newData = std::make_unique(newMaxSize); std::copy_n(mData.get(), mDataWritten, newData.get()); mDataMaxSize = newMaxSize; mData = std::move(newData); } uint32_t mDataMaxSize; std::unique_ptr mData; uint32_t mDataWritten; // end offset of the current command uint32_t mCommandEnd; std::vector mDataHandles; std::vector mTemporaryHandles; std::unique_ptr mQueue; }; // This class helps parse a command queue. Note that all sizes/lengths are in units of uint32_t's. class CommandReaderBase { public: CommandReaderBase() : mDataMaxSize(0) { reset(); } bool setMQDescriptor(const MQDescriptorSync& descriptor) { mQueue = std::make_unique(descriptor, false); if (mQueue->isValid()) { return true; } else { mQueue = nullptr; return false; } } bool readQueue(uint32_t commandLength, const hidl_vec& commandHandles) { if (!mQueue) { return false; } auto quantumCount = mQueue->getQuantumCount(); if (mDataMaxSize < quantumCount) { mDataMaxSize = quantumCount; mData = std::make_unique(mDataMaxSize); } if (commandLength > mDataMaxSize || !mQueue->read(mData.get(), commandLength)) { ALOGE("failed to read commands from message queue"); return false; } mDataSize = commandLength; mDataRead = 0; mCommandBegin = 0; mCommandEnd = 0; mDataHandles.setToExternal(const_cast(commandHandles.data()), commandHandles.size()); return true; } void reset() { mDataSize = 0; mDataRead = 0; mCommandBegin = 0; mCommandEnd = 0; mDataHandles.setToExternal(nullptr, 0); } protected: bool isEmpty() const { return (mDataRead >= mDataSize); } bool beginCommand(IQtiComposerClient::Command& command, uint16_t& length) { if (mCommandEnd) { LOG_FATAL("endCommand was not called before command 0x%x", command); } constexpr uint32_t opcode_mask = static_cast(IQtiComposerClient::Command::OPCODE_MASK); constexpr uint32_t length_mask = static_cast(IQtiComposerClient::Command::LENGTH_MASK); uint32_t val = read(); command = static_cast(val & opcode_mask); length = static_cast(val & length_mask); if (mDataRead + length > mDataSize) { ALOGE("command 0x%x has invalid command length %" PRIu16, command, length); // undo the read() above mDataRead--; return false; } mCommandEnd = mDataRead + length; return true; } void endCommand() { if (!mCommandEnd) { LOG_FATAL("beginCommand was not called"); } else if (mDataRead > mCommandEnd) { LOG_FATAL("too much data read"); mDataRead = mCommandEnd; } else if (mDataRead < mCommandEnd) { LOG_FATAL("too little data read"); mDataRead = mCommandEnd; } mCommandBegin = mCommandEnd; mCommandEnd = 0; } uint32_t getCommandLoc() const { return mCommandBegin; } uint32_t read() { return mData[mDataRead++]; } int32_t readSigned() { int32_t val; memcpy(&val, &mData[mDataRead++], sizeof(val)); return val; } float readFloat() { float val; memcpy(&val, &mData[mDataRead++], sizeof(val)); return val; } uint64_t read64() { uint32_t lo = read(); uint32_t hi = read(); return (static_cast(hi) << 32) | lo; } void readBlob(uint32_t size, void* blob) { memcpy(blob, &mData[mDataRead], size); uint32_t numElements = size / sizeof(uint32_t); mDataRead += numElements; mDataRead += (size - numElements * sizeof(uint32_t) != 0) ? 1 : 0; } IQtiComposerClient::Color readColor() { uint32_t val = read(); return IQtiComposerClient::Color{ static_cast((val >> 0) & 0xff), static_cast((val >> 8) & 0xff), static_cast((val >> 16) & 0xff), static_cast((val >> 24) & 0xff), }; } // ownership of handle is not transferred const native_handle_t* readHandle(bool& useCache) { const native_handle_t* handle = nullptr; int32_t index = readSigned(); switch (index) { case static_cast(IQtiComposerClient::HandleIndex::EMPTY): useCache = false; break; case static_cast(IQtiComposerClient::HandleIndex::CACHED): useCache = true; break; default: if (static_cast(index) < mDataHandles.size()) { handle = mDataHandles[index].getNativeHandle(); } else { ALOGE("invalid handle index %zu", static_cast(index)); } useCache = false; break; } return handle; } const native_handle_t* readHandle() { bool useCache; return readHandle(useCache); } // Handle would still own original fence. Hence create a Fence object on duped fd. void readFence(shared_ptr* fence, const string &name) { auto handle = readHandle(); if (!handle || handle->numFds == 0) { return; } if (handle->numFds != 1) { ALOGE("invalid fence handle with %d fds", handle->numFds); return; } *fence = Fence::Create(dup(handle->data[0]), name); if (*fence == nullptr) { ALOGW("failed to dup fence %d", handle->data[0]); sync_wait(handle->data[0], -1); } } private: std::unique_ptr mQueue; uint32_t mDataMaxSize; std::unique_ptr mData; uint32_t mDataSize; uint32_t mDataRead; // begin/end offsets of the current command uint32_t mCommandBegin; uint32_t mCommandEnd; hidl_vec mDataHandles; }; } // namespace V3_0 } // namespace composer } // namespace display } // namespace hardware } // namespace qti } // namespace vendor #endif // __QTICOMPOSERCOMMANDBUFFER_H__