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
26BufferItem::BufferItem() :
27    mGraphicBuffer(NULL),
28    mFence(NULL),
29    mCrop(Rect::INVALID_RECT),
30    mTransform(0),
31    mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
32    mTimestamp(0),
33    mIsAutoTimestamp(false),
34    mDataSpace(HAL_DATASPACE_UNKNOWN),
35    mFrameNumber(0),
36    mSlot(INVALID_BUFFER_SLOT),
37    mIsDroppable(false),
38    mAcquireCalled(false),
39    mTransformToDisplayInverse(false),
40    mSurfaceDamage(),
41    mAutoRefresh(false),
42    mQueuedBuffer(true),
43    mIsStale(false) {
44}
45
46BufferItem::~BufferItem() {}
47
48template <typename T>
49static void addAligned(size_t& size, T /* value */) {
50    size = FlattenableUtils::align<sizeof(T)>(size);
51    size += sizeof(T);
52}
53
54size_t BufferItem::getPodSize() const {
55    size_t size = 0;
56    addAligned(size, mCrop);
57    addAligned(size, mTransform);
58    addAligned(size, mScalingMode);
59    addAligned(size, mTimestampLo);
60    addAligned(size, mTimestampHi);
61    addAligned(size, mIsAutoTimestamp);
62    addAligned(size, mDataSpace);
63    addAligned(size, mFrameNumberLo);
64    addAligned(size, mFrameNumberHi);
65    addAligned(size, mSlot);
66    addAligned(size, mIsDroppable);
67    addAligned(size, mAcquireCalled);
68    addAligned(size, mTransformToDisplayInverse);
69    return size;
70}
71
72size_t BufferItem::getFlattenedSize() const {
73    size_t size = sizeof(uint32_t); // Flags
74    if (mGraphicBuffer != 0) {
75        size += mGraphicBuffer->getFlattenedSize();
76        FlattenableUtils::align<4>(size);
77    }
78    if (mFence != 0) {
79        size += mFence->getFlattenedSize();
80        FlattenableUtils::align<4>(size);
81    }
82    size += mSurfaceDamage.getFlattenedSize();
83    size = FlattenableUtils::align<8>(size);
84    return size + getPodSize();
85}
86
87size_t BufferItem::getFdCount() const {
88    size_t count = 0;
89    if (mGraphicBuffer != 0) {
90        count += mGraphicBuffer->getFdCount();
91    }
92    if (mFence != 0) {
93        count += mFence->getFdCount();
94    }
95    return count;
96}
97
98template <typename T>
99static void writeAligned(void*& buffer, size_t& size, T value) {
100    size -= FlattenableUtils::align<alignof(T)>(buffer);
101    FlattenableUtils::write(buffer, size, value);
102}
103
104status_t BufferItem::flatten(
105        void*& buffer, size_t& size, int*& fds, size_t& count) const {
106
107    // make sure we have enough space
108    if (size < BufferItem::getFlattenedSize()) {
109        return NO_MEMORY;
110    }
111
112    // content flags are stored first
113    uint32_t& flags = *static_cast<uint32_t*>(buffer);
114
115    // advance the pointer
116    FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
117
118    flags = 0;
119    if (mGraphicBuffer != 0) {
120        status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
121        if (err) return err;
122        size -= FlattenableUtils::align<4>(buffer);
123        flags |= 1;
124    }
125    if (mFence != 0) {
126        status_t err = mFence->flatten(buffer, size, fds, count);
127        if (err) return err;
128        size -= FlattenableUtils::align<4>(buffer);
129        flags |= 2;
130    }
131
132    status_t err = mSurfaceDamage.flatten(buffer, size);
133    if (err) return err;
134    FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
135
136    // Check we still have enough space
137    if (size < getPodSize()) {
138        return NO_MEMORY;
139    }
140
141    writeAligned(buffer, size, mCrop);
142    writeAligned(buffer, size, mTransform);
143    writeAligned(buffer, size, mScalingMode);
144    writeAligned(buffer, size, mTimestampLo);
145    writeAligned(buffer, size, mTimestampHi);
146    writeAligned(buffer, size, mIsAutoTimestamp);
147    writeAligned(buffer, size, mDataSpace);
148    writeAligned(buffer, size, mFrameNumberLo);
149    writeAligned(buffer, size, mFrameNumberHi);
150    writeAligned(buffer, size, mSlot);
151    writeAligned(buffer, size, mIsDroppable);
152    writeAligned(buffer, size, mAcquireCalled);
153    writeAligned(buffer, size, mTransformToDisplayInverse);
154
155    return NO_ERROR;
156}
157
158template <typename T>
159static void readAligned(const void*& buffer, size_t& size, T& value) {
160    size -= FlattenableUtils::align<alignof(T)>(buffer);
161    FlattenableUtils::read(buffer, size, value);
162}
163
164status_t BufferItem::unflatten(
165        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
166
167    if (size < sizeof(uint32_t)) {
168        return NO_MEMORY;
169    }
170
171    uint32_t flags = 0;
172    FlattenableUtils::read(buffer, size, flags);
173
174    if (flags & 1) {
175        mGraphicBuffer = new GraphicBuffer();
176        status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
177        if (err) return err;
178        size -= FlattenableUtils::align<4>(buffer);
179    }
180
181    if (flags & 2) {
182        mFence = new Fence();
183        status_t err = mFence->unflatten(buffer, size, fds, count);
184        if (err) return err;
185        size -= FlattenableUtils::align<4>(buffer);
186    }
187
188    status_t err = mSurfaceDamage.unflatten(buffer, size);
189    if (err) return err;
190    FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
191
192    // Check we still have enough space
193    if (size < getPodSize()) {
194        return NO_MEMORY;
195    }
196
197    readAligned(buffer, size, mCrop);
198    readAligned(buffer, size, mTransform);
199    readAligned(buffer, size, mScalingMode);
200    readAligned(buffer, size, mTimestampLo);
201    readAligned(buffer, size, mTimestampHi);
202    readAligned(buffer, size, mIsAutoTimestamp);
203    readAligned(buffer, size, mDataSpace);
204    readAligned(buffer, size, mFrameNumberLo);
205    readAligned(buffer, size, mFrameNumberHi);
206    readAligned(buffer, size, mSlot);
207    readAligned(buffer, size, mIsDroppable);
208    readAligned(buffer, size, mAcquireCalled);
209    readAligned(buffer, size, mTransformToDisplayInverse);
210
211    return NO_ERROR;
212}
213
214const char* BufferItem::scalingModeName(uint32_t scalingMode) {
215    switch (scalingMode) {
216        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
217        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
218        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
219        default: return "Unknown";
220    }
221}
222
223} // namespace android
224