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 
24 namespace android {
25 
26 template<typename T>
low32(const T n)27 static inline constexpr uint32_t low32(const T n) {
28     return static_cast<uint32_t>(static_cast<uint64_t>(n));
29 }
30 
31 template<typename T>
high32(const T n)32 static inline constexpr uint32_t high32(const T n) {
33     return static_cast<uint32_t>(static_cast<uint64_t>(n)>>32);
34 }
35 
36 template<typename T>
to64(const uint32_t lo,const uint32_t hi)37 static 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 
BufferItem()41 BufferItem::BufferItem() :
42     mGraphicBuffer(nullptr),
43     mFence(nullptr),
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 
~BufferItem()62 BufferItem::~BufferItem() {}
63 
64 template <typename T>
addAligned(size_t & size,T)65 static void addAligned(size_t& size, T /* value */) {
66     size = FlattenableUtils::align<sizeof(T)>(size);
67     size += sizeof(T);
68 }
69 
getPodSize() const70 size_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 
getFlattenedSize() const92 size_t BufferItem::getFlattenedSize() const {
93     size_t size = sizeof(uint32_t); // Flags
94     if (mGraphicBuffer != nullptr) {
95         size += mGraphicBuffer->getFlattenedSize();
96         size = FlattenableUtils::align<4>(size);
97     }
98     if (mFence != nullptr) {
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 
getFdCount() const108 size_t BufferItem::getFdCount() const {
109     size_t count = 0;
110     if (mGraphicBuffer != nullptr) {
111         count += mGraphicBuffer->getFdCount();
112     }
113     if (mFence != nullptr) {
114         count += mFence->getFdCount();
115     }
116     return count;
117 }
118 
119 template <typename T>
writeAligned(void * & buffer,size_t & size,T value)120 static void writeAligned(void*& buffer, size_t& size, T value) {
121     size -= FlattenableUtils::align<alignof(T)>(buffer);
122     FlattenableUtils::write(buffer, size, value);
123 }
124 
flatten(void * & buffer,size_t & size,int * & fds,size_t & count) const125 status_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 != nullptr) {
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 != nullptr) {
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 
187 template <typename T>
readAligned(const void * & buffer,size_t & size,T & value)188 static 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 
unflatten(void const * & buffer,size_t & size,int const * & fds,size_t & count)193 status_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 
scalingModeName(uint32_t scalingMode)258 const 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