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 MOZ_ASSERT(XRE_IsGPUProcess());
46 sInstance
= new AndroidHardwareBufferApi();
47 if (!sInstance
->Load()) {
53 void AndroidHardwareBufferApi::Shutdown() { sInstance
= nullptr; }
55 AndroidHardwareBufferApi::AndroidHardwareBufferApi() {}
57 bool AndroidHardwareBufferApi::Load() {
58 void* handle
= dlopen("libandroid.so", RTLD_LAZY
| RTLD_LOCAL
);
61 gfxCriticalNote
<< "Failed to load libandroid.so";
65 mAHardwareBuffer_allocate
=
66 (_AHardwareBuffer_allocate
)dlsym(handle
, "AHardwareBuffer_allocate");
67 mAHardwareBuffer_acquire
=
68 (_AHardwareBuffer_acquire
)dlsym(handle
, "AHardwareBuffer_acquire");
69 mAHardwareBuffer_release
=
70 (_AHardwareBuffer_release
)dlsym(handle
, "AHardwareBuffer_release");
71 mAHardwareBuffer_describe
=
72 (_AHardwareBuffer_describe
)dlsym(handle
, "AHardwareBuffer_describe");
73 mAHardwareBuffer_lock
=
74 (_AHardwareBuffer_lock
)dlsym(handle
, "AHardwareBuffer_lock");
75 mAHardwareBuffer_unlock
=
76 (_AHardwareBuffer_unlock
)dlsym(handle
, "AHardwareBuffer_unlock");
77 mAHardwareBuffer_sendHandleToUnixSocket
=
78 (_AHardwareBuffer_sendHandleToUnixSocket
)dlsym(
79 handle
, "AHardwareBuffer_sendHandleToUnixSocket");
80 mAHardwareBuffer_recvHandleFromUnixSocket
=
81 (_AHardwareBuffer_recvHandleFromUnixSocket
)dlsym(
82 handle
, "AHardwareBuffer_recvHandleFromUnixSocket");
84 if (!mAHardwareBuffer_allocate
|| !mAHardwareBuffer_acquire
||
85 !mAHardwareBuffer_release
|| !mAHardwareBuffer_describe
||
86 !mAHardwareBuffer_lock
|| !mAHardwareBuffer_unlock
||
87 !mAHardwareBuffer_sendHandleToUnixSocket
||
88 !mAHardwareBuffer_recvHandleFromUnixSocket
) {
89 gfxCriticalNote
<< "Failed to load AHardwareBuffer";
95 void AndroidHardwareBufferApi::Allocate(const AHardwareBuffer_Desc
* aDesc
,
96 AHardwareBuffer
** aOutBuffer
) {
97 mAHardwareBuffer_allocate(aDesc
, aOutBuffer
);
100 void AndroidHardwareBufferApi::Acquire(AHardwareBuffer
* aBuffer
) {
101 mAHardwareBuffer_acquire(aBuffer
);
104 void AndroidHardwareBufferApi::Release(AHardwareBuffer
* aBuffer
) {
105 mAHardwareBuffer_release(aBuffer
);
108 void AndroidHardwareBufferApi::Describe(const AHardwareBuffer
* aBuffer
,
109 AHardwareBuffer_Desc
* aOutDesc
) {
110 mAHardwareBuffer_describe(aBuffer
, aOutDesc
);
113 int AndroidHardwareBufferApi::Lock(AHardwareBuffer
* aBuffer
, uint64_t aUsage
,
114 int32_t aFence
, const ARect
* aRect
,
115 void** aOutVirtualAddress
) {
116 return mAHardwareBuffer_lock(aBuffer
, aUsage
, aFence
, aRect
,
120 int AndroidHardwareBufferApi::Unlock(AHardwareBuffer
* aBuffer
,
122 return mAHardwareBuffer_unlock(aBuffer
, aFence
);
125 int AndroidHardwareBufferApi::SendHandleToUnixSocket(
126 const AHardwareBuffer
* aBuffer
, int aSocketFd
) {
127 return mAHardwareBuffer_sendHandleToUnixSocket(aBuffer
, aSocketFd
);
130 int AndroidHardwareBufferApi::RecvHandleFromUnixSocket(
131 int aSocketFd
, AHardwareBuffer
** aOutBuffer
) {
132 return mAHardwareBuffer_recvHandleFromUnixSocket(aSocketFd
, aOutBuffer
);
136 uint64_t AndroidHardwareBuffer::GetNextId() {
137 static std::atomic
<uint64_t> sNextId
= 0;
138 uint64_t id
= ++sNextId
;
143 already_AddRefed
<AndroidHardwareBuffer
> AndroidHardwareBuffer::Create(
144 gfx::IntSize aSize
, gfx::SurfaceFormat aFormat
) {
145 if (!AndroidHardwareBufferApi::Get()) {
149 if (aFormat
!= gfx::SurfaceFormat::R8G8B8A8
&&
150 aFormat
!= gfx::SurfaceFormat::R8G8B8X8
&&
151 aFormat
!= gfx::SurfaceFormat::B8G8R8A8
&&
152 aFormat
!= gfx::SurfaceFormat::B8G8R8X8
&&
153 aFormat
!= gfx::SurfaceFormat::R5G6B5_UINT16
) {
157 AHardwareBuffer_Desc desc
= {};
158 desc
.width
= aSize
.width
;
159 desc
.height
= aSize
.height
;
160 desc
.layers
= 1; // number of images
161 desc
.usage
= AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
|
162 AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN
|
163 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE
|
164 AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT
;
165 desc
.format
= ToAHardwareBuffer_Format(aFormat
);
167 AHardwareBuffer
* nativeBuffer
= nullptr;
168 AndroidHardwareBufferApi::Get()->Allocate(&desc
, &nativeBuffer
);
173 AHardwareBuffer_Desc bufferInfo
= {};
174 AndroidHardwareBufferApi::Get()->Describe(nativeBuffer
, &bufferInfo
);
176 RefPtr
<AndroidHardwareBuffer
> buffer
= new AndroidHardwareBuffer(
177 nativeBuffer
, aSize
, bufferInfo
.stride
, aFormat
, GetNextId());
178 AndroidHardwareBufferManager::Get()->Register(buffer
);
179 return buffer
.forget();
182 AndroidHardwareBuffer::AndroidHardwareBuffer(AHardwareBuffer
* aNativeBuffer
,
185 gfx::SurfaceFormat aFormat
,
191 mNativeBuffer(aNativeBuffer
),
192 mIsRegistered(false) {
193 MOZ_ASSERT(mNativeBuffer
);
195 AHardwareBuffer_Desc bufferInfo
= {};
196 AndroidHardwareBufferApi::Get()->Describe(mNativeBuffer
, &bufferInfo
);
197 MOZ_ASSERT(mSize
.width
== (int32_t)bufferInfo
.width
);
198 MOZ_ASSERT(mSize
.height
== (int32_t)bufferInfo
.height
);
199 MOZ_ASSERT(mStride
== bufferInfo
.stride
);
200 MOZ_ASSERT(ToAHardwareBuffer_Format(mFormat
) == bufferInfo
.format
);
204 AndroidHardwareBuffer::~AndroidHardwareBuffer() {
206 AndroidHardwareBufferManager::Get()->Unregister(this);
208 AndroidHardwareBufferApi::Get()->Release(mNativeBuffer
);
211 int AndroidHardwareBuffer::Lock(uint64_t aUsage
, const ARect
* aRect
,
212 void** aOutVirtualAddress
) {
213 ipc::FileDescriptor fd
= GetAndResetReleaseFence();
214 int32_t fenceFd
= -1;
215 ipc::FileDescriptor::UniquePlatformHandle rawFd
;
217 rawFd
= fd
.TakePlatformHandle();
218 fenceFd
= rawFd
.get();
220 return AndroidHardwareBufferApi::Get()->Lock(mNativeBuffer
, aUsage
, fenceFd
,
221 aRect
, aOutVirtualAddress
);
224 int AndroidHardwareBuffer::Unlock() {
226 // XXX All tested recent Android devices did not return valid fence.
227 int ret
= AndroidHardwareBufferApi::Get()->Unlock(mNativeBuffer
, &rawFd
);
232 ipc::FileDescriptor acquireFenceFd
;
233 // The value -1 indicates that unlocking has already completed before
234 // the function returned and no further operations are necessary.
236 acquireFenceFd
= ipc::FileDescriptor(UniqueFileHandle(rawFd
));
239 if (acquireFenceFd
.IsValid()) {
240 SetAcquireFence(std::move(acquireFenceFd
));
245 void AndroidHardwareBuffer::SetReleaseFence(ipc::FileDescriptor
&& aFenceFd
) {
246 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
247 SetReleaseFence(std::move(aFenceFd
), lock
);
250 void AndroidHardwareBuffer::SetReleaseFence(ipc::FileDescriptor
&& aFenceFd
,
251 const MonitorAutoLock
& aAutoLock
) {
252 mReleaseFenceFd
= std::move(aFenceFd
);
255 void AndroidHardwareBuffer::SetAcquireFence(ipc::FileDescriptor
&& aFenceFd
) {
256 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
258 mAcquireFenceFd
= std::move(aFenceFd
);
261 ipc::FileDescriptor
AndroidHardwareBuffer::GetAndResetReleaseFence() {
262 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
264 if (!mReleaseFenceFd
.IsValid()) {
265 return ipc::FileDescriptor();
268 return std::move(mReleaseFenceFd
);
271 ipc::FileDescriptor
AndroidHardwareBuffer::GetAndResetAcquireFence() {
272 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
274 if (!mAcquireFenceFd
.IsValid()) {
275 return ipc::FileDescriptor();
278 return std::move(mAcquireFenceFd
);
281 ipc::FileDescriptor
AndroidHardwareBuffer::GetAcquireFence() {
282 MonitorAutoLock
lock(AndroidHardwareBufferManager::Get()->GetMonitor());
284 if (!mAcquireFenceFd
.IsValid()) {
285 return ipc::FileDescriptor();
288 return mAcquireFenceFd
;
291 StaticAutoPtr
<AndroidHardwareBufferManager
>
292 AndroidHardwareBufferManager::sInstance
;
295 void AndroidHardwareBufferManager::Init() {
296 MOZ_ASSERT(XRE_IsGPUProcess());
298 sInstance
= new AndroidHardwareBufferManager();
302 void AndroidHardwareBufferManager::Shutdown() { sInstance
= nullptr; }
304 AndroidHardwareBufferManager::AndroidHardwareBufferManager()
305 : mMonitor("AndroidHardwareBufferManager.mMonitor") {}
307 void AndroidHardwareBufferManager::Register(
308 RefPtr
<AndroidHardwareBuffer
> aBuffer
) {
309 MonitorAutoLock
lock(mMonitor
);
311 aBuffer
->mIsRegistered
= true;
312 ThreadSafeWeakPtr
<AndroidHardwareBuffer
> weak(aBuffer
);
315 const auto it
= mBuffers
.find(aBuffer
->mId
);
316 MOZ_ASSERT(it
== mBuffers
.end());
318 mBuffers
.emplace(aBuffer
->mId
, weak
);
321 void AndroidHardwareBufferManager::Unregister(AndroidHardwareBuffer
* aBuffer
) {
322 MonitorAutoLock
lock(mMonitor
);
324 const auto it
= mBuffers
.find(aBuffer
->mId
);
325 MOZ_ASSERT(it
!= mBuffers
.end());
326 if (it
== mBuffers
.end()) {
327 gfxCriticalNote
<< "AndroidHardwareBuffer id mismatch happened";
333 already_AddRefed
<AndroidHardwareBuffer
> AndroidHardwareBufferManager::GetBuffer(
334 uint64_t aBufferId
) {
335 MonitorAutoLock
lock(mMonitor
);
337 const auto it
= mBuffers
.find(aBufferId
);
338 if (it
== mBuffers
.end()) {
341 auto buffer
= RefPtr
<AndroidHardwareBuffer
>(it
->second
);
342 return buffer
.forget();
345 } // namespace layers
346 } // namespace mozilla