Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 */ |