1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/SharedSurfaceGL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,438 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "SharedSurfaceGL.h" 1.10 +#include "GLContext.h" 1.11 +#include "GLBlitHelper.h" 1.12 +#include "ScopedGLHelpers.h" 1.13 +#include "gfxImageSurface.h" 1.14 +#include "mozilla/gfx/2D.h" 1.15 +#include "GLReadTexImageHelper.h" 1.16 + 1.17 +using namespace mozilla::gfx; 1.18 + 1.19 +namespace mozilla { 1.20 +namespace gl { 1.21 + 1.22 +// |src| must begin and end locked, though we may 1.23 +// temporarily unlock it if we need to. 1.24 +void 1.25 +SharedSurface_GL::ProdCopy(SharedSurface_GL* src, SharedSurface_GL* dest, 1.26 + SurfaceFactory_GL* factory) 1.27 +{ 1.28 + GLContext* gl = src->GL(); 1.29 + 1.30 + gl->MakeCurrent(); 1.31 + 1.32 + if (src->AttachType() == AttachmentType::Screen && 1.33 + dest->AttachType() == AttachmentType::Screen) 1.34 + { 1.35 + // Here, we actually need to blit through a temp surface, so let's make one. 1.36 + nsAutoPtr<SharedSurface_GLTexture> tempSurf( 1.37 + SharedSurface_GLTexture::Create(gl, gl, 1.38 + factory->Formats(), 1.39 + src->Size(), 1.40 + factory->Caps().alpha)); 1.41 + 1.42 + ProdCopy(src, tempSurf, factory); 1.43 + ProdCopy(tempSurf, dest, factory); 1.44 + return; 1.45 + } 1.46 + 1.47 + if (src->AttachType() == AttachmentType::Screen) { 1.48 + SharedSurface_GL* origLocked = gl->GetLockedSurface(); 1.49 + bool srcNeedsUnlock = false; 1.50 + bool origNeedsRelock = false; 1.51 + if (origLocked != src) { 1.52 + if (origLocked) { 1.53 + origLocked->UnlockProd(); 1.54 + origNeedsRelock = true; 1.55 + } 1.56 + 1.57 + src->LockProd(); 1.58 + srcNeedsUnlock = true; 1.59 + } 1.60 + 1.61 + if (dest->AttachType() == AttachmentType::GLTexture) { 1.62 + GLuint destTex = dest->ProdTexture(); 1.63 + GLenum destTarget = dest->ProdTextureTarget(); 1.64 + 1.65 + gl->BlitHelper()->BlitFramebufferToTexture(0, destTex, src->Size(), dest->Size(), destTarget); 1.66 + } else if (dest->AttachType() == AttachmentType::GLRenderbuffer) { 1.67 + GLuint destRB = dest->ProdRenderbuffer(); 1.68 + ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); 1.69 + 1.70 + gl->BlitHelper()->BlitFramebufferToFramebuffer(0, destWrapper.FB(), 1.71 + src->Size(), dest->Size()); 1.72 + } else { 1.73 + MOZ_CRASH("Unhandled dest->AttachType()."); 1.74 + } 1.75 + 1.76 + if (srcNeedsUnlock) 1.77 + src->UnlockProd(); 1.78 + 1.79 + if (origNeedsRelock) 1.80 + origLocked->LockProd(); 1.81 + 1.82 + return; 1.83 + } 1.84 + 1.85 + if (dest->AttachType() == AttachmentType::Screen) { 1.86 + SharedSurface_GL* origLocked = gl->GetLockedSurface(); 1.87 + bool destNeedsUnlock = false; 1.88 + bool origNeedsRelock = false; 1.89 + if (origLocked != dest) { 1.90 + if (origLocked) { 1.91 + origLocked->UnlockProd(); 1.92 + origNeedsRelock = true; 1.93 + } 1.94 + 1.95 + dest->LockProd(); 1.96 + destNeedsUnlock = true; 1.97 + } 1.98 + 1.99 + if (src->AttachType() == AttachmentType::GLTexture) { 1.100 + GLuint srcTex = src->ProdTexture(); 1.101 + GLenum srcTarget = src->ProdTextureTarget(); 1.102 + 1.103 + gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0, src->Size(), dest->Size(), srcTarget); 1.104 + } else if (src->AttachType() == AttachmentType::GLRenderbuffer) { 1.105 + GLuint srcRB = src->ProdRenderbuffer(); 1.106 + ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); 1.107 + 1.108 + gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0, 1.109 + src->Size(), dest->Size()); 1.110 + } else { 1.111 + MOZ_CRASH("Unhandled src->AttachType()."); 1.112 + } 1.113 + 1.114 + if (destNeedsUnlock) 1.115 + dest->UnlockProd(); 1.116 + 1.117 + if (origNeedsRelock) 1.118 + origLocked->LockProd(); 1.119 + 1.120 + return; 1.121 + } 1.122 + 1.123 + // Alright, done with cases involving Screen types. 1.124 + // Only {src,dest}x{texture,renderbuffer} left. 1.125 + 1.126 + if (src->AttachType() == AttachmentType::GLTexture) { 1.127 + GLuint srcTex = src->ProdTexture(); 1.128 + GLenum srcTarget = src->ProdTextureTarget(); 1.129 + 1.130 + if (dest->AttachType() == AttachmentType::GLTexture) { 1.131 + GLuint destTex = dest->ProdTexture(); 1.132 + GLenum destTarget = dest->ProdTextureTarget(); 1.133 + 1.134 + gl->BlitHelper()->BlitTextureToTexture(srcTex, destTex, 1.135 + src->Size(), dest->Size(), 1.136 + srcTarget, destTarget); 1.137 + 1.138 + return; 1.139 + } 1.140 + 1.141 + if (dest->AttachType() == AttachmentType::GLRenderbuffer) { 1.142 + GLuint destRB = dest->ProdRenderbuffer(); 1.143 + ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); 1.144 + 1.145 + gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(), 1.146 + src->Size(), dest->Size(), srcTarget); 1.147 + 1.148 + return; 1.149 + } 1.150 + 1.151 + MOZ_CRASH("Unhandled dest->AttachType()."); 1.152 + } 1.153 + 1.154 + if (src->AttachType() == AttachmentType::GLRenderbuffer) { 1.155 + GLuint srcRB = src->ProdRenderbuffer(); 1.156 + ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); 1.157 + 1.158 + if (dest->AttachType() == AttachmentType::GLTexture) { 1.159 + GLuint destTex = dest->ProdTexture(); 1.160 + GLenum destTarget = dest->ProdTextureTarget(); 1.161 + 1.162 + gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex, 1.163 + src->Size(), dest->Size(), destTarget); 1.164 + 1.165 + return; 1.166 + } 1.167 + 1.168 + if (dest->AttachType() == AttachmentType::GLRenderbuffer) { 1.169 + GLuint destRB = dest->ProdRenderbuffer(); 1.170 + ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); 1.171 + 1.172 + gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(), 1.173 + src->Size(), dest->Size()); 1.174 + 1.175 + return; 1.176 + } 1.177 + 1.178 + MOZ_CRASH("Unhandled dest->AttachType()."); 1.179 + } 1.180 + 1.181 + MOZ_CRASH("Unhandled src->AttachType()."); 1.182 +} 1.183 + 1.184 +void 1.185 +SharedSurface_GL::LockProd() 1.186 +{ 1.187 + MOZ_ASSERT(!mIsLocked); 1.188 + 1.189 + LockProdImpl(); 1.190 + 1.191 + mGL->LockSurface(this); 1.192 + mIsLocked = true; 1.193 +} 1.194 + 1.195 +void 1.196 +SharedSurface_GL::UnlockProd() 1.197 +{ 1.198 + if (!mIsLocked) 1.199 + return; 1.200 + 1.201 + UnlockProdImpl(); 1.202 + 1.203 + mGL->UnlockSurface(this); 1.204 + mIsLocked = false; 1.205 +} 1.206 + 1.207 + 1.208 +SurfaceFactory_GL::SurfaceFactory_GL(GLContext* gl, 1.209 + SharedSurfaceType type, 1.210 + const SurfaceCaps& caps) 1.211 + : SurfaceFactory(type, caps) 1.212 + , mGL(gl) 1.213 + , mFormats(gl->ChooseGLFormats(caps)) 1.214 +{ 1.215 + ChooseBufferBits(caps, mDrawCaps, mReadCaps); 1.216 +} 1.217 + 1.218 +void 1.219 +SurfaceFactory_GL::ChooseBufferBits(const SurfaceCaps& caps, 1.220 + SurfaceCaps& drawCaps, 1.221 + SurfaceCaps& readCaps) const 1.222 +{ 1.223 + SurfaceCaps screenCaps; 1.224 + 1.225 + screenCaps.color = caps.color; 1.226 + screenCaps.alpha = caps.alpha; 1.227 + screenCaps.bpp16 = caps.bpp16; 1.228 + 1.229 + screenCaps.depth = caps.depth; 1.230 + screenCaps.stencil = caps.stencil; 1.231 + 1.232 + screenCaps.antialias = caps.antialias; 1.233 + screenCaps.preserve = caps.preserve; 1.234 + 1.235 + if (caps.antialias) { 1.236 + drawCaps = screenCaps; 1.237 + readCaps.Clear(); 1.238 + 1.239 + // Color caps need to be duplicated in readCaps. 1.240 + readCaps.color = caps.color; 1.241 + readCaps.alpha = caps.alpha; 1.242 + readCaps.bpp16 = caps.bpp16; 1.243 + } else { 1.244 + drawCaps.Clear(); 1.245 + readCaps = screenCaps; 1.246 + } 1.247 +} 1.248 + 1.249 + 1.250 +SharedSurface_Basic* 1.251 +SharedSurface_Basic::Create(GLContext* gl, 1.252 + const GLFormats& formats, 1.253 + const IntSize& size, 1.254 + bool hasAlpha) 1.255 +{ 1.256 + gl->MakeCurrent(); 1.257 + GLuint tex = CreateTexture(gl, formats.color_texInternalFormat, 1.258 + formats.color_texFormat, 1.259 + formats.color_texType, 1.260 + size); 1.261 + 1.262 + SurfaceFormat format = SurfaceFormat::B8G8R8X8; 1.263 + switch (formats.color_texInternalFormat) { 1.264 + case LOCAL_GL_RGB: 1.265 + case LOCAL_GL_RGB8: 1.266 + if (formats.color_texType == LOCAL_GL_UNSIGNED_SHORT_5_6_5) 1.267 + format = SurfaceFormat::R5G6B5; 1.268 + else 1.269 + format = SurfaceFormat::B8G8R8X8; 1.270 + break; 1.271 + case LOCAL_GL_RGBA: 1.272 + case LOCAL_GL_RGBA8: 1.273 + format = SurfaceFormat::B8G8R8A8; 1.274 + break; 1.275 + default: 1.276 + MOZ_CRASH("Unhandled Tex format."); 1.277 + } 1.278 + return new SharedSurface_Basic(gl, size, hasAlpha, format, tex); 1.279 +} 1.280 + 1.281 +SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, 1.282 + const IntSize& size, 1.283 + bool hasAlpha, 1.284 + SurfaceFormat format, 1.285 + GLuint tex) 1.286 + : SharedSurface_GL(SharedSurfaceType::Basic, 1.287 + AttachmentType::GLTexture, 1.288 + gl, 1.289 + size, 1.290 + hasAlpha) 1.291 + , mTex(tex), mFB(0) 1.292 +{ 1.293 + mGL->MakeCurrent(); 1.294 + mGL->fGenFramebuffers(1, &mFB); 1.295 + 1.296 + ScopedBindFramebuffer autoFB(mGL, mFB); 1.297 + mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, 1.298 + LOCAL_GL_COLOR_ATTACHMENT0, 1.299 + LOCAL_GL_TEXTURE_2D, 1.300 + mTex, 1.301 + 0); 1.302 + 1.303 + GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); 1.304 + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { 1.305 + mGL->fDeleteFramebuffers(1, &mFB); 1.306 + mFB = 0; 1.307 + } 1.308 + 1.309 + mData = Factory::CreateDataSourceSurfaceWithStride(size, format, 1.310 + GetAlignedStride<4>(size.width * BytesPerPixel(format))); 1.311 +} 1.312 + 1.313 +SharedSurface_Basic::~SharedSurface_Basic() 1.314 +{ 1.315 + if (!mGL->MakeCurrent()) 1.316 + return; 1.317 + 1.318 + if (mFB) 1.319 + mGL->fDeleteFramebuffers(1, &mFB); 1.320 + 1.321 + mGL->fDeleteTextures(1, &mTex); 1.322 +} 1.323 + 1.324 +void 1.325 +SharedSurface_Basic::Fence() 1.326 +{ 1.327 + mGL->MakeCurrent(); 1.328 + 1.329 + ScopedBindFramebuffer autoFB(mGL, mFB); 1.330 + 1.331 + DataSourceSurface::MappedSurface map; 1.332 + mData->Map(DataSourceSurface::MapType::WRITE, &map); 1.333 + nsRefPtr<gfxImageSurface> wrappedData = 1.334 + new gfxImageSurface(map.mData, 1.335 + ThebesIntSize(mData->GetSize()), 1.336 + map.mStride, 1.337 + SurfaceFormatToImageFormat(mData->GetFormat())); 1.338 + ReadPixelsIntoImageSurface(mGL, wrappedData); 1.339 + mData->Unmap(); 1.340 +} 1.341 + 1.342 + 1.343 + 1.344 +SharedSurface_GLTexture* 1.345 +SharedSurface_GLTexture::Create(GLContext* prodGL, 1.346 + GLContext* consGL, 1.347 + const GLFormats& formats, 1.348 + const gfx::IntSize& size, 1.349 + bool hasAlpha, 1.350 + GLuint texture) 1.351 +{ 1.352 + MOZ_ASSERT(prodGL); 1.353 + MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL)); 1.354 + 1.355 + prodGL->MakeCurrent(); 1.356 + 1.357 + GLuint tex = texture; 1.358 + 1.359 + bool ownsTex = false; 1.360 + 1.361 + if (!tex) { 1.362 + tex = CreateTextureForOffscreen(prodGL, formats, size); 1.363 + ownsTex = true; 1.364 + } 1.365 + 1.366 + return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex, ownsTex); 1.367 +} 1.368 + 1.369 +SharedSurface_GLTexture::~SharedSurface_GLTexture() 1.370 +{ 1.371 + if (!mGL->MakeCurrent()) 1.372 + return; 1.373 + 1.374 + if (mOwnsTex) { 1.375 + mGL->fDeleteTextures(1, &mTex); 1.376 + } 1.377 + 1.378 + if (mSync) { 1.379 + mGL->fDeleteSync(mSync); 1.380 + } 1.381 +} 1.382 + 1.383 +void 1.384 +SharedSurface_GLTexture::Fence() 1.385 +{ 1.386 + MutexAutoLock lock(mMutex); 1.387 + mGL->MakeCurrent(); 1.388 + 1.389 + if (mConsGL && mGL->IsExtensionSupported(GLContext::ARB_sync)) { 1.390 + if (mSync) { 1.391 + mGL->fDeleteSync(mSync); 1.392 + mSync = 0; 1.393 + } 1.394 + 1.395 + mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 1.396 + if (mSync) { 1.397 + mGL->fFlush(); 1.398 + return; 1.399 + } 1.400 + } 1.401 + MOZ_ASSERT(!mSync); 1.402 + 1.403 + mGL->fFinish(); 1.404 +} 1.405 + 1.406 +bool 1.407 +SharedSurface_GLTexture::WaitSync() 1.408 +{ 1.409 + MutexAutoLock lock(mMutex); 1.410 + if (!mSync) { 1.411 + // We must have used glFinish instead of glFenceSync. 1.412 + return true; 1.413 + } 1.414 + 1.415 + mConsGL->MakeCurrent(); 1.416 + MOZ_ASSERT(mConsGL->IsExtensionSupported(GLContext::ARB_sync)); 1.417 + 1.418 + mConsGL->fWaitSync(mSync, 1.419 + 0, 1.420 + LOCAL_GL_TIMEOUT_IGNORED); 1.421 + mConsGL->fDeleteSync(mSync); 1.422 + mSync = 0; 1.423 + 1.424 + return true; 1.425 +} 1.426 + 1.427 +GLuint 1.428 +SharedSurface_GLTexture::ConsTexture(GLContext* consGL) 1.429 +{ 1.430 + MutexAutoLock lock(mMutex); 1.431 + MOZ_ASSERT(consGL); 1.432 + MOZ_ASSERT(mGL->SharesWith(consGL)); 1.433 + MOZ_ASSERT_IF(mConsGL, consGL == mConsGL); 1.434 + 1.435 + mConsGL = consGL; 1.436 + 1.437 + return mTex; 1.438 +} 1.439 + 1.440 +} /* namespace gfx */ 1.441 +} /* namespace mozilla */