Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / gfx / gl / GLScreenBuffer.cpp
blob1d9d89feaf81f3ddf944f21b918ce43c56402d32
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 "CompositorTypes.h"
10 #include "GLContext.h"
11 #include "GLBlitHelper.h"
12 #include "GLReadTexImageHelper.h"
13 #include "SharedSurfaceGL.h"
14 #ifdef MOZ_WIDGET_GONK
15 #include "SharedSurfaceGralloc.h"
16 #include "nsXULAppAPI.h"
17 #endif
18 #ifdef XP_MACOSX
19 #include "SharedSurfaceIO.h"
20 #endif
21 #include "ScopedGLHelpers.h"
22 #include "gfx2DGlue.h"
23 #include "../layers/ipc/ShadowLayers.h"
25 namespace mozilla {
26 namespace gl {
28 using gfx::SurfaceFormat;
30 UniquePtr<GLScreenBuffer>
31 GLScreenBuffer::Create(GLContext* gl,
32 const gfx::IntSize& size,
33 const SurfaceCaps& caps)
35 UniquePtr<GLScreenBuffer> ret;
36 if (caps.antialias &&
37 !gl->IsSupported(GLFeature::framebuffer_multisample))
39 return Move(ret);
42 UniquePtr<SurfaceFactory> factory;
44 #ifdef MOZ_WIDGET_GONK
45 /* On B2G, we want a Gralloc factory, and we want one right at the start */
46 layers::ISurfaceAllocator* allocator = caps.surfaceAllocator;
47 if (!factory &&
48 allocator &&
49 XRE_GetProcessType() != GeckoProcessType_Default)
51 layers::TextureFlags flags = layers::TextureFlags::DEALLOCATE_CLIENT |
52 layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
53 if (!caps.premultAlpha) {
54 flags |= layers::TextureFlags::NON_PREMULTIPLIED;
57 factory = MakeUnique<SurfaceFactory_Gralloc>(gl, caps, flags,
58 allocator);
60 #endif
61 #ifdef XP_MACOSX
62 /* On OSX, we want an IOSurface factory, and we want one right at the start */
63 if (!factory) {
64 factory = SurfaceFactory_IOSurface::Create(gl, caps);
66 #endif
68 if (!factory) {
69 factory = MakeUnique<SurfaceFactory_Basic>(gl, caps);
72 ret.reset( new GLScreenBuffer(gl, caps, Move(factory)) );
73 return Move(ret);
76 GLScreenBuffer::~GLScreenBuffer()
78 mDraw = nullptr;
79 mRead = nullptr;
81 // bug 914823: it is crucial to destroy the Factory _after_ we destroy
82 // the SharedSurfaces around here! Reason: the shared surfaces will want
83 // to ask the Allocator (e.g. the ClientLayerManager) to destroy their
84 // buffers, but that Allocator may be kept alive by the Factory,
85 // as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr
86 // to the Allocator!
87 mFactory = nullptr;
91 void
92 GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
94 GLuint drawFB = DrawFB();
95 GLuint readFB = ReadFB();
97 if (!gl->IsSupported(GLFeature::framebuffer_blit)) {
98 MOZ_ASSERT(drawFB == readFB);
99 gl->raw_fBindFramebuffer(target, readFB);
100 return;
103 switch (target) {
104 case LOCAL_GL_FRAMEBUFFER:
105 gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
106 gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
107 break;
109 case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
110 if (!gl->IsSupported(GLFeature::framebuffer_blit))
111 NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable.");
113 gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
114 break;
116 case LOCAL_GL_READ_FRAMEBUFFER_EXT:
117 if (!gl->IsSupported(GLFeature::framebuffer_blit))
118 NS_WARNING("READ_FRAMEBUFFER requested but unavailable.");
120 gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
121 break;
123 default:
124 MOZ_CRASH("Bad `target` for BindFramebuffer.");
128 void
129 GLScreenBuffer::BindFB(GLuint fb)
131 GLuint drawFB = DrawFB();
132 GLuint readFB = ReadFB();
134 mUserDrawFB = fb;
135 mUserReadFB = fb;
136 mInternalDrawFB = (fb == 0) ? drawFB : fb;
137 mInternalReadFB = (fb == 0) ? readFB : fb;
139 if (mInternalDrawFB == mInternalReadFB) {
140 mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
141 } else {
142 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
143 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
144 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
147 #ifdef DEBUG
148 mInInternalMode_DrawFB = false;
149 mInInternalMode_ReadFB = false;
150 #endif
153 void
154 GLScreenBuffer::BindDrawFB(GLuint fb)
156 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
158 GLuint drawFB = DrawFB();
159 mUserDrawFB = fb;
160 mInternalDrawFB = (fb == 0) ? drawFB : fb;
162 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
164 #ifdef DEBUG
165 mInInternalMode_DrawFB = false;
166 #endif
169 void
170 GLScreenBuffer::BindReadFB(GLuint fb)
172 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
174 GLuint readFB = ReadFB();
175 mUserReadFB = fb;
176 mInternalReadFB = (fb == 0) ? readFB : fb;
178 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
180 #ifdef DEBUG
181 mInInternalMode_ReadFB = false;
182 #endif
185 void
186 GLScreenBuffer::BindFB_Internal(GLuint fb)
188 mInternalDrawFB = mUserDrawFB = fb;
189 mInternalReadFB = mUserReadFB = fb;
190 mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
192 #ifdef DEBUG
193 mInInternalMode_DrawFB = true;
194 mInInternalMode_ReadFB = true;
195 #endif
198 void
199 GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
201 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
203 mInternalDrawFB = mUserDrawFB = fb;
204 mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
206 #ifdef DEBUG
207 mInInternalMode_DrawFB = true;
208 #endif
211 void
212 GLScreenBuffer::BindReadFB_Internal(GLuint fb)
214 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
216 mInternalReadFB = mUserReadFB = fb;
217 mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
219 #ifdef DEBUG
220 mInInternalMode_ReadFB = true;
221 #endif
225 GLuint
226 GLScreenBuffer::GetDrawFB() const
228 #ifdef DEBUG
229 MOZ_ASSERT(mGL->IsCurrent());
230 MOZ_ASSERT(!mInInternalMode_DrawFB);
232 // Don't need a branch here, because:
233 // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
234 // We use raw_ here because this is debug code and we need to see what
235 // the driver thinks.
236 GLuint actual = 0;
237 mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
239 GLuint predicted = mInternalDrawFB;
240 if (predicted != actual) {
241 printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
242 predicted, actual);
243 MOZ_ASSERT(false, "Draw FB binding misprediction!");
245 #endif
247 return mUserDrawFB;
250 GLuint
251 GLScreenBuffer::GetReadFB() const
253 #ifdef DEBUG
254 MOZ_ASSERT(mGL->IsCurrent());
255 MOZ_ASSERT(!mInInternalMode_ReadFB);
257 // We use raw_ here because this is debug code and we need to see what
258 // the driver thinks.
259 GLuint actual = 0;
260 if (mGL->IsSupported(GLFeature::framebuffer_blit))
261 mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
262 else
263 mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
265 GLuint predicted = mInternalReadFB;
266 if (predicted != actual) {
267 printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
268 predicted, actual);
269 MOZ_ASSERT(false, "Read FB binding misprediction!");
271 #endif
273 return mUserReadFB;
276 GLuint
277 GLScreenBuffer::GetFB() const
279 MOZ_ASSERT(GetDrawFB() == GetReadFB());
280 return GetDrawFB();
284 void
285 GLScreenBuffer::DeletingFB(GLuint fb)
287 if (fb == mInternalDrawFB) {
288 mInternalDrawFB = 0;
289 mUserDrawFB = 0;
291 if (fb == mInternalReadFB) {
292 mInternalReadFB = 0;
293 mUserReadFB = 0;
298 void
299 GLScreenBuffer::AfterDrawCall()
301 if (mUserDrawFB != 0)
302 return;
304 RequireBlit();
307 void
308 GLScreenBuffer::BeforeReadCall()
310 if (mUserReadFB != 0)
311 return;
313 AssureBlitted();
316 bool
317 GLScreenBuffer::ReadPixels(GLint x, GLint y,
318 GLsizei width, GLsizei height,
319 GLenum format, GLenum type,
320 GLvoid* pixels)
322 // If the currently bound framebuffer is backed by a SharedSurface
323 // then it might want to override how we read pixel data from it.
324 // This is normally only the default framebuffer, but we can also
325 // have SharedSurfaces bound to other framebuffers when doing
326 // readback for BasicLayers.
327 SharedSurface* surf;
328 if (GetReadFB() == 0) {
329 surf = SharedSurf();
330 } else {
331 surf = mGL->mFBOMapping[GetReadFB()];
333 if (surf) {
334 return surf->ReadPixels(x, y, width, height, format, type, pixels);
337 return false;
340 void
341 GLScreenBuffer::RequireBlit()
343 mNeedsBlit = true;
346 void
347 GLScreenBuffer::AssureBlitted()
349 if (!mNeedsBlit)
350 return;
352 if (mDraw) {
353 GLuint drawFB = DrawFB();
354 GLuint readFB = ReadFB();
356 MOZ_ASSERT(drawFB != 0);
357 MOZ_ASSERT(drawFB != readFB);
358 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
359 MOZ_ASSERT(mDraw->mSize == mRead->Size());
361 ScopedBindFramebuffer boundFB(mGL);
362 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
364 BindReadFB_Internal(drawFB);
365 BindDrawFB_Internal(readFB);
367 const gfx::IntSize& srcSize = mDraw->mSize;
368 const gfx::IntSize& destSize = mRead->Size();
370 mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
371 0, 0, destSize.width, destSize.height,
372 LOCAL_GL_COLOR_BUFFER_BIT,
373 LOCAL_GL_NEAREST);
374 // Done!
377 mNeedsBlit = false;
380 void
381 GLScreenBuffer::Morph(UniquePtr<SurfaceFactory> newFactory)
383 MOZ_ASSERT(newFactory);
384 mFactory = Move(newFactory);
387 bool
388 GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
390 ScopedBindFramebuffer autoFB(mGL);
392 if (mRead && SharedSurf())
393 SharedSurf()->UnlockProd();
395 surf->LockProd();
397 if (mRead &&
398 surf->mAttachType == SharedSurf()->mAttachType &&
399 size == Size())
401 // Same size, same type, ready for reuse!
402 mRead->Attach(surf);
403 } else {
404 // Else something changed, so resize:
405 UniquePtr<DrawBuffer> draw;
406 bool drawOk = CreateDraw(size, &draw); // Can be null.
408 UniquePtr<ReadBuffer> read = CreateRead(surf);
409 bool readOk = !!read;
411 if (!drawOk || !readOk) {
412 surf->UnlockProd();
414 return false;
417 mDraw = Move(draw);
418 mRead = Move(read);
421 // Check that we're all set up.
422 MOZ_ASSERT(SharedSurf() == surf);
424 return true;
427 bool
428 GLScreenBuffer::Swap(const gfx::IntSize& size)
430 RefPtr<ShSurfHandle> newBack = mFactory->NewShSurfHandle(size);
431 if (!newBack)
432 return false;
434 if (!Attach(newBack->Surf(), size))
435 return false;
436 // Attach was successful.
438 mFront = mBack;
439 mBack = newBack;
441 if (mBack) {
442 mBack->Surf()->ProducerAcquire();
445 if (ShouldPreserveBuffer() &&
446 mFront &&
447 mBack)
449 auto src = mFront->Surf();
450 auto dest = mBack->Surf();
451 SharedSurface::ProdCopy(src, dest, mFactory.get());
454 // XXX: We would prefer to fence earlier on platforms that don't need
455 // the full ProducerAcquire/ProducerRelease semantics, so that the fence
456 // doesn't include the copy operation. Unfortunately, the current API
457 // doesn't expose a good way to do that.
458 if (mFront) {
459 mFront->Surf()->ProducerRelease();
462 return true;
465 bool
466 GLScreenBuffer::PublishFrame(const gfx::IntSize& size)
468 AssureBlitted();
470 bool good = Swap(size);
471 return good;
474 bool
475 GLScreenBuffer::Resize(const gfx::IntSize& size)
477 RefPtr<ShSurfHandle> newBack = mFactory->NewShSurfHandle(size);
478 if (!newBack)
479 return false;
481 if (!Attach(newBack->Surf(), size))
482 return false;
484 if (mBack)
485 mBack->Surf()->ProducerRelease();
487 mBack = newBack;
489 mBack->Surf()->ProducerAcquire();
491 return true;
494 bool
495 GLScreenBuffer::CreateDraw(const gfx::IntSize& size,
496 UniquePtr<DrawBuffer>* out_buffer)
498 GLContext* gl = mFactory->mGL;
499 const GLFormats& formats = mFactory->mFormats;
500 const SurfaceCaps& caps = mFactory->DrawCaps();
502 return DrawBuffer::Create(gl, caps, formats, size, out_buffer);
505 UniquePtr<ReadBuffer>
506 GLScreenBuffer::CreateRead(SharedSurface* surf)
508 GLContext* gl = mFactory->mGL;
509 const GLFormats& formats = mFactory->mFormats;
510 const SurfaceCaps& caps = mFactory->ReadCaps();
512 return ReadBuffer::Create(gl, caps, formats, surf);
515 void
516 GLScreenBuffer::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
518 MOZ_ASSERT(src && dest);
519 MOZ_ASSERT(dest->GetSize() == src->mSize);
520 MOZ_ASSERT(dest->GetFormat() == (src->mHasAlpha ? SurfaceFormat::B8G8R8A8
521 : SurfaceFormat::B8G8R8X8));
523 mGL->MakeCurrent();
525 bool needsSwap = src != SharedSurf();
526 if (needsSwap) {
527 SharedSurf()->UnlockProd();
528 src->LockProd();
532 // Even though we're reading. We're doing it on
533 // the producer side. So we call ProducerAcquire
534 // instead of ConsumerAcquire.
535 src->ProducerAcquire();
537 UniquePtr<ReadBuffer> buffer = CreateRead(src);
538 MOZ_ASSERT(buffer);
540 ScopedBindFramebuffer autoFB(mGL, buffer->mFB);
541 ReadPixelsIntoDataSurface(mGL, dest);
543 src->ProducerRelease();
546 if (needsSwap) {
547 src->UnlockProd();
548 SharedSurf()->LockProd();
552 bool
553 GLScreenBuffer::IsDrawFramebufferDefault() const
555 if (!mDraw)
556 return IsReadFramebufferDefault();
557 return mDraw->mFB == 0;
560 bool
561 GLScreenBuffer::IsReadFramebufferDefault() const
563 return SharedSurf()->mAttachType == AttachmentType::Screen;
566 ////////////////////////////////////////////////////////////////////////
567 // DrawBuffer
569 bool
570 DrawBuffer::Create(GLContext* const gl,
571 const SurfaceCaps& caps,
572 const GLFormats& formats,
573 const gfx::IntSize& size,
574 UniquePtr<DrawBuffer>* out_buffer)
576 MOZ_ASSERT(out_buffer);
577 *out_buffer = nullptr;
579 if (!caps.color) {
580 MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil);
582 // Nothing is needed.
583 return true;
586 if (caps.antialias) {
587 if (formats.samples == 0)
588 return false; // Can't create it.
590 MOZ_ASSERT(formats.samples <= gl->MaxSamples());
593 GLuint colorMSRB = 0;
594 GLuint depthRB = 0;
595 GLuint stencilRB = 0;
597 GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr;
598 GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
599 GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
601 if (!formats.color_rbFormat)
602 pColorMSRB = nullptr;
604 if (pDepthRB && pStencilRB) {
605 if (!formats.depth && !formats.depthStencil)
606 pDepthRB = nullptr;
608 if (!formats.stencil && !formats.depthStencil)
609 pStencilRB = nullptr;
610 } else {
611 if (!formats.depth)
612 pDepthRB = nullptr;
614 if (!formats.stencil)
615 pStencilRB = nullptr;
618 GLContext::LocalErrorScope localError(*gl);
620 CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
621 pColorMSRB, pDepthRB, pStencilRB);
623 GLuint fb = 0;
624 gl->fGenFramebuffers(1, &fb);
625 gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
627 UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, fb, colorMSRB,
628 depthRB, stencilRB) );
630 GLenum err = localError.GetError();
631 MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
632 if (err || !gl->IsFramebufferComplete(fb))
633 return false;
635 *out_buffer = Move(ret);
636 return true;
639 DrawBuffer::~DrawBuffer()
641 mGL->MakeCurrent();
643 GLuint fb = mFB;
644 GLuint rbs[] = {
645 mColorMSRB,
646 mDepthRB,
647 mStencilRB
650 mGL->fDeleteFramebuffers(1, &fb);
651 mGL->fDeleteRenderbuffers(3, rbs);
654 ////////////////////////////////////////////////////////////////////////
655 // ReadBuffer
657 UniquePtr<ReadBuffer>
658 ReadBuffer::Create(GLContext* gl,
659 const SurfaceCaps& caps,
660 const GLFormats& formats,
661 SharedSurface* surf)
663 MOZ_ASSERT(surf);
665 if (surf->mAttachType == AttachmentType::Screen) {
666 // Don't need anything. Our read buffer will be the 'screen'.
668 return UniquePtr<ReadBuffer>( new ReadBuffer(gl, 0, 0, 0,
669 surf) );
672 GLuint depthRB = 0;
673 GLuint stencilRB = 0;
675 GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
676 GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
678 GLContext::LocalErrorScope localError(*gl);
680 CreateRenderbuffersForOffscreen(gl, formats, surf->mSize, caps.antialias,
681 nullptr, pDepthRB, pStencilRB);
683 GLuint colorTex = 0;
684 GLuint colorRB = 0;
685 GLenum target = 0;
687 switch (surf->mAttachType) {
688 case AttachmentType::GLTexture:
689 colorTex = surf->ProdTexture();
690 target = surf->ProdTextureTarget();
691 break;
692 case AttachmentType::GLRenderbuffer:
693 colorRB = surf->ProdRenderbuffer();
694 break;
695 default:
696 MOZ_CRASH("Unknown attachment type?");
698 MOZ_ASSERT(colorTex || colorRB);
700 GLuint fb = 0;
701 gl->fGenFramebuffers(1, &fb);
702 gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target);
703 gl->mFBOMapping[fb] = surf;
705 UniquePtr<ReadBuffer> ret( new ReadBuffer(gl, fb, depthRB,
706 stencilRB, surf) );
708 GLenum err = localError.GetError();
709 MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
710 if (err || !gl->IsFramebufferComplete(fb)) {
711 ret = nullptr;
714 return Move(ret);
717 ReadBuffer::~ReadBuffer()
719 mGL->MakeCurrent();
721 GLuint fb = mFB;
722 GLuint rbs[] = {
723 mDepthRB,
724 mStencilRB
727 mGL->fDeleteFramebuffers(1, &fb);
728 mGL->fDeleteRenderbuffers(2, rbs);
729 mGL->mFBOMapping.erase(mFB);
732 void
733 ReadBuffer::Attach(SharedSurface* surf)
735 MOZ_ASSERT(surf && mSurf);
736 MOZ_ASSERT(surf->mAttachType == mSurf->mAttachType);
737 MOZ_ASSERT(surf->mSize == mSurf->mSize);
739 // Nothing else is needed for AttachType Screen.
740 if (surf->mAttachType != AttachmentType::Screen) {
741 GLuint colorTex = 0;
742 GLuint colorRB = 0;
743 GLenum target = 0;
745 switch (surf->mAttachType) {
746 case AttachmentType::GLTexture:
747 colorTex = surf->ProdTexture();
748 target = surf->ProdTextureTarget();
749 break;
750 case AttachmentType::GLRenderbuffer:
751 colorRB = surf->ProdRenderbuffer();
752 break;
753 default:
754 MOZ_CRASH("Unknown attachment type?");
757 mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB, target);
758 mGL->mFBOMapping[mFB] = surf;
759 MOZ_ASSERT(mGL->IsFramebufferComplete(mFB));
762 mSurf = surf;
765 const gfx::IntSize&
766 ReadBuffer::Size() const
768 return mSurf->mSize;
771 } /* namespace gl */
772 } /* namespace mozilla */