| /* |
| * Copyright 2014 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 <gui/BufferItem.h> |
| |
| #include <ui/Fence.h> |
| #include <ui/GraphicBuffer.h> |
| |
| #include <system/window.h> |
| |
| namespace android { |
| |
| template<typename T> |
| static inline constexpr uint32_t low32(const T n) { |
| return static_cast<uint32_t>(static_cast<uint64_t>(n)); |
| } |
| |
| template<typename T> |
| static inline constexpr uint32_t high32(const T n) { |
| return static_cast<uint32_t>(static_cast<uint64_t>(n)>>32); |
| } |
| |
| template<typename T> |
| static inline constexpr T to64(const uint32_t lo, const uint32_t hi) { |
| return static_cast<T>(static_cast<uint64_t>(hi)<<32 | lo); |
| } |
| |
| BufferItem::BufferItem() : |
| mGraphicBuffer(NULL), |
| mFence(NULL), |
| mCrop(Rect::INVALID_RECT), |
| mTransform(0), |
| mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), |
| mTimestamp(0), |
| mIsAutoTimestamp(false), |
| mDataSpace(HAL_DATASPACE_UNKNOWN), |
| mFrameNumber(0), |
| mSlot(INVALID_BUFFER_SLOT), |
| mIsDroppable(false), |
| mAcquireCalled(false), |
| mTransformToDisplayInverse(false), |
| mSurfaceDamage(), |
| mAutoRefresh(false), |
| mQueuedBuffer(true), |
| mIsStale(false) { |
| } |
| |
| BufferItem::~BufferItem() {} |
| |
| template <typename T> |
| static void addAligned(size_t& size, T /* value */) { |
| size = FlattenableUtils::align<sizeof(T)>(size); |
| size += sizeof(T); |
| } |
| |
| size_t BufferItem::getPodSize() const { |
| size_t size = 0; |
| addAligned(size, mCrop); |
| addAligned(size, mTransform); |
| addAligned(size, mScalingMode); |
| addAligned(size, low32(mTimestamp)); |
| addAligned(size, high32(mTimestamp)); |
| addAligned(size, mIsAutoTimestamp); |
| addAligned(size, mDataSpace); |
| addAligned(size, low32(mFrameNumber)); |
| addAligned(size, high32(mFrameNumber)); |
| addAligned(size, mSlot); |
| addAligned(size, mIsDroppable); |
| addAligned(size, mAcquireCalled); |
| addAligned(size, mTransformToDisplayInverse); |
| addAligned(size, mAutoRefresh); |
| addAligned(size, mQueuedBuffer); |
| addAligned(size, mIsStale); |
| return size; |
| } |
| |
| size_t BufferItem::getFlattenedSize() const { |
| size_t size = sizeof(uint32_t); // Flags |
| if (mGraphicBuffer != 0) { |
| size += mGraphicBuffer->getFlattenedSize(); |
| size = FlattenableUtils::align<4>(size); |
| } |
| if (mFence != 0) { |
| size += mFence->getFlattenedSize(); |
| size = FlattenableUtils::align<4>(size); |
| } |
| size += mSurfaceDamage.getFlattenedSize(); |
| size = FlattenableUtils::align<8>(size); |
| return size + getPodSize(); |
| } |
| |
| size_t BufferItem::getFdCount() const { |
| size_t count = 0; |
| if (mGraphicBuffer != 0) { |
| count += mGraphicBuffer->getFdCount(); |
| } |
| if (mFence != 0) { |
| count += mFence->getFdCount(); |
| } |
| return count; |
| } |
| |
| template <typename T> |
| static void writeAligned(void*& buffer, size_t& size, T value) { |
| size -= FlattenableUtils::align<alignof(T)>(buffer); |
| FlattenableUtils::write(buffer, size, value); |
| } |
| |
| status_t BufferItem::flatten( |
| void*& buffer, size_t& size, int*& fds, size_t& count) const { |
| |
| // make sure we have enough space |
| if (size < BufferItem::getFlattenedSize()) { |
| return NO_MEMORY; |
| } |
| |
| // content flags are stored first |
| uint32_t& flags = *static_cast<uint32_t*>(buffer); |
| |
| // advance the pointer |
| FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); |
| |
| flags = 0; |
| if (mGraphicBuffer != 0) { |
| status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); |
| if (err) return err; |
| size -= FlattenableUtils::align<4>(buffer); |
| flags |= 1; |
| } |
| if (mFence != 0) { |
| status_t err = mFence->flatten(buffer, size, fds, count); |
| if (err) return err; |
| size -= FlattenableUtils::align<4>(buffer); |
| flags |= 2; |
| } |
| |
| status_t err = mSurfaceDamage.flatten(buffer, size); |
| if (err) return err; |
| FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); |
| |
| // Check we still have enough space |
| if (size < getPodSize()) { |
| return NO_MEMORY; |
| } |
| |
| writeAligned(buffer, size, mCrop); |
| writeAligned(buffer, size, mTransform); |
| writeAligned(buffer, size, mScalingMode); |
| writeAligned(buffer, size, low32(mTimestamp)); |
| writeAligned(buffer, size, high32(mTimestamp)); |
| writeAligned(buffer, size, mIsAutoTimestamp); |
| writeAligned(buffer, size, mDataSpace); |
| writeAligned(buffer, size, low32(mFrameNumber)); |
| writeAligned(buffer, size, high32(mFrameNumber)); |
| writeAligned(buffer, size, mSlot); |
| writeAligned(buffer, size, mIsDroppable); |
| writeAligned(buffer, size, mAcquireCalled); |
| writeAligned(buffer, size, mTransformToDisplayInverse); |
| writeAligned(buffer, size, mAutoRefresh); |
| writeAligned(buffer, size, mQueuedBuffer); |
| writeAligned(buffer, size, mIsStale); |
| |
| return NO_ERROR; |
| } |
| |
| template <typename T> |
| static void readAligned(const void*& buffer, size_t& size, T& value) { |
| size -= FlattenableUtils::align<alignof(T)>(buffer); |
| FlattenableUtils::read(buffer, size, value); |
| } |
| |
| status_t BufferItem::unflatten( |
| void const*& buffer, size_t& size, int const*& fds, size_t& count) { |
| |
| if (size < sizeof(uint32_t)) { |
| return NO_MEMORY; |
| } |
| |
| uint32_t flags = 0; |
| FlattenableUtils::read(buffer, size, flags); |
| |
| if (flags & 1) { |
| mGraphicBuffer = new GraphicBuffer(); |
| status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); |
| if (err) return err; |
| size -= FlattenableUtils::align<4>(buffer); |
| } |
| |
| if (flags & 2) { |
| mFence = new Fence(); |
| status_t err = mFence->unflatten(buffer, size, fds, count); |
| if (err) return err; |
| size -= FlattenableUtils::align<4>(buffer); |
| |
| mFenceTime = std::make_shared<FenceTime>(mFence); |
| } |
| |
| status_t err = mSurfaceDamage.unflatten(buffer, size); |
| if (err) return err; |
| FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); |
| |
| // Check we still have enough space |
| if (size < getPodSize()) { |
| return NO_MEMORY; |
| } |
| |
| uint32_t timestampLo = 0, timestampHi = 0; |
| uint32_t frameNumberLo = 0, frameNumberHi = 0; |
| |
| readAligned(buffer, size, mCrop); |
| readAligned(buffer, size, mTransform); |
| readAligned(buffer, size, mScalingMode); |
| readAligned(buffer, size, timestampLo); |
| readAligned(buffer, size, timestampHi); |
| mTimestamp = to64<int64_t>(timestampLo, timestampHi); |
| readAligned(buffer, size, mIsAutoTimestamp); |
| readAligned(buffer, size, mDataSpace); |
| readAligned(buffer, size, frameNumberLo); |
| readAligned(buffer, size, frameNumberHi); |
| mFrameNumber = to64<uint64_t>(frameNumberLo, frameNumberHi); |
| readAligned(buffer, size, mSlot); |
| readAligned(buffer, size, mIsDroppable); |
| readAligned(buffer, size, mAcquireCalled); |
| readAligned(buffer, size, mTransformToDisplayInverse); |
| readAligned(buffer, size, mAutoRefresh); |
| readAligned(buffer, size, mQueuedBuffer); |
| readAligned(buffer, size, mIsStale); |
| |
| return NO_ERROR; |
| } |
| |
| const char* BufferItem::scalingModeName(uint32_t scalingMode) { |
| switch (scalingMode) { |
| case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; |
| case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; |
| case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; |
| default: return "Unknown"; |
| } |
| } |
| |
| } // namespace android |