gecko/gfx/gl/SurfaceStream.cpp
Wes Kocher 546f98d63d Backed out 6 changesets (bug 877115) for mochitest-1 and reftest orange on this CLOSED TREE
Backed out changeset 65ad9d8860d6 (bug 877115)
Backed out changeset bf8095c168fb (bug 877115)
Backed out changeset 290ad5863615 (bug 877115)
Backed out changeset 4488ec28910e (bug 877115)
Backed out changeset 45f8859c6fd6 (bug 877115)
Backed out changeset 111cc426fa9e (bug 877115)
2013-12-16 16:33:07 -08:00

470 lines
11 KiB
C++

/* -*- 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 "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;
}
void
SurfaceStream::New(SurfaceFactory* factory, const gfxIntSize& 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 gfxIntSize& 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 gfxIntSize& 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 gfxIntSize& 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 gfxIntSize& 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)
mMonitor.Wait();
return true;
}
} /* namespace gfx */
} /* namespace mozilla */