| /* |
| * Copyright (c) 2019-2021, 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 <log/log.h> |
| #include <sync/sync.h> |
| #include <fmq/MessageQueue.h> |
| #include <hidl/MQDescriptor.h> |
| #include <utils/fence.h> |
| |
| #include <limits> |
| #include <algorithm> |
| #include <vector> |
| #include <string> |
| |
| 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<uint32_t, ::android::hardware::kSynchronizedReadWrite>; |
| |
| 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<uint32_t[]>(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<IQtiComposerClient::Command>(val & |
| static_cast<uint32_t>(IQtiComposerClient::Command::OPCODE_MASK)); |
| } |
| |
| bool writeQueue(bool& queueChanged, uint32_t& commandLength, |
| hidl_vec<hidl_handle>& 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<CommandQueueType>(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<hidl_handle*>(mDataHandles.data()), |
| mDataHandles.size()); |
| |
| return true; |
| } |
| |
| const MQDescriptorSync<uint32_t>* 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<int32_t>(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<Layer>& layers, |
| const std::vector<IQtiComposerClient::Composition>& 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<size_t>(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<int32_t>(types[currentLayer + i])); |
| } |
| endCommand(); |
| |
| currentLayer += count; |
| } |
| } |
| |
| void setDisplayRequests(uint32_t displayRequestMask, const std::vector<Layer>& layers, |
| const std::vector<uint32_t>& 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<size_t>(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<int32_t>(layerRequestMasks[currentLayer + i])); |
| } |
| endCommand(); |
| |
| currentLayer += count; |
| } |
| } |
| |
| static constexpr uint16_t kSetPresentFenceLength = 1; |
| void setPresentFence(const shared_ptr<Fence> &presentFence) { |
| beginCommand(IQtiComposerClient::Command::SET_PRESENT_FENCE, kSetPresentFenceLength); |
| writeFence(presentFence); |
| endCommand(); |
| } |
| |
| void setReleaseFences(const std::vector<Layer>& layers, |
| const std::vector<shared_ptr<Fence>>& 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<size_t>(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<int32_t>(hint)); |
| endCommand(); |
| } |
| |
| void setClientTarget(uint32_t slot, const native_handle_t* target, |
| const shared_ptr<Fence>& acquireFence, Dataspace dataspace, |
| const std::vector<IQtiComposerClient::Rect>& 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<int32_t>(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<Fence>& 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<Fence>& acquireFence) { |
| beginCommand(IQtiComposerClient::Command::SET_LAYER_BUFFER, kSetLayerBufferLength); |
| write(slot); |
| writeHandle(buffer, true); |
| writeFence(acquireFence); |
| endCommand(); |
| } |
| |
| void setLayerSurfaceDamage(const std::vector<IQtiComposerClient::Rect>& 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<int32_t>(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<int32_t>(type)); |
| endCommand(); |
| } |
| |
| static constexpr uint16_t kSetLayerDataspaceLength = 1; |
| void setLayerDataspace(Dataspace dataspace) { |
| beginCommand(IQtiComposerClient::Command::SET_LAYER_DATASPACE, kSetLayerDataspaceLength); |
| writeSigned(static_cast<int32_t>(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<int32_t>(transform)); |
| endCommand(); |
| } |
| |
| void setLayerVisibleRegion(const std::vector<IQtiComposerClient::Rect>& 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<IQtiComposerClient::PerFrameMetadata>& metadataVec) { |
| beginCommand(IQtiComposerClient::Command::SET_LAYER_PER_FRAME_METADATA, |
| metadataVec.size() * 2); |
| for (const auto& metadata : metadataVec) { |
| writeSigned(static_cast<int32_t>(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<IQtiComposerClient::PerFrameMetadataBlob>& metadata) { |
| size_t commandLength = 0; |
| |
| if (metadata.size() > std::numeric_limits<uint32_t>::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<uint16_t>::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<uint16_t>(commandLength); |
| beginCommand(IQtiComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length); |
| write(static_cast<uint32_t>(metadata.size())); |
| for (auto metadataBlob : metadata) { |
| writeSigned(static_cast<int32_t>(metadataBlob.key)); |
| write(static_cast<uint32_t>(metadataBlob.blob.size())); |
| writeBlob(static_cast<uint32_t>(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(); |
| } |
| |
| // Commands from ::android::hardware::graphics::composer::V2_4::IComposerClient follow. |
| static constexpr uint16_t kSetClientTargetPropertyLength = 2; |
| void setClientTargetProperty( |
| const IQtiComposerClient::ClientTargetProperty& clientTargetProperty) { |
| beginCommand(IQtiComposerClient::Command::SET_CLIENT_TARGET_PROPERTY, |
| kSetClientTargetPropertyLength); |
| writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat)); |
| writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace)); |
| 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<uint32_t>(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<uint32_t>(val & 0xffffffff); |
| uint32_t hi = static_cast<uint32_t>(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<IQtiComposerClient::Rect>& 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<int32_t>((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>& 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<uint16_t>::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<uint32_t[]>(newMaxSize); |
| std::copy_n(mData.get(), mDataWritten, newData.get()); |
| mDataMaxSize = newMaxSize; |
| mData = std::move(newData); |
| } |
| |
| uint32_t mDataMaxSize; |
| std::unique_ptr<uint32_t[]> mData; |
| |
| uint32_t mDataWritten; |
| // end offset of the current command |
| uint32_t mCommandEnd; |
| |
| std::vector<hidl_handle> mDataHandles; |
| std::vector<native_handle_t *> mTemporaryHandles; |
| |
| std::unique_ptr<CommandQueueType> 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<uint32_t>& descriptor) { |
| mQueue = std::make_unique<CommandQueueType>(descriptor, false); |
| if (mQueue->isValid()) { |
| return true; |
| } else { |
| mQueue = nullptr; |
| return false; |
| } |
| } |
| |
| bool readQueue(uint32_t commandLength, const hidl_vec<hidl_handle>& commandHandles) { |
| if (!mQueue) { |
| return false; |
| } |
| |
| auto quantumCount = mQueue->getQuantumCount(); |
| if (mDataMaxSize < quantumCount) { |
| mDataMaxSize = quantumCount; |
| mData = std::make_unique<uint32_t[]>(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<hidl_handle*>(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<uint32_t>(IQtiComposerClient::Command::OPCODE_MASK); |
| constexpr uint32_t length_mask = |
| static_cast<uint32_t>(IQtiComposerClient::Command::LENGTH_MASK); |
| |
| uint32_t val = read(); |
| command = static_cast<IQtiComposerClient::Command>(val & opcode_mask); |
| length = static_cast<uint16_t>(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<uint64_t>(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<uint8_t>((val >> 0) & 0xff), |
| static_cast<uint8_t>((val >> 8) & 0xff), |
| static_cast<uint8_t>((val >> 16) & 0xff), |
| static_cast<uint8_t>((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<int32_t>(IQtiComposerClient::HandleIndex::EMPTY): |
| useCache = false; |
| break; |
| case static_cast<int32_t>(IQtiComposerClient::HandleIndex::CACHED): |
| useCache = true; |
| break; |
| default: |
| if (static_cast<size_t>(index) < mDataHandles.size()) { |
| handle = mDataHandles[index].getNativeHandle(); |
| } else { |
| ALOGE("invalid handle index %zu", static_cast<size_t>(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>* 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<CommandQueueType> mQueue; |
| uint32_t mDataMaxSize; |
| std::unique_ptr<uint32_t[]> mData; |
| |
| uint32_t mDataSize; |
| uint32_t mDataRead; |
| |
| // begin/end offsets of the current command |
| uint32_t mCommandBegin; |
| uint32_t mCommandEnd; |
| |
| hidl_vec<hidl_handle> mDataHandles; |
| }; |
| |
| } // namespace V3_0 |
| } // namespace composer |
| } // namespace display |
| } // namespace hardware |
| } // namespace qti |
| } // namespace vendor |
| |
| #endif // __QTICOMPOSERCOMMANDBUFFER_H__ |