Bumping manifests a=b2g-bump
[gecko.git] / gfx / gl / SurfaceStream.cpp
blobaf2abf82356fd0841307067bb4ddbe75633e4285
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"
8 #include "gfxPoint.h"
9 #include "SharedSurface.h"
10 #include "SharedSurfaceGL.h"
11 #include "GeckoProfiler.h"
12 #include "mozilla/Move.h"
14 namespace mozilla {
15 namespace gl {
17 SurfaceStreamType
18 SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc,
19 bool preserveBuffer)
21 if (omtc == SurfaceStream::OffMainThread) {
22 if (preserveBuffer)
23 return SurfaceStreamType::TripleBuffer_Copy;
24 else
25 return SurfaceStreamType::TripleBuffer_Async;
26 } else {
27 if (preserveBuffer)
28 return SurfaceStreamType::SingleBuffer;
29 else
30 return SurfaceStreamType::TripleBuffer;
34 TemporaryRef<SurfaceStream>
35 SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glContext, SurfaceStream* prevStream)
37 RefPtr<SurfaceStream> result;
39 switch (type) {
40 case SurfaceStreamType::SingleBuffer:
41 result = new SurfaceStream_SingleBuffer(prevStream);
42 break;
43 case SurfaceStreamType::TripleBuffer_Copy:
44 result = new SurfaceStream_TripleBuffer_Copy(prevStream);
45 break;
46 case SurfaceStreamType::TripleBuffer_Async:
47 result = new SurfaceStream_TripleBuffer_Async(prevStream);
48 break;
49 case SurfaceStreamType::TripleBuffer:
50 result = new SurfaceStream_TripleBuffer(prevStream);
51 break;
52 default:
53 MOZ_CRASH("Invalid Type.");
56 result->mGLContext = glContext;
58 return result.forget();
61 bool
62 SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory)
64 if (!mProducer) {
65 New(factory, src->mSize, &mProducer);
66 if (!mProducer) {
67 return false;
71 MOZ_ASSERT(src->mSize == mProducer->mSize, "Size mismatch");
73 SharedSurface::ProdCopy(src, mProducer.get(), factory);
74 return true;
77 void
78 SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size,
79 UniquePtr<SharedSurface>* surfSlot)
81 MOZ_ASSERT(surfSlot);
82 UniquePtr<SharedSurface>& surf = *surfSlot;
84 MOZ_ASSERT(!surf);
85 surf = factory->NewSharedSurface(size);
87 if (surf) {
88 // Before next use, wait until SharedSurface's buffer
89 // is no longer being used.
90 surf->WaitForBufferOwnership();
91 #ifdef DEBUG
92 mSurfaces.insert(surf.get());
93 #endif
97 void
98 SurfaceStream::MoveTo(UniquePtr<SharedSurface>* slotFrom,
99 UniquePtr<SharedSurface>* slotTo)
101 MOZ_ASSERT(slotFrom);
102 UniquePtr<SharedSurface>& from = *slotFrom;
104 MOZ_ASSERT(slotTo);
105 UniquePtr<SharedSurface>& to = *slotTo;
107 MOZ_ASSERT(!to);
108 to = Move(from);
109 MOZ_ASSERT(!from);
112 void
113 SurfaceStream::Recycle(SurfaceFactory* factory, UniquePtr<SharedSurface>* surfSlot)
115 MOZ_ASSERT(surfSlot);
116 UniquePtr<SharedSurface>& surf = *surfSlot;
118 if (surf) {
119 #ifdef DEBUG
120 mSurfaces.erase(surf.get());
121 #endif
122 factory->Recycle(Move(surf));
124 MOZ_ASSERT(!surf);
127 void
128 SurfaceStream::Delete(UniquePtr<SharedSurface>* surfSlot)
130 MOZ_ASSERT(surfSlot);
131 UniquePtr<SharedSurface>& surf = *surfSlot;
133 if (surf) {
134 #ifdef DEBUG
135 mSurfaces.erase(surf.get());
136 #endif
137 surf = nullptr;
139 MOZ_ASSERT(!surf);
142 UniquePtr<SharedSurface>
143 SurfaceStream::Surrender(UniquePtr<SharedSurface>* surfSlot)
145 MOZ_ASSERT(surfSlot);
146 UniquePtr<SharedSurface>& surf = *surfSlot;
148 #ifdef DEBUG
149 if (surf) {
150 mSurfaces.erase(surf.get());
152 #endif
154 UniquePtr<SharedSurface> ret = Move(surf);
155 MOZ_ASSERT(!surf);
157 return Move(ret);
160 // Move `surfSlot` to `return`, but record that the surf is now part of
161 // this stream.
162 UniquePtr<SharedSurface>
163 SurfaceStream::Absorb(UniquePtr<SharedSurface>* surfSlot)
165 MOZ_ASSERT(surfSlot);
166 UniquePtr<SharedSurface>& surf = *surfSlot;
168 #ifdef DEBUG
169 if (surf) {
170 mSurfaces.insert(surf.get());
172 #endif
174 UniquePtr<SharedSurface> ret = Move(surf);
175 MOZ_ASSERT(!surf);
177 return Move(ret);
180 void
181 SurfaceStream::Scrap(UniquePtr<SharedSurface>* surfSlot)
183 MOZ_ASSERT(surfSlot);
184 UniquePtr<SharedSurface>& surf = *surfSlot;
186 if (surf) {
187 mScraps.Push(Move(surf));
189 MOZ_ASSERT(!surf);
193 void
194 SurfaceStream::RecycleScraps(SurfaceFactory* factory)
196 while (!mScraps.Empty()) {
197 UniquePtr<SharedSurface> cur = mScraps.Pop();
199 Recycle(factory, &cur);
203 ////////////////////////////////////////////////////////////////////////
204 // SurfaceStream
206 SurfaceStream::SurfaceStream(SurfaceStreamType type,
207 SurfaceStream* prevStream)
208 : mType(type)
209 , mProducer(nullptr)
210 , mMonitor("SurfaceStream monitor")
211 , mIsAlive(true)
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()
220 Delete(&mProducer);
222 while (!mScraps.Empty()) {
223 UniquePtr<SharedSurface> cur = mScraps.Pop();
225 Delete(&cur);
228 MOZ_ASSERT(mSurfaces.empty());
231 SharedSurface*
232 SurfaceStream::SwapConsumer()
234 MOZ_ASSERT(mIsAlive);
236 SharedSurface* ret = SwapConsumer_NoWait();
237 if (!ret)
238 return nullptr;
240 if (!ret->WaitSync()) {
241 return nullptr;
244 return ret;
247 SharedSurface*
248 SurfaceStream::Resize(SurfaceFactory* factory, const gfx::IntSize& size)
250 MonitorAutoLock lock(mMonitor);
252 if (mProducer) {
253 Scrap(&mProducer);
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)
265 , mConsumer(nullptr)
267 if (!prevStream)
268 return;
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()
280 Delete(&mConsumer);
283 void
284 SurfaceStream_SingleBuffer::SurrenderSurfaces(UniquePtr<SharedSurface>* out_producer,
285 UniquePtr<SharedSurface>* out_consumer)
287 MOZ_ASSERT(out_producer);
288 MOZ_ASSERT(out_consumer);
290 mIsAlive = false;
292 *out_producer = Surrender(&mProducer);
293 *out_consumer = Surrender(&mConsumer);
296 SharedSurface*
297 SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory,
298 const gfx::IntSize& size)
300 MonitorAutoLock lock(mMonitor);
301 if (mConsumer) {
302 Recycle(factory, &mConsumer);
305 if (mProducer) {
306 // Fence now, before we start (maybe) juggling Prod around.
307 mProducer->Fence();
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.
328 if (!mProducer) {
329 New(factory, size, &mProducer);
332 return mProducer.get();
335 SharedSurface*
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();
343 if (!toConsume)
344 toConsume = mProducer.get();
346 return toConsume;
349 ////////////////////////////////////////////////////////////////////////
350 // SurfaceStream_TripleBuffer_Copy
352 SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream)
353 : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream)
354 , mStaging(nullptr)
355 , mConsumer(nullptr)
357 if (!prevStream)
358 return;
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()
370 Delete(&mStaging);
371 Delete(&mConsumer);
374 void
375 SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(UniquePtr<SharedSurface>* out_producer,
376 UniquePtr<SharedSurface>* out_consumer)
378 MOZ_ASSERT(out_producer);
379 MOZ_ASSERT(out_consumer);
381 mIsAlive = false;
383 *out_producer = Surrender(&mProducer);
384 *out_consumer = Surrender(&mConsumer);
386 if (!*out_consumer)
387 *out_consumer = Surrender(&mStaging);
390 SharedSurface*
391 SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory,
392 const gfx::IntSize& size)
394 MonitorAutoLock lock(mMonitor);
396 RecycleScraps(factory);
397 if (mProducer) {
398 if (mStaging) {
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);
405 mStaging->Fence();
407 New(factory, size, &mProducer);
409 if (mProducer &&
410 mStaging->mSize == mProducer->mSize)
412 SharedSurface::ProdCopy(mStaging.get(), mProducer.get(), factory);
414 } else {
415 New(factory, size, &mProducer);
418 return mProducer.get();
421 SharedSurface*
422 SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait()
424 MonitorAutoLock lock(mMonitor);
426 if (mStaging) {
427 Scrap(&mConsumer);
428 MoveTo(&mStaging, &mConsumer);
431 return mConsumer.get();
434 ////////////////////////////////////////////////////////////////////////
435 // SurfaceStream_TripleBuffer
437 void SurfaceStream_TripleBuffer::Init(SurfaceStream* prevStream)
439 if (!prevStream)
440 return;
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)
453 , mStaging(nullptr)
454 , mConsumer(nullptr)
456 SurfaceStream_TripleBuffer::Init(prevStream);
459 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream)
460 : SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream)
461 , mStaging(nullptr)
462 , mConsumer(nullptr)
464 SurfaceStream_TripleBuffer::Init(prevStream);
467 SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer()
469 Delete(&mStaging);
470 Delete(&mConsumer);
473 void
474 SurfaceStream_TripleBuffer::SurrenderSurfaces(UniquePtr<SharedSurface>* out_producer,
475 UniquePtr<SharedSurface>* out_consumer)
477 MOZ_ASSERT(out_producer);
478 MOZ_ASSERT(out_consumer);
480 mIsAlive = false;
482 *out_producer = Surrender(&mProducer);
483 *out_consumer = Surrender(&mConsumer);
485 if (!*out_consumer)
486 *out_consumer = Surrender(&mStaging);
489 SharedSurface*
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);
497 if (mProducer) {
498 RecycleScraps(factory);
500 // If WaitForCompositor succeeds, mStaging has moved to mConsumer.
501 // If it failed, we might have to scrap it.
502 if (mStaging) {
503 WaitForCompositor();
505 if (mStaging) {
506 Scrap(&mStaging);
509 MoveTo(&mProducer, &mStaging);
510 mStaging->Fence();
513 MOZ_ASSERT(!mProducer);
514 New(factory, size, &mProducer);
516 return mProducer.get();
519 SharedSurface*
520 SurfaceStream_TripleBuffer::SwapConsumer_NoWait()
522 MonitorAutoLock lock(mMonitor);
523 if (mStaging) {
524 Scrap(&mConsumer);
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,
537 prevStream)
541 SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async()
545 void
546 SurfaceStream_TripleBuffer_Async::WaitForCompositor()
548 PROFILER_LABEL("SurfaceStream_TripleBuffer_Async",
549 "WaitForCompositor",
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 */