1 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "SurfaceStream.h"
9 #include "SharedSurface.h"
10 #include "SharedSurfaceGL.h"
11 #include "GeckoProfiler.h"
12 #include "mozilla/Move.h"
18 SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc
,
21 if (omtc
== SurfaceStream::OffMainThread
) {
23 return SurfaceStreamType::TripleBuffer_Copy
;
25 return SurfaceStreamType::TripleBuffer_Async
;
28 return SurfaceStreamType::SingleBuffer
;
30 return SurfaceStreamType::TripleBuffer
;
34 TemporaryRef
<SurfaceStream
>
35 SurfaceStream::CreateForType(SurfaceStreamType type
, mozilla::gl::GLContext
* glContext
, SurfaceStream
* prevStream
)
37 RefPtr
<SurfaceStream
> result
;
40 case SurfaceStreamType::SingleBuffer
:
41 result
= new SurfaceStream_SingleBuffer(prevStream
);
43 case SurfaceStreamType::TripleBuffer_Copy
:
44 result
= new SurfaceStream_TripleBuffer_Copy(prevStream
);
46 case SurfaceStreamType::TripleBuffer_Async
:
47 result
= new SurfaceStream_TripleBuffer_Async(prevStream
);
49 case SurfaceStreamType::TripleBuffer
:
50 result
= new SurfaceStream_TripleBuffer(prevStream
);
53 MOZ_CRASH("Invalid Type.");
56 result
->mGLContext
= glContext
;
58 return result
.forget();
62 SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface
* src
, SurfaceFactory
* factory
)
65 New(factory
, src
->mSize
, &mProducer
);
71 MOZ_ASSERT(src
->mSize
== mProducer
->mSize
, "Size mismatch");
73 SharedSurface::ProdCopy(src
, mProducer
.get(), factory
);
78 SurfaceStream::New(SurfaceFactory
* factory
, const gfx::IntSize
& size
,
79 UniquePtr
<SharedSurface
>* surfSlot
)
82 UniquePtr
<SharedSurface
>& surf
= *surfSlot
;
85 surf
= factory
->NewSharedSurface(size
);
88 // Before next use, wait until SharedSurface's buffer
89 // is no longer being used.
90 surf
->WaitForBufferOwnership();
92 mSurfaces
.insert(surf
.get());
98 SurfaceStream::MoveTo(UniquePtr
<SharedSurface
>* slotFrom
,
99 UniquePtr
<SharedSurface
>* slotTo
)
101 MOZ_ASSERT(slotFrom
);
102 UniquePtr
<SharedSurface
>& from
= *slotFrom
;
105 UniquePtr
<SharedSurface
>& to
= *slotTo
;
113 SurfaceStream::Recycle(SurfaceFactory
* factory
, UniquePtr
<SharedSurface
>* surfSlot
)
115 MOZ_ASSERT(surfSlot
);
116 UniquePtr
<SharedSurface
>& surf
= *surfSlot
;
120 mSurfaces
.erase(surf
.get());
122 factory
->Recycle(Move(surf
));
128 SurfaceStream::Delete(UniquePtr
<SharedSurface
>* surfSlot
)
130 MOZ_ASSERT(surfSlot
);
131 UniquePtr
<SharedSurface
>& surf
= *surfSlot
;
135 mSurfaces
.erase(surf
.get());
142 UniquePtr
<SharedSurface
>
143 SurfaceStream::Surrender(UniquePtr
<SharedSurface
>* surfSlot
)
145 MOZ_ASSERT(surfSlot
);
146 UniquePtr
<SharedSurface
>& surf
= *surfSlot
;
150 mSurfaces
.erase(surf
.get());
154 UniquePtr
<SharedSurface
> ret
= Move(surf
);
160 // Move `surfSlot` to `return`, but record that the surf is now part of
162 UniquePtr
<SharedSurface
>
163 SurfaceStream::Absorb(UniquePtr
<SharedSurface
>* surfSlot
)
165 MOZ_ASSERT(surfSlot
);
166 UniquePtr
<SharedSurface
>& surf
= *surfSlot
;
170 mSurfaces
.insert(surf
.get());
174 UniquePtr
<SharedSurface
> ret
= Move(surf
);
181 SurfaceStream::Scrap(UniquePtr
<SharedSurface
>* surfSlot
)
183 MOZ_ASSERT(surfSlot
);
184 UniquePtr
<SharedSurface
>& surf
= *surfSlot
;
187 mScraps
.Push(Move(surf
));
194 SurfaceStream::RecycleScraps(SurfaceFactory
* factory
)
196 while (!mScraps
.Empty()) {
197 UniquePtr
<SharedSurface
> cur
= mScraps
.Pop();
199 Recycle(factory
, &cur
);
203 ////////////////////////////////////////////////////////////////////////
206 SurfaceStream::SurfaceStream(SurfaceStreamType type
,
207 SurfaceStream
* prevStream
)
210 , mMonitor("SurfaceStream monitor")
213 MOZ_ASSERT(!prevStream
|| mType
!= prevStream
->mType
,
214 "We should not need to create a SurfaceStream from another "
215 "of the same type.");
218 SurfaceStream::~SurfaceStream()
222 while (!mScraps
.Empty()) {
223 UniquePtr
<SharedSurface
> cur
= mScraps
.Pop();
228 MOZ_ASSERT(mSurfaces
.empty());
232 SurfaceStream::SwapConsumer()
234 MOZ_ASSERT(mIsAlive
);
236 SharedSurface
* ret
= SwapConsumer_NoWait();
240 if (!ret
->WaitSync()) {
248 SurfaceStream::Resize(SurfaceFactory
* factory
, const gfx::IntSize
& size
)
250 MonitorAutoLock
lock(mMonitor
);
256 New(factory
, size
, &mProducer
);
257 return mProducer
.get();
260 ////////////////////////////////////////////////////////////////////////
261 // SurfaceStream_SingleBuffer
263 SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream
* prevStream
)
264 : SurfaceStream(SurfaceStreamType::SingleBuffer
, prevStream
)
270 UniquePtr
<SharedSurface
> prevProducer
;
271 UniquePtr
<SharedSurface
> prevConsumer
;
272 prevStream
->SurrenderSurfaces(&prevProducer
, &prevConsumer
);
274 mProducer
= Absorb(&prevProducer
);
275 mConsumer
= Absorb(&prevConsumer
);
278 SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer()
284 SurfaceStream_SingleBuffer::SurrenderSurfaces(UniquePtr
<SharedSurface
>* out_producer
,
285 UniquePtr
<SharedSurface
>* out_consumer
)
287 MOZ_ASSERT(out_producer
);
288 MOZ_ASSERT(out_consumer
);
292 *out_producer
= Surrender(&mProducer
);
293 *out_consumer
= Surrender(&mConsumer
);
297 SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory
* factory
,
298 const gfx::IntSize
& size
)
300 MonitorAutoLock
lock(mMonitor
);
302 Recycle(factory
, &mConsumer
);
306 // Fence now, before we start (maybe) juggling Prod around.
309 // Size mismatch means we need to squirrel the current Prod
310 // into Cons, and leave Prod empty, so it gets a new surface below.
311 bool needsNewBuffer
= mProducer
->mSize
!= size
;
313 // Even if we're the right size, if the type has changed, and we don't
314 // need to preserve, we should switch out for (presumedly) better perf.
315 if (mProducer
->mType
!= factory
->mType
&&
316 !factory
->mCaps
.preserve
)
318 needsNewBuffer
= true;
321 if (needsNewBuffer
) {
322 MoveTo(&mProducer
, &mConsumer
);
326 // The old Prod (if there every was one) was invalid,
327 // so we need a new one.
329 New(factory
, size
, &mProducer
);
332 return mProducer
.get();
336 SurfaceStream_SingleBuffer::SwapConsumer_NoWait()
338 MonitorAutoLock
lock(mMonitor
);
340 // Use Cons, if present.
341 // Otherwise, just use Prod directly.
342 SharedSurface
* toConsume
= mConsumer
.get();
344 toConsume
= mProducer
.get();
349 ////////////////////////////////////////////////////////////////////////
350 // SurfaceStream_TripleBuffer_Copy
352 SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream
* prevStream
)
353 : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy
, prevStream
)
360 UniquePtr
<SharedSurface
> prevProducer
;
361 UniquePtr
<SharedSurface
> prevConsumer
;
362 prevStream
->SurrenderSurfaces(&prevProducer
, &prevConsumer
);
364 mProducer
= Absorb(&prevProducer
);
365 mConsumer
= Absorb(&prevConsumer
);
368 SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy()
375 SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(UniquePtr
<SharedSurface
>* out_producer
,
376 UniquePtr
<SharedSurface
>* out_consumer
)
378 MOZ_ASSERT(out_producer
);
379 MOZ_ASSERT(out_consumer
);
383 *out_producer
= Surrender(&mProducer
);
384 *out_consumer
= Surrender(&mConsumer
);
387 *out_consumer
= Surrender(&mStaging
);
391 SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory
* factory
,
392 const gfx::IntSize
& size
)
394 MonitorAutoLock
lock(mMonitor
);
396 RecycleScraps(factory
);
399 // We'll re-use this for a new mProducer later on if
400 // the size remains the same
401 Recycle(factory
, &mStaging
);
404 MoveTo(&mProducer
, &mStaging
);
407 New(factory
, size
, &mProducer
);
410 mStaging
->mSize
== mProducer
->mSize
)
412 SharedSurface::ProdCopy(mStaging
.get(), mProducer
.get(), factory
);
415 New(factory
, size
, &mProducer
);
418 return mProducer
.get();
422 SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait()
424 MonitorAutoLock
lock(mMonitor
);
428 MoveTo(&mStaging
, &mConsumer
);
431 return mConsumer
.get();
434 ////////////////////////////////////////////////////////////////////////
435 // SurfaceStream_TripleBuffer
437 void SurfaceStream_TripleBuffer::Init(SurfaceStream
* prevStream
)
442 UniquePtr
<SharedSurface
> prevProducer
;
443 UniquePtr
<SharedSurface
> prevConsumer
;
444 prevStream
->SurrenderSurfaces(&prevProducer
, &prevConsumer
);
446 mProducer
= Absorb(&prevProducer
);
447 mConsumer
= Absorb(&prevConsumer
);
450 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStreamType type
,
451 SurfaceStream
* prevStream
)
452 : SurfaceStream(type
, prevStream
)
456 SurfaceStream_TripleBuffer::Init(prevStream
);
459 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream
* prevStream
)
460 : SurfaceStream(SurfaceStreamType::TripleBuffer
, prevStream
)
464 SurfaceStream_TripleBuffer::Init(prevStream
);
467 SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer()
474 SurfaceStream_TripleBuffer::SurrenderSurfaces(UniquePtr
<SharedSurface
>* out_producer
,
475 UniquePtr
<SharedSurface
>* out_consumer
)
477 MOZ_ASSERT(out_producer
);
478 MOZ_ASSERT(out_consumer
);
482 *out_producer
= Surrender(&mProducer
);
483 *out_consumer
= Surrender(&mConsumer
);
486 *out_consumer
= Surrender(&mStaging
);
490 SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory
* factory
,
491 const gfx::IntSize
& size
)
493 PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer",
494 js::ProfileEntry::Category::GRAPHICS
);
496 MonitorAutoLock
lock(mMonitor
);
498 RecycleScraps(factory
);
500 // If WaitForCompositor succeeds, mStaging has moved to mConsumer.
501 // If it failed, we might have to scrap it.
509 MoveTo(&mProducer
, &mStaging
);
513 MOZ_ASSERT(!mProducer
);
514 New(factory
, size
, &mProducer
);
516 return mProducer
.get();
520 SurfaceStream_TripleBuffer::SwapConsumer_NoWait()
522 MonitorAutoLock
lock(mMonitor
);
525 MoveTo(&mStaging
, &mConsumer
);
526 mMonitor
.NotifyAll();
529 return mConsumer
.get();
532 ////////////////////////////////////////////////////////////////////////
533 // SurfaceStream_TripleBuffer_Async
535 SurfaceStream_TripleBuffer_Async::SurfaceStream_TripleBuffer_Async(SurfaceStream
* prevStream
)
536 : SurfaceStream_TripleBuffer(SurfaceStreamType::TripleBuffer_Async
,
541 SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async()
546 SurfaceStream_TripleBuffer_Async::WaitForCompositor()
548 PROFILER_LABEL("SurfaceStream_TripleBuffer_Async",
550 js::ProfileEntry::Category::GRAPHICS
);
552 // If we haven't be notified within 100ms, then
553 // something must have happened and it will never arrive.
554 // Bail out to avoid deadlocking.
555 mMonitor
.Wait(PR_MillisecondsToInterval(100));
558 } /* namespace gfx */
559 } /* namespace mozilla */