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    mApi(0) {
60}
61
62BufferItem::~BufferItem() {}
63
64template <typename T>
65static void addAligned(size_t& size, T /* value */) {
66    size = FlattenableUtils::align<sizeof(T)>(size);
67    size += sizeof(T);
68}
69
70size_t BufferItem::getPodSize() const {
71    size_t size = 0;
72    addAligned(size, mCrop);
73    addAligned(size, mTransform);
74    addAligned(size, mScalingMode);
75    addAligned(size, low32(mTimestamp));
76    addAligned(size, high32(mTimestamp));
77    addAligned(size, mIsAutoTimestamp);
78    addAligned(size, mDataSpace);
79    addAligned(size, low32(mFrameNumber));
80    addAligned(size, high32(mFrameNumber));
81    addAligned(size, mSlot);
82    addAligned(size, mIsDroppable);
83    addAligned(size, mAcquireCalled);
84    addAligned(size, mTransformToDisplayInverse);
85    addAligned(size, mAutoRefresh);
86    addAligned(size, mQueuedBuffer);
87    addAligned(size, mIsStale);
88    addAligned(size, mApi);
89    return size;
90}
91
92size_t BufferItem::getFlattenedSize() const {
93    size_t size = sizeof(uint32_t); // Flags
94    if (mGraphicBuffer != 0) {
95        size += mGraphicBuffer->getFlattenedSize();
96        size = FlattenableUtils::align<4>(size);
97    }
98    if (mFence != 0) {
99        size += mFence->getFlattenedSize();
100        size = FlattenableUtils::align<4>(size);
101    }
102    size += mSurfaceDamage.getFlattenedSize();
103    size += mHdrMetadata.getFlattenedSize();
104    size = FlattenableUtils::align<8>(size);
105    return size + getPodSize();
106}
107
108size_t BufferItem::getFdCount() const {
109    size_t count = 0;
110    if (mGraphicBuffer != 0) {
111        count += mGraphicBuffer->getFdCount();
112    }
113    if (mFence != 0) {
114        count += mFence->getFdCount();
115    }
116    return count;
117}
118
119template <typename T>
120static void writeAligned(void*& buffer, size_t& size, T value) {
121    size -= FlattenableUtils::align<alignof(T)>(buffer);
122    FlattenableUtils::write(buffer, size, value);
123}
124
125status_t BufferItem::flatten(
126        void*& buffer, size_t& size, int*& fds, size_t& count) const {
127
128    // make sure we have enough space
129    if (size < BufferItem::getFlattenedSize()) {
130        return NO_MEMORY;
131    }
132
133    // content flags are stored first
134    uint32_t& flags = *static_cast<uint32_t*>(buffer);
135
136    // advance the pointer
137    FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
138
139    flags = 0;
140    if (mGraphicBuffer != 0) {
141        status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
142        if (err) return err;
143        size -= FlattenableUtils::align<4>(buffer);
144        flags |= 1;
145    }
146    if (mFence != 0) {
147        status_t err = mFence->flatten(buffer, size, fds, count);
148        if (err) return err;
149        size -= FlattenableUtils::align<4>(buffer);
150        flags |= 2;
151    }
152
153    status_t err = mSurfaceDamage.flatten(buffer, size);
154    if (err) return err;
155    FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
156
157    err = mHdrMetadata.flatten(buffer, size);
158    if (err) return err;
159    FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
160
161    // Check we still have enough space
162    if (size < getPodSize()) {
163        return NO_MEMORY;
164    }
165
166    writeAligned(buffer, size, mCrop);
167    writeAligned(buffer, size, mTransform);
168    writeAligned(buffer, size, mScalingMode);
169    writeAligned(buffer, size, low32(mTimestamp));
170    writeAligned(buffer, size, high32(mTimestamp));
171    writeAligned(buffer, size, mIsAutoTimestamp);
172    writeAligned(buffer, size, mDataSpace);
173    writeAligned(buffer, size, low32(mFrameNumber));
174    writeAligned(buffer, size, high32(mFrameNumber));
175    writeAligned(buffer, size, mSlot);
176    writeAligned(buffer, size, mIsDroppable);
177    writeAligned(buffer, size, mAcquireCalled);
178    writeAligned(buffer, size, mTransformToDisplayInverse);
179    writeAligned(buffer, size, mAutoRefresh);
180    writeAligned(buffer, size, mQueuedBuffer);
181    writeAligned(buffer, size, mIsStale);
182    writeAligned(buffer, size, mApi);
183
184    return NO_ERROR;
185}
186
187template <typename T>
188static void readAligned(const void*& buffer, size_t& size, T& value) {
189    size -= FlattenableUtils::align<alignof(T)>(buffer);
190    FlattenableUtils::read(buffer, size, value);
191}
192
193status_t BufferItem::unflatten(
194        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
195
196    if (size < sizeof(uint32_t)) {
197        return NO_MEMORY;
198    }
199
200    uint32_t flags = 0;
201    FlattenableUtils::read(buffer, size, flags);
202
203    if (flags & 1) {
204        mGraphicBuffer = new GraphicBuffer();
205        status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
206        if (err) return err;
207        size -= FlattenableUtils::align<4>(buffer);
208    }
209
210    if (flags & 2) {
211        mFence = new Fence();
212        status_t err = mFence->unflatten(buffer, size, fds, count);
213        if (err) return err;
214        size -= FlattenableUtils::align<4>(buffer);
215
216        mFenceTime = std::make_shared<FenceTime>(mFence);
217    }
218
219    status_t err = mSurfaceDamage.unflatten(buffer, size);
220    if (err) return err;
221    FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
222
223    err = mHdrMetadata.unflatten(buffer, size);
224    if (err) return err;
225    FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
226
227    // Check we still have enough space
228    if (size < getPodSize()) {
229        return NO_MEMORY;
230    }
231
232    uint32_t timestampLo = 0, timestampHi = 0;
233    uint32_t frameNumberLo = 0, frameNumberHi = 0;
234
235    readAligned(buffer, size, mCrop);
236    readAligned(buffer, size, mTransform);
237    readAligned(buffer, size, mScalingMode);
238    readAligned(buffer, size, timestampLo);
239    readAligned(buffer, size, timestampHi);
240    mTimestamp = to64<int64_t>(timestampLo, timestampHi);
241    readAligned(buffer, size, mIsAutoTimestamp);
242    readAligned(buffer, size, mDataSpace);
243    readAligned(buffer, size, frameNumberLo);
244    readAligned(buffer, size, frameNumberHi);
245    mFrameNumber = to64<uint64_t>(frameNumberLo, frameNumberHi);
246    readAligned(buffer, size, mSlot);
247    readAligned(buffer, size, mIsDroppable);
248    readAligned(buffer, size, mAcquireCalled);
249    readAligned(buffer, size, mTransformToDisplayInverse);
250    readAligned(buffer, size, mAutoRefresh);
251    readAligned(buffer, size, mQueuedBuffer);
252    readAligned(buffer, size, mIsStale);
253    readAligned(buffer, size, mApi);
254
255    return NO_ERROR;
256}
257
258const char* BufferItem::scalingModeName(uint32_t scalingMode) {
259    switch (scalingMode) {
260        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
261        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
262        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
263        default: return "Unknown";
264    }
265}
266
267} // namespace android
268