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