1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "AndroidHardwareBuffer.h"
11 #include "mozilla/gfx/2D.h"
12 #include "mozilla/gfx/gfxVars.h"
13 #include "mozilla/layers/ImageBridgeChild.h"
14 #include "mozilla/layers/TextureClientSharedSurface.h"
15 #include "mozilla/TimeStamp.h"
16 #include "mozilla/UniquePtrExtensions.h"
21 static uint32_t ToAHardwareBuffer_Format(gfx::SurfaceFormat aFormat
) {
23 case gfx::SurfaceFormat::R8G8B8A8
:
24 case gfx::SurfaceFormat::B8G8R8A8
:
25 return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
;
27 case gfx::SurfaceFormat::R8G8B8X8
:
28 case gfx::SurfaceFormat::B8G8R8X8
:
29 return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM
;
31 case gfx::SurfaceFormat::R5G6B5_UINT16
:
32 return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM
;
35 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceFormat");
36 return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM
;
40 StaticAutoPtr
<AndroidHardwareBufferApi
> AndroidHardwareBufferApi::sInstance
;
43 void AndroidHardwareBufferApi::Init() {
44 sInstance
= new AndroidHardwareBufferApi();
45 if (!sInstance
->Load()) {
51 void AndroidHardwareBufferApi::Shutdown() { sInstance
= nullptr; }
53 AndroidHardwareBufferApi::AndroidHardwareBufferApi() {}
55 bool AndroidHardwareBufferApi::Load() {
56 void* handle
= dlopen("libandroid.so", RTLD_LAZY
| RTLD_LOCAL
);
59 gfxCriticalNote
<< "Failed to load libandroid.so";
63 mAHardwareBuffer_allocate
=
64 (_AHardwareBuffer_allocate
)dlsym(handle
, "AHardwareBuffer_allocate");
65 mAHardwareBuffer_acquire
=
66 (_AHardwareBuffer_acquire
)dlsym(handle
, "AHardwareBuffer_acquire");
67 mAHardwareBuffer_release
=
68 (_AHardwareBuffer_release
)dlsym(handle
, "AHardwareBuffer_release");
69 mAHardwareBuffer_describe
=
70 (_AHardwareBuffer_describe
)dlsym(handle
, "AHardwareBuffer_describe");
71 mAHardwareBuffer_lock
=
72 (_AHardwareBuffer_lock
)dlsym(handle
, "AHardwareBuffer_lock");
73 mAHardwareBuffer_unlock
=
74 (_AHardwareBuffer_unlock
)dlsym(handle
, "AHardwareBuffer_unlock");
75 mAHardwareBuffer_sendHandleToUnixSocket
=
76 (_AHardwareBuffer_sendHandleToUnixSocket
)dlsym(
77 handle
, "AHardwareBuffer_sendHandleToUnixSocket");
78 mAHardwareBuffer_recvHandleFromUnixSocket
=
79 (_AHardwareBuffer_recvHandleFromUnixSocket
)dlsym(
80 handle
, "AHardwareBuffer_recvHandleFromUnixSocket");
82 if (!mAHardwareBuffer_allocate
|| !mAHardwareBuffer_acquire
||
83 !mAHardwareBuffer_release
|| !mAHardwareBuffer_describe
||
84 !mAHardwareBuffer_lock
|| !mAHardwareBuffer_unlock
||
85 !mAHardwareBuffer_sendHandleToUnixSocket
||
86 !mAHardwareBuffer_recvHandleFromUnixSocket
) {
87 gfxCriticalNote
<< "Failed to load AHardwareBuffer";
93 void AndroidHardwareBufferApi::Allocate(const AHardwareBuffer_Desc
* aDesc
,
94 AHardwareBuffer
** aOutBuffer
) {
95 mAHardwareBuffer_allocate(aDesc
, aOutBuffer
);
98 void AndroidHardwareBufferApi::Acquire(AHardwareBuffer
* aBuffer
) {
99 mAHardwareBuffer_acquire(aBuffer
);
102 void AndroidHardwareBufferApi::Release(AHardwareBuffer
* aBuffer
) {
103 mAHardwareBuffer_release(aBuffer
);
106 void AndroidHardwareBufferApi::Describe(const AHardwareBuffer
* aBuffer
,
107 AHardwareBuffer_Desc
* aOutDesc
) {
108 mAHardwareBuffer_describe(aBuffer
, aOutDesc
);
111 int AndroidHardwareBufferApi::Lock(AHardwareBuffer
* aBuffer
, uint64_t aUsage
,
112 int32_t aFence
, const ARect
* aRect
,
113 void** aOutVirtualAddress
) {
114 return mAHardwareBuffer_lock(aBuffer
, aUsage
, aFence
, aRect
,
118 int AndroidHardwareBufferApi::Unlock(AHardwareBuffer
* aBuffer
,
120 return mAHardwareBuffer_unlock(aBuffer
, aFence
);
123 int AndroidHardwareBufferApi::SendHandleToUnixSocket(
124 const AHardwareBuffer
* aBuffer
, int aSocketFd
) {
125 return mAHardwareBuffer_sendHandleToUnixSocket(aBuffer
, aSocketFd
);
128 int AndroidHardwareBufferApi::RecvHandleFromUnixSocket(
129 int aSocketFd
, AHardwareBuffer
** aOutBuffer
) {
130 return mAHardwareBuffer_recvHandleFromUnixSocket(aSocketFd
, aOutBuffer
);
134 uint64_t AndroidHardwareBuffer::GetNextId() {
135 static std::atomic
<uint64_t> sNextId
= 0;
136 uint64_t id
= ++sNextId
;
141 already_AddRefed
<AndroidHardwareBuffer
> AndroidHardwareBuffer::Create(
142 gfx::IntSize aSize
, gfx::SurfaceFormat aFormat
) {
143 if (!AndroidHardwareBufferApi::Get()) {
147 if (aFormat
!= gfx::SurfaceFormat::R8G8B8A8
&&
148 aFormat
!= gfx::SurfaceFormat::R8G8B8X8
&&
149 aFormat
!= gfx::SurfaceFormat::B8G8R8A8
&&
150 aFormat
!= gfx::SurfaceFormat::B8G8R8X8
&&
151 aFormat
!= gfx::SurfaceFormat::R5G6B5_UINT16
) {
155 AHardwareBuffer_Desc desc
= {};
156 desc
.width
= aSize
.width
;
157 desc
.height
= aSize
.height
;
158 desc
.layers
= 1; // number of images
159 desc
.usage
= AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
|
160 AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN
|
161 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE
|
162 AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT
;
163 desc
.format
= ToAHardwareBuffer_Format(aFormat
);
165 AHardwareBuffer
* nativeBuffer
= nullptr;
166 AndroidHardwareBufferApi::Get()->Allocate(&desc
, &nativeBuffer
);
171 AHardwareBuffer_Desc bufferInfo
= {};
172 AndroidHardwareBufferApi::Get()->Describe(nativeBuffer
, &bufferInfo
);
174 RefPtr
<AndroidHardwareBuffer
> buffer
= new AndroidHardwareBuffer(
175 nativeBuffer
, aSize
, bufferInfo
.stride
, aFormat
, GetNextId());
176 AndroidHardwareBufferManager::Get()->Register(buffer
);
177 return buffer
.forget();
181 already_AddRefed
<AndroidHardwareBuffer
>
182 AndroidHardwareBuffer::FromFileDescriptor(ipc::FileDescriptor
& aFileDescriptor
,
185 gfx::SurfaceFormat aFormat
) {
186 if (!aFileDescriptor
.IsValid()) {
187 gfxCriticalNote
<< "AndroidHardwareBuffer invalid FileDescriptor";
191 ipc::FileDescriptor
& fileDescriptor
=
192 const_cast<ipc::FileDescriptor
&>(aFileDescriptor
);
193 auto rawFD
= fileDescriptor
.TakePlatformHandle();
194 AHardwareBuffer
* nativeBuffer
= nullptr;
195 int ret
= AndroidHardwareBufferApi::Get()->RecvHandleFromUnixSocket(
196 rawFD
.get(), &nativeBuffer
);
198 gfxCriticalNote
<< "RecvHandleFromUnixSocket failed";
202 AHardwareBuffer_Desc bufferInfo
= {};
203 AndroidHardwareBufferApi::Get()->Describe(nativeBuffer
, &bufferInfo
);
205 RefPtr
<AndroidHardwareBuffer
> buffer
= new AndroidHardwareBuffer(
206 nativeBuffer
, aSize
, bufferInfo
.stride
, aFormat
, aBufferId
);
207 return buffer
.forget();
210 AndroidHardwareBuffer::AndroidHardwareBuffer(AHardwareBuffer
* aNativeBuffer
,
213 gfx::SurfaceFormat aFormat
,
219 mNativeBuffer(aNativeBuffer
),
220 mIsRegistered(false) {
221 MOZ_ASSERT(mNativeBuffer
);
223 AHardwareBuffer_Desc bufferInfo
= {};
224 AndroidHardwareBufferApi::Get()->Describe(mNativeBuffer
, &bufferInfo
);
225 MOZ_ASSERT(mSize
.width
== (int32_t)bufferInfo
.width
);
226 MOZ_ASSERT(mSize
.height
== (int32_t)bufferInfo
.height
);
227 MOZ_ASSERT(mStride
== bufferInfo
.stride
);
228 MOZ_ASSERT(ToAHardwareBuffer_Format(mFormat
) == bufferInfo
.format
);
232 AndroidHardwareBuffer::~AndroidHardwareBuffer() {
234 AndroidHardwareBufferManager::Get()->Unregister(this);
236 AndroidHardwareBufferApi::Get()->Release(mNativeBuffer
);
239 int AndroidHardwareBuffer::Lock(uint64_t aUsage
, const ARect
* aRect
,
240 void** aOutVirtualAddress
) {
241 ipc::FileDescriptor fd
= GetAndResetReleaseFence();
242 int32_t fenceFd
= -1;
243 ipc::FileDescriptor::UniquePlatformHandle rawFd
;
245 rawFd
= fd
.TakePlatformHandle();
246 fenceFd
= rawFd
.get();
248 return AndroidHardwareBufferApi::Get()->Lock(mNativeBuffer
, aUsage
, fenceFd
,
249 aRect
, aOutVirtualAddress
);
252 int AndroidHardwareBuffer::Unlock() {
254 // XXX All tested recent Android devices did not return valid fence.
255 int ret
= AndroidHardwareBufferApi::Get()->Unlock(mNativeBuffer
, &rawFd
);
260 ipc::FileDescriptor acquireFenceFd
;
261 // The value -1 indicates that unlocking has already completed before
262 // the function returned and no further operations are necessary.
264 acquireFenceFd
= ipc::FileDescriptor(UniqueFileHandle(rawFd
));
267 if (acquireFenceFd
.IsValid()) {
268 SetAcquireFence(std::move(acquireFenceFd
));
273 int AndroidHardwareBuffer::SendHandleToUnixSocket(int aSocketFd
) {
274 return AndroidHardwareBufferApi::Get()->SendHandleToUnixSocket(mNativeBuffer
,
278 void AndroidHardwareBuffer::SetLastFwdTransactionId(
279 uint64_t aFwdTransactionId
, bool aUsesImageBridge
,
280 const MonitorAutoLock
& aAutoLock
) {
281 if (mTransactionId
.isNothing()) {
283 Some(FwdTransactionId(aFwdTransactionId
, aUsesImageBridge
));
286 MOZ_RELEASE_ASSERT(mTransactionId
.ref().mUsesImageBridge
== aUsesImageBridge
);
287 MOZ_RELEASE_ASSERT(mTransactionId
.ref().mId
<= aFwdTransactionId
);
289 mTransactionId
.ref().mId
= aFwdTransactionId
;
292 uint64_t AndroidHardwareBuffer::GetLastFwdTransactionId(
293 const MonitorAutoLock
& aAutoLock
) {
294 if (mTransactionId
.isNothing()) {
295 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
298 return mTransactionId
.ref().mId
;
301 void AndroidHardwareBuffer::SetReleaseFence(ipc::FileDescriptor
&& aFenceFd
) {
302 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
303 SetReleaseFence(std::move(aFenceFd
), lock
);
306 void AndroidHardwareBuffer::SetReleaseFence(ipc::FileDescriptor
&& aFenceFd
,
307 const MonitorAutoLock
& aAutoLock
) {
308 mReleaseFenceFd
= std::move(aFenceFd
);
311 void AndroidHardwareBuffer::SetAcquireFence(ipc::FileDescriptor
&& aFenceFd
) {
312 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
314 mAcquireFenceFd
= std::move(aFenceFd
);
317 ipc::FileDescriptor
AndroidHardwareBuffer::GetAndResetReleaseFence() {
318 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
320 if (!mReleaseFenceFd
.IsValid()) {
321 return ipc::FileDescriptor();
324 return std::move(mReleaseFenceFd
);
327 ipc::FileDescriptor
AndroidHardwareBuffer::GetAndResetAcquireFence() {
328 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
330 if (!mAcquireFenceFd
.IsValid()) {
331 return ipc::FileDescriptor();
334 return std::move(mAcquireFenceFd
);
337 ipc::FileDescriptor
AndroidHardwareBuffer::GetAcquireFence() {
338 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
340 if (!mAcquireFenceFd
.IsValid()) {
341 return ipc::FileDescriptor();
344 return mAcquireFenceFd
;
347 bool AndroidHardwareBuffer::WaitForBufferOwnership() {
348 return AndroidHardwareBufferManager::Get()->WaitForBufferOwnership(this);
351 bool AndroidHardwareBuffer::IsWaitingForBufferOwnership() {
352 return AndroidHardwareBufferManager::Get()->IsWaitingForBufferOwnership(this);
355 RefPtr
<TextureClient
>
356 AndroidHardwareBuffer::GetTextureClientOfSharedSurfaceTextureData(
357 const layers::SurfaceDescriptor
& aDesc
, const gfx::SurfaceFormat aFormat
,
358 const gfx::IntSize
& aSize
, const TextureFlags aFlags
,
359 LayersIPCChannel
* aAllocator
) {
360 if (mTextureClientOfSharedSurfaceTextureData
) {
361 return mTextureClientOfSharedSurfaceTextureData
;
363 mTextureClientOfSharedSurfaceTextureData
=
364 SharedSurfaceTextureData::CreateTextureClient(aDesc
, aFormat
, aSize
,
366 return mTextureClientOfSharedSurfaceTextureData
;
369 StaticAutoPtr
<AndroidHardwareBufferManager
>
370 AndroidHardwareBufferManager::sInstance
;
373 void AndroidHardwareBufferManager::Init() {
374 sInstance
= new AndroidHardwareBufferManager();
378 void AndroidHardwareBufferManager::Shutdown() { sInstance
= nullptr; }
380 AndroidHardwareBufferManager::AndroidHardwareBufferManager()
381 : mMonitor("AndroidHardwareBufferManager.mMonitor") {}
383 void AndroidHardwareBufferManager::Register(
384 RefPtr
<AndroidHardwareBuffer
> aBuffer
) {
385 MonitorAutoLock
lock(mMonitor
);
387 aBuffer
->mIsRegistered
= true;
388 ThreadSafeWeakPtr
<AndroidHardwareBuffer
> weak(aBuffer
);
391 const auto it
= mBuffers
.find(aBuffer
->mId
);
392 MOZ_ASSERT(it
== mBuffers
.end());
394 mBuffers
.emplace(aBuffer
->mId
, weak
);
397 void AndroidHardwareBufferManager::Unregister(AndroidHardwareBuffer
* aBuffer
) {
398 MonitorAutoLock
lock(mMonitor
);
400 const auto it
= mBuffers
.find(aBuffer
->mId
);
401 MOZ_ASSERT(it
!= mBuffers
.end());
402 if (it
== mBuffers
.end()) {
403 gfxCriticalNote
<< "AndroidHardwareBuffer id mismatch happened";
409 already_AddRefed
<AndroidHardwareBuffer
> AndroidHardwareBufferManager::GetBuffer(
410 uint64_t aBufferId
) {
411 MonitorAutoLock
lock(mMonitor
);
413 const auto it
= mBuffers
.find(aBufferId
);
414 if (it
== mBuffers
.end()) {
417 auto buffer
= RefPtr
<AndroidHardwareBuffer
>(it
->second
);
418 return buffer
.forget();
421 bool AndroidHardwareBufferManager::WaitForBufferOwnership(
422 AndroidHardwareBuffer
* aBuffer
) {
423 MonitorAutoLock
lock(mMonitor
);
425 if (aBuffer
->mTransactionId
.isNothing()) {
429 auto it
= mWaitingNotifyNotUsed
.find(aBuffer
->mId
);
430 if (it
== mWaitingNotifyNotUsed
.end()) {
434 const double waitWarningTimeoutMs
= 300;
435 const double maxTimeoutSec
= 3;
436 auto begin
= TimeStamp::Now();
438 bool isWaiting
= true;
440 TimeDuration timeout
= TimeDuration::FromMilliseconds(waitWarningTimeoutMs
);
441 CVStatus status
= mMonitor
.Wait(timeout
);
442 if (status
== CVStatus::Timeout
) {
443 gfxCriticalNoteOnce
<< "AndroidHardwareBuffer wait is slow";
445 const auto it
= mWaitingNotifyNotUsed
.find(aBuffer
->mId
);
446 if (it
== mWaitingNotifyNotUsed
.end()) {
449 auto now
= TimeStamp::Now();
450 if ((now
- begin
).ToSeconds() > maxTimeoutSec
) {
452 gfxCriticalNote
<< "AndroidHardwareBuffer wait timeout";
459 bool AndroidHardwareBufferManager::IsWaitingForBufferOwnership(
460 AndroidHardwareBuffer
* aBuffer
) {
461 MonitorAutoLock
lock(mMonitor
);
463 if (aBuffer
->mTransactionId
.isNothing()) {
467 auto it
= mWaitingNotifyNotUsed
.find(aBuffer
->mId
);
468 if (it
== mWaitingNotifyNotUsed
.end()) {
474 void AndroidHardwareBufferManager::HoldUntilNotifyNotUsed(
475 uint64_t aBufferId
, uint64_t aFwdTransactionId
, bool aUsesImageBridge
) {
476 MOZ_ASSERT(NS_IsMainThread() || InImageBridgeChildThread());
478 const auto it
= mBuffers
.find(aBufferId
);
479 if (it
== mBuffers
.end()) {
482 auto buffer
= RefPtr
<AndroidHardwareBuffer
>(it
->second
);
484 MonitorAutoLock
lock(mMonitor
);
485 buffer
->SetLastFwdTransactionId(aFwdTransactionId
, aUsesImageBridge
, lock
);
486 mWaitingNotifyNotUsed
.emplace(aBufferId
, buffer
);
489 void AndroidHardwareBufferManager::NotifyNotUsed(ipc::FileDescriptor
&& aFenceFd
,
491 uint64_t aTransactionId
,
492 bool aUsesImageBridge
) {
493 MOZ_ASSERT(InImageBridgeChildThread());
495 MonitorAutoLock
lock(mMonitor
);
497 auto it
= mWaitingNotifyNotUsed
.find(aBufferId
);
498 if (it
!= mWaitingNotifyNotUsed
.end()) {
499 if (aTransactionId
< it
->second
->GetLastFwdTransactionId(lock
)) {
500 // Released on host side, but client already requested newer use texture.
503 it
->second
->SetReleaseFence(std::move(aFenceFd
), lock
);
504 mWaitingNotifyNotUsed
.erase(it
);
505 mMonitor
.NotifyAll();
509 } // namespace layers
510 } // namespace mozilla