Merge m-c to b2g-inbound.
[gecko.git] / gfx / gl / SurfaceStream.cpp
blob4048fe78abe0cd90ee07163b6ac904a4fea72f98
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 "SurfaceFactory.h"
11 #include "GeckoProfiler.h"
13 namespace mozilla {
14 namespace gfx {
16 SurfaceStreamType
17 SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc,
18 bool preserveBuffer)
20 if (omtc == SurfaceStream::OffMainThread) {
21 if (preserveBuffer)
22 return SurfaceStreamType::TripleBuffer_Copy;
23 else
24 return SurfaceStreamType::TripleBuffer_Async;
25 } else {
26 if (preserveBuffer)
27 return SurfaceStreamType::SingleBuffer;
28 else
29 return SurfaceStreamType::TripleBuffer;
33 SurfaceStream*
34 SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glContext, SurfaceStream* prevStream)
36 SurfaceStream* result = nullptr;
38 switch (type) {
39 case SurfaceStreamType::SingleBuffer:
40 result = new SurfaceStream_SingleBuffer(prevStream);
41 break;
42 case SurfaceStreamType::TripleBuffer_Copy:
43 result = new SurfaceStream_TripleBuffer_Copy(prevStream);
44 break;
45 case SurfaceStreamType::TripleBuffer_Async:
46 result = new SurfaceStream_TripleBuffer_Async(prevStream);
47 break;
48 case SurfaceStreamType::TripleBuffer:
49 result = new SurfaceStream_TripleBuffer(prevStream);
50 break;
51 default:
52 MOZ_CRASH("Invalid Type.");
55 result->mGLContext = glContext;
56 return result;
59 void
60 SurfaceStream::New(SurfaceFactory* factory, const gfxIntSize& size,
61 SharedSurface*& surf)
63 MOZ_ASSERT(!surf);
64 surf = factory->NewSharedSurface(size);
66 if (surf)
67 mSurfaces.insert(surf);
70 void
71 SurfaceStream::Recycle(SurfaceFactory* factory, SharedSurface*& surf)
73 if (surf) {
74 mSurfaces.erase(surf);
75 factory->Recycle(surf);
77 MOZ_ASSERT(!surf);
80 void
81 SurfaceStream::Delete(SharedSurface*& surf)
83 if (surf) {
84 mSurfaces.erase(surf);
85 delete surf;
86 surf = nullptr;
88 MOZ_ASSERT(!surf);
91 SharedSurface*
92 SurfaceStream::Surrender(SharedSurface*& surf)
94 SharedSurface* ret = surf;
96 if (surf) {
97 mSurfaces.erase(surf);
98 surf = nullptr;
100 MOZ_ASSERT(!surf);
102 return ret;
105 SharedSurface*
106 SurfaceStream::Absorb(SharedSurface*& surf)
108 SharedSurface* ret = surf;
110 if (surf) {
111 mSurfaces.insert(surf);
112 surf = nullptr;
114 MOZ_ASSERT(!surf);
116 return ret;
119 void
120 SurfaceStream::Scrap(SharedSurface*& scrap)
122 if (scrap) {
123 mScraps.push(scrap);
124 scrap = nullptr;
126 MOZ_ASSERT(!scrap);
129 void
130 SurfaceStream::RecycleScraps(SurfaceFactory* factory)
132 while (!mScraps.empty()) {
133 SharedSurface* cur = mScraps.top();
134 mScraps.pop();
136 Recycle(factory, cur);
142 SurfaceStream::~SurfaceStream()
144 Delete(mProducer);
146 while (!mScraps.empty()) {
147 SharedSurface* cur = mScraps.top();
148 mScraps.pop();
150 Delete(cur);
153 MOZ_ASSERT(mSurfaces.empty());
156 SharedSurface*
157 SurfaceStream::SwapConsumer()
159 MOZ_ASSERT(mIsAlive);
161 SharedSurface* ret = SwapConsumer_NoWait();
162 if (!ret)
163 return nullptr;
165 if (!ret->WaitSync()) {
166 return nullptr;
169 return ret;
172 SharedSurface*
173 SurfaceStream::Resize(SurfaceFactory* factory, const gfxIntSize& size)
175 MonitorAutoLock lock(mMonitor);
177 if (mProducer) {
178 Scrap(mProducer);
181 New(factory, size, mProducer);
182 return mProducer;
185 SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream* prevStream)
186 : SurfaceStream(SurfaceStreamType::SingleBuffer, prevStream)
187 , mConsumer(nullptr)
189 if (!prevStream)
190 return;
192 SharedSurface* prevProducer = nullptr;
193 SharedSurface* prevConsumer = nullptr;
194 prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
196 if (prevConsumer == prevProducer)
197 prevConsumer = nullptr;
199 mProducer = Absorb(prevProducer);
200 mConsumer = Absorb(prevConsumer);
203 SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer()
205 Delete(mConsumer);
208 void
209 SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer,
210 SharedSurface*& consumer)
212 mIsAlive = false;
214 producer = Surrender(mProducer);
215 consumer = Surrender(mConsumer);
217 if (!consumer)
218 consumer = producer;
221 SharedSurface*
222 SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory,
223 const gfxIntSize& size)
225 MonitorAutoLock lock(mMonitor);
226 if (mConsumer) {
227 Recycle(factory, mConsumer);
230 if (mProducer) {
231 // Fence now, before we start (maybe) juggling Prod around.
232 mProducer->Fence();
234 // Size mismatch means we need to squirrel the current Prod
235 // into Cons, and leave Prod empty, so it gets a new surface below.
236 bool needsNewBuffer = mProducer->Size() != size;
238 // Even if we're the right size, if the type has changed, and we don't
239 // need to preserve, we should switch out for (presumedly) better perf.
240 if (mProducer->Type() != factory->Type() &&
241 !factory->Caps().preserve)
243 needsNewBuffer = true;
246 if (needsNewBuffer) {
247 Move(mProducer, mConsumer);
251 // The old Prod (if there every was one) was invalid,
252 // so we need a new one.
253 if (!mProducer) {
254 New(factory, size, mProducer);
257 return mProducer;
260 SharedSurface*
261 SurfaceStream_SingleBuffer::SwapConsumer_NoWait()
263 MonitorAutoLock lock(mMonitor);
265 // Use Cons, if present.
266 // Otherwise, just use Prod directly.
267 SharedSurface* toConsume = mConsumer;
268 if (!toConsume)
269 toConsume = mProducer;
271 return toConsume;
276 SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream)
277 : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream)
278 , mStaging(nullptr)
279 , mConsumer(nullptr)
281 if (!prevStream)
282 return;
284 SharedSurface* prevProducer = nullptr;
285 SharedSurface* prevConsumer = nullptr;
286 prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
288 if (prevConsumer == prevProducer)
289 prevConsumer = nullptr;
291 mProducer = Absorb(prevProducer);
292 mConsumer = Absorb(prevConsumer);
295 SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy()
297 Delete(mStaging);
298 Delete(mConsumer);
301 void
302 SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer,
303 SharedSurface*& consumer)
305 mIsAlive = false;
307 producer = Surrender(mProducer);
308 consumer = Surrender(mConsumer);
310 if (!consumer)
311 consumer = Surrender(mStaging);
314 SharedSurface*
315 SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory,
316 const gfxIntSize& size)
318 MonitorAutoLock lock(mMonitor);
320 RecycleScraps(factory);
321 if (mProducer) {
322 if (mStaging) {
323 // We'll re-use this for a new mProducer later on if
324 // the size remains the same
325 Recycle(factory, mStaging);
328 Move(mProducer, mStaging);
329 mStaging->Fence();
331 New(factory, size, mProducer);
333 if (mProducer && mStaging->Size() == mProducer->Size())
334 SharedSurface::Copy(mStaging, mProducer, factory);
335 } else {
336 New(factory, size, mProducer);
339 return mProducer;
343 SharedSurface*
344 SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait()
346 MonitorAutoLock lock(mMonitor);
348 if (mStaging) {
349 Scrap(mConsumer);
350 Move(mStaging, mConsumer);
353 return mConsumer;
356 void SurfaceStream_TripleBuffer::Init(SurfaceStream* prevStream)
358 if (!prevStream)
359 return;
361 SharedSurface* prevProducer = nullptr;
362 SharedSurface* prevConsumer = nullptr;
363 prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
365 if (prevConsumer == prevProducer)
366 prevConsumer = nullptr;
368 mProducer = Absorb(prevProducer);
369 mConsumer = Absorb(prevConsumer);
373 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream)
374 : SurfaceStream(type, prevStream)
375 , mStaging(nullptr)
376 , mConsumer(nullptr)
378 SurfaceStream_TripleBuffer::Init(prevStream);
381 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream)
382 : SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream)
383 , mStaging(nullptr)
384 , mConsumer(nullptr)
386 SurfaceStream_TripleBuffer::Init(prevStream);
389 SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer()
391 Delete(mStaging);
392 Delete(mConsumer);
395 void
396 SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer,
397 SharedSurface*& consumer)
399 mIsAlive = false;
401 producer = Surrender(mProducer);
402 consumer = Surrender(mConsumer);
404 if (!consumer)
405 consumer = Surrender(mStaging);
408 SharedSurface*
409 SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory,
410 const gfxIntSize& size)
412 PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer");
414 MonitorAutoLock lock(mMonitor);
415 if (mProducer) {
416 RecycleScraps(factory);
418 // If WaitForCompositor succeeds, mStaging has moved to mConsumer.
419 // If it failed, we might have to scrap it.
420 if (mStaging && !WaitForCompositor())
421 Scrap(mStaging);
423 MOZ_ASSERT(!mStaging);
424 Move(mProducer, mStaging);
425 mStaging->Fence();
428 MOZ_ASSERT(!mProducer);
429 New(factory, size, mProducer);
431 return mProducer;
434 SharedSurface*
435 SurfaceStream_TripleBuffer::SwapConsumer_NoWait()
437 MonitorAutoLock lock(mMonitor);
438 if (mStaging) {
439 Scrap(mConsumer);
440 Move(mStaging, mConsumer);
441 mMonitor.NotifyAll();
444 return mConsumer;
447 SurfaceStream_TripleBuffer_Async::SurfaceStream_TripleBuffer_Async(SurfaceStream* prevStream)
448 : SurfaceStream_TripleBuffer(SurfaceStreamType::TripleBuffer_Async, prevStream)
452 SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async()
456 bool
457 SurfaceStream_TripleBuffer_Async::WaitForCompositor()
459 PROFILER_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor");
461 // We are assumed to be locked
462 while (mStaging)
463 mMonitor.Wait();
465 return true;
468 } /* namespace gfx */
469 } /* namespace mozilla */