diff -r 000000000000 -r 6474c204b198 gfx/gl/SurfaceStream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/gl/SurfaceStream.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,489 @@ +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SurfaceStream.h" + +#include "gfxPoint.h" +#include "SharedSurface.h" +#include "SharedSurfaceGL.h" +#include "SurfaceFactory.h" +#include "GeckoProfiler.h" + +namespace mozilla { +namespace gfx { + +SurfaceStreamType +SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc, + bool preserveBuffer) +{ + if (omtc == SurfaceStream::OffMainThread) { + if (preserveBuffer) + return SurfaceStreamType::TripleBuffer_Copy; + else + return SurfaceStreamType::TripleBuffer_Async; + } else { + if (preserveBuffer) + return SurfaceStreamType::SingleBuffer; + else + return SurfaceStreamType::TripleBuffer; + } +} + +SurfaceStream* +SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glContext, SurfaceStream* prevStream) +{ + SurfaceStream* result = nullptr; + + switch (type) { + case SurfaceStreamType::SingleBuffer: + result = new SurfaceStream_SingleBuffer(prevStream); + break; + case SurfaceStreamType::TripleBuffer_Copy: + result = new SurfaceStream_TripleBuffer_Copy(prevStream); + break; + case SurfaceStreamType::TripleBuffer_Async: + result = new SurfaceStream_TripleBuffer_Async(prevStream); + break; + case SurfaceStreamType::TripleBuffer: + result = new SurfaceStream_TripleBuffer(prevStream); + break; + default: + MOZ_CRASH("Invalid Type."); + } + + result->mGLContext = glContext; + return result; +} + +bool +SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory) +{ + if (!mProducer) { + New(factory, src->Size(), mProducer); + if (!mProducer) { + return false; + } + } + + MOZ_ASSERT(src->Size() == mProducer->Size(), "Size mismatch"); + + SharedSurface::Copy(src, mProducer, factory); + return true; +} + +void +SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size, + SharedSurface*& surf) +{ + MOZ_ASSERT(!surf); + surf = factory->NewSharedSurface(size); + + if (surf) + mSurfaces.insert(surf); +} + +void +SurfaceStream::Recycle(SurfaceFactory* factory, SharedSurface*& surf) +{ + if (surf) { + mSurfaces.erase(surf); + factory->Recycle(surf); + } + MOZ_ASSERT(!surf); +} + +void +SurfaceStream::Delete(SharedSurface*& surf) +{ + if (surf) { + mSurfaces.erase(surf); + delete surf; + surf = nullptr; + } + MOZ_ASSERT(!surf); +} + +SharedSurface* +SurfaceStream::Surrender(SharedSurface*& surf) +{ + SharedSurface* ret = surf; + + if (surf) { + mSurfaces.erase(surf); + surf = nullptr; + } + MOZ_ASSERT(!surf); + + return ret; +} + +SharedSurface* +SurfaceStream::Absorb(SharedSurface*& surf) +{ + SharedSurface* ret = surf; + + if (surf) { + mSurfaces.insert(surf); + surf = nullptr; + } + MOZ_ASSERT(!surf); + + return ret; +} + +void +SurfaceStream::Scrap(SharedSurface*& scrap) +{ + if (scrap) { + mScraps.push(scrap); + scrap = nullptr; + } + MOZ_ASSERT(!scrap); +} + +void +SurfaceStream::RecycleScraps(SurfaceFactory* factory) +{ + while (!mScraps.empty()) { + SharedSurface* cur = mScraps.top(); + mScraps.pop(); + + Recycle(factory, cur); + } +} + + + +SurfaceStream::~SurfaceStream() +{ + Delete(mProducer); + + while (!mScraps.empty()) { + SharedSurface* cur = mScraps.top(); + mScraps.pop(); + + Delete(cur); + } + + MOZ_ASSERT(mSurfaces.empty()); +} + +SharedSurface* +SurfaceStream::SwapConsumer() +{ + MOZ_ASSERT(mIsAlive); + + SharedSurface* ret = SwapConsumer_NoWait(); + if (!ret) + return nullptr; + + if (!ret->WaitSync()) { + return nullptr; + } + + return ret; +} + +SharedSurface* +SurfaceStream::Resize(SurfaceFactory* factory, const gfx::IntSize& size) +{ + MonitorAutoLock lock(mMonitor); + + if (mProducer) { + Scrap(mProducer); + } + + New(factory, size, mProducer); + return mProducer; +} + +SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream* prevStream) + : SurfaceStream(SurfaceStreamType::SingleBuffer, prevStream) + , mConsumer(nullptr) +{ + if (!prevStream) + return; + + SharedSurface* prevProducer = nullptr; + SharedSurface* prevConsumer = nullptr; + prevStream->SurrenderSurfaces(prevProducer, prevConsumer); + + if (prevConsumer == prevProducer) + prevConsumer = nullptr; + + mProducer = Absorb(prevProducer); + mConsumer = Absorb(prevConsumer); +} + +SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer() +{ + Delete(mConsumer); +} + +void +SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer, + SharedSurface*& consumer) +{ + mIsAlive = false; + + producer = Surrender(mProducer); + consumer = Surrender(mConsumer); + + if (!consumer) + consumer = producer; +} + +SharedSurface* +SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory, + const gfx::IntSize& size) +{ + MonitorAutoLock lock(mMonitor); + if (mConsumer) { + Recycle(factory, mConsumer); + } + + if (mProducer) { + // Fence now, before we start (maybe) juggling Prod around. + mProducer->Fence(); + + // Size mismatch means we need to squirrel the current Prod + // into Cons, and leave Prod empty, so it gets a new surface below. + bool needsNewBuffer = mProducer->Size() != size; + + // Even if we're the right size, if the type has changed, and we don't + // need to preserve, we should switch out for (presumedly) better perf. + if (mProducer->Type() != factory->Type() && + !factory->Caps().preserve) + { + needsNewBuffer = true; + } + + if (needsNewBuffer) { + Move(mProducer, mConsumer); + } + } + + // The old Prod (if there every was one) was invalid, + // so we need a new one. + if (!mProducer) { + New(factory, size, mProducer); + } + + return mProducer; +} + +SharedSurface* +SurfaceStream_SingleBuffer::SwapConsumer_NoWait() +{ + MonitorAutoLock lock(mMonitor); + + // Use Cons, if present. + // Otherwise, just use Prod directly. + SharedSurface* toConsume = mConsumer; + if (!toConsume) + toConsume = mProducer; + + return toConsume; +} + + + +SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream) + : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream) + , mStaging(nullptr) + , mConsumer(nullptr) +{ + if (!prevStream) + return; + + SharedSurface* prevProducer = nullptr; + SharedSurface* prevConsumer = nullptr; + prevStream->SurrenderSurfaces(prevProducer, prevConsumer); + + if (prevConsumer == prevProducer) + prevConsumer = nullptr; + + mProducer = Absorb(prevProducer); + mConsumer = Absorb(prevConsumer); +} + +SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy() +{ + Delete(mStaging); + Delete(mConsumer); +} + +void +SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer, + SharedSurface*& consumer) +{ + mIsAlive = false; + + producer = Surrender(mProducer); + consumer = Surrender(mConsumer); + + if (!consumer) + consumer = Surrender(mStaging); +} + +SharedSurface* +SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory, + const gfx::IntSize& size) +{ + MonitorAutoLock lock(mMonitor); + + RecycleScraps(factory); + if (mProducer) { + if (mStaging) { + // We'll re-use this for a new mProducer later on if + // the size remains the same + Recycle(factory, mStaging); + } + + Move(mProducer, mStaging); + mStaging->Fence(); + + New(factory, size, mProducer); + + if (mProducer && mStaging->Size() == mProducer->Size()) + SharedSurface::Copy(mStaging, mProducer, factory); + } else { + New(factory, size, mProducer); + } + + return mProducer; +} + + +SharedSurface* +SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait() +{ + MonitorAutoLock lock(mMonitor); + + if (mStaging) { + Scrap(mConsumer); + Move(mStaging, mConsumer); + } + + return mConsumer; +} + +void SurfaceStream_TripleBuffer::Init(SurfaceStream* prevStream) +{ + if (!prevStream) + return; + + SharedSurface* prevProducer = nullptr; + SharedSurface* prevConsumer = nullptr; + prevStream->SurrenderSurfaces(prevProducer, prevConsumer); + + if (prevConsumer == prevProducer) + prevConsumer = nullptr; + + mProducer = Absorb(prevProducer); + mConsumer = Absorb(prevConsumer); +} + + +SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream) + : SurfaceStream(type, prevStream) + , mStaging(nullptr) + , mConsumer(nullptr) +{ + SurfaceStream_TripleBuffer::Init(prevStream); +} + +SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream) + : SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream) + , mStaging(nullptr) + , mConsumer(nullptr) +{ + SurfaceStream_TripleBuffer::Init(prevStream); +} + +SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer() +{ + Delete(mStaging); + Delete(mConsumer); +} + +void +SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer, + SharedSurface*& consumer) +{ + mIsAlive = false; + + producer = Surrender(mProducer); + consumer = Surrender(mConsumer); + + if (!consumer) + consumer = Surrender(mStaging); +} + +SharedSurface* +SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory, + const gfx::IntSize& size) +{ + PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer"); + + MonitorAutoLock lock(mMonitor); + if (mProducer) { + RecycleScraps(factory); + + // If WaitForCompositor succeeds, mStaging has moved to mConsumer. + // If it failed, we might have to scrap it. + if (mStaging && !WaitForCompositor()) + Scrap(mStaging); + + MOZ_ASSERT(!mStaging); + Move(mProducer, mStaging); + mStaging->Fence(); + } + + MOZ_ASSERT(!mProducer); + New(factory, size, mProducer); + + return mProducer; +} + +SharedSurface* +SurfaceStream_TripleBuffer::SwapConsumer_NoWait() +{ + MonitorAutoLock lock(mMonitor); + if (mStaging) { + Scrap(mConsumer); + Move(mStaging, mConsumer); + mMonitor.NotifyAll(); + } + + return mConsumer; +} + +SurfaceStream_TripleBuffer_Async::SurfaceStream_TripleBuffer_Async(SurfaceStream* prevStream) + : SurfaceStream_TripleBuffer(SurfaceStreamType::TripleBuffer_Async, prevStream) +{ +} + +SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async() +{ +} + +bool +SurfaceStream_TripleBuffer_Async::WaitForCompositor() +{ + PROFILER_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor"); + + // We are assumed to be locked + while (mStaging) { + if (!NS_SUCCEEDED(mMonitor.Wait(PR_MillisecondsToInterval(100)))) { + return false; + } + } + + return true; +} + +} /* namespace gfx */ +} /* namespace mozilla */