1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/GLSharedHandleHelpers.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,330 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "GLContextEGL.h" 1.9 +#include "GLSharedHandleHelpers.h" 1.10 +#ifdef MOZ_WIDGET_ANDROID 1.11 +#include "nsSurfaceTexture.h" 1.12 +#endif 1.13 + 1.14 +namespace mozilla { 1.15 +namespace gl { 1.16 + 1.17 +enum SharedHandleType { 1.18 + SharedHandleType_Image 1.19 +#ifdef MOZ_WIDGET_ANDROID 1.20 + , SharedHandleType_SurfaceTexture 1.21 +#endif 1.22 +}; 1.23 + 1.24 +class SharedTextureHandleWrapper 1.25 +{ 1.26 +public: 1.27 + SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType) 1.28 + { 1.29 + } 1.30 + 1.31 + virtual ~SharedTextureHandleWrapper() 1.32 + { 1.33 + } 1.34 + 1.35 + SharedHandleType Type() { return mHandleType; } 1.36 + 1.37 + SharedHandleType mHandleType; 1.38 +}; 1.39 + 1.40 +#ifdef MOZ_WIDGET_ANDROID 1.41 + 1.42 +class SurfaceTextureWrapper: public SharedTextureHandleWrapper 1.43 +{ 1.44 +public: 1.45 + SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) : 1.46 + SharedTextureHandleWrapper(SharedHandleType_SurfaceTexture) 1.47 + , mSurfaceTexture(aSurfaceTexture) 1.48 + { 1.49 + } 1.50 + 1.51 + virtual ~SurfaceTextureWrapper() { 1.52 + mSurfaceTexture = nullptr; 1.53 + } 1.54 + 1.55 + nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; } 1.56 + 1.57 + nsRefPtr<nsSurfaceTexture> mSurfaceTexture; 1.58 +}; 1.59 + 1.60 +#endif // MOZ_WIDGET_ANDROID 1.61 + 1.62 +class EGLTextureWrapper : public SharedTextureHandleWrapper 1.63 +{ 1.64 +public: 1.65 + EGLTextureWrapper() : 1.66 + SharedTextureHandleWrapper(SharedHandleType_Image) 1.67 + , mEGLImage(nullptr) 1.68 + , mSyncObject(nullptr) 1.69 + { 1.70 + } 1.71 + 1.72 + // Args are the active GL context, and a texture in that GL 1.73 + // context for which to create an EGLImage. After the EGLImage 1.74 + // is created, the texture is unused by EGLTextureWrapper. 1.75 + bool CreateEGLImage(GLContext *ctx, uintptr_t texture) { 1.76 + MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase()); 1.77 + static const EGLint eglAttributes[] = { 1.78 + LOCAL_EGL_NONE 1.79 + }; 1.80 + EGLContext eglContext = GLContextEGL::Cast(ctx)->GetEGLContext(); 1.81 + mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, 1.82 + (EGLClientBuffer)texture, eglAttributes); 1.83 + if (!mEGLImage) { 1.84 +#ifdef DEBUG 1.85 + printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); 1.86 +#endif 1.87 + return false; 1.88 + } 1.89 + return true; 1.90 + } 1.91 + 1.92 + virtual ~EGLTextureWrapper() { 1.93 + if (mEGLImage) { 1.94 + sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage); 1.95 + mEGLImage = nullptr; 1.96 + } 1.97 + } 1.98 + 1.99 + const EGLImage GetEGLImage() { 1.100 + return mEGLImage; 1.101 + } 1.102 + 1.103 + // Insert a sync point on the given context, which should be the current active 1.104 + // context. 1.105 + bool MakeSync(GLContext *ctx) { 1.106 + MOZ_ASSERT(mSyncObject == nullptr); 1.107 + 1.108 + if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) { 1.109 + mSyncObject = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr); 1.110 + // We need to flush to make sure the sync object enters the command stream; 1.111 + // we can't use EGL_SYNC_FLUSH_COMMANDS_BIT at wait time, because the wait 1.112 + // happens on a different thread/context. 1.113 + ctx->fFlush(); 1.114 + } 1.115 + 1.116 + if (mSyncObject == EGL_NO_SYNC) { 1.117 + // we failed to create one, so just do a finish 1.118 + ctx->fFinish(); 1.119 + } 1.120 + 1.121 + return true; 1.122 + } 1.123 + 1.124 + bool WaitSync() { 1.125 + if (!mSyncObject) { 1.126 + // if we have no sync object, then we did a Finish() earlier 1.127 + return true; 1.128 + } 1.129 + 1.130 + // wait at most 1 second; this should really be never/rarely hit 1.131 + const uint64_t ns_per_ms = 1000 * 1000; 1.132 + EGLTime timeout = 1000 * ns_per_ms; 1.133 + 1.134 + EGLint result = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSyncObject, 0, timeout); 1.135 + sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSyncObject); 1.136 + mSyncObject = nullptr; 1.137 + 1.138 + return result == LOCAL_EGL_CONDITION_SATISFIED; 1.139 + } 1.140 + 1.141 +private: 1.142 + EGLImage mEGLImage; 1.143 + EGLSync mSyncObject; 1.144 +}; 1.145 + 1.146 +static bool DoesEGLContextSupportSharingWithEGLImage(GLContext *gl) 1.147 +{ 1.148 + return sEGLLibrary.HasKHRImageBase() && 1.149 + sEGLLibrary.HasKHRImageTexture2D() && 1.150 + gl->IsExtensionSupported(GLContext::OES_EGL_image); 1.151 +} 1.152 + 1.153 +SharedTextureHandle CreateSharedHandle(GLContext* gl, 1.154 + SharedTextureShareType shareType, 1.155 + void* buffer, 1.156 + SharedTextureBufferType bufferType) 1.157 +{ 1.158 + // unimplemented outside of EGL 1.159 + if (gl->GetContextType() != GLContextType::EGL) 1.160 + return 0; 1.161 + 1.162 + // Both EGLImage and SurfaceTexture only support same-process currently, but 1.163 + // it's possible to make SurfaceTexture work across processes. We should do that. 1.164 + if (shareType != SharedTextureShareType::SameProcess) 1.165 + return 0; 1.166 + 1.167 + switch (bufferType) { 1.168 +#ifdef MOZ_WIDGET_ANDROID 1.169 + case SharedTextureBufferType::SurfaceTexture: 1.170 + if (!gl->IsExtensionSupported(GLContext::OES_EGL_image_external)) { 1.171 + NS_WARNING("Missing GL_OES_EGL_image_external"); 1.172 + return 0; 1.173 + } 1.174 + 1.175 + return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(buffer)); 1.176 +#endif 1.177 + case SharedTextureBufferType::TextureID: { 1.178 + if (!DoesEGLContextSupportSharingWithEGLImage(gl)) 1.179 + return 0; 1.180 + 1.181 + GLuint texture = (uintptr_t)buffer; 1.182 + EGLTextureWrapper* tex = new EGLTextureWrapper(); 1.183 + if (!tex->CreateEGLImage(gl, texture)) { 1.184 + NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); 1.185 + delete tex; 1.186 + return 0; 1.187 + } 1.188 + 1.189 + return (SharedTextureHandle)tex; 1.190 + } 1.191 + default: 1.192 + NS_ERROR("Unknown shared texture buffer type"); 1.193 + return 0; 1.194 + } 1.195 +} 1.196 + 1.197 +void ReleaseSharedHandle(GLContext* gl, 1.198 + SharedTextureShareType shareType, 1.199 + SharedTextureHandle sharedHandle) 1.200 +{ 1.201 + // unimplemented outside of EGL 1.202 + if (gl->GetContextType() != GLContextType::EGL) 1.203 + return; 1.204 + 1.205 + if (shareType != SharedTextureShareType::SameProcess) { 1.206 + NS_ERROR("Implementation not available for this sharing type"); 1.207 + return; 1.208 + } 1.209 + 1.210 + SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle); 1.211 + 1.212 + switch (wrapper->Type()) { 1.213 +#ifdef MOZ_WIDGET_ANDROID 1.214 + case SharedHandleType_SurfaceTexture: 1.215 + delete wrapper; 1.216 + break; 1.217 +#endif 1.218 + 1.219 + case SharedHandleType_Image: { 1.220 + NS_ASSERTION(DoesEGLContextSupportSharingWithEGLImage(gl), "EGLImage not supported or disabled in runtime"); 1.221 + 1.222 + EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; 1.223 + delete wrap; 1.224 + break; 1.225 + } 1.226 + 1.227 + default: 1.228 + NS_ERROR("Unknown shared handle type"); 1.229 + return; 1.230 + } 1.231 +} 1.232 + 1.233 +bool GetSharedHandleDetails(GLContext* gl, 1.234 + SharedTextureShareType shareType, 1.235 + SharedTextureHandle sharedHandle, 1.236 + SharedHandleDetails& details) 1.237 +{ 1.238 + // unimplemented outside of EGL 1.239 + if (gl->GetContextType() != GLContextType::EGL) 1.240 + return false; 1.241 + 1.242 + if (shareType != SharedTextureShareType::SameProcess) 1.243 + return false; 1.244 + 1.245 + SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle); 1.246 + 1.247 + switch (wrapper->Type()) { 1.248 +#ifdef MOZ_WIDGET_ANDROID 1.249 + case SharedHandleType_SurfaceTexture: { 1.250 + SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper); 1.251 + 1.252 + details.mTarget = LOCAL_GL_TEXTURE_EXTERNAL; 1.253 + details.mTextureFormat = gfx::SurfaceFormat::R8G8B8A8; 1.254 + surfaceWrapper->SurfaceTexture()->GetTransformMatrix(details.mTextureTransform); 1.255 + break; 1.256 + } 1.257 +#endif 1.258 + 1.259 + case SharedHandleType_Image: 1.260 + details.mTarget = LOCAL_GL_TEXTURE_2D; 1.261 + details.mTextureFormat = gfx::SurfaceFormat::R8G8B8A8; 1.262 + break; 1.263 + 1.264 + default: 1.265 + NS_ERROR("Unknown shared handle type"); 1.266 + return false; 1.267 + } 1.268 + 1.269 + return true; 1.270 +} 1.271 + 1.272 +bool AttachSharedHandle(GLContext* gl, 1.273 + SharedTextureShareType shareType, 1.274 + SharedTextureHandle sharedHandle) 1.275 +{ 1.276 + // unimplemented outside of EGL 1.277 + if (gl->GetContextType() != GLContextType::EGL) 1.278 + return false; 1.279 + 1.280 + if (shareType != SharedTextureShareType::SameProcess) 1.281 + return false; 1.282 + 1.283 + SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle); 1.284 + 1.285 + switch (wrapper->Type()) { 1.286 +#ifdef MOZ_WIDGET_ANDROID 1.287 + case SharedHandleType_SurfaceTexture: { 1.288 +#ifndef DEBUG 1.289 + /* 1.290 + * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear 1.291 + * them here in order to avoid that. 1.292 + */ 1.293 + gl->GetAndClearError(); 1.294 +#endif 1.295 + SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper); 1.296 + 1.297 + // FIXME: SurfaceTexture provides a transform matrix which is supposed to 1.298 + // be applied to the texture coordinates. We should return that here 1.299 + // so we can render correctly. Bug 775083 1.300 + surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage(); 1.301 + break; 1.302 + } 1.303 +#endif // MOZ_WIDGET_ANDROID 1.304 + 1.305 + case SharedHandleType_Image: { 1.306 + NS_ASSERTION(DoesEGLContextSupportSharingWithEGLImage(gl), "EGLImage not supported or disabled in runtime"); 1.307 + 1.308 + EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; 1.309 + wrap->WaitSync(); 1.310 + gl->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); 1.311 + break; 1.312 + } 1.313 + 1.314 + default: 1.315 + NS_ERROR("Unknown shared handle type"); 1.316 + return false; 1.317 + } 1.318 + 1.319 + return true; 1.320 +} 1.321 + 1.322 +/** 1.323 + * Detach Shared GL Handle from GL_TEXTURE_2D target 1.324 + */ 1.325 +void DetachSharedHandle(GLContext*, 1.326 + SharedTextureShareType, 1.327 + SharedTextureHandle) 1.328 +{ 1.329 + // currently a no-operation 1.330 +} 1.331 + 1.332 +} 1.333 +}