gfx/gl/SurfaceStream.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:da936beacf64
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/. */
5
6 #include "SurfaceStream.h"
7
8 #include "gfxPoint.h"
9 #include "SharedSurface.h"
10 #include "SharedSurfaceGL.h"
11 #include "SurfaceFactory.h"
12 #include "GeckoProfiler.h"
13
14 namespace mozilla {
15 namespace gfx {
16
17 SurfaceStreamType
18 SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc,
19 bool preserveBuffer)
20 {
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;
31 }
32 }
33
34 SurfaceStream*
35 SurfaceStream::CreateForType(SurfaceStreamType type, mozilla::gl::GLContext* glContext, SurfaceStream* prevStream)
36 {
37 SurfaceStream* result = nullptr;
38
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.");
54 }
55
56 result->mGLContext = glContext;
57 return result;
58 }
59
60 bool
61 SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory)
62 {
63 if (!mProducer) {
64 New(factory, src->Size(), mProducer);
65 if (!mProducer) {
66 return false;
67 }
68 }
69
70 MOZ_ASSERT(src->Size() == mProducer->Size(), "Size mismatch");
71
72 SharedSurface::Copy(src, mProducer, factory);
73 return true;
74 }
75
76 void
77 SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size,
78 SharedSurface*& surf)
79 {
80 MOZ_ASSERT(!surf);
81 surf = factory->NewSharedSurface(size);
82
83 if (surf)
84 mSurfaces.insert(surf);
85 }
86
87 void
88 SurfaceStream::Recycle(SurfaceFactory* factory, SharedSurface*& surf)
89 {
90 if (surf) {
91 mSurfaces.erase(surf);
92 factory->Recycle(surf);
93 }
94 MOZ_ASSERT(!surf);
95 }
96
97 void
98 SurfaceStream::Delete(SharedSurface*& surf)
99 {
100 if (surf) {
101 mSurfaces.erase(surf);
102 delete surf;
103 surf = nullptr;
104 }
105 MOZ_ASSERT(!surf);
106 }
107
108 SharedSurface*
109 SurfaceStream::Surrender(SharedSurface*& surf)
110 {
111 SharedSurface* ret = surf;
112
113 if (surf) {
114 mSurfaces.erase(surf);
115 surf = nullptr;
116 }
117 MOZ_ASSERT(!surf);
118
119 return ret;
120 }
121
122 SharedSurface*
123 SurfaceStream::Absorb(SharedSurface*& surf)
124 {
125 SharedSurface* ret = surf;
126
127 if (surf) {
128 mSurfaces.insert(surf);
129 surf = nullptr;
130 }
131 MOZ_ASSERT(!surf);
132
133 return ret;
134 }
135
136 void
137 SurfaceStream::Scrap(SharedSurface*& scrap)
138 {
139 if (scrap) {
140 mScraps.push(scrap);
141 scrap = nullptr;
142 }
143 MOZ_ASSERT(!scrap);
144 }
145
146 void
147 SurfaceStream::RecycleScraps(SurfaceFactory* factory)
148 {
149 while (!mScraps.empty()) {
150 SharedSurface* cur = mScraps.top();
151 mScraps.pop();
152
153 Recycle(factory, cur);
154 }
155 }
156
157
158
159 SurfaceStream::~SurfaceStream()
160 {
161 Delete(mProducer);
162
163 while (!mScraps.empty()) {
164 SharedSurface* cur = mScraps.top();
165 mScraps.pop();
166
167 Delete(cur);
168 }
169
170 MOZ_ASSERT(mSurfaces.empty());
171 }
172
173 SharedSurface*
174 SurfaceStream::SwapConsumer()
175 {
176 MOZ_ASSERT(mIsAlive);
177
178 SharedSurface* ret = SwapConsumer_NoWait();
179 if (!ret)
180 return nullptr;
181
182 if (!ret->WaitSync()) {
183 return nullptr;
184 }
185
186 return ret;
187 }
188
189 SharedSurface*
190 SurfaceStream::Resize(SurfaceFactory* factory, const gfx::IntSize& size)
191 {
192 MonitorAutoLock lock(mMonitor);
193
194 if (mProducer) {
195 Scrap(mProducer);
196 }
197
198 New(factory, size, mProducer);
199 return mProducer;
200 }
201
202 SurfaceStream_SingleBuffer::SurfaceStream_SingleBuffer(SurfaceStream* prevStream)
203 : SurfaceStream(SurfaceStreamType::SingleBuffer, prevStream)
204 , mConsumer(nullptr)
205 {
206 if (!prevStream)
207 return;
208
209 SharedSurface* prevProducer = nullptr;
210 SharedSurface* prevConsumer = nullptr;
211 prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
212
213 if (prevConsumer == prevProducer)
214 prevConsumer = nullptr;
215
216 mProducer = Absorb(prevProducer);
217 mConsumer = Absorb(prevConsumer);
218 }
219
220 SurfaceStream_SingleBuffer::~SurfaceStream_SingleBuffer()
221 {
222 Delete(mConsumer);
223 }
224
225 void
226 SurfaceStream_SingleBuffer::SurrenderSurfaces(SharedSurface*& producer,
227 SharedSurface*& consumer)
228 {
229 mIsAlive = false;
230
231 producer = Surrender(mProducer);
232 consumer = Surrender(mConsumer);
233
234 if (!consumer)
235 consumer = producer;
236 }
237
238 SharedSurface*
239 SurfaceStream_SingleBuffer::SwapProducer(SurfaceFactory* factory,
240 const gfx::IntSize& size)
241 {
242 MonitorAutoLock lock(mMonitor);
243 if (mConsumer) {
244 Recycle(factory, mConsumer);
245 }
246
247 if (mProducer) {
248 // Fence now, before we start (maybe) juggling Prod around.
249 mProducer->Fence();
250
251 // Size mismatch means we need to squirrel the current Prod
252 // into Cons, and leave Prod empty, so it gets a new surface below.
253 bool needsNewBuffer = mProducer->Size() != size;
254
255 // Even if we're the right size, if the type has changed, and we don't
256 // need to preserve, we should switch out for (presumedly) better perf.
257 if (mProducer->Type() != factory->Type() &&
258 !factory->Caps().preserve)
259 {
260 needsNewBuffer = true;
261 }
262
263 if (needsNewBuffer) {
264 Move(mProducer, mConsumer);
265 }
266 }
267
268 // The old Prod (if there every was one) was invalid,
269 // so we need a new one.
270 if (!mProducer) {
271 New(factory, size, mProducer);
272 }
273
274 return mProducer;
275 }
276
277 SharedSurface*
278 SurfaceStream_SingleBuffer::SwapConsumer_NoWait()
279 {
280 MonitorAutoLock lock(mMonitor);
281
282 // Use Cons, if present.
283 // Otherwise, just use Prod directly.
284 SharedSurface* toConsume = mConsumer;
285 if (!toConsume)
286 toConsume = mProducer;
287
288 return toConsume;
289 }
290
291
292
293 SurfaceStream_TripleBuffer_Copy::SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream)
294 : SurfaceStream(SurfaceStreamType::TripleBuffer_Copy, prevStream)
295 , mStaging(nullptr)
296 , mConsumer(nullptr)
297 {
298 if (!prevStream)
299 return;
300
301 SharedSurface* prevProducer = nullptr;
302 SharedSurface* prevConsumer = nullptr;
303 prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
304
305 if (prevConsumer == prevProducer)
306 prevConsumer = nullptr;
307
308 mProducer = Absorb(prevProducer);
309 mConsumer = Absorb(prevConsumer);
310 }
311
312 SurfaceStream_TripleBuffer_Copy::~SurfaceStream_TripleBuffer_Copy()
313 {
314 Delete(mStaging);
315 Delete(mConsumer);
316 }
317
318 void
319 SurfaceStream_TripleBuffer_Copy::SurrenderSurfaces(SharedSurface*& producer,
320 SharedSurface*& consumer)
321 {
322 mIsAlive = false;
323
324 producer = Surrender(mProducer);
325 consumer = Surrender(mConsumer);
326
327 if (!consumer)
328 consumer = Surrender(mStaging);
329 }
330
331 SharedSurface*
332 SurfaceStream_TripleBuffer_Copy::SwapProducer(SurfaceFactory* factory,
333 const gfx::IntSize& size)
334 {
335 MonitorAutoLock lock(mMonitor);
336
337 RecycleScraps(factory);
338 if (mProducer) {
339 if (mStaging) {
340 // We'll re-use this for a new mProducer later on if
341 // the size remains the same
342 Recycle(factory, mStaging);
343 }
344
345 Move(mProducer, mStaging);
346 mStaging->Fence();
347
348 New(factory, size, mProducer);
349
350 if (mProducer && mStaging->Size() == mProducer->Size())
351 SharedSurface::Copy(mStaging, mProducer, factory);
352 } else {
353 New(factory, size, mProducer);
354 }
355
356 return mProducer;
357 }
358
359
360 SharedSurface*
361 SurfaceStream_TripleBuffer_Copy::SwapConsumer_NoWait()
362 {
363 MonitorAutoLock lock(mMonitor);
364
365 if (mStaging) {
366 Scrap(mConsumer);
367 Move(mStaging, mConsumer);
368 }
369
370 return mConsumer;
371 }
372
373 void SurfaceStream_TripleBuffer::Init(SurfaceStream* prevStream)
374 {
375 if (!prevStream)
376 return;
377
378 SharedSurface* prevProducer = nullptr;
379 SharedSurface* prevConsumer = nullptr;
380 prevStream->SurrenderSurfaces(prevProducer, prevConsumer);
381
382 if (prevConsumer == prevProducer)
383 prevConsumer = nullptr;
384
385 mProducer = Absorb(prevProducer);
386 mConsumer = Absorb(prevConsumer);
387 }
388
389
390 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream)
391 : SurfaceStream(type, prevStream)
392 , mStaging(nullptr)
393 , mConsumer(nullptr)
394 {
395 SurfaceStream_TripleBuffer::Init(prevStream);
396 }
397
398 SurfaceStream_TripleBuffer::SurfaceStream_TripleBuffer(SurfaceStream* prevStream)
399 : SurfaceStream(SurfaceStreamType::TripleBuffer, prevStream)
400 , mStaging(nullptr)
401 , mConsumer(nullptr)
402 {
403 SurfaceStream_TripleBuffer::Init(prevStream);
404 }
405
406 SurfaceStream_TripleBuffer::~SurfaceStream_TripleBuffer()
407 {
408 Delete(mStaging);
409 Delete(mConsumer);
410 }
411
412 void
413 SurfaceStream_TripleBuffer::SurrenderSurfaces(SharedSurface*& producer,
414 SharedSurface*& consumer)
415 {
416 mIsAlive = false;
417
418 producer = Surrender(mProducer);
419 consumer = Surrender(mConsumer);
420
421 if (!consumer)
422 consumer = Surrender(mStaging);
423 }
424
425 SharedSurface*
426 SurfaceStream_TripleBuffer::SwapProducer(SurfaceFactory* factory,
427 const gfx::IntSize& size)
428 {
429 PROFILER_LABEL("SurfaceStream_TripleBuffer", "SwapProducer");
430
431 MonitorAutoLock lock(mMonitor);
432 if (mProducer) {
433 RecycleScraps(factory);
434
435 // If WaitForCompositor succeeds, mStaging has moved to mConsumer.
436 // If it failed, we might have to scrap it.
437 if (mStaging && !WaitForCompositor())
438 Scrap(mStaging);
439
440 MOZ_ASSERT(!mStaging);
441 Move(mProducer, mStaging);
442 mStaging->Fence();
443 }
444
445 MOZ_ASSERT(!mProducer);
446 New(factory, size, mProducer);
447
448 return mProducer;
449 }
450
451 SharedSurface*
452 SurfaceStream_TripleBuffer::SwapConsumer_NoWait()
453 {
454 MonitorAutoLock lock(mMonitor);
455 if (mStaging) {
456 Scrap(mConsumer);
457 Move(mStaging, mConsumer);
458 mMonitor.NotifyAll();
459 }
460
461 return mConsumer;
462 }
463
464 SurfaceStream_TripleBuffer_Async::SurfaceStream_TripleBuffer_Async(SurfaceStream* prevStream)
465 : SurfaceStream_TripleBuffer(SurfaceStreamType::TripleBuffer_Async, prevStream)
466 {
467 }
468
469 SurfaceStream_TripleBuffer_Async::~SurfaceStream_TripleBuffer_Async()
470 {
471 }
472
473 bool
474 SurfaceStream_TripleBuffer_Async::WaitForCompositor()
475 {
476 PROFILER_LABEL("SurfaceStream_TripleBuffer_Async", "WaitForCompositor");
477
478 // We are assumed to be locked
479 while (mStaging) {
480 if (!NS_SUCCEEDED(mMonitor.Wait(PR_MillisecondsToInterval(100)))) {
481 return false;
482 }
483 }
484
485 return true;
486 }
487
488 } /* namespace gfx */
489 } /* namespace mozilla */

mercurial