Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 "GLScreenBuffer.h"
8 #include <cstring>
9 #include "gfxImageSurface.h"
10 #include "GLContext.h"
11 #include "GLBlitHelper.h"
12 #include "GLReadTexImageHelper.h"
13 #include "SharedSurfaceGL.h"
14 #include "SurfaceStream.h"
15 #ifdef MOZ_WIDGET_GONK
16 #include "SharedSurfaceGralloc.h"
17 #include "nsXULAppAPI.h"
18 #endif
19 #ifdef XP_MACOSX
20 #include "SharedSurfaceIO.h"
21 #endif
22 #include "ScopedGLHelpers.h"
23 #include "gfx2DGlue.h"
25 using namespace mozilla::gfx;
27 namespace mozilla {
28 namespace gl {
30 GLScreenBuffer*
31 GLScreenBuffer::Create(GLContext* gl,
32 const gfx::IntSize& size,
33 const SurfaceCaps& caps)
34 {
35 if (caps.antialias &&
36 !gl->IsSupported(GLFeature::framebuffer_multisample))
37 {
38 return nullptr;
39 }
41 SurfaceFactory_GL* factory = nullptr;
43 #ifdef MOZ_WIDGET_GONK
44 /* On B2G, we want a Gralloc factory, and we want one right at the start */
45 if (!factory &&
46 caps.surfaceAllocator &&
47 XRE_GetProcessType() != GeckoProcessType_Default)
48 {
49 factory = new SurfaceFactory_Gralloc(gl, caps);
50 }
51 #endif
52 #ifdef XP_MACOSX
53 /* On OSX, we want an IOSurface factory, and we want one right at the start */
54 if (!factory)
55 {
56 factory = new SurfaceFactory_IOSurface(gl, caps);
57 }
58 #endif
60 if (!factory)
61 factory = new SurfaceFactory_Basic(gl, caps);
63 SurfaceStream* stream = SurfaceStream::CreateForType(
64 SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread,
65 caps.preserve),
66 gl,
67 nullptr);
69 return new GLScreenBuffer(gl, caps, factory, stream);
70 }
72 GLScreenBuffer::~GLScreenBuffer()
73 {
74 delete mDraw;
75 delete mRead;
77 // bug 914823: it is crucial to destroy the Factory _after_ we destroy
78 // the SharedSurfaces around here! Reason: the shared surfaces will want
79 // to ask the Allocator (e.g. the ClientLayerManager) to destroy their
80 // buffers, but that Allocator may be kept alive by the Factory,
81 // as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr
82 // to the Allocator!
83 delete mFactory;
84 }
87 void
88 GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
89 {
90 GLuint drawFB = DrawFB();
91 GLuint readFB = ReadFB();
93 if (!gl->IsSupported(GLFeature::framebuffer_blit)) {
94 MOZ_ASSERT(drawFB == readFB);
95 gl->raw_fBindFramebuffer(target, readFB);
96 return;
97 }
99 switch (target) {
100 case LOCAL_GL_FRAMEBUFFER:
101 gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
102 gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
103 break;
105 case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
106 if (!gl->IsSupported(GLFeature::framebuffer_blit))
107 NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable.");
109 gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
110 break;
112 case LOCAL_GL_READ_FRAMEBUFFER_EXT:
113 if (!gl->IsSupported(GLFeature::framebuffer_blit))
114 NS_WARNING("READ_FRAMEBUFFER requested but unavailable.");
116 gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
117 break;
119 default:
120 MOZ_CRASH("Bad `target` for BindFramebuffer.");
121 }
122 }
124 void
125 GLScreenBuffer::BindFB(GLuint fb)
126 {
127 GLuint drawFB = DrawFB();
128 GLuint readFB = ReadFB();
130 mUserDrawFB = fb;
131 mUserReadFB = fb;
132 mInternalDrawFB = (fb == 0) ? drawFB : fb;
133 mInternalReadFB = (fb == 0) ? readFB : fb;
135 if (mInternalDrawFB == mInternalReadFB) {
136 mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
137 } else {
138 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
139 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
140 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
141 }
143 #ifdef DEBUG
144 mInInternalMode_DrawFB = false;
145 mInInternalMode_ReadFB = false;
146 #endif
147 }
149 void
150 GLScreenBuffer::BindDrawFB(GLuint fb)
151 {
152 if (!mGL->IsSupported(GLFeature::framebuffer_blit)) {
153 NS_WARNING("DRAW_FRAMEBUFFER requested, but unsupported.");
155 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
156 } else {
157 GLuint drawFB = DrawFB();
158 mUserDrawFB = fb;
159 mInternalDrawFB = (fb == 0) ? drawFB : fb;
161 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
162 }
164 #ifdef DEBUG
165 mInInternalMode_DrawFB = false;
166 #endif
167 }
169 void
170 GLScreenBuffer::BindReadFB(GLuint fb)
171 {
172 if (!mGL->IsSupported(GLFeature::framebuffer_blit)) {
173 NS_WARNING("READ_FRAMEBUFFER requested, but unsupported.");
175 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
176 } else {
177 GLuint readFB = ReadFB();
178 mUserReadFB = fb;
179 mInternalReadFB = (fb == 0) ? readFB : fb;
181 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
182 }
184 #ifdef DEBUG
185 mInInternalMode_ReadFB = false;
186 #endif
187 }
189 void
190 GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
191 {
192 mInternalDrawFB = mUserDrawFB = fb;
193 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
195 #ifdef DEBUG
196 mInInternalMode_DrawFB = true;
197 #endif
198 }
200 void
201 GLScreenBuffer::BindReadFB_Internal(GLuint fb)
202 {
203 mInternalReadFB = mUserReadFB = fb;
204 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
206 #ifdef DEBUG
207 mInInternalMode_ReadFB = true;
208 #endif
209 }
212 GLuint
213 GLScreenBuffer::GetDrawFB() const
214 {
215 #ifdef DEBUG
216 MOZ_ASSERT(mGL->IsCurrent());
217 MOZ_ASSERT(!mInInternalMode_DrawFB);
219 // Don't need a branch here, because:
220 // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
221 // We use raw_ here because this is debug code and we need to see what
222 // the driver thinks.
223 GLuint actual = 0;
224 mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
226 GLuint predicted = mInternalDrawFB;
227 if (predicted != actual) {
228 printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
229 predicted, actual);
230 MOZ_ASSERT(false, "Draw FB binding misprediction!");
231 }
232 #endif
234 return mUserDrawFB;
235 }
237 GLuint
238 GLScreenBuffer::GetReadFB() const
239 {
240 #ifdef DEBUG
241 MOZ_ASSERT(mGL->IsCurrent());
242 MOZ_ASSERT(!mInInternalMode_ReadFB);
244 // We use raw_ here because this is debug code and we need to see what
245 // the driver thinks.
246 GLuint actual = 0;
247 if (mGL->IsSupported(GLFeature::framebuffer_blit))
248 mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
249 else
250 mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
252 GLuint predicted = mInternalReadFB;
253 if (predicted != actual) {
254 printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
255 predicted, actual);
256 MOZ_ASSERT(false, "Read FB binding misprediction!");
257 }
258 #endif
260 return mUserReadFB;
261 }
263 GLuint
264 GLScreenBuffer::GetFB() const
265 {
266 MOZ_ASSERT(GetDrawFB() == GetReadFB());
267 return GetDrawFB();
268 }
271 void
272 GLScreenBuffer::DeletingFB(GLuint fb)
273 {
274 if (fb == mInternalDrawFB) {
275 mInternalDrawFB = 0;
276 mUserDrawFB = 0;
277 }
278 if (fb == mInternalReadFB) {
279 mInternalReadFB = 0;
280 mUserReadFB = 0;
281 }
282 }
285 void
286 GLScreenBuffer::AfterDrawCall()
287 {
288 if (mUserDrawFB != 0)
289 return;
291 RequireBlit();
292 }
294 void
295 GLScreenBuffer::BeforeReadCall()
296 {
297 if (mUserReadFB != 0)
298 return;
300 AssureBlitted();
301 }
303 bool
304 GLScreenBuffer::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
305 GLenum format, GLenum type, GLvoid *pixels)
306 {
307 // If the currently bound framebuffer is backed by a SharedSurface_GL
308 // then it might want to override how we read pixel data from it.
309 // This is normally only the default framebuffer, but we can also
310 // have SharedSurfaces bound to other framebuffers when doing
311 // readback for BasicLayers.
312 SharedSurface_GL* surf;
313 if (GetReadFB() == 0) {
314 surf = SharedSurf();
315 } else {
316 surf = mGL->mFBOMapping[GetReadFB()];
317 }
318 if (surf) {
319 return surf->ReadPixels(x, y, width, height, format, type, pixels);
320 }
322 return false;
323 }
325 void
326 GLScreenBuffer::RequireBlit()
327 {
328 mNeedsBlit = true;
329 }
331 void
332 GLScreenBuffer::AssureBlitted()
333 {
334 if (!mNeedsBlit)
335 return;
337 if (mDraw) {
338 GLuint drawFB = DrawFB();
339 GLuint readFB = ReadFB();
341 MOZ_ASSERT(drawFB != 0);
342 MOZ_ASSERT(drawFB != readFB);
343 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
344 MOZ_ASSERT(mDraw->Size() == mRead->Size());
346 ScopedBindFramebuffer boundFB(mGL);
347 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
349 BindReadFB_Internal(drawFB);
350 BindDrawFB_Internal(readFB);
352 const gfx::IntSize& srcSize = mDraw->Size();
353 const gfx::IntSize& destSize = mRead->Size();
355 mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
356 0, 0, destSize.width, destSize.height,
357 LOCAL_GL_COLOR_BUFFER_BIT,
358 LOCAL_GL_NEAREST);
359 // Done!
360 }
362 mNeedsBlit = false;
363 }
365 void
366 GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType)
367 {
368 MOZ_ASSERT(mStream);
370 if (newFactory) {
371 delete mFactory;
372 mFactory = newFactory;
373 }
375 if (mStream->mType == streamType)
376 return;
378 SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mGL, mStream);
379 MOZ_ASSERT(newStream);
381 mStream = newStream;
382 }
384 void
385 GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size)
386 {
387 ScopedBindFramebuffer autoFB(mGL);
389 SharedSurface_GL* surf = SharedSurface_GL::Cast(surface);
390 if (mRead && SharedSurf())
391 SharedSurf()->UnlockProd();
393 surf->LockProd();
395 if (mRead &&
396 surf->AttachType() == SharedSurf()->AttachType() &&
397 size == Size())
398 {
399 // Same size, same type, ready for reuse!
400 mRead->Attach(surf);
401 } else {
402 // Else something changed, so resize:
403 DrawBuffer* draw = CreateDraw(size); // Can be null.
404 ReadBuffer* read = CreateRead(surf);
405 MOZ_ASSERT(read); // Should never fail if SwapProd succeeded.
407 delete mDraw;
408 delete mRead;
410 mDraw = draw;
411 mRead = read;
412 }
414 // Check that we're all set up.
415 MOZ_ASSERT(SharedSurf() == surf);
417 if (!PreserveBuffer()) {
418 // DiscardFramebuffer here could help perf on some mobile platforms.
419 }
420 }
422 bool
423 GLScreenBuffer::Swap(const gfx::IntSize& size)
424 {
425 SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size);
426 if (!nextSurf) {
427 SurfaceFactory_Basic basicFactory(mGL, mFactory->Caps());
428 nextSurf = mStream->SwapProducer(&basicFactory, size);
429 if (!nextSurf)
430 return false;
432 NS_WARNING("SwapProd failed for sophisticated Factory type, fell back to Basic.");
433 }
434 MOZ_ASSERT(nextSurf);
436 Attach(nextSurf, size);
438 return true;
439 }
441 bool
442 GLScreenBuffer::PublishFrame(const gfx::IntSize& size)
443 {
444 AssureBlitted();
446 bool good = Swap(size);
447 return good;
448 }
450 bool
451 GLScreenBuffer::Resize(const gfx::IntSize& size)
452 {
453 SharedSurface* surface = mStream->Resize(mFactory, size);
454 if (!surface)
455 return false;
457 Attach(surface, size);
458 return true;
459 }
461 DrawBuffer*
462 GLScreenBuffer::CreateDraw(const gfx::IntSize& size)
463 {
464 GLContext* gl = mFactory->GL();
465 const GLFormats& formats = mFactory->Formats();
466 const SurfaceCaps& caps = mFactory->DrawCaps();
468 return DrawBuffer::Create(gl, caps, formats, size);
469 }
471 ReadBuffer*
472 GLScreenBuffer::CreateRead(SharedSurface_GL* surf)
473 {
474 GLContext* gl = mFactory->GL();
475 const GLFormats& formats = mFactory->Formats();
476 const SurfaceCaps& caps = mFactory->ReadCaps();
478 return ReadBuffer::Create(gl, caps, formats, surf);
479 }
481 void
482 GLScreenBuffer::Readback(SharedSurface_GL* src, DataSourceSurface* dest)
483 {
484 MOZ_ASSERT(src && dest);
485 DataSourceSurface::MappedSurface ms;
486 dest->Map(DataSourceSurface::MapType::READ, &ms);
487 nsRefPtr<gfxImageSurface> wrappedDest =
488 new gfxImageSurface(ms.mData,
489 ThebesIntSize(dest->GetSize()),
490 ms.mStride,
491 SurfaceFormatToImageFormat(dest->GetFormat()));
492 DeprecatedReadback(src, wrappedDest);
493 dest->Unmap();
494 }
496 void
497 GLScreenBuffer::DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest)
498 {
499 MOZ_ASSERT(src && dest);
500 MOZ_ASSERT(ToIntSize(dest->GetSize()) == src->Size());
501 MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageFormat::ARGB32
502 : gfxImageFormat::RGB24));
504 mGL->MakeCurrent();
506 bool needsSwap = src != SharedSurf();
507 if (needsSwap) {
508 SharedSurf()->UnlockProd();
509 src->LockProd();
510 }
512 ReadBuffer* buffer = CreateRead(src);
513 MOZ_ASSERT(buffer);
515 ScopedBindFramebuffer autoFB(mGL, buffer->FB());
516 ReadPixelsIntoImageSurface(mGL, dest);
518 delete buffer;
520 if (needsSwap) {
521 src->UnlockProd();
522 SharedSurf()->LockProd();
523 }
524 }
526 DrawBuffer*
527 DrawBuffer::Create(GLContext* const gl,
528 const SurfaceCaps& caps,
529 const GLFormats& formats,
530 const gfx::IntSize& size)
531 {
532 if (!caps.color) {
533 MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil);
535 // Nothing is needed.
536 return nullptr;
537 }
539 GLuint colorMSRB = 0;
540 GLuint depthRB = 0;
541 GLuint stencilRB = 0;
543 GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr;
544 GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
545 GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
547 if (!formats.color_rbFormat)
548 pColorMSRB = nullptr;
550 if (pDepthRB && pStencilRB) {
551 if (!formats.depth && !formats.depthStencil)
552 pDepthRB = nullptr;
554 if (!formats.stencil && !formats.depthStencil)
555 pStencilRB = nullptr;
556 } else {
557 if (!formats.depth)
558 pDepthRB = nullptr;
560 if (!formats.stencil)
561 pStencilRB = nullptr;
562 }
564 CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
565 pColorMSRB, pDepthRB, pStencilRB);
567 GLuint fb = 0;
568 gl->fGenFramebuffers(1, &fb);
569 gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
570 MOZ_ASSERT(gl->IsFramebufferComplete(fb));
572 return new DrawBuffer(gl, size, fb, colorMSRB, depthRB, stencilRB);
573 }
575 DrawBuffer::~DrawBuffer()
576 {
577 mGL->MakeCurrent();
579 GLuint fb = mFB;
580 GLuint rbs[] = {
581 mColorMSRB,
582 mDepthRB,
583 mStencilRB
584 };
586 mGL->fDeleteFramebuffers(1, &fb);
587 mGL->fDeleteRenderbuffers(3, rbs);
588 }
595 ReadBuffer*
596 ReadBuffer::Create(GLContext* gl,
597 const SurfaceCaps& caps,
598 const GLFormats& formats,
599 SharedSurface_GL* surf)
600 {
601 MOZ_ASSERT(surf);
603 if (surf->AttachType() == AttachmentType::Screen) {
604 // Don't need anything. Our read buffer will be the 'screen'.
606 return new ReadBuffer(gl,
607 0, 0, 0,
608 surf);
609 }
611 GLuint depthRB = 0;
612 GLuint stencilRB = 0;
614 GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
615 GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
617 CreateRenderbuffersForOffscreen(gl, formats, surf->Size(), caps.antialias,
618 nullptr, pDepthRB, pStencilRB);
620 GLuint colorTex = 0;
621 GLuint colorRB = 0;
622 GLenum target = 0;
624 switch (surf->AttachType()) {
625 case AttachmentType::GLTexture:
626 colorTex = surf->ProdTexture();
627 target = surf->ProdTextureTarget();
628 break;
629 case AttachmentType::GLRenderbuffer:
630 colorRB = surf->ProdRenderbuffer();
631 break;
632 default:
633 MOZ_CRASH("Unknown attachment type?");
634 }
635 MOZ_ASSERT(colorTex || colorRB);
637 GLuint fb = 0;
638 gl->fGenFramebuffers(1, &fb);
639 gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target);
640 gl->mFBOMapping[fb] = surf;
642 MOZ_ASSERT(gl->IsFramebufferComplete(fb));
644 return new ReadBuffer(gl,
645 fb, depthRB, stencilRB,
646 surf);
647 }
649 ReadBuffer::~ReadBuffer()
650 {
651 mGL->MakeCurrent();
653 GLuint fb = mFB;
654 GLuint rbs[] = {
655 mDepthRB,
656 mStencilRB
657 };
659 mGL->fDeleteFramebuffers(1, &fb);
660 mGL->fDeleteRenderbuffers(2, rbs);
661 mGL->mFBOMapping.erase(mFB);
662 }
664 void
665 ReadBuffer::Attach(SharedSurface_GL* surf)
666 {
667 MOZ_ASSERT(surf && mSurf);
668 MOZ_ASSERT(surf->AttachType() == mSurf->AttachType());
669 MOZ_ASSERT(surf->Size() == mSurf->Size());
671 // Nothing else is needed for AttachType Screen.
672 if (surf->AttachType() != AttachmentType::Screen) {
673 GLuint colorTex = 0;
674 GLuint colorRB = 0;
675 GLenum target = 0;
677 switch (surf->AttachType()) {
678 case AttachmentType::GLTexture:
679 colorTex = surf->ProdTexture();
680 target = surf->ProdTextureTarget();
681 break;
682 case AttachmentType::GLRenderbuffer:
683 colorRB = surf->ProdRenderbuffer();
684 break;
685 default:
686 MOZ_CRASH("Unknown attachment type?");
687 }
689 mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB, target);
690 mGL->mFBOMapping[mFB] = surf;
691 MOZ_ASSERT(mGL->IsFramebufferComplete(mFB));
692 }
694 mSurf = surf;
695 }
697 const gfx::IntSize&
698 ReadBuffer::Size() const
699 {
700 return mSurf->Size();
701 }
703 } /* namespace gl */
704 } /* namespace mozilla */