Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / gfx / layers / AndroidHardwareBuffer.cpp
blob6c474194aa8ca6582ae8b680010030f9ca7b3fc5
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 MOZ_ASSERT(XRE_IsGPUProcess());
46 sInstance = new AndroidHardwareBufferApi();
47 if (!sInstance->Load()) {
48 sInstance = nullptr;
52 /* static */
53 void AndroidHardwareBufferApi::Shutdown() { sInstance = nullptr; }
55 AndroidHardwareBufferApi::AndroidHardwareBufferApi() {}
57 bool AndroidHardwareBufferApi::Load() {
58 void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
59 MOZ_ASSERT(handle);
60 if (!handle) {
61 gfxCriticalNote << "Failed to load libandroid.so";
62 return false;
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";
90 return false;
92 return true;
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,
117 aOutVirtualAddress);
120 int AndroidHardwareBufferApi::Unlock(AHardwareBuffer* aBuffer,
121 int32_t* aFence) {
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);
135 /* static */
136 uint64_t AndroidHardwareBuffer::GetNextId() {
137 static std::atomic<uint64_t> sNextId = 0;
138 uint64_t id = ++sNextId;
139 return id;
142 /* static */
143 already_AddRefed<AndroidHardwareBuffer> AndroidHardwareBuffer::Create(
144 gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
145 if (!AndroidHardwareBufferApi::Get()) {
146 return nullptr;
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) {
154 return nullptr;
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);
169 if (!nativeBuffer) {
170 return nullptr;
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,
183 gfx::IntSize aSize,
184 uint32_t aStride,
185 gfx::SurfaceFormat aFormat,
186 uint64_t aId)
187 : mSize(aSize),
188 mStride(aStride),
189 mFormat(aFormat),
190 mId(aId),
191 mNativeBuffer(aNativeBuffer),
192 mIsRegistered(false) {
193 MOZ_ASSERT(mNativeBuffer);
194 #ifdef DEBUG
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);
201 #endif
204 AndroidHardwareBuffer::~AndroidHardwareBuffer() {
205 if (mIsRegistered) {
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;
216 if (fd.IsValid()) {
217 rawFd = fd.TakePlatformHandle();
218 fenceFd = rawFd.get();
220 return AndroidHardwareBufferApi::Get()->Lock(mNativeBuffer, aUsage, fenceFd,
221 aRect, aOutVirtualAddress);
224 int AndroidHardwareBuffer::Unlock() {
225 int rawFd = -1;
226 // XXX All tested recent Android devices did not return valid fence.
227 int ret = AndroidHardwareBufferApi::Get()->Unlock(mNativeBuffer, &rawFd);
228 if (ret != 0) {
229 return ret;
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.
235 if (rawFd >= 0) {
236 acquireFenceFd = ipc::FileDescriptor(UniqueFileHandle(rawFd));
239 if (acquireFenceFd.IsValid()) {
240 SetAcquireFence(std::move(acquireFenceFd));
242 return 0;
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;
294 /* static */
295 void AndroidHardwareBufferManager::Init() {
296 MOZ_ASSERT(XRE_IsGPUProcess());
298 sInstance = new AndroidHardwareBufferManager();
301 /* static */
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);
314 #ifdef DEBUG
315 const auto it = mBuffers.find(aBuffer->mId);
316 MOZ_ASSERT(it == mBuffers.end());
317 #endif
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";
328 return;
330 mBuffers.erase(it);
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()) {
339 return nullptr;
341 auto buffer = RefPtr<AndroidHardwareBuffer>(it->second);
342 return buffer.forget();
345 } // namespace layers
346 } // namespace mozilla