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