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/. */
6
7 #include "AndroidHardwareBuffer.h"
8
9 #include <dlfcn.h>
10
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"
17
18 namespace mozilla {
19 namespace layers {
20
ToAHardwareBuffer_Format(gfx::SurfaceFormat aFormat)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;
26
27 case gfx::SurfaceFormat::R8G8B8X8:
28 case gfx::SurfaceFormat::B8G8R8X8:
29 return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
30
31 case gfx::SurfaceFormat::R5G6B5_UINT16:
32 return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
33
34 default:
35 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceFormat");
36 return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
37 }
38 }
39
40 StaticAutoPtr<AndroidHardwareBufferApi> AndroidHardwareBufferApi::sInstance;
41
42 /* static */
Init()43 void AndroidHardwareBufferApi::Init() {
44 sInstance = new AndroidHardwareBufferApi();
45 if (!sInstance->Load()) {
46 sInstance = nullptr;
47 }
48 }
49
50 /* static */
Shutdown()51 void AndroidHardwareBufferApi::Shutdown() { sInstance = nullptr; }
52
AndroidHardwareBufferApi()53 AndroidHardwareBufferApi::AndroidHardwareBufferApi() {}
54
Load()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;
61 }
62
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");
81
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;
89 }
90 return true;
91 }
92
Allocate(const AHardwareBuffer_Desc * aDesc,AHardwareBuffer ** aOutBuffer)93 void AndroidHardwareBufferApi::Allocate(const AHardwareBuffer_Desc* aDesc,
94 AHardwareBuffer** aOutBuffer) {
95 mAHardwareBuffer_allocate(aDesc, aOutBuffer);
96 }
97
Acquire(AHardwareBuffer * aBuffer)98 void AndroidHardwareBufferApi::Acquire(AHardwareBuffer* aBuffer) {
99 mAHardwareBuffer_acquire(aBuffer);
100 }
101
Release(AHardwareBuffer * aBuffer)102 void AndroidHardwareBufferApi::Release(AHardwareBuffer* aBuffer) {
103 mAHardwareBuffer_release(aBuffer);
104 }
105
Describe(const AHardwareBuffer * aBuffer,AHardwareBuffer_Desc * aOutDesc)106 void AndroidHardwareBufferApi::Describe(const AHardwareBuffer* aBuffer,
107 AHardwareBuffer_Desc* aOutDesc) {
108 mAHardwareBuffer_describe(aBuffer, aOutDesc);
109 }
110
Lock(AHardwareBuffer * aBuffer,uint64_t aUsage,int32_t aFence,const ARect * aRect,void ** aOutVirtualAddress)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);
116 }
117
Unlock(AHardwareBuffer * aBuffer,int32_t * aFence)118 int AndroidHardwareBufferApi::Unlock(AHardwareBuffer* aBuffer,
119 int32_t* aFence) {
120 return mAHardwareBuffer_unlock(aBuffer, aFence);
121 }
122
SendHandleToUnixSocket(const AHardwareBuffer * aBuffer,int aSocketFd)123 int AndroidHardwareBufferApi::SendHandleToUnixSocket(
124 const AHardwareBuffer* aBuffer, int aSocketFd) {
125 return mAHardwareBuffer_sendHandleToUnixSocket(aBuffer, aSocketFd);
126 }
127
RecvHandleFromUnixSocket(int aSocketFd,AHardwareBuffer ** aOutBuffer)128 int AndroidHardwareBufferApi::RecvHandleFromUnixSocket(
129 int aSocketFd, AHardwareBuffer** aOutBuffer) {
130 return mAHardwareBuffer_recvHandleFromUnixSocket(aSocketFd, aOutBuffer);
131 }
132
133 /* static */
GetNextId()134 uint64_t AndroidHardwareBuffer::GetNextId() {
135 static std::atomic<uint64_t> sNextId = 0;
136 uint64_t id = ++sNextId;
137 return id;
138 }
139
140 /* static */
Create(gfx::IntSize aSize,gfx::SurfaceFormat aFormat)141 already_AddRefed<AndroidHardwareBuffer> AndroidHardwareBuffer::Create(
142 gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
143 if (!AndroidHardwareBufferApi::Get()) {
144 return nullptr;
145 }
146
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;
153 }
154
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);
164
165 AHardwareBuffer* nativeBuffer = nullptr;
166 AndroidHardwareBufferApi::Get()->Allocate(&desc, &nativeBuffer);
167 if (!nativeBuffer) {
168 return nullptr;
169 }
170
171 AHardwareBuffer_Desc bufferInfo = {};
172 AndroidHardwareBufferApi::Get()->Describe(nativeBuffer, &bufferInfo);
173
174 RefPtr<AndroidHardwareBuffer> buffer = new AndroidHardwareBuffer(
175 nativeBuffer, aSize, bufferInfo.stride, aFormat, GetNextId());
176 AndroidHardwareBufferManager::Get()->Register(buffer);
177 return buffer.forget();
178 }
179
180 /* static */
181 already_AddRefed<AndroidHardwareBuffer>
FromFileDescriptor(ipc::FileDescriptor & aFileDescriptor,uint64_t aBufferId,gfx::IntSize aSize,gfx::SurfaceFormat aFormat)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;
189 }
190
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;
200 }
201
202 AHardwareBuffer_Desc bufferInfo = {};
203 AndroidHardwareBufferApi::Get()->Describe(nativeBuffer, &bufferInfo);
204
205 RefPtr<AndroidHardwareBuffer> buffer = new AndroidHardwareBuffer(
206 nativeBuffer, aSize, bufferInfo.stride, aFormat, aBufferId);
207 return buffer.forget();
208 }
209
AndroidHardwareBuffer(AHardwareBuffer * aNativeBuffer,gfx::IntSize aSize,uint32_t aStride,gfx::SurfaceFormat aFormat,uint64_t aId)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
230 }
231
~AndroidHardwareBuffer()232 AndroidHardwareBuffer::~AndroidHardwareBuffer() {
233 if (mIsRegistered) {
234 AndroidHardwareBufferManager::Get()->Unregister(this);
235 }
236 AndroidHardwareBufferApi::Get()->Release(mNativeBuffer);
237 }
238
Lock(uint64_t aUsage,const ARect * aRect,void ** aOutVirtualAddress)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();
247 }
248 return AndroidHardwareBufferApi::Get()->Lock(mNativeBuffer, aUsage, fenceFd,
249 aRect, aOutVirtualAddress);
250 }
251
Unlock()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;
258 }
259
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));
265 }
266
267 if (acquireFenceFd.IsValid()) {
268 SetAcquireFence(std::move(acquireFenceFd));
269 }
270 return 0;
271 }
272
SendHandleToUnixSocket(int aSocketFd)273 int AndroidHardwareBuffer::SendHandleToUnixSocket(int aSocketFd) {
274 return AndroidHardwareBufferApi::Get()->SendHandleToUnixSocket(mNativeBuffer,
275 aSocketFd);
276 }
277
SetLastFwdTransactionId(uint64_t aFwdTransactionId,bool aUsesImageBridge,const MonitorAutoLock & aAutoLock)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;
285 }
286 MOZ_RELEASE_ASSERT(mTransactionId.ref().mUsesImageBridge == aUsesImageBridge);
287 MOZ_RELEASE_ASSERT(mTransactionId.ref().mId <= aFwdTransactionId);
288
289 mTransactionId.ref().mId = aFwdTransactionId;
290 }
291
GetLastFwdTransactionId(const MonitorAutoLock & aAutoLock)292 uint64_t AndroidHardwareBuffer::GetLastFwdTransactionId(
293 const MonitorAutoLock& aAutoLock) {
294 if (mTransactionId.isNothing()) {
295 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
296 return 0;
297 }
298 return mTransactionId.ref().mId;
299 }
300
SetReleaseFence(ipc::FileDescriptor && aFenceFd)301 void AndroidHardwareBuffer::SetReleaseFence(ipc::FileDescriptor&& aFenceFd) {
302 MonitorAutoLock lock(AndroidHardwareBufferManager::Get()->GetMonitor());
303 SetReleaseFence(std::move(aFenceFd), lock);
304 }
305
SetReleaseFence(ipc::FileDescriptor && aFenceFd,const MonitorAutoLock & aAutoLock)306 void AndroidHardwareBuffer::SetReleaseFence(ipc::FileDescriptor&& aFenceFd,
307 const MonitorAutoLock& aAutoLock) {
308 mReleaseFenceFd = std::move(aFenceFd);
309 }
310
SetAcquireFence(ipc::FileDescriptor && aFenceFd)311 void AndroidHardwareBuffer::SetAcquireFence(ipc::FileDescriptor&& aFenceFd) {
312 MonitorAutoLock lock(AndroidHardwareBufferManager::Get()->GetMonitor());
313
314 mAcquireFenceFd = std::move(aFenceFd);
315 }
316
GetAndResetReleaseFence()317 ipc::FileDescriptor AndroidHardwareBuffer::GetAndResetReleaseFence() {
318 MonitorAutoLock lock(AndroidHardwareBufferManager::Get()->GetMonitor());
319
320 if (!mReleaseFenceFd.IsValid()) {
321 return ipc::FileDescriptor();
322 }
323
324 return std::move(mReleaseFenceFd);
325 }
326
GetAndResetAcquireFence()327 ipc::FileDescriptor AndroidHardwareBuffer::GetAndResetAcquireFence() {
328 MonitorAutoLock lock(AndroidHardwareBufferManager::Get()->GetMonitor());
329
330 if (!mAcquireFenceFd.IsValid()) {
331 return ipc::FileDescriptor();
332 }
333
334 return std::move(mAcquireFenceFd);
335 }
336
GetAcquireFence()337 ipc::FileDescriptor AndroidHardwareBuffer::GetAcquireFence() {
338 MonitorAutoLock lock(AndroidHardwareBufferManager::Get()->GetMonitor());
339
340 if (!mAcquireFenceFd.IsValid()) {
341 return ipc::FileDescriptor();
342 }
343
344 return mAcquireFenceFd;
345 }
346
WaitForBufferOwnership()347 bool AndroidHardwareBuffer::WaitForBufferOwnership() {
348 return AndroidHardwareBufferManager::Get()->WaitForBufferOwnership(this);
349 }
350
IsWaitingForBufferOwnership()351 bool AndroidHardwareBuffer::IsWaitingForBufferOwnership() {
352 return AndroidHardwareBufferManager::Get()->IsWaitingForBufferOwnership(this);
353 }
354
355 RefPtr<TextureClient>
GetTextureClientOfSharedSurfaceTextureData(const layers::SurfaceDescriptor & aDesc,const gfx::SurfaceFormat aFormat,const gfx::IntSize & aSize,const TextureFlags aFlags,LayersIPCChannel * aAllocator)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;
362 }
363 mTextureClientOfSharedSurfaceTextureData =
364 SharedSurfaceTextureData::CreateTextureClient(aDesc, aFormat, aSize,
365 aFlags, aAllocator);
366 return mTextureClientOfSharedSurfaceTextureData;
367 }
368
369 StaticAutoPtr<AndroidHardwareBufferManager>
370 AndroidHardwareBufferManager::sInstance;
371
372 /* static */
Init()373 void AndroidHardwareBufferManager::Init() {
374 sInstance = new AndroidHardwareBufferManager();
375 }
376
377 /* static */
Shutdown()378 void AndroidHardwareBufferManager::Shutdown() { sInstance = nullptr; }
379
AndroidHardwareBufferManager()380 AndroidHardwareBufferManager::AndroidHardwareBufferManager()
381 : mMonitor("AndroidHardwareBufferManager.mMonitor") {}
382
Register(RefPtr<AndroidHardwareBuffer> aBuffer)383 void AndroidHardwareBufferManager::Register(
384 RefPtr<AndroidHardwareBuffer> aBuffer) {
385 MonitorAutoLock lock(mMonitor);
386
387 aBuffer->mIsRegistered = true;
388 ThreadSafeWeakPtr<AndroidHardwareBuffer> weak(aBuffer);
389
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);
395 }
396
Unregister(AndroidHardwareBuffer * aBuffer)397 void AndroidHardwareBufferManager::Unregister(AndroidHardwareBuffer* aBuffer) {
398 MonitorAutoLock lock(mMonitor);
399
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;
405 }
406 mBuffers.erase(it);
407 }
408
GetBuffer(uint64_t aBufferId)409 already_AddRefed<AndroidHardwareBuffer> AndroidHardwareBufferManager::GetBuffer(
410 uint64_t aBufferId) {
411 MonitorAutoLock lock(mMonitor);
412
413 const auto it = mBuffers.find(aBufferId);
414 if (it == mBuffers.end()) {
415 return nullptr;
416 }
417 auto buffer = RefPtr<AndroidHardwareBuffer>(it->second);
418 return buffer.forget();
419 }
420
WaitForBufferOwnership(AndroidHardwareBuffer * aBuffer)421 bool AndroidHardwareBufferManager::WaitForBufferOwnership(
422 AndroidHardwareBuffer* aBuffer) {
423 MonitorAutoLock lock(mMonitor);
424
425 if (aBuffer->mTransactionId.isNothing()) {
426 return true;
427 }
428
429 auto it = mWaitingNotifyNotUsed.find(aBuffer->mId);
430 if (it == mWaitingNotifyNotUsed.end()) {
431 return true;
432 }
433
434 const double waitWarningTimeoutMs = 300;
435 const double maxTimeoutSec = 3;
436 auto begin = TimeStamp::Now();
437
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";
444 }
445 const auto it = mWaitingNotifyNotUsed.find(aBuffer->mId);
446 if (it == mWaitingNotifyNotUsed.end()) {
447 return true;
448 }
449 auto now = TimeStamp::Now();
450 if ((now - begin).ToSeconds() > maxTimeoutSec) {
451 isWaiting = false;
452 gfxCriticalNote << "AndroidHardwareBuffer wait timeout";
453 }
454 }
455
456 return false;
457 }
458
IsWaitingForBufferOwnership(AndroidHardwareBuffer * aBuffer)459 bool AndroidHardwareBufferManager::IsWaitingForBufferOwnership(
460 AndroidHardwareBuffer* aBuffer) {
461 MonitorAutoLock lock(mMonitor);
462
463 if (aBuffer->mTransactionId.isNothing()) {
464 return false;
465 }
466
467 auto it = mWaitingNotifyNotUsed.find(aBuffer->mId);
468 if (it == mWaitingNotifyNotUsed.end()) {
469 return false;
470 }
471 return true;
472 }
473
HoldUntilNotifyNotUsed(uint64_t aBufferId,uint64_t aFwdTransactionId,bool aUsesImageBridge)474 void AndroidHardwareBufferManager::HoldUntilNotifyNotUsed(
475 uint64_t aBufferId, uint64_t aFwdTransactionId, bool aUsesImageBridge) {
476 MOZ_ASSERT(NS_IsMainThread() || InImageBridgeChildThread());
477
478 const auto it = mBuffers.find(aBufferId);
479 if (it == mBuffers.end()) {
480 return;
481 }
482 auto buffer = RefPtr<AndroidHardwareBuffer>(it->second);
483
484 MonitorAutoLock lock(mMonitor);
485 buffer->SetLastFwdTransactionId(aFwdTransactionId, aUsesImageBridge, lock);
486 mWaitingNotifyNotUsed.emplace(aBufferId, buffer);
487 }
488
NotifyNotUsed(ipc::FileDescriptor && aFenceFd,uint64_t aBufferId,uint64_t aTransactionId,bool aUsesImageBridge)489 void AndroidHardwareBufferManager::NotifyNotUsed(ipc::FileDescriptor&& aFenceFd,
490 uint64_t aBufferId,
491 uint64_t aTransactionId,
492 bool aUsesImageBridge) {
493 MOZ_ASSERT(InImageBridgeChildThread());
494
495 MonitorAutoLock lock(mMonitor);
496
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;
502 }
503 it->second->SetReleaseFence(std::move(aFenceFd), lock);
504 mWaitingNotifyNotUsed.erase(it);
505 mMonitor.NotifyAll();
506 }
507 }
508
509 } // namespace layers
510 } // namespace mozilla
511