SharedSurfaceEGL.cpp (8756B)
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 "SharedSurfaceEGL.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 "SharedSurface.h" 16 17 #if defined(MOZ_WIDGET_ANDROID) 18 # include "AndroidNativeWindow.h" 19 # include "mozilla/java/SurfaceAllocatorWrappers.h" 20 # include "mozilla/java/GeckoSurfaceTextureWrappers.h" 21 #endif // defined(MOZ_WIDGET_ANDROID) 22 23 namespace mozilla { 24 namespace gl { 25 26 static bool HasEglImageExtensions(const GLContextEGL& gl) { 27 const auto& egl = *(gl.mEgl); 28 return egl.HasKHRImageBase() && 29 egl.IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) && 30 (gl.IsExtensionSupported(GLContext::OES_EGL_image_external) || 31 gl.IsExtensionSupported(GLContext::OES_EGL_image)); 32 } 33 34 /*static*/ 35 UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create( 36 GLContext& gl_) { 37 auto& gl = *GLContextEGL::Cast(&gl_); 38 if (!HasEglImageExtensions(gl)) return nullptr; 39 40 const auto partialDesc = PartialSharedSurfaceDesc{ 41 &gl, SharedSurfaceType::EGLImageShare, layers::TextureType::EGLImage, 42 false, // Can't recycle, as mSync changes never update TextureHost. 43 }; 44 return AsUnique(new SurfaceFactory_EGLImage(partialDesc)); 45 } 46 47 // - 48 49 /*static*/ 50 UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create( 51 const SharedSurfaceDesc& desc) { 52 const auto& gle = GLContextEGL::Cast(desc.gl); 53 const auto& context = gle->mContext; 54 const auto& egl = *(gle->mEgl); 55 56 auto fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false); 57 if (!fb) return nullptr; 58 59 const auto buffer = reinterpret_cast<EGLClientBuffer>(fb->ColorTex()); 60 const auto image = 61 egl.fCreateImage(context, LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr); 62 if (!image) return nullptr; 63 64 return AsUnique(new SharedSurface_EGLImage(desc, std::move(fb), image)); 65 } 66 67 SharedSurface_EGLImage::SharedSurface_EGLImage(const SharedSurfaceDesc& desc, 68 UniquePtr<MozFramebuffer>&& fb, 69 const EGLImage image) 70 : SharedSurface(desc, std::move(fb)), 71 mMutex("SharedSurface_EGLImage mutex"), 72 mEglDisplay(GLContextEGL::Cast(desc.gl)->mEgl), 73 mImage(image) {} 74 75 SharedSurface_EGLImage::~SharedSurface_EGLImage() { 76 if (auto display = mEglDisplay.lock()) { 77 display->fDestroyImage(mImage); 78 79 if (mSync) { 80 // We can't call this unless we have the ext, but we will always have 81 // the ext if we have something to destroy. 82 display->fDestroySync(mSync); 83 } 84 } 85 } 86 87 void SharedSurface_EGLImage::ProducerReleaseImpl() { 88 const auto& gl = GLContextEGL::Cast(mDesc.gl); 89 const auto& egl = gl->mEgl; 90 91 MutexAutoLock lock(mMutex); 92 gl->MakeCurrent(); 93 94 if (egl->IsExtensionSupported(EGLExtension::KHR_fence_sync) && 95 gl->IsExtensionSupported(GLContext::OES_EGL_sync)) { 96 if (mSync) { 97 MOZ_ALWAYS_TRUE(egl->fDestroySync(mSync)); 98 mSync = 0; 99 } 100 101 mSync = egl->fCreateSync(LOCAL_EGL_SYNC_FENCE, nullptr); 102 if (mSync) { 103 gl->fFlush(); 104 return; 105 } 106 } 107 108 MOZ_ASSERT(!mSync); 109 gl->fFinish(); 110 } 111 112 void SharedSurface_EGLImage::ProducerReadAcquireImpl() { 113 const auto& gle = GLContextEGL::Cast(mDesc.gl); 114 const auto& egl = gle->mEgl; 115 // Wait on the fence, because presumably we're going to want to read this 116 // surface 117 if (mSync) { 118 egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER); 119 } 120 } 121 122 Maybe<layers::SurfaceDescriptor> SharedSurface_EGLImage::ToSurfaceDescriptor() { 123 return Some(layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync, 124 mDesc.size, true)); 125 } 126 127 //////////////////////////////////////////////////////////////////////// 128 129 #ifdef MOZ_WIDGET_ANDROID 130 131 /*static*/ 132 UniquePtr<SharedSurface_SurfaceTexture> SharedSurface_SurfaceTexture::Create( 133 const SharedSurfaceDesc& desc) { 134 const auto& size = desc.size; 135 136 jni::Object::LocalRef surfaceObj; 137 const bool useSingleBuffer = 138 desc.gl->Renderer() != GLRenderer::AndroidEmulator; 139 140 if (useSingleBuffer) { 141 surfaceObj = 142 java::SurfaceAllocator::AcquireSurface(size.width, size.height, true); 143 } 144 145 if (!surfaceObj) { 146 // Try multi-buffer mode 147 surfaceObj = 148 java::SurfaceAllocator::AcquireSurface(size.width, size.height, false); 149 } 150 151 if (!surfaceObj) { 152 // Give up 153 NS_WARNING("Failed to allocate SurfaceTexture!"); 154 return nullptr; 155 } 156 const auto surface = java::GeckoSurface::Ref::From(surfaceObj); 157 158 AndroidNativeWindow window(surface); 159 const auto& gle = GLContextEGL::Cast(desc.gl); 160 MOZ_ASSERT(gle); 161 const auto eglSurface = gle->CreateCompatibleSurface(window.NativeWindow()); 162 if (!eglSurface) return nullptr; 163 164 return AsUnique(new SharedSurface_SurfaceTexture(desc, surface, eglSurface)); 165 } 166 167 SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture( 168 const SharedSurfaceDesc& desc, java::GeckoSurface::Param surface, 169 const EGLSurface eglSurface) 170 : SharedSurface(desc, nullptr), 171 mSurface(surface), 172 mEglSurface(eglSurface), 173 mEglDisplay(GLContextEGL::Cast(desc.gl)->mEgl) {} 174 175 SharedSurface_SurfaceTexture::~SharedSurface_SurfaceTexture() { 176 if (mOrigEglSurface) { 177 // We are about to destroy mEglSurface. 178 // Make sure gl->SetEGLSurfaceOverride() doesn't keep a reference 179 // to the surface. 180 UnlockProd(); 181 } 182 183 std::shared_ptr<EglDisplay> display = mEglDisplay.lock(); 184 if (display) { 185 display->fDestroySurface(mEglSurface); 186 } 187 java::SurfaceAllocator::DisposeSurface(mSurface); 188 } 189 190 void SharedSurface_SurfaceTexture::LockProdImpl() { 191 MOZ_RELEASE_ASSERT(mSurface->GetAvailable()); 192 193 GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl); 194 mOrigEglSurface = gl->GetEGLSurfaceOverride(); 195 gl->SetEGLSurfaceOverride(mEglSurface); 196 } 197 198 void SharedSurface_SurfaceTexture::UnlockProdImpl() { 199 MOZ_RELEASE_ASSERT(mSurface->GetAvailable()); 200 201 GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl); 202 MOZ_ASSERT(gl->GetEGLSurfaceOverride() == mEglSurface); 203 204 gl->SetEGLSurfaceOverride(mOrigEglSurface); 205 mOrigEglSurface = nullptr; 206 } 207 208 void SharedSurface_SurfaceTexture::ProducerReadReleaseImpl() { 209 // This GeckoSurfaceTexture is not SurfaceTexture of this class's GeckoSurface 210 // when current process is content process. In this case, SurfaceTexture of 211 // this class's GeckoSurface does not exist in this process. It exists in 212 // compositor's process. Then GeckoSurfaceTexture in this process is a sync 213 // surface that copies back the SurfaceTextrure from compositor's process. It 214 // was added by Bug 1486659. Then SurfaceTexture::UpdateTexImage() becomes 215 // very heavy weight, since it does copy back the SurfaceTextrure from 216 // compositor's process. 217 java::GeckoSurfaceTexture::LocalRef surfaceTexture = 218 java::GeckoSurfaceTexture::Lookup(mSurface->GetHandle()); 219 if (!surfaceTexture) { 220 NS_ERROR("Didn't find GeckoSurfaceTexture in ProducerReadReleaseImpl"); 221 return; 222 } 223 surfaceTexture->UpdateTexImage(); 224 // Non single buffer mode Surface does not need ReleaseTexImage() call. 225 // When SurfaceTexture is sync Surface, it might not be single buffer mode. 226 if (surfaceTexture->IsSingleBuffer()) { 227 surfaceTexture->ReleaseTexImage(); 228 } 229 } 230 231 void SharedSurface_SurfaceTexture::Commit() { 232 MOZ_RELEASE_ASSERT(mSurface->GetAvailable()); 233 234 LockProdImpl(); 235 mDesc.gl->SwapBuffers(); 236 UnlockProdImpl(); 237 mSurface->SetAvailable(false); 238 } 239 240 void SharedSurface_SurfaceTexture::WaitForBufferOwnership() { 241 mSurface->SetAvailable(true); 242 } 243 244 bool SharedSurface_SurfaceTexture::IsBufferAvailable() const { 245 return mSurface->GetAvailable(); 246 } 247 248 bool SharedSurface_SurfaceTexture::IsValid() const { 249 return !mSurface->IsReleased(); 250 } 251 252 Maybe<layers::SurfaceDescriptor> 253 SharedSurface_SurfaceTexture::ToSurfaceDescriptor() { 254 return Some(layers::SurfaceTextureDescriptor( 255 mSurface->GetHandle(), mDesc.size, gfx::SurfaceFormat::R8G8B8A8, 256 false /* Do NOT override colorspace */, false /* NOT continuous */, 257 Nothing() /* Do not override transform */)); 258 } 259 260 SurfaceFactory_SurfaceTexture::SurfaceFactory_SurfaceTexture(GLContext& gl) 261 : SurfaceFactory({&gl, SharedSurfaceType::AndroidSurfaceTexture, 262 layers::TextureType::AndroidNativeWindow, true}) {} 263 264 #endif // MOZ_WIDGET_ANDROID 265 266 } // namespace gl 267 268 } /* namespace mozilla */