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 "RenderAndroidHardwareBufferTextureHost.h"
8 
9 #include "mozilla/layers/AndroidHardwareBuffer.h"
10 #include "GLContextEGL.h"
11 #include "GLLibraryEGL.h"
12 
13 namespace mozilla {
14 namespace wr {
15 
RenderAndroidHardwareBufferTextureHost(layers::AndroidHardwareBuffer * aAndroidHardwareBuffer)16 RenderAndroidHardwareBufferTextureHost::RenderAndroidHardwareBufferTextureHost(
17     layers::AndroidHardwareBuffer* aAndroidHardwareBuffer)
18     : mAndroidHardwareBuffer(aAndroidHardwareBuffer),
19       mEGLImage(EGL_NO_IMAGE),
20       mTextureHandle(0) {
21   MOZ_ASSERT(mAndroidHardwareBuffer);
22   MOZ_COUNT_CTOR_INHERITED(RenderAndroidHardwareBufferTextureHost,
23                            RenderTextureHost);
24 }
25 
26 RenderAndroidHardwareBufferTextureHost::
~RenderAndroidHardwareBufferTextureHost()27     ~RenderAndroidHardwareBufferTextureHost() {
28   MOZ_COUNT_DTOR_INHERITED(RenderAndroidHardwareBufferTextureHost,
29                            RenderTextureHost);
30   DeleteTextureHandle();
31   DestroyEGLImage();
32 }
33 
GetSize() const34 gfx::IntSize RenderAndroidHardwareBufferTextureHost::GetSize() const {
35   if (mAndroidHardwareBuffer) {
36     return mAndroidHardwareBuffer->mSize;
37   }
38   return gfx::IntSize();
39 }
40 
EnsureLockable(wr::ImageRendering aRendering)41 bool RenderAndroidHardwareBufferTextureHost::EnsureLockable(
42     wr::ImageRendering aRendering) {
43   if (!mAndroidHardwareBuffer) {
44     return false;
45   }
46 
47   auto fenceFd = mAndroidHardwareBuffer->GetAndResetAcquireFence();
48   if (fenceFd.IsValid()) {
49     const auto& gle = gl::GLContextEGL::Cast(mGL);
50     const auto& egl = gle->mEgl;
51 
52     auto rawFD = fenceFd.TakePlatformHandle();
53     const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
54                               rawFD.get(), LOCAL_EGL_NONE};
55 
56     EGLSync sync =
57         egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
58     if (sync) {
59       // Release fd here, since it is owned by EGLSync
60       Unused << rawFD.release();
61 
62       if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) {
63         egl->fWaitSync(sync, 0);
64       } else {
65         egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER);
66       }
67       egl->fDestroySync(sync);
68     } else {
69       gfxCriticalNote << "Failed to create EGLSync from acquire fence fd";
70     }
71   }
72 
73   if (mTextureHandle) {
74     // Update filter if filter was changed.
75     if (IsFilterUpdateNecessary(aRendering)) {
76       ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
77                                    LOCAL_GL_TEXTURE_EXTERNAL_OES,
78                                    mTextureHandle, aRendering);
79       // Cache new rendering filter.
80       mCachedRendering = aRendering;
81     }
82     return true;
83   }
84 
85   if (!mEGLImage) {
86     // XXX add crop handling for video
87     // Should only happen the first time.
88     const auto& gle = gl::GLContextEGL::Cast(mGL);
89     const auto& egl = gle->mEgl;
90 
91     const EGLint attrs[] = {
92         LOCAL_EGL_IMAGE_PRESERVED,
93         LOCAL_EGL_TRUE,
94         LOCAL_EGL_NONE,
95         LOCAL_EGL_NONE,
96     };
97 
98     EGLClientBuffer clientBuffer = egl->mLib->fGetNativeClientBufferANDROID(
99         mAndroidHardwareBuffer->GetNativeBuffer());
100     mEGLImage = egl->fCreateImage(
101         EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
102   }
103   MOZ_ASSERT(mEGLImage);
104 
105   mGL->fGenTextures(1, &mTextureHandle);
106   mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTextureHandle);
107   mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_T,
108                       LOCAL_GL_CLAMP_TO_EDGE);
109   mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_S,
110                       LOCAL_GL_CLAMP_TO_EDGE);
111   mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mEGLImage);
112 
113   ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
114                                LOCAL_GL_TEXTURE_EXTERNAL_OES, mTextureHandle,
115                                aRendering);
116   // Cache rendering filter.
117   mCachedRendering = aRendering;
118   return true;
119 }
120 
Lock(uint8_t aChannelIndex,gl::GLContext * aGL,wr::ImageRendering aRendering)121 wr::WrExternalImage RenderAndroidHardwareBufferTextureHost::Lock(
122     uint8_t aChannelIndex, gl::GLContext* aGL, wr::ImageRendering aRendering) {
123   MOZ_ASSERT(aChannelIndex == 0);
124 
125   if (mGL.get() != aGL) {
126     if (mGL) {
127       // This should not happen.
128       MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
129       return InvalidToWrExternalImage();
130     }
131     mGL = aGL;
132   }
133 
134   if (!mGL || !mGL->MakeCurrent()) {
135     return InvalidToWrExternalImage();
136   }
137 
138   if (!EnsureLockable(aRendering)) {
139     return InvalidToWrExternalImage();
140   }
141 
142   return NativeTextureToWrExternalImage(mTextureHandle, 0, 0, GetSize().width,
143                                         GetSize().height);
144 }
145 
Unlock()146 void RenderAndroidHardwareBufferTextureHost::Unlock() {}
147 
Bytes()148 size_t RenderAndroidHardwareBufferTextureHost::Bytes() {
149   return GetSize().width * GetSize().height *
150          BytesPerPixel(mAndroidHardwareBuffer->mFormat);
151 }
152 
DeleteTextureHandle()153 void RenderAndroidHardwareBufferTextureHost::DeleteTextureHandle() {
154   if (!mTextureHandle) {
155     return;
156   }
157   MOZ_ASSERT(mGL);
158   mGL->fDeleteTextures(1, &mTextureHandle);
159   mTextureHandle = 0;
160 }
161 
DestroyEGLImage()162 void RenderAndroidHardwareBufferTextureHost::DestroyEGLImage() {
163   if (!mEGLImage) {
164     return;
165   }
166   MOZ_ASSERT(mGL);
167   const auto& gle = gl::GLContextEGL::Cast(mGL);
168   const auto& egl = gle->mEgl;
169   egl->fDestroyImage(mEGLImage);
170   mEGLImage = EGL_NO_IMAGE;
171 }
172 
173 }  // namespace wr
174 }  // namespace mozilla
175