gfx/gl/GLScreenBuffer.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

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.

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

mercurial