mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
546f98d63d
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)
470 lines
11 KiB
C++
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 */
|