1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/SurfaceStream.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,489 @@ 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 "SurfaceStream.h" 1.10 + 1.11 +#include "gfxPoint.h" 1.12 +#include "SharedSurface.h" 1.13 +#include "SharedSurfaceGL.h" 1.14 +#include "SurfaceFactory.h" 1.15 +#include "GeckoProfiler.h" 1.16 + 1.17 +namespace mozilla { 1.18 +namespace gfx { 1.19 + 1.20 +SurfaceStreamType 1.21 +SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc, 1.22 + bool preserveBuffer) 1.23 +{ 1.24 + if (omtc == SurfaceStream::OffMainThread) { 1.25 + if (preserveBuffer) 1.26 + return SurfaceStreamType::TripleBuffer_Copy; 1.27 + else 1.28 + return SurfaceStreamType::TripleBuffer_Async; 1.29 + } else { 1.30 + if (preserveBuffer) 1.31 + return SurfaceStreamType::SingleBuffer; 1.32 + else 1.33 + return SurfaceStreamType::TripleBuffer; 1.34 + } 1.35 +} 1.36 + 1.37 +SurfaceStream* 1.38 +SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glContext, SurfaceStream* prevStream) 1.39 +{ 1.40 + SurfaceStream* result = nullptr; 1.41 + 1.42 + switch (type) { 1.43 + case SurfaceStreamType::SingleBuffer: 1.44 + result = new SurfaceStream_SingleBuffer(prevStream); 1.45 + break; 1.46 + case SurfaceStreamType::TripleBuffer_Copy: 1.47 + result = new SurfaceStream_TripleBuffer_Copy(prevStream); 1.48 + break; 1.49 + case SurfaceStreamType::TripleBuffer_Async: 1.50 + result = new SurfaceStream_TripleBuffer_Async(prevStream); 1.51 + break; 1.52 + case SurfaceStreamType::TripleBuffer: 1.53 + result = new SurfaceStream_TripleBuffer(prevStream); 1.54 + break; 1.55 + default: 1.56 + MOZ_CRASH("Invalid Type."); 1.57 + } 1.58 + 1.59 + result->mGLContext = glContext; 1.60 + return result; 1.61 +} 1.62 + 1.63 +bool 1.64 +SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory) 1.65 +{ 1.66 + if (!mProducer) { 1.67 + New(factory, src->Size(), mProducer); 1.68 + if (!mProducer) { 1.69 + return false; 1.70 + } 1.71 + } 1.72 + 1.73 + MOZ_ASSERT(src->Size() == mProducer->Size(), "Size mismatch"); 1.74 + 1.75 + SharedSurface::Copy(src, mProducer, factory); 1.76 + return true; 1.77 +} 1.78 + 1.79 +void 1.80 +SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size, 1.81 + SharedSurface*& surf) 1.82 +{ 1.83 + MOZ_ASSERT(!surf); 1.84 + surf = factory->NewSharedSurface(size); 1.85 + 1.86 + if (surf) 1.87 + mSurfaces.insert(surf); 1.88 +} 1.89 + 1.90 +void 1.91 +SurfaceStream::Recycle(SurfaceFactory* factory, SharedSurface*& surf) 1.92 +{ 1.93 + if (surf) { 1.94 + mSurfaces.erase(surf); 1.95 + factory->Recycle(surf); 1.96 + } 1.97 + MOZ_ASSERT(!surf); 1.98 +} 1.99 + 1.100 +void 1.101 +SurfaceStream::Delete(SharedSurface*& surf) 1.102 +{ 1.103 + if (surf) { 1.104 + mSurfaces.erase(surf); 1.105 + delete surf; 1.106 + surf = nullptr; 1.107 + } 1.108 + MOZ_ASSERT(!surf); 1.109 +} 1.110 + 1.111 +SharedSurface* 1.112 +SurfaceStream::Surrender(SharedSurface*& surf) 1.113 +{ 1.114 + SharedSurface* ret = surf; 1.115 + 1.116 + if (surf) { 1.117 + mSurfaces.erase(surf); 1.118 + surf = nullptr; 1.119 + } 1.120 + MOZ_ASSERT(!surf); 1.121 + 1.122 + return ret; 1.123 +} 1.124 + 1.125 +SharedSurface* 1.126 +SurfaceStream::Absorb(SharedSurface*& surf) 1.127 +{ 1.128 + SharedSurface* ret = surf; 1.129 + 1.130 + if (surf) { 1.131 + mSurfaces.insert(surf); 1.132 + surf = nullptr; 1.133 + } 1.134 + MOZ_ASSERT(!surf); 1.135 + 1.136 + return ret; 1.137 +} 1.138 + 1.139 +void 1.140 +SurfaceStream::Scrap(SharedSurface*& scrap) 1.141 +{ 1.142 + if (scrap) { 1.143 + mScraps.push(scrap); 1.144 + scrap = nullptr; 1.145 + } 1.146 + MOZ_ASSERT(!scrap); 1.147 +} 1.148 + 1.149 +void 1.150 +SurfaceStream::RecycleScraps(SurfaceFactory* factory) 1.151 +{ 1.152 + while (!mScraps.empty()) { 1.153 + SharedSurface* cur = mScraps.top(); 1.154 + mScraps.pop(); 1.155 + 1.156 + Recycle(factory, cur); 1.157 + } 1.158 +} 1.159 + 1.160 + 1.161 + 1.162 +SurfaceStream::~SurfaceStream() 1.163 +{ 1.164 + Delete(mProducer); 1.165 + 1.166 + while (!mScraps.empty()) { 1.167 + SharedSurface* cur = mScraps.top(); 1.168 + mScraps.pop(); 1.169 + 1.170 + Delete(cur); 1.171 + } 1.172 + 1.173 + MOZ_ASSERT(mSurfaces.empty()); 1.174 +} 1.175 + 1.176 +SharedSurface* 1.177 +SurfaceStream::SwapConsumer() 1.178 +{ 1.179 + MOZ_ASSERT(mIsAlive); 1.180 + 1.181 + SharedSurface* ret = SwapConsumer_NoWait(); 1.182 + if (!ret) 1.183 + return nullptr; 1.184 + 1.185 + if (!ret->WaitSync()) { 1.186 + return nullptr; 1.187 + } 1.188 + 1.189 + return ret; 1.190 +} 1.191 + 1.192 +SharedSurface* 1.193 +SurfaceStream::Resize(SurfaceFactory* factory, const gfx::IntSize& size) 1.194 +{ 1.195 + MonitorAutoLock lock(mMonitor); 1.196 + 1.197 + if (mProducer) { 1.198 + Scrap(mProducer); 1.199 + } 1.200 + 1.201 + New(factory, size, mProducer); 1.202 + return mProducer; 1.203 +} 1.204 + 1.205 +SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream* prevStream) 1.206 + : SurfaceStream(SurfaceStreamType::SingleBuffer, prevStream) 1.207 + , mConsumer(nullptr) 1.208 +{ 1.209 + if (!prevStream) 1.210 + return; 1.211 + 1.212 + SharedSurface* prevProducer = nullptr; 1.213 + SharedSurface* prevConsumer = nullptr; 1.214 + prevStream->SurrenderSurfaces(prevProducer, prevConsumer); 1.215 + 1.216 + if (prevConsumer == prevProducer) 1.217 + prevConsumer = nullptr; 1.218 + 1.219 + mProducer = Absorb(prevProducer); 1.220 + mConsumer = Absorb(prevConsumer); 1.221 +} 1.222 + 1.223 +SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer() 1.224 +{ 1.225 + Delete(mConsumer); 1.226 +} 1.227 + 1.228 +void 1.229 +SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer, 1.230 + SharedSurface*& consumer) 1.231 +{ 1.232 + mIsAlive = false; 1.233 + 1.234 + producer = Surrender(mProducer); 1.235 + consumer = Surrender(mConsumer); 1.236 + 1.237 + if (!consumer) 1.238 + consumer = producer; 1.239 +} 1.240 + 1.241 +SharedSurface* 1.242 +SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory, 1.243 + const gfx::IntSize& size) 1.244 +{ 1.245 + MonitorAutoLock lock(mMonitor); 1.246 + if (mConsumer) { 1.247 + Recycle(factory, mConsumer); 1.248 + } 1.249 + 1.250 + if (mProducer) { 1.251 + // Fence now, before we start (maybe) juggling Prod around. 1.252 + mProducer->Fence(); 1.253 + 1.254 + // Size mismatch means we need to squirrel the current Prod 1.255 + // into Cons, and leave Prod empty, so it gets a new surface below. 1.256 + bool needsNewBuffer = mProducer->Size() != size; 1.257 + 1.258 + // Even if we're the right size, if the type has changed, and we don't 1.259 + // need to preserve, we should switch out for (presumedly) better perf. 1.260 + if (mProducer->Type() != factory->Type() && 1.261 + !factory->Caps().preserve) 1.262 + { 1.263 + needsNewBuffer = true; 1.264 + } 1.265 + 1.266 + if (needsNewBuffer) { 1.267 + Move(mProducer, mConsumer); 1.268 + } 1.269 + } 1.270 + 1.271 + // The old Prod (if there every was one) was invalid, 1.272 + // so we need a new one. 1.273 + if (!mProducer) { 1.274 + New(factory, size, mProducer); 1.275 + } 1.276 + 1.277 + return mProducer; 1.278 +} 1.279 + 1.280 +SharedSurface* 1.281 +SurfaceStream_SingleBuffer::SwapConsumer_NoWait() 1.282 +{ 1.283 + MonitorAutoLock lock(mMonitor); 1.284 + 1.285 + // Use Cons, if present. 1.286 + // Otherwise, just use Prod directly. 1.287 + SharedSurface* toConsume = mConsumer; 1.288 + if (!toConsume) 1.289 + toConsume = mProducer; 1.290 + 1.291 + return toConsume; 1.292 +} 1.293 + 1.294 + 1.295 + 1.296 +SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream) 1.297 + : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream) 1.298 + , mStaging(nullptr) 1.299 + , mConsumer(nullptr) 1.300 +{ 1.301 + if (!prevStream) 1.302 + return; 1.303 + 1.304 + SharedSurface* prevProducer = nullptr; 1.305 + SharedSurface* prevConsumer = nullptr; 1.306 + prevStream->SurrenderSurfaces(prevProducer, prevConsumer); 1.307 + 1.308 + if (prevConsumer == prevProducer) 1.309 + prevConsumer = nullptr; 1.310 + 1.311 + mProducer = Absorb(prevProducer); 1.312 + mConsumer = Absorb(prevConsumer); 1.313 +} 1.314 + 1.315 +SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy() 1.316 +{ 1.317 + Delete(mStaging); 1.318 + Delete(mConsumer); 1.319 +} 1.320 + 1.321 +void 1.322 +SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer, 1.323 + SharedSurface*& consumer) 1.324 +{ 1.325 + mIsAlive = false; 1.326 + 1.327 + producer = Surrender(mProducer); 1.328 + consumer = Surrender(mConsumer); 1.329 + 1.330 + if (!consumer) 1.331 + consumer = Surrender(mStaging); 1.332 +} 1.333 + 1.334 +SharedSurface* 1.335 +SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory, 1.336 + const gfx::IntSize& size) 1.337 +{ 1.338 + MonitorAutoLock lock(mMonitor); 1.339 + 1.340 + RecycleScraps(factory); 1.341 + if (mProducer) { 1.342 + if (mStaging) { 1.343 + // We'll re-use this for a new mProducer later on if 1.344 + // the size remains the same 1.345 + Recycle(factory, mStaging); 1.346 + } 1.347 + 1.348 + Move(mProducer, mStaging); 1.349 + mStaging->Fence(); 1.350 + 1.351 + New(factory, size, mProducer); 1.352 + 1.353 + if (mProducer && mStaging->Size() == mProducer->Size()) 1.354 + SharedSurface::Copy(mStaging, mProducer, factory); 1.355 + } else { 1.356 + New(factory, size, mProducer); 1.357 + } 1.358 + 1.359 + return mProducer; 1.360 +} 1.361 + 1.362 + 1.363 +SharedSurface* 1.364 +SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait() 1.365 +{ 1.366 + MonitorAutoLock lock(mMonitor); 1.367 + 1.368 + if (mStaging) { 1.369 + Scrap(mConsumer); 1.370 + Move(mStaging, mConsumer); 1.371 + } 1.372 + 1.373 + return mConsumer; 1.374 +} 1.375 + 1.376 +void SurfaceStream_TripleBuffer::Init(SurfaceStream* prevStream) 1.377 +{ 1.378 + if (!prevStream) 1.379 + return; 1.380 + 1.381 + SharedSurface* prevProducer = nullptr; 1.382 + SharedSurface* prevConsumer = nullptr; 1.383 + prevStream->SurrenderSurfaces(prevProducer, prevConsumer); 1.384 + 1.385 + if (prevConsumer == prevProducer) 1.386 + prevConsumer = nullptr; 1.387 + 1.388 + mProducer = Absorb(prevProducer); 1.389 + mConsumer = Absorb(prevConsumer); 1.390 +} 1.391 + 1.392 + 1.393 +SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream) 1.394 + : SurfaceStream(type, prevStream) 1.395 + , mStaging(nullptr) 1.396 + , mConsumer(nullptr) 1.397 +{ 1.398 + SurfaceStream_TripleBuffer::Init(prevStream); 1.399 +} 1.400 + 1.401 +SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream) 1.402 + : SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream) 1.403 + , mStaging(nullptr) 1.404 + , mConsumer(nullptr) 1.405 +{ 1.406 + SurfaceStream_TripleBuffer::Init(prevStream); 1.407 +} 1.408 + 1.409 +SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer() 1.410 +{ 1.411 + Delete(mStaging); 1.412 + Delete(mConsumer); 1.413 +} 1.414 + 1.415 +void 1.416 +SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer, 1.417 + SharedSurface*& consumer) 1.418 +{ 1.419 + mIsAlive = false; 1.420 + 1.421 + producer = Surrender(mProducer); 1.422 + consumer = Surrender(mConsumer); 1.423 + 1.424 + if (!consumer) 1.425 + consumer = Surrender(mStaging); 1.426 +} 1.427 + 1.428 +SharedSurface* 1.429 +SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory, 1.430 + const gfx::IntSize& size) 1.431 +{ 1.432 + PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer"); 1.433 + 1.434 + MonitorAutoLock lock(mMonitor); 1.435 + if (mProducer) { 1.436 + RecycleScraps(factory); 1.437 + 1.438 + // If WaitForCompositor succeeds, mStaging has moved to mConsumer. 1.439 + // If it failed, we might have to scrap it. 1.440 + if (mStaging && !WaitForCompositor()) 1.441 + Scrap(mStaging); 1.442 + 1.443 + MOZ_ASSERT(!mStaging); 1.444 + Move(mProducer, mStaging); 1.445 + mStaging->Fence(); 1.446 + } 1.447 + 1.448 + MOZ_ASSERT(!mProducer); 1.449 + New(factory, size, mProducer); 1.450 + 1.451 + return mProducer; 1.452 +} 1.453 + 1.454 +SharedSurface* 1.455 +SurfaceStream_TripleBuffer::SwapConsumer_NoWait() 1.456 +{ 1.457 + MonitorAutoLock lock(mMonitor); 1.458 + if (mStaging) { 1.459 + Scrap(mConsumer); 1.460 + Move(mStaging, mConsumer); 1.461 + mMonitor.NotifyAll(); 1.462 + } 1.463 + 1.464 + return mConsumer; 1.465 +} 1.466 + 1.467 +SurfaceStream_TripleBuffer_Async::SurfaceStream_TripleBuffer_Async(SurfaceStream* prevStream) 1.468 + : SurfaceStream_TripleBuffer(SurfaceStreamType::TripleBuffer_Async, prevStream) 1.469 +{ 1.470 +} 1.471 + 1.472 +SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async() 1.473 +{ 1.474 +} 1.475 + 1.476 +bool 1.477 +SurfaceStream_TripleBuffer_Async::WaitForCompositor() 1.478 +{ 1.479 + PROFILER_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor"); 1.480 + 1.481 + // We are assumed to be locked 1.482 + while (mStaging) { 1.483 + if (!NS_SUCCEEDED(mMonitor.Wait(PR_MillisecondsToInterval(100)))) { 1.484 + return false; 1.485 + } 1.486 + } 1.487 + 1.488 + return true; 1.489 +} 1.490 + 1.491 +} /* namespace gfx */ 1.492 +} /* namespace mozilla */