• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 //#define LOG_NDEBUG 0
17 #define LOG_TAG "C2IgbaBuffer"
18 #include <android-base/logging.h>
19 #include <aidl/android/hardware/media/c2/IGraphicBufferAllocator.h>
20 #include <vndk/hardware_buffer.h>
21 #include <utils/Log.h>
22 
23 #include <C2AllocatorGralloc.h>
24 #include <C2BlockInternal.h>
25 #include <C2FenceFactory.h>
26 #include <C2IgbaBufferPriv.h>
27 #include <C2PlatformSupport.h>
28 
29 using ::android::C2AllocatorAhwb;
30 using C2IGBA = ::aidl::android::hardware::media::c2::IGraphicBufferAllocator;
31 
32 namespace {
ToAidl(uint32_t u)33 int32_t static inline ToAidl(uint32_t u) {return static_cast<int32_t>(u);}
ToAidl(uint64_t u)34 int64_t static inline ToAidl(uint64_t u) {return static_cast<int64_t>(u);}
35 
36 c2_nsecs_t static constexpr kBlockingFetchTimeoutNs = 5000000000LL; // 5 secs
37 c2_nsecs_t static constexpr kSyncFenceWaitNs = (1000000000LL / 60LL); // 60 fps frame secs
38 
CreateGraphicBlockFromAhwb(AHardwareBuffer * ahwb,const std::shared_ptr<C2Allocator> & allocator,const std::shared_ptr<C2IGBA> & igba,std::shared_ptr<C2GraphicBlock> * block)39 c2_status_t static CreateGraphicBlockFromAhwb(AHardwareBuffer *ahwb,
40                                             const std::shared_ptr<C2Allocator> &allocator,
41                                             const std::shared_ptr<C2IGBA> &igba,
42                                             std::shared_ptr<C2GraphicBlock> *block) {
43     if (__builtin_available(android __ANDROID_API_T__, *)) {
44         uint64_t origId = 0;
45         CHECK(AHardwareBuffer_getId(ahwb, &origId) == ::android::OK);
46 
47         AHardwareBuffer_Desc desc;
48         AHardwareBuffer_describe(ahwb, &desc);
49         const native_handle_t *handle = AHardwareBuffer_getNativeHandle(ahwb);
50         // cloned handle with wrapped data.(independent lifecycle with Ahwb)
51         C2Handle *c2Handle = android::WrapNativeCodec2AhwbHandle(
52                 handle,
53                 desc.width,
54                 desc.height,
55                 desc.format,
56                 desc.usage,
57                 desc.stride,
58                 origId);
59         if (!c2Handle) {
60             return C2_NO_MEMORY;
61         }
62         std::shared_ptr<C2GraphicAllocation> alloc;
63         c2_status_t err = allocator->priorGraphicAllocation(c2Handle, &alloc);
64         if (err != C2_OK) {
65             native_handle_close(c2Handle);
66             native_handle_delete(c2Handle);
67             return err;
68         }
69         std::shared_ptr<C2IgbaBlockPoolData> poolData =
70                 std::make_shared<C2IgbaBlockPoolData>(
71                         ahwb, const_cast<std::shared_ptr<C2IGBA>&>(igba));
72         *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
73         return C2_OK;
74     } else {
75         return C2_OMITTED;
76     }
77 }
78 
79 } // anonymous namespace
80 
C2IgbaBlockPoolData(const AHardwareBuffer * buffer,std::shared_ptr<C2IGBA> & igba)81 C2IgbaBlockPoolData::C2IgbaBlockPoolData(
82         const AHardwareBuffer *buffer,
83         std::shared_ptr<C2IGBA> &igba) : mOwned(true), mBuffer(buffer), mIgba(igba) {
84     CHECK(mBuffer);
85     AHardwareBuffer_acquire(const_cast<AHardwareBuffer *>(mBuffer));
86 }
87 
~C2IgbaBlockPoolData()88 C2IgbaBlockPoolData::~C2IgbaBlockPoolData() {
89     CHECK(mBuffer);
90     if (mOwned) {
91         if (__builtin_available(android __ANDROID_API_T__, *)) {
92             auto igba = mIgba.lock();
93             if (igba) {
94                 uint64_t origId;
95                 CHECK(AHardwareBuffer_getId(mBuffer, &origId) == ::android::OK);
96                 bool aidlRet = true;
97                 ::ndk::ScopedAStatus status = igba->deallocate(origId, &aidlRet);
98                 if (!status.isOk() || !aidlRet) {
99                     ALOGW("AHwb destruction notifying failure %d(%d)", status.isOk(), aidlRet);
100                 }
101             }
102         }
103     }
104     AHardwareBuffer_release(const_cast<AHardwareBuffer *>(mBuffer));
105 }
106 
getType() const107 C2IgbaBlockPoolData::type_t C2IgbaBlockPoolData::getType() const {
108     return TYPE_AHWBUFFER;
109 }
110 
getAHardwareBuffer(AHardwareBuffer ** pBuf) const111 void C2IgbaBlockPoolData::getAHardwareBuffer(AHardwareBuffer **pBuf) const {
112     *pBuf = const_cast<AHardwareBuffer *>(mBuffer);
113 }
114 
disown()115 void C2IgbaBlockPoolData::disown() {
116     mOwned = false;
117 }
118 
registerIgba(std::shared_ptr<C2IGBA> & igba)119 void C2IgbaBlockPoolData::registerIgba(std::shared_ptr<C2IGBA> &igba) {
120     mIgba = igba;
121 }
122 
CreateGraphicBlock(AHardwareBuffer * ahwb)123 std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(AHardwareBuffer *ahwb) {
124     // TODO: get proper allocator? and synchronization? or allocator-less?
125     static std::shared_ptr<C2AllocatorAhwb> sAllocator = std::make_shared<C2AllocatorAhwb>(0);
126     std::shared_ptr<C2GraphicBlock> block;
127     c2_status_t res = CreateGraphicBlockFromAhwb(
128             ahwb, std::static_pointer_cast<C2Allocator>(sAllocator), nullptr, &block);
129     if (res != C2_OK) {
130         return nullptr;
131     }
132     return block;
133 }
134 
GetAHardwareBuffer(const std::shared_ptr<const _C2BlockPoolData> & data,AHardwareBuffer ** pBuf)135 bool _C2BlockFactory::GetAHardwareBuffer(
136         const std::shared_ptr<const _C2BlockPoolData>& data,
137         AHardwareBuffer **pBuf) {
138     if (data && data->getType() == _C2BlockPoolData::TYPE_AHWBUFFER) {
139         const std::shared_ptr<const C2IgbaBlockPoolData> poolData =
140                 std::static_pointer_cast<const C2IgbaBlockPoolData>(data);
141         poolData->getAHardwareBuffer(pBuf);
142         return true;
143     }
144     return false;
145 }
146 
DisownIgbaBlock(const std::shared_ptr<_C2BlockPoolData> & data)147 void _C2BlockFactory::DisownIgbaBlock(
148         const std::shared_ptr<_C2BlockPoolData>& data) {
149     if (data && data->getType() == _C2BlockPoolData::TYPE_AHWBUFFER) {
150         const std::shared_ptr<C2IgbaBlockPoolData> poolData =
151                 std::static_pointer_cast<C2IgbaBlockPoolData>(data);
152         poolData->disown();
153     }
154 }
155 
RegisterIgba(const std::shared_ptr<_C2BlockPoolData> & data,std::shared_ptr<C2IGBA> & igba)156 void _C2BlockFactory::RegisterIgba(
157         const std::shared_ptr<_C2BlockPoolData>& data,
158         std::shared_ptr<C2IGBA> &igba) {
159     if (data && data->getType() == _C2BlockPoolData::TYPE_AHWBUFFER) {
160         const std::shared_ptr<C2IgbaBlockPoolData> poolData =
161                 std::static_pointer_cast<C2IgbaBlockPoolData>(data);
162         poolData->registerIgba(igba);
163     }
164 }
165 
C2IgbaBlockPool(const std::shared_ptr<C2Allocator> & allocator,const std::shared_ptr<C2IGBA> & igba,::android::base::unique_fd && ufd,const bool blockFence,const local_id_t localId)166 C2IgbaBlockPool::C2IgbaBlockPool(
167         const std::shared_ptr<C2Allocator> &allocator,
168         const std::shared_ptr<C2IGBA> &igba,
169         ::android::base::unique_fd &&ufd,
170         const bool blockFence,
171         const local_id_t localId) :
172                 mAllocator(allocator), mIgba(igba),
173                 mBlockFence(blockFence), mLocalId(localId) {
174     if (!mIgba) {
175         mValid = false;
176         return;
177     }
178     if (ufd.get() < 0) {
179         mValid = false;
180         return;
181     }
182     mWaitFence = _C2FenceFactory::CreatePipeFence(std::move(ufd));
183     if (!mWaitFence.valid()) {
184         mValid = false;
185         return;
186     }
187     mValid = true;
188 }
189 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)190 c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
191         uint32_t width, uint32_t height, uint32_t format,
192         C2MemoryUsage usage, std::shared_ptr<C2GraphicBlock> *block) {
193     uint64_t origId;
194     C2Fence fence;
195     c2_status_t res = _fetchGraphicBlock(
196             width, height, format, usage, kBlockingFetchTimeoutNs, false,
197             &origId, block, &fence);
198 
199     if (res == C2_TIMED_OUT) {
200         // SyncFence waiting timeout.
201         // Usually HAL treats C2_TIMED_OUT as an irrecoverable error.
202         // We want HAL to re-try.
203         return C2_BLOCKING;
204     }
205     return res;
206 }
207 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block,C2Fence * fence)208 c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
209         uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
210         std::shared_ptr<C2GraphicBlock> *block, C2Fence *fence) {
211     uint64_t origId;
212     c2_status_t res = _fetchGraphicBlock(
213             width, height, format, usage, 0LL, mBlockFence, &origId, block, fence);
214     if (res == C2_TIMED_OUT) {
215         *fence = C2Fence();
216         return C2_BLOCKING;
217     }
218     return res;
219 }
220 
_fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,c2_nsecs_t timeoutNs,bool blockFence,uint64_t * origId,std::shared_ptr<C2GraphicBlock> * block,C2Fence * fence)221 c2_status_t C2IgbaBlockPool::_fetchGraphicBlock(
222         uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
223         c2_nsecs_t timeoutNs,
224         bool blockFence,
225         uint64_t *origId,
226         std::shared_ptr<C2GraphicBlock> *block,
227         C2Fence *fence) {
228     if (!mValid) {
229         return C2_BAD_STATE;
230     }
231     if (__builtin_available(android __ANDROID_API_T__, *)) {
232         c2_status_t waitRes = mWaitFence.wait(timeoutNs);
233         switch (waitRes) {
234             case C2_CANCELED: {
235                 *fence = mWaitFence;
236                 return C2_BLOCKING;
237             }
238             case C2_TIMED_OUT: {
239                 *fence = mWaitFence;
240                 return C2_BLOCKING;
241             }
242             case C2_OK:
243                 break;
244             default: { // C2_BAD_STATE
245                 mValid = false;
246                 return C2_BAD_STATE;
247             }
248         }
249 
250         ::android::C2AndroidMemoryUsage memUsage{usage};
251         C2IGBA::Description desc{
252             ToAidl(width), ToAidl(height), ToAidl(format), ToAidl(memUsage.asGrallocUsage())};
253         C2IGBA::Allocation allocation;
254         ::ndk::ScopedAStatus status = mIgba->allocate(desc, &allocation);
255         if (!status.isOk()) {
256             binder_exception_t ex = status.getExceptionCode();
257             if (ex == EX_SERVICE_SPECIFIC) {
258                 c2_status_t err = static_cast<c2_status_t>(status.getServiceSpecificError());
259                 if (err == C2_BLOCKING) {
260                     *fence = mWaitFence;
261                 }
262                 return err;
263             } else {
264                 ALOGW("igba::allocate transaction failed: %d", ex);
265                 return C2_CORRUPTED;
266             }
267         }
268 
269         C2Fence syncFence  = _C2FenceFactory::CreateSyncFence(allocation.fence.release());
270         AHardwareBuffer *ahwb = allocation.buffer.release(); // This is acquired.
271         CHECK(AHardwareBuffer_getId(ahwb, origId) == ::android::OK);
272         bool syncFenceSignaled = false;
273 
274         if (!blockFence) {
275             // If a sync fence is not supposed to return along with a block,
276             // We are waiting for SyncFence here for backward compatibility.
277             c2_status_t res = syncFence.wait(kSyncFenceWaitNs);
278             if (res != C2_OK) {
279                 AHardwareBuffer_release(ahwb);
280                 bool aidlRet = true;
281                 ::ndk::ScopedAStatus status = mIgba->deallocate(*origId, &aidlRet);
282                 ALOGE("Waiting a sync fence failed %d aidl(%d: %d)",
283                       res, status.isOk(), aidlRet);
284                 return C2_TIMED_OUT;
285             }
286             syncFenceSignaled = true;
287         }
288 
289         c2_status_t res = CreateGraphicBlockFromAhwb(ahwb, mAllocator, mIgba, block);
290         AHardwareBuffer_release(ahwb);
291         if (res != C2_OK) {
292             bool aidlRet = true;
293             ::ndk::ScopedAStatus status = mIgba->deallocate(*origId, &aidlRet);
294             ALOGE("We got AHWB via AIDL but failed to created C2GraphicBlock err(%d) aidl(%d, %d)",
295                   res, status.isOk(), aidlRet);
296             return res;
297         }
298         if (!syncFenceSignaled) {
299             *fence = syncFence;
300         }
301         return C2_OK;
302     } else {
303         return C2_OMITTED;
304     }
305 }
306 
invalidate()307 void C2IgbaBlockPool::invalidate() {
308     mValid = false;
309 }
310