|
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 */ |