1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "SharedSurfaceAndroidHardwareBuffer.h"
7 
8 #include "GLBlitHelper.h"
9 #include "GLContextEGL.h"
10 #include "GLContextProvider.h"
11 #include "GLLibraryEGL.h"
12 #include "GLReadTexImageHelper.h"
13 #include "MozFramebuffer.h"
14 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
15 #include "mozilla/layers/AndroidHardwareBuffer.h"
16 #include "ScopedGLHelpers.h"
17 #include "SharedSurface.h"
18 
19 namespace mozilla {
20 namespace gl {
21 
22 /*static*/
23 UniquePtr<SharedSurface_AndroidHardwareBuffer>
Create(const SharedSurfaceDesc & desc)24 SharedSurface_AndroidHardwareBuffer::Create(const SharedSurfaceDesc& desc) {
25   const auto& gle = GLContextEGL::Cast(desc.gl);
26   const auto& egl = gle->mEgl;
27 
28   RefPtr<layers::AndroidHardwareBuffer> buffer =
29       layers::AndroidHardwareBuffer::Create(desc.size,
30                                             gfx::SurfaceFormat::R8G8B8A8);
31   if (!buffer) {
32     return nullptr;
33   }
34 
35   const EGLint attrs[] = {
36       LOCAL_EGL_IMAGE_PRESERVED,
37       LOCAL_EGL_TRUE,
38       LOCAL_EGL_NONE,
39       LOCAL_EGL_NONE,
40   };
41 
42   EGLClientBuffer clientBuffer =
43       egl->mLib->fGetNativeClientBufferANDROID(buffer->GetNativeBuffer());
44   const auto image = egl->fCreateImage(
45       EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
46   if (!image) {
47     return nullptr;
48   }
49 
50   auto tex = MakeUnique<Texture>(*desc.gl);
51   {
52     ScopedBindTexture texture(gle, tex->name, LOCAL_GL_TEXTURE_2D);
53     gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
54                         LOCAL_GL_LINEAR);
55     gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
56                         LOCAL_GL_LINEAR);
57     gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
58                         LOCAL_GL_CLAMP_TO_EDGE);
59     gle->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
60                         LOCAL_GL_CLAMP_TO_EDGE);
61     gle->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image);
62     egl->fDestroyImage(image);
63   }
64 
65   const GLenum target = LOCAL_GL_TEXTURE_2D;
66   auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false,
67                                              target, tex->name);
68   if (!fb) {
69     return nullptr;
70   }
71 
72   return AsUnique(new SharedSurface_AndroidHardwareBuffer(
73       desc, std::move(fb), std::move(tex), buffer));
74 }
75 
SharedSurface_AndroidHardwareBuffer(const SharedSurfaceDesc & desc,UniquePtr<MozFramebuffer> fb,UniquePtr<Texture> tex,RefPtr<layers::AndroidHardwareBuffer> buffer)76 SharedSurface_AndroidHardwareBuffer::SharedSurface_AndroidHardwareBuffer(
77     const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer> fb,
78     UniquePtr<Texture> tex, RefPtr<layers::AndroidHardwareBuffer> buffer)
79     : SharedSurface(desc, std::move(fb)),
80       mTex(std::move(tex)),
81       mAndroidHardwareBuffer(buffer) {}
82 
~SharedSurface_AndroidHardwareBuffer()83 SharedSurface_AndroidHardwareBuffer::~SharedSurface_AndroidHardwareBuffer() {
84   const auto& gl = mDesc.gl;
85   if (!gl || !gl->MakeCurrent()) {
86     return;
87   }
88   const auto& gle = GLContextEGL::Cast(gl);
89   const auto& egl = gle->mEgl;
90 
91   if (mSync) {
92     egl->fDestroySync(mSync);
93     mSync = 0;
94   }
95 }
96 
ProducerReleaseImpl()97 void SharedSurface_AndroidHardwareBuffer::ProducerReleaseImpl() {
98   const auto& gl = mDesc.gl;
99   if (!gl || !gl->MakeCurrent()) {
100     return;
101   }
102   const auto& gle = GLContextEGL::Cast(gl);
103   const auto& egl = gle->mEgl;
104 
105   if (mSync) {
106     MOZ_ALWAYS_TRUE(egl->fDestroySync(mSync));
107     mSync = 0;
108   }
109 
110   mSync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
111   MOZ_ASSERT(mSync);
112   int rawFd = egl->fDupNativeFenceFDANDROID(mSync);
113   if (rawFd >= 0) {
114     auto fenceFd = ipc::FileDescriptor(UniqueFileHandle(rawFd));
115     mAndroidHardwareBuffer->SetAcquireFence(std::move(fenceFd));
116   }
117 
118   gl->fFlush();
119 }
120 
121 Maybe<layers::SurfaceDescriptor>
ToSurfaceDescriptor()122 SharedSurface_AndroidHardwareBuffer::ToSurfaceDescriptor() {
123   // Create SurfaceDescriptor without a valid file descriptor.
124   // The valid file descriptor is created by
125   // SharedSurfaceTextureData::Serialize().
126   // When valid file descriptor is created in this function,
127   // It causes out of file descriptor in this process, since the function is
128   // called for each layer transaction.
129   return Some(layers::SurfaceDescriptorAndroidHardwareBuffer(
130       ipc::FileDescriptor(), mAndroidHardwareBuffer->mId,
131       mAndroidHardwareBuffer->mSize, mAndroidHardwareBuffer->mFormat));
132 }
133 
WaitForBufferOwnership()134 void SharedSurface_AndroidHardwareBuffer::WaitForBufferOwnership() {
135   mAndroidHardwareBuffer->WaitForBufferOwnership();
136 
137   ipc::FileDescriptor fenceFd =
138       mAndroidHardwareBuffer->GetAndResetReleaseFence();
139   if (!fenceFd.IsValid()) {
140     return;
141   }
142 
143   const auto& gle = GLContextEGL::Cast(mDesc.gl);
144   const auto& egl = gle->mEgl;
145 
146   auto rawFD = fenceFd.TakePlatformHandle();
147   const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, rawFD.get(),
148                             LOCAL_EGL_NONE};
149 
150   EGLSync sync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
151   if (!sync) {
152     gfxCriticalNote << "Failed to create EGLSync from fd";
153     return;
154   }
155   // Release fd here, since it is owned by EGLSync
156   Unused << rawFD.release();
157 
158   egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER);
159   egl->fDestroySync(sync);
160 }
161 
162 /*static*/
163 UniquePtr<SurfaceFactory_AndroidHardwareBuffer>
Create(GLContext & gl)164 SurfaceFactory_AndroidHardwareBuffer::Create(GLContext& gl) {
165   const auto partialDesc = PartialSharedSurfaceDesc{
166       &gl,
167       SharedSurfaceType::AndroidHardwareBuffer,
168       layers::TextureType::AndroidHardwareBuffer,
169       true,
170   };
171   return AsUnique(new SurfaceFactory_AndroidHardwareBuffer(partialDesc));
172 }
173 
174 }  // namespace gl
175 
176 } /* namespace mozilla */
177