1/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gui/BufferItem.h>
18
19#include <ui/Fence.h>
20#include <ui/GraphicBuffer.h>
21
22#include <system/window.h>
23
24namespace android {
25
26template<typename T>
27static inline constexpr uint32_t low32(const T n) {
28    return static_cast<uint32_t>(static_cast<uint64_t>(n));
29}
30
31template<typename T>
32static inline constexpr uint32_t high32(const T n) {
33    return static_cast<uint32_t>(static_cast<uint64_t>(n)>>32);
34}
35
36template<typename T>
37static inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
38    return static_cast<T>(static_cast<uint64_t>(hi)<<32 | lo);
39}
40
41BufferItem::BufferItem() :
42    mGraphicBuffer(NULL),
43    mFence(NULL),
44    mCrop(Rect::INVALID_RECT),
45    mTransform(0),
46    mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
47    mTimestamp(0),
48    mIsAutoTimestamp(false),
49    mDataSpace(HAL_DATASPACE_UNKNOWN),
50    mFrameNumber(0),
51    mSlot(INVALID_BUFFER_SLOT),
52    mIsDroppable(false),
53    mAcquireCalled(false),
54    mTransformToDisplayInverse(false),
55    mSurfaceDamage(),
56    mAutoRefresh(false),
57    mQueuedBuffer(true),
58    mIsStale(false) {
59}
60
61BufferItem::~BufferItem() {}
62
63template <typename T>
64static void addAligned(size_t& size, T /* value */) {
65    size = FlattenableUtils::align<sizeof(T)>(size);
66    size += sizeof(T);
67}
68
69size_t BufferItem::getPodSize() const {
70    size_t size = 0;
71    addAligned(size, mCrop);
72    addAligned(size, mTransform);
73    addAligned(size, mScalingMode);
74    addAligned(size, low32(mTimestamp));
75    addAligned(size, high32(mTimestamp));
76    addAligned(size, mIsAutoTimestamp);
77    addAligned(size, mDataSpace);
78    addAligned(size, low32(mFrameNumber));
79    addAligned(size, high32(mFrameNumber));
80    addAligned(size, mSlot);
81    addAligned(size, mIsDroppable);
82    addAligned(size, mAcquireCalled);
83    addAligned(size, mTransformToDisplayInverse);
84    addAligned(size, mAutoRefresh);
85    addAligned(size, mQueuedBuffer);
86    addAligned(size, mIsStale);
87    return size;
88}
89
90size_t BufferItem::getFlattenedSize() const {
91    size_t size = sizeof(uint32_t); // Flags
92    if (mGraphicBuffer != 0) {
93        size += mGraphicBuffer->getFlattenedSize();
94        size = FlattenableUtils::align<4>(size);
95    }
96    if (mFence != 0) {
97        size += mFence->getFlattenedSize();
98        size = FlattenableUtils::align<4>(size);
99    }
100    size += mSurfaceDamage.getFlattenedSize();
101    size = FlattenableUtils::align<8>(size);
102    return size + getPodSize();
103}
104
105size_t BufferItem::getFdCount() const {
106    size_t count = 0;
107    if (mGraphicBuffer != 0) {
108        count += mGraphicBuffer->getFdCount();
109    }
110    if (mFence != 0) {
111        count += mFence->getFdCount();
112    }
113    return count;
114}
115
116template <typename T>
117static void writeAligned(void*& buffer, size_t& size, T value) {
118    size -= FlattenableUtils::align<alignof(T)>(buffer);
119    FlattenableUtils::write(buffer, size, value);
120}
121
122status_t BufferItem::flatten(
123        void*& buffer, size_t& size, int*& fds, size_t& count) const {
124
125    // make sure we have enough space
126    if (size < BufferItem::getFlattenedSize()) {
127        return NO_MEMORY;
128    }
129
130    // content flags are stored first
131    uint32_t& flags = *static_cast<uint32_t*>(buffer);
132
133    // advance the pointer
134    FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
135
136    flags = 0;
137    if (mGraphicBuffer != 0) {
138        status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
139        if (err) return err;
140        size -= FlattenableUtils::align<4>(buffer);
141        flags |= 1;
142    }
143    if (mFence != 0) {
144        status_t err = mFence->flatten(buffer, size, fds, count);
145        if (err) return err;
146        size -= FlattenableUtils::align<4>(buffer);
147        flags |= 2;
148    }
149
150    status_t err = mSurfaceDamage.flatten(buffer, size);
151    if (err) return err;
152    FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
153
154    // Check we still have enough space
155    if (size < getPodSize()) {
156        return NO_MEMORY;
157    }
158
159    writeAligned(buffer, size, mCrop);
160    writeAligned(buffer, size, mTransform);
161    writeAligned(buffer, size, mScalingMode);
162    writeAligned(buffer, size, low32(mTimestamp));
163    writeAligned(buffer, size, high32(mTimestamp));
164    writeAligned(buffer, size, mIsAutoTimestamp);
165    writeAligned(buffer, size, mDataSpace);
166    writeAligned(buffer, size, low32(mFrameNumber));
167    writeAligned(buffer, size, high32(mFrameNumber));
168    writeAligned(buffer, size, mSlot);
169    writeAligned(buffer, size, mIsDroppable);
170    writeAligned(buffer, size, mAcquireCalled);
171    writeAligned(buffer, size, mTransformToDisplayInverse);
172    writeAligned(buffer, size, mAutoRefresh);
173    writeAligned(buffer, size, mQueuedBuffer);
174    writeAligned(buffer, size, mIsStale);
175
176    return NO_ERROR;
177}
178
179template <typename T>
180static void readAligned(const void*& buffer, size_t& size, T& value) {
181    size -= FlattenableUtils::align<alignof(T)>(buffer);
182    FlattenableUtils::read(buffer, size, value);
183}
184
185status_t BufferItem::unflatten(
186        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
187
188    if (size < sizeof(uint32_t)) {
189        return NO_MEMORY;
190    }
191
192    uint32_t flags = 0;
193    FlattenableUtils::read(buffer, size, flags);
194
195    if (flags & 1) {
196        mGraphicBuffer = new GraphicBuffer();
197        status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
198        if (err) return err;
199        size -= FlattenableUtils::align<4>(buffer);
200    }
201
202    if (flags & 2) {
203        mFence = new Fence();
204        status_t err = mFence->unflatten(buffer, size, fds, count);
205        if (err) return err;
206        size -= FlattenableUtils::align<4>(buffer);
207
208        mFenceTime = std::make_shared<FenceTime>(mFence);
209    }
210
211    status_t err = mSurfaceDamage.unflatten(buffer, size);
212    if (err) return err;
213    FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
214
215    // Check we still have enough space
216    if (size < getPodSize()) {
217        return NO_MEMORY;
218    }
219
220    uint32_t timestampLo = 0, timestampHi = 0;
221    uint32_t frameNumberLo = 0, frameNumberHi = 0;
222
223    readAligned(buffer, size, mCrop);
224    readAligned(buffer, size, mTransform);
225    readAligned(buffer, size, mScalingMode);
226    readAligned(buffer, size, timestampLo);
227    readAligned(buffer, size, timestampHi);
228    mTimestamp = to64<int64_t>(timestampLo, timestampHi);
229    readAligned(buffer, size, mIsAutoTimestamp);
230    readAligned(buffer, size, mDataSpace);
231    readAligned(buffer, size, frameNumberLo);
232    readAligned(buffer, size, frameNumberHi);
233    mFrameNumber = to64<uint64_t>(frameNumberLo, frameNumberHi);
234    readAligned(buffer, size, mSlot);
235    readAligned(buffer, size, mIsDroppable);
236    readAligned(buffer, size, mAcquireCalled);
237    readAligned(buffer, size, mTransformToDisplayInverse);
238    readAligned(buffer, size, mAutoRefresh);
239    readAligned(buffer, size, mQueuedBuffer);
240    readAligned(buffer, size, mIsStale);
241
242    return NO_ERROR;
243}
244
245const char* BufferItem::scalingModeName(uint32_t scalingMode) {
246    switch (scalingMode) {
247        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
248        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
249        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
250        default: return "Unknown";
251    }
252}
253
254} // namespace android
255