• 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 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 local_id_t localId) : mAllocator(allocator), mIgba(igba), mLocalId(localId) {
171     if (!mIgba) {
172         mValid = false;
173         return;
174     }
175     if (ufd.get() < 0) {
176         mValid = false;
177         return;
178     }
179     mWaitFence = _C2FenceFactory::CreatePipeFence(std::move(ufd));
180     if (!mWaitFence.valid()) {
181         mValid = false;
182         return;
183     }
184     mValid = true;
185 }
186 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)187 c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
188         uint32_t width, uint32_t height, uint32_t format,
189         C2MemoryUsage usage, std::shared_ptr<C2GraphicBlock> *block) {
190     uint64_t origId;
191     C2Fence fence;
192     c2_status_t res = _fetchGraphicBlock(
193             width, height, format, usage, kBlockingFetchTimeoutNs, &origId, block, &fence);
194 
195     if (res == C2_TIMED_OUT) {
196         // SyncFence waiting timeout.
197         // Usually HAL treats C2_TIMED_OUT as an irrecoverable error.
198         // We want HAL to re-try.
199         return C2_BLOCKING;
200     }
201     return res;
202 }
203 
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block,C2Fence * fence)204 c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
205         uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
206         std::shared_ptr<C2GraphicBlock> *block, C2Fence *fence) {
207     uint64_t origId;
208     c2_status_t res = _fetchGraphicBlock(width, height, format, usage, 0LL, &origId, block, fence);
209     if (res == C2_TIMED_OUT) {
210         *fence = C2Fence();
211         return C2_BLOCKING;
212     }
213     return res;
214 }
215 
_fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,c2_nsecs_t timeoutNs,uint64_t * origId,std::shared_ptr<C2GraphicBlock> * block,C2Fence * fence)216 c2_status_t C2IgbaBlockPool::_fetchGraphicBlock(
217         uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
218         c2_nsecs_t timeoutNs,
219         uint64_t *origId,
220         std::shared_ptr<C2GraphicBlock> *block,
221         C2Fence *fence) {
222     if (!mValid) {
223         return C2_BAD_STATE;
224     }
225     if (__builtin_available(android __ANDROID_API_T__, *)) {
226         c2_status_t waitRes = mWaitFence.wait(timeoutNs);
227         switch (waitRes) {
228             case C2_CANCELED: {
229                 *fence = mWaitFence;
230                 return C2_BLOCKING;
231             }
232             case C2_TIMED_OUT: {
233                 *fence = mWaitFence;
234                 return C2_BLOCKING;
235             }
236             case C2_OK:
237                 break;
238             default: { // C2_BAD_STATE
239                 mValid = false;
240                 return C2_BAD_STATE;
241             }
242         }
243 
244         ::android::C2AndroidMemoryUsage memUsage{usage};
245         C2IGBA::Description desc{
246             ToAidl(width), ToAidl(height), ToAidl(format), ToAidl(memUsage.asGrallocUsage())};
247         C2IGBA::Allocation allocation;
248         ::ndk::ScopedAStatus status = mIgba->allocate(desc, &allocation);
249         if (!status.isOk()) {
250             binder_exception_t ex = status.getExceptionCode();
251             if (ex == EX_SERVICE_SPECIFIC) {
252                 c2_status_t err = static_cast<c2_status_t>(status.getServiceSpecificError());
253                 if (err == C2_BLOCKING) {
254                     *fence = mWaitFence;
255                 }
256                 return err;
257             } else {
258                 ALOGW("igba::allocate transaction failed: %d", ex);
259                 return C2_CORRUPTED;
260             }
261         }
262 
263         C2Fence syncFence  = _C2FenceFactory::CreateSyncFence(allocation.fence.release());
264         AHardwareBuffer *ahwb = allocation.buffer.release(); // This is acquired.
265         CHECK(AHardwareBuffer_getId(ahwb, origId) == ::android::OK);
266 
267         // We are waiting for SyncFence here for backward compatibility.
268         // H/W based Sync Fence could be returned to improve pipeline latency.
269         //
270         // TODO: Add a component configuration for returning sync fence
271         // from fetchGraphicBlock() as the C2Fence output param(b/322283520).
272         // In the case C2_OK along with GraphicBlock must be returned together.
273         c2_status_t res = syncFence.wait(kSyncFenceWaitNs);
274         if (res != C2_OK) {
275             AHardwareBuffer_release(ahwb);
276             bool aidlRet = true;
277             ::ndk::ScopedAStatus status = mIgba->deallocate(*origId, &aidlRet);
278             ALOGE("Waiting a sync fence failed %d aidl(%d: %d)",
279                   res, status.isOk(), aidlRet);
280             return C2_TIMED_OUT;
281         }
282 
283         res = CreateGraphicBlockFromAhwb(ahwb, mAllocator, mIgba, block);
284         AHardwareBuffer_release(ahwb);
285         if (res != C2_OK) {
286             bool aidlRet = true;
287             ::ndk::ScopedAStatus status = mIgba->deallocate(*origId, &aidlRet);
288             ALOGE("We got AHWB via AIDL but failed to created C2GraphicBlock err(%d) aidl(%d, %d)",
289                   res, status.isOk(), aidlRet);
290         }
291         return res;
292     } else {
293         return C2_OMITTED;
294     }
295 }
296 
invalidate()297 void C2IgbaBlockPool::invalidate() {
298     mValid = false;
299 }
300