Bug 1744524: part 2) Add `WindowContext::GetUserGestureStart` and remove `WindowConte...
[gecko.git] / gfx / layers / AndroidHardwareBuffer.cpp
blob58a8b35c7ec43d77ff3d388e87bad8163e3399ec
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"
9 #include <dlfcn.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"
18 namespace mozilla {
19 namespace layers {
21 static uint32_t ToAHardwareBuffer_Format(gfx::SurfaceFormat aFormat) {
22 switch (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;
34 default:
35 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceFormat");
36 return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
40 StaticAutoPtr<AndroidHardwareBufferApi> AndroidHardwareBufferApi::sInstance;
42 /* static */
43 void AndroidHardwareBufferApi::Init() {
44 sInstance = new AndroidHardwareBufferApi();
45 if (!sInstance->Load()) {
46 sInstance = nullptr;
50 /* static */
51 void AndroidHardwareBufferApi::Shutdown() { sInstance = nullptr; }
53 AndroidHardwareBufferApi::AndroidHardwareBufferApi() {}
55 bool AndroidHardwareBufferApi::Load() {
56 void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
57 MOZ_ASSERT(handle);
58 if (!handle) {
59 gfxCriticalNote << "Failed to load libandroid.so";
60 return false;
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";
88 return false;
90 return true;
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,
115 aOutVirtualAddress);
118 int AndroidHardwareBufferApi::Unlock(AHardwareBuffer* aBuffer,
119 int32_t* aFence) {
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);
133 /* static */
134 uint64_t AndroidHardwareBuffer::GetNextId() {
135 static std::atomic<uint64_t> sNextId = 0;
136 uint64_t id = ++sNextId;
137 return id;
140 /* static */
141 already_AddRefed<AndroidHardwareBuffer> AndroidHardwareBuffer::Create(
142 gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
143 if (!AndroidHardwareBufferApi::Get()) {
144 return nullptr;
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) {
152 return nullptr;
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);
167 if (!nativeBuffer) {
168 return nullptr;
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();
180 /* static */
181 already_AddRefed<AndroidHardwareBuffer>
182 AndroidHardwareBuffer::FromFileDescriptor(ipc::FileDescriptor& aFileDescriptor,
183 uint64_t aBufferId,
184 gfx::IntSize aSize,
185 gfx::SurfaceFormat aFormat) {
186 if (!aFileDescriptor.IsValid()) {
187 gfxCriticalNote << "AndroidHardwareBuffer invalid FileDescriptor";
188 return nullptr;
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);
197 if (ret < 0) {
198 gfxCriticalNote << "RecvHandleFromUnixSocket failed";
199 return nullptr;
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,
211 gfx::IntSize aSize,
212 uint32_t aStride,
213 gfx::SurfaceFormat aFormat,
214 uint64_t aId)
215 : mSize(aSize),
216 mStride(aStride),
217 mFormat(aFormat),
218 mId(aId),
219 mNativeBuffer(aNativeBuffer),
220 mIsRegistered(false) {
221 MOZ_ASSERT(mNativeBuffer);
222 #ifdef DEBUG
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);
229 #endif
232 AndroidHardwareBuffer::~AndroidHardwareBuffer() {
233 if (mIsRegistered) {
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;
244 if (fd.IsValid()) {
245 rawFd = fd.TakePlatformHandle();
246 fenceFd = rawFd.get();
248 return AndroidHardwareBufferApi::Get()->Lock(mNativeBuffer, aUsage, fenceFd,
249 aRect, aOutVirtualAddress);
252 int AndroidHardwareBuffer::Unlock() {
253 int rawFd = -1;
254 // XXX All tested recent Android devices did not return valid fence.
255 int ret = AndroidHardwareBufferApi::Get()->Unlock(mNativeBuffer, &rawFd);
256 if (ret != 0) {
257 return ret;
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.
263 if (rawFd >= 0) {
264 acquireFenceFd = ipc::FileDescriptor(UniqueFileHandle(rawFd));
267 if (acquireFenceFd.IsValid()) {
268 SetAcquireFence(std::move(acquireFenceFd));
270 return 0;
273 int AndroidHardwareBuffer::SendHandleToUnixSocket(int aSocketFd) {
274 return AndroidHardwareBufferApi::Get()->SendHandleToUnixSocket(mNativeBuffer,
275 aSocketFd);
278 void AndroidHardwareBuffer::SetLastFwdTransactionId(
279 uint64_t aFwdTransactionId, bool aUsesImageBridge,
280 const MonitorAutoLock& aAutoLock) {
281 if (mTransactionId.isNothing()) {
282 mTransactionId =
283 Some(FwdTransactionId(aFwdTransactionId, aUsesImageBridge));
284 return;
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");
296 return 0;
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,
365 aFlags, aAllocator);
366 return mTextureClientOfSharedSurfaceTextureData;
369 StaticAutoPtr<AndroidHardwareBufferManager>
370 AndroidHardwareBufferManager::sInstance;
372 /* static */
373 void AndroidHardwareBufferManager::Init() {
374 sInstance = new AndroidHardwareBufferManager();
377 /* static */
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);
390 #ifdef DEBUG
391 const auto it = mBuffers.find(aBuffer->mId);
392 MOZ_ASSERT(it == mBuffers.end());
393 #endif
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";
404 return;
406 mBuffers.erase(it);
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()) {
415 return nullptr;
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()) {
426 return true;
429 auto it = mWaitingNotifyNotUsed.find(aBuffer->mId);
430 if (it == mWaitingNotifyNotUsed.end()) {
431 return true;
434 const double waitWarningTimeoutMs = 300;
435 const double maxTimeoutSec = 3;
436 auto begin = TimeStamp::Now();
438 bool isWaiting = true;
439 while (isWaiting) {
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()) {
447 return true;
449 auto now = TimeStamp::Now();
450 if ((now - begin).ToSeconds() > maxTimeoutSec) {
451 isWaiting = false;
452 gfxCriticalNote << "AndroidHardwareBuffer wait timeout";
456 return false;
459 bool AndroidHardwareBufferManager::IsWaitingForBufferOwnership(
460 AndroidHardwareBuffer* aBuffer) {
461 MonitorAutoLock lock(mMonitor);
463 if (aBuffer->mTransactionId.isNothing()) {
464 return false;
467 auto it = mWaitingNotifyNotUsed.find(aBuffer->mId);
468 if (it == mWaitingNotifyNotUsed.end()) {
469 return false;
471 return true;
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()) {
480 return;
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,
490 uint64_t aBufferId,
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.
501 return;
503 it->second->SetReleaseFence(std::move(aFenceFd), lock);
504 mWaitingNotifyNotUsed.erase(it);
505 mMonitor.NotifyAll();
509 } // namespace layers
510 } // namespace mozilla