CompositorOGL.cpp (60131B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CompositorOGL.h" 8 #include <stddef.h> // for size_t 9 #include <stdint.h> // for uint32_t, uint8_t 10 #include <stdlib.h> // for free, malloc 11 #include "GLContextProvider.h" // for GLContextProvider 12 #include "GLContext.h" // for GLContext 13 #include "GLUploadHelpers.h" 14 #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter 15 #include "gfxEnv.h" // for gfxEnv 16 #include "gfxPlatform.h" // for gfxPlatform 17 #include "gfxRect.h" // for gfxRect 18 #include "gfxUtils.h" // for gfxUtils, etc 19 #include "mozilla/Preferences.h" // for Preferences 20 #include "mozilla/ProfilerLabels.h" 21 #include "mozilla/StaticPrefs_gfx.h" 22 #include "mozilla/StaticPrefs_layers.h" 23 #include "mozilla/StaticPrefs_nglayout.h" 24 #include "mozilla/gfx/BasePoint.h" // for BasePoint 25 #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix 26 #include "mozilla/gfx/Triangle.h" // for Triangle 27 #include "mozilla/gfx/gfxVars.h" // for gfxVars 28 #include "mozilla/layers/ImageDataSerializer.h" 29 #include "mozilla/layers/NativeLayer.h" 30 #include "mozilla/layers/CompositingRenderTargetOGL.h" 31 #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc 32 #include "mozilla/layers/TextureHost.h" // for TextureSource, etc 33 #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc 34 #include "mozilla/layers/PTextureParent.h" // for OtherPid() on PTextureParent 35 #include "mozilla/mozalloc.h" // for operator delete, etc 36 #include "nsAppRunner.h" 37 #include "nsAString.h" 38 #include "nsClassHashtable.h" 39 #include "nsIConsoleService.h" // for nsIConsoleService, etc 40 #include "nsIWidget.h" // for nsIWidget 41 #include "nsLiteralString.h" // for NS_LITERAL_STRING 42 #include "nsMathUtils.h" // for NS_roundf 43 #include "nsRect.h" // for mozilla::gfx::IntRect 44 #include "nsServiceManagerUtils.h" // for do_GetService 45 #include "nsString.h" // for nsString, nsAutoCString, etc 46 #include "OGLShaderProgram.h" // for ShaderProgramOGL, etc 47 #include "ScopedGLHelpers.h" 48 #include "GLReadTexImageHelper.h" 49 #include "HeapCopyOfStackArray.h" 50 #include "GLBlitHelper.h" 51 #include "mozilla/gfx/Swizzle.h" 52 #ifdef MOZ_WIDGET_GTK 53 # include "mozilla/widget/GtkCompositorWidget.h" 54 #endif 55 #if MOZ_WIDGET_ANDROID 56 # include "GLContextEGL.h" 57 # include "GLLibraryEGL.h" 58 # include "mozilla/java/GeckoSurfaceTextureWrappers.h" 59 # include "mozilla/layers/AndroidHardwareBuffer.h" 60 #endif 61 62 namespace mozilla { 63 64 using namespace gfx; 65 66 namespace layers { 67 68 using namespace mozilla::gl; 69 70 static const GLuint kCoordinateAttributeIndex = 0; 71 static const GLuint kTexCoordinateAttributeIndex = 1; 72 73 class DummyTextureSourceOGL : public TextureSource, public TextureSourceOGL { 74 public: 75 const char* Name() const override { return "DummyTextureSourceOGL"; } 76 77 TextureSourceOGL* AsSourceOGL() override { return this; } 78 79 void BindTexture(GLenum activetex, 80 gfx::SamplingFilter aSamplingFilter) override {} 81 82 bool IsValid() const override { return false; } 83 84 gfx::IntSize GetSize() const override { return gfx::IntSize(); } 85 86 gfx::SurfaceFormat GetFormat() const override { 87 return gfx::SurfaceFormat::B8G8R8A8; 88 } 89 90 GLenum GetWrapMode() const override { return LOCAL_GL_CLAMP_TO_EDGE; } 91 92 protected: 93 }; 94 95 class AsyncReadbackBufferOGL final : public AsyncReadbackBuffer { 96 public: 97 AsyncReadbackBufferOGL(GLContext* aGL, const IntSize& aSize); 98 99 bool MapAndCopyInto(DataSourceSurface* aSurface, 100 const IntSize& aReadSize) const override; 101 102 void Bind() const { 103 mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mBufferHandle); 104 mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1); 105 } 106 107 protected: 108 virtual ~AsyncReadbackBufferOGL(); 109 110 private: 111 GLContext* mGL; 112 GLuint mBufferHandle; 113 }; 114 115 AsyncReadbackBufferOGL::AsyncReadbackBufferOGL(GLContext* aGL, 116 const IntSize& aSize) 117 : AsyncReadbackBuffer(aSize), mGL(aGL), mBufferHandle(0) { 118 size_t bufferByteCount = mSize.width * mSize.height * 4; 119 mGL->fGenBuffers(1, &mBufferHandle); 120 121 ScopedPackState scopedPackState(mGL); 122 Bind(); 123 mGL->fBufferData(LOCAL_GL_PIXEL_PACK_BUFFER, bufferByteCount, nullptr, 124 LOCAL_GL_STREAM_READ); 125 } 126 127 AsyncReadbackBufferOGL::~AsyncReadbackBufferOGL() { 128 if (mGL && mGL->MakeCurrent()) { 129 mGL->fDeleteBuffers(1, &mBufferHandle); 130 } 131 } 132 133 bool AsyncReadbackBufferOGL::MapAndCopyInto(DataSourceSurface* aSurface, 134 const IntSize& aReadSize) const { 135 MOZ_RELEASE_ASSERT(aReadSize <= aSurface->GetSize()); 136 137 if (!mGL || !mGL->MakeCurrent()) { 138 return false; 139 } 140 141 ScopedPackState scopedPackState(mGL); 142 Bind(); 143 144 const uint8_t* srcData = nullptr; 145 if (mGL->IsSupported(GLFeature::map_buffer_range)) { 146 srcData = static_cast<uint8_t*>(mGL->fMapBufferRange( 147 LOCAL_GL_PIXEL_PACK_BUFFER, 0, aReadSize.height * aReadSize.width * 4, 148 LOCAL_GL_MAP_READ_BIT)); 149 } else { 150 srcData = static_cast<uint8_t*>( 151 mGL->fMapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, LOCAL_GL_READ_ONLY)); 152 } 153 154 if (!srcData) { 155 return false; 156 } 157 158 int32_t srcStride = mSize.width * 4; // Bind() sets an alignment of 1 159 DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::WRITE); 160 uint8_t* destData = map.GetData(); 161 int32_t destStride = map.GetStride(); 162 SurfaceFormat destFormat = aSurface->GetFormat(); 163 for (int32_t destRow = 0; destRow < aReadSize.height; destRow++) { 164 // Turn srcData upside down during the copy. 165 int32_t srcRow = aReadSize.height - 1 - destRow; 166 const uint8_t* src = &srcData[srcRow * srcStride]; 167 uint8_t* dest = &destData[destRow * destStride]; 168 SwizzleData(src, srcStride, SurfaceFormat::R8G8B8A8, dest, destStride, 169 destFormat, IntSize(aReadSize.width, 1)); 170 } 171 172 mGL->fUnmapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER); 173 174 return true; 175 } 176 177 PerUnitTexturePoolOGL::PerUnitTexturePoolOGL(gl::GLContext* aGL) 178 : mTextureTarget(0), // zero is never a valid texture target 179 mGL(aGL) {} 180 181 PerUnitTexturePoolOGL::~PerUnitTexturePoolOGL() { DestroyTextures(); } 182 183 CompositorOGL::CompositorOGL(widget::CompositorWidget* aWidget, 184 int aSurfaceWidth, int aSurfaceHeight, 185 bool aUseExternalSurfaceSize) 186 : Compositor(aWidget), 187 mWidgetSize(-1, -1), 188 mSurfaceSize(aSurfaceWidth, aSurfaceHeight), 189 mFBOTextureTarget(0), 190 mWindowRenderTarget(nullptr), 191 mQuadVBO(0), 192 mTriangleVBO(0), 193 mPreviousFrameDoneSync(nullptr), 194 mThisFrameDoneSync(nullptr), 195 mHasBGRA(0), 196 mUseExternalSurfaceSize(aUseExternalSurfaceSize), 197 mFrameInProgress(false), 198 mDestroyed(false), 199 mViewportSize(0, 0) { 200 // If we render into native layers, our GLContext won't have a usable default 201 // framebuffer. 202 mCanRenderToDefaultFramebuffer = !aWidget->GetNativeLayerRoot(); 203 MOZ_COUNT_CTOR(CompositorOGL); 204 } 205 206 CompositorOGL::~CompositorOGL() { MOZ_COUNT_DTOR(CompositorOGL); } 207 208 already_AddRefed<mozilla::gl::GLContext> CompositorOGL::CreateContext() { 209 RefPtr<GLContext> context; 210 211 // Used by mock widget to create an offscreen context 212 nsIWidget* widget = mWidget->RealWidget(); 213 void* widgetOpenGLContext = 214 widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr; 215 if (widgetOpenGLContext) { 216 GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext); 217 return already_AddRefed<GLContext>(alreadyRefed); 218 } 219 220 #ifdef XP_WIN 221 if (gfxEnv::MOZ_LAYERS_PREFER_EGL()) { 222 printf_stderr("Trying GL layers...\n"); 223 context = gl::GLContextProviderEGL::CreateForCompositorWidget( 224 mWidget, /* aHardwareWebRender */ false, /* aForceAccelerated */ false); 225 } 226 #endif 227 228 // Allow to create offscreen GL context for main Layer Manager 229 if (!context && gfxEnv::MOZ_LAYERS_PREFER_OFFSCREEN()) { 230 nsCString discardFailureId; 231 context = GLContextProvider::CreateHeadless( 232 {CreateContextFlags::REQUIRE_COMPAT_PROFILE}, &discardFailureId); 233 if (!context->CreateOffscreenDefaultFb(mSurfaceSize)) { 234 context = nullptr; 235 } 236 } 237 238 if (!context) { 239 context = gl::GLContextProvider::CreateForCompositorWidget( 240 mWidget, 241 /* aHardwareWebRender */ false, 242 gfxVars::RequiresAcceleratedGLContextForCompositorOGL()); 243 } 244 245 if (!context) { 246 NS_WARNING("Failed to create CompositorOGL context"); 247 } 248 249 return context.forget(); 250 } 251 252 void CompositorOGL::Destroy() { 253 Compositor::Destroy(); 254 255 if (mTexturePool) { 256 mTexturePool->Clear(); 257 mTexturePool = nullptr; 258 } 259 260 if (!mDestroyed) { 261 mDestroyed = true; 262 CleanupResources(); 263 } 264 } 265 266 void CompositorOGL::CleanupResources() { 267 if (!mGLContext) return; 268 269 if (mSurfacePoolHandle) { 270 mSurfacePoolHandle->Pool()->DestroyGLResourcesForContext(mGLContext); 271 mSurfacePoolHandle = nullptr; 272 } 273 274 RefPtr<GLContext> ctx = mGLContext->GetSharedContext(); 275 if (!ctx) { 276 ctx = mGLContext; 277 } 278 279 if (!ctx->MakeCurrent()) { 280 // Leak resources! 281 mQuadVBO = 0; 282 mTriangleVBO = 0; 283 mPreviousFrameDoneSync = nullptr; 284 mThisFrameDoneSync = nullptr; 285 mProgramsHolder = nullptr; 286 mGLContext = nullptr; 287 mNativeLayersReferenceRT = nullptr; 288 mFullWindowRenderTarget = nullptr; 289 return; 290 } 291 292 mProgramsHolder = nullptr; 293 mNativeLayersReferenceRT = nullptr; 294 mFullWindowRenderTarget = nullptr; 295 296 #ifdef MOZ_WIDGET_GTK 297 // TextureSources might hold RefPtr<gl::GLContext>. 298 // All of them needs to be released to destroy GLContext. 299 // GLContextGLX has to be destroyed before related gtk window is destroyed. 300 for (auto textureSource : mRegisteredTextureSources) { 301 textureSource->DeallocateDeviceData(); 302 } 303 mRegisteredTextureSources.clear(); 304 #endif 305 306 ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); 307 308 if (mQuadVBO) { 309 ctx->fDeleteBuffers(1, &mQuadVBO); 310 mQuadVBO = 0; 311 } 312 313 if (mTriangleVBO) { 314 ctx->fDeleteBuffers(1, &mTriangleVBO); 315 mTriangleVBO = 0; 316 } 317 318 mGLContext->MakeCurrent(); 319 320 if (mPreviousFrameDoneSync) { 321 mGLContext->fDeleteSync(mPreviousFrameDoneSync); 322 mPreviousFrameDoneSync = nullptr; 323 } 324 325 if (mThisFrameDoneSync) { 326 mGLContext->fDeleteSync(mThisFrameDoneSync); 327 mThisFrameDoneSync = nullptr; 328 } 329 330 if (mOwnsGLContext) { 331 // On the main thread the Widget will be destroyed soon and calling 332 // MakeCurrent after that could cause a crash (at least with GLX, see bug 333 // 1059793), unless context is marked as destroyed. There may be some 334 // textures still alive that will try to call MakeCurrent on the context so 335 // let's make sure it is marked destroyed now. 336 mGLContext->MarkDestroyed(); 337 } 338 339 mGLContext = nullptr; 340 } 341 342 bool CompositorOGL::Initialize(GLContext* aGLContext, 343 RefPtr<ShaderProgramOGLsHolder> aProgramsHolder, 344 nsCString* const out_failureReason) { 345 MOZ_ASSERT(!mDestroyed); 346 MOZ_ASSERT(!mGLContext); 347 348 mGLContext = aGLContext; 349 mProgramsHolder = aProgramsHolder; 350 mOwnsGLContext = false; 351 352 return Initialize(out_failureReason); 353 } 354 355 bool CompositorOGL::Initialize(nsCString* const out_failureReason) { 356 ScopedGfxFeatureReporter reporter("GL Layers"); 357 358 // Do not allow double initialization 359 MOZ_ASSERT(mGLContext == nullptr || !mOwnsGLContext, 360 "Don't reinitialize CompositorOGL"); 361 362 if (!mGLContext) { 363 MOZ_ASSERT(mOwnsGLContext); 364 mGLContext = CreateContext(); 365 } 366 367 #ifdef MOZ_WIDGET_ANDROID 368 if (!mGLContext) { 369 *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_ANDROID_CONTEXT"; 370 MOZ_CRASH("We need a context on Android"); 371 } 372 #endif 373 374 if (!mGLContext) { 375 *out_failureReason = "FEATURE_FAILURE_OPENGL_CREATE_CONTEXT"; 376 return false; 377 } 378 379 if (!mProgramsHolder) { 380 mProgramsHolder = new ShaderProgramOGLsHolder(mGLContext); 381 } 382 383 MakeCurrent(); 384 385 mHasBGRA = mGLContext->IsExtensionSupported( 386 gl::GLContext::EXT_texture_format_BGRA8888) || 387 mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra); 388 389 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 390 LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); 391 mGLContext->fEnable(LOCAL_GL_BLEND); 392 393 // initialise a common shader to check that we can actually compile a shader 394 RefPtr<DummyTextureSourceOGL> source = new DummyTextureSourceOGL; 395 RefPtr<EffectRGB> effect = 396 new EffectRGB(source, /* aPremultiplied */ true, SamplingFilter::GOOD); 397 ShaderConfigOGL config = GetShaderConfigFor(effect); 398 if (!GetShaderProgramFor(config)) { 399 *out_failureReason = "FEATURE_FAILURE_OPENGL_COMPILE_SHADER"; 400 return false; 401 } 402 403 if (mGLContext->WorkAroundDriverBugs()) { 404 /** 405 * We'll test the ability here to bind NPOT textures to a framebuffer, if 406 * this fails we'll try ARB_texture_rectangle. 407 */ 408 409 GLenum textureTargets[] = {LOCAL_GL_TEXTURE_2D, LOCAL_GL_NONE}; 410 411 if (!mGLContext->IsGLES()) { 412 // No TEXTURE_RECTANGLE_ARB available on ES2 413 textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB; 414 } 415 416 mFBOTextureTarget = LOCAL_GL_NONE; 417 418 GLuint testFBO = 0; 419 mGLContext->fGenFramebuffers(1, &testFBO); 420 GLuint testTexture = 0; 421 422 for (uint32_t i = 0; i < std::size(textureTargets); i++) { 423 GLenum target = textureTargets[i]; 424 if (!target) continue; 425 426 mGLContext->fGenTextures(1, &testTexture); 427 mGLContext->fBindTexture(target, testTexture); 428 mGLContext->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, 429 LOCAL_GL_NEAREST); 430 mGLContext->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, 431 LOCAL_GL_NEAREST); 432 mGLContext->fTexImage2D( 433 target, 0, LOCAL_GL_RGBA, 5, 3, /* sufficiently NPOT */ 434 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr); 435 436 // unbind this texture, in preparation for binding it to the FBO 437 mGLContext->fBindTexture(target, 0); 438 439 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO); 440 mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, 441 LOCAL_GL_COLOR_ATTACHMENT0, target, 442 testTexture, 0); 443 444 if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == 445 LOCAL_GL_FRAMEBUFFER_COMPLETE) { 446 mFBOTextureTarget = target; 447 mGLContext->fDeleteTextures(1, &testTexture); 448 break; 449 } 450 451 mGLContext->fDeleteTextures(1, &testTexture); 452 } 453 454 if (testFBO) { 455 mGLContext->fDeleteFramebuffers(1, &testFBO); 456 } 457 458 if (mFBOTextureTarget == LOCAL_GL_NONE) { 459 /* Unable to find a texture target that works with FBOs and NPOT textures 460 */ 461 *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET"; 462 return false; 463 } 464 } else { 465 // not trying to work around driver bugs, so TEXTURE_2D should just work 466 mFBOTextureTarget = LOCAL_GL_TEXTURE_2D; 467 } 468 469 // back to default framebuffer, to avoid confusion 470 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); 471 472 if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { 473 /* If we're using TEXTURE_RECTANGLE, then we must have the ARB 474 * extension -- the EXT variant does not provide support for 475 * texture rectangle access inside GLSL (sampler2DRect, 476 * texture2DRect). 477 */ 478 if (!mGLContext->IsExtensionSupported( 479 gl::GLContext::ARB_texture_rectangle)) { 480 *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT"; 481 return false; 482 } 483 } 484 485 // Create a VBO for triangle vertices. 486 mGLContext->fGenBuffers(1, &mTriangleVBO); 487 488 /* Create a simple quad VBO */ 489 mGLContext->fGenBuffers(1, &mQuadVBO); 490 491 // 4 quads, with the number of the quad (vertexID) encoded in w. 492 GLfloat vertices[] = { 493 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 494 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 495 496 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 497 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 498 499 0.0f, 0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 2.0f, 500 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 2.0f, 501 502 0.0f, 0.0f, 0.0f, 3.0f, 1.0f, 0.0f, 0.0f, 3.0f, 0.0f, 1.0f, 0.0f, 3.0f, 503 1.0f, 0.0f, 0.0f, 3.0f, 0.0f, 1.0f, 0.0f, 3.0f, 1.0f, 1.0f, 0.0f, 3.0f, 504 }; 505 HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices); 506 507 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); 508 mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, verticesOnHeap.ByteLength(), 509 verticesOnHeap.Data(), LOCAL_GL_STATIC_DRAW); 510 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 511 512 nsCOMPtr<nsIConsoleService> console( 513 do_GetService(NS_CONSOLESERVICE_CONTRACTID)); 514 515 if (console) { 516 nsString msg; 517 msg += nsLiteralString( 518 u"OpenGL compositor Initialized Succesfully.\nVersion: "); 519 msg += NS_ConvertUTF8toUTF16(nsDependentCString( 520 (const char*)mGLContext->fGetString(LOCAL_GL_VERSION))); 521 msg += u"\nVendor: "_ns; 522 msg += NS_ConvertUTF8toUTF16(nsDependentCString( 523 (const char*)mGLContext->fGetString(LOCAL_GL_VENDOR))); 524 msg += u"\nRenderer: "_ns; 525 msg += NS_ConvertUTF8toUTF16(nsDependentCString( 526 (const char*)mGLContext->fGetString(LOCAL_GL_RENDERER))); 527 msg += u"\nFBO Texture Target: "_ns; 528 if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D) 529 msg += u"TEXTURE_2D"_ns; 530 else 531 msg += u"TEXTURE_RECTANGLE"_ns; 532 console->LogStringMessage(msg.get()); 533 } 534 535 reporter.SetSuccessful(); 536 537 return true; 538 } 539 540 /* 541 * Returns a size that is equal to, or larger than and closest to, 542 * aSize where both width and height are powers of two. 543 * If the OpenGL setup is capable of using non-POT textures, 544 * then it will just return aSize. 545 */ 546 static IntSize CalculatePOTSize(const IntSize& aSize, GLContext* gl) { 547 if (CanUploadNonPowerOfTwo(gl)) return aSize; 548 549 return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height)); 550 } 551 552 gfx::Rect CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect, 553 TextureSource* aTexture) { 554 // If the OpenGL setup does not support non-power-of-two textures then the 555 // texture's width and height will have been increased to the next 556 // power-of-two (unless already a power of two). In that case we must scale 557 // the texture coordinates to account for that. 558 if (!CanUploadNonPowerOfTwo(mGLContext)) { 559 const IntSize& textureSize = aTexture->GetSize(); 560 const IntSize potSize = CalculatePOTSize(textureSize, mGLContext); 561 if (potSize != textureSize) { 562 const float xScale = (float)textureSize.width / (float)potSize.width; 563 const float yScale = (float)textureSize.height / (float)potSize.height; 564 textureRect.Scale(xScale, yScale); 565 } 566 } 567 568 return textureRect; 569 } 570 571 void CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget) { 572 MOZ_ASSERT(aRenderTarget); 573 // Logical surface size. 574 const gfx::IntSize& size = aRenderTarget->GetSize(); 575 // Physical surface size. 576 const gfx::IntSize& phySize = aRenderTarget->GetPhysicalSize(); 577 578 // Set the viewport correctly. 579 mGLContext->fViewport(mSurfaceOrigin.x, mSurfaceOrigin.y, phySize.width, 580 phySize.height); 581 582 mViewportSize = size; 583 584 if (!aRenderTarget->HasComplexProjection()) { 585 // We flip the view matrix around so that everything is right-side up; we're 586 // drawing directly into the window's back buffer, so this keeps things 587 // looking correct. 588 // XXX: We keep track of whether the window size changed, so we could skip 589 // this update if it hadn't changed since the last call. 590 591 // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0, 592 // 2, 2) and flip the contents. 593 Matrix viewMatrix; 594 viewMatrix.PreTranslate(-1.0, 1.0); 595 viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height)); 596 viewMatrix.PreScale(1.0f, -1.0f); 597 598 MOZ_ASSERT(mCurrentRenderTarget, "No destination"); 599 600 Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix); 601 matrix3d._33 = 0.0f; 602 mProjMatrix = matrix3d; 603 mGLContext->fDepthRange(0.0f, 1.0f); 604 } else { 605 bool depthEnable; 606 float zNear, zFar; 607 aRenderTarget->GetProjection(mProjMatrix, depthEnable, zNear, zFar); 608 mGLContext->fDepthRange(zNear, zFar); 609 } 610 } 611 612 already_AddRefed<CompositingRenderTarget> CompositorOGL::CreateRenderTarget( 613 const IntRect& aRect, SurfaceInitMode aInit) { 614 MOZ_ASSERT(!aRect.IsZeroArea(), 615 "Trying to create a render target of invalid size"); 616 617 if (aRect.IsZeroArea()) { 618 return nullptr; 619 } 620 621 if (!gl()) { 622 // CompositingRenderTargetOGL does not work without a gl context. 623 return nullptr; 624 } 625 626 GLuint tex = 0; 627 GLuint fbo = 0; 628 IntRect rect = aRect; 629 IntSize fboSize; 630 CreateFBOWithTexture(rect, false, 0, &fbo, &tex, &fboSize); 631 return CompositingRenderTargetOGL::CreateForNewFBOAndTakeOwnership( 632 this, tex, fbo, aRect, aRect.TopLeft(), aRect.Size(), mFBOTextureTarget, 633 aInit); 634 } 635 636 void CompositorOGL::SetRenderTarget(CompositingRenderTarget* aSurface) { 637 MOZ_ASSERT(aSurface); 638 CompositingRenderTargetOGL* surface = 639 static_cast<CompositingRenderTargetOGL*>(aSurface); 640 if (mCurrentRenderTarget != surface) { 641 mCurrentRenderTarget = surface; 642 surface->BindRenderTarget(); 643 } 644 645 PrepareViewport(mCurrentRenderTarget); 646 } 647 648 already_AddRefed<CompositingRenderTarget> 649 CompositorOGL::GetCurrentRenderTarget() const { 650 return do_AddRef(mCurrentRenderTarget); 651 } 652 653 already_AddRefed<CompositingRenderTarget> CompositorOGL::GetWindowRenderTarget() 654 const { 655 return do_AddRef(mWindowRenderTarget); 656 } 657 658 already_AddRefed<AsyncReadbackBuffer> CompositorOGL::CreateAsyncReadbackBuffer( 659 const IntSize& aSize) { 660 return MakeAndAddRef<AsyncReadbackBufferOGL>(mGLContext, aSize); 661 } 662 663 bool CompositorOGL::ReadbackRenderTarget(CompositingRenderTarget* aSource, 664 AsyncReadbackBuffer* aDest) { 665 IntSize size = aSource->GetSize(); 666 MOZ_RELEASE_ASSERT(aDest->GetSize() == size); 667 668 RefPtr<CompositingRenderTarget> previousTarget = GetCurrentRenderTarget(); 669 if (previousTarget != aSource) { 670 SetRenderTarget(aSource); 671 } 672 673 ScopedPackState scopedPackState(mGLContext); 674 static_cast<AsyncReadbackBufferOGL*>(aDest)->Bind(); 675 676 mGLContext->fReadPixels(0, 0, size.width, size.height, LOCAL_GL_RGBA, 677 LOCAL_GL_UNSIGNED_BYTE, 0); 678 679 if (previousTarget != aSource) { 680 SetRenderTarget(previousTarget); 681 } 682 return true; 683 } 684 685 bool CompositorOGL::BlitRenderTarget(CompositingRenderTarget* aSource, 686 const gfx::IntSize& aSourceSize, 687 const gfx::IntSize& aDestSize) { 688 if (!mGLContext->IsSupported(GLFeature::framebuffer_blit)) { 689 return false; 690 } 691 CompositingRenderTargetOGL* source = 692 static_cast<CompositingRenderTargetOGL*>(aSource); 693 GLuint srcFBO = source->GetFBO(); 694 GLuint destFBO = mCurrentRenderTarget->GetFBO(); 695 mGLContext->BlitHelper()->BlitFramebufferToFramebuffer( 696 srcFBO, destFBO, IntRect(IntPoint(), aSourceSize), 697 IntRect(IntPoint(), aDestSize), LOCAL_GL_LINEAR); 698 return true; 699 } 700 701 static GLenum GetFrameBufferInternalFormat( 702 GLContext* gl, GLuint aFrameBuffer, 703 mozilla::widget::CompositorWidget* aWidget) { 704 if (aFrameBuffer == 0) { // default framebuffer 705 return aWidget->GetGLFrameBufferFormat(); 706 } 707 return LOCAL_GL_RGBA; 708 } 709 710 Maybe<IntRect> CompositorOGL::BeginFrameForWindow( 711 const nsIntRegion& aInvalidRegion, const Maybe<IntRect>& aClipRect, 712 const IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion) { 713 MOZ_RELEASE_ASSERT(!mTarget, "mTarget not cleared properly"); 714 return BeginFrame(aInvalidRegion, aClipRect, aRenderBounds, aOpaqueRegion); 715 } 716 717 Maybe<IntRect> CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion, 718 const Maybe<IntRect>& aClipRect, 719 const IntRect& aRenderBounds, 720 const nsIntRegion& aOpaqueRegion) { 721 AUTO_PROFILER_LABEL("CompositorOGL::BeginFrame", GRAPHICS); 722 723 MOZ_ASSERT(!mFrameInProgress, 724 "frame still in progress (should have called EndFrame"); 725 726 IntRect rect; 727 if (mUseExternalSurfaceSize) { 728 rect = IntRect(IntPoint(), mSurfaceSize); 729 } else { 730 rect = aRenderBounds; 731 } 732 733 // We can't draw anything to something with no area 734 // so just return 735 if (rect.IsZeroArea()) { 736 return Nothing(); 737 } 738 739 // If the widget size changed, we have to force a MakeCurrent 740 // to make sure that GL sees the updated widget size. 741 if (mWidgetSize.ToUnknownSize() != rect.Size()) { 742 MakeCurrent(ForceMakeCurrent); 743 744 mWidgetSize = LayoutDeviceIntSize::FromUnknownSize(rect.Size()); 745 #ifdef MOZ_WAYLAND 746 if (mWidget && mWidget->AsGTK()) { 747 // Set correct window size to avoid rendering artifacts. 748 mWidget->AsGTK()->SetEGLNativeWindowSize(mWidgetSize); 749 } 750 #endif 751 } else { 752 MakeCurrent(); 753 } 754 755 #ifdef MOZ_WIDGET_ANDROID 756 java::GeckoSurfaceTexture::DestroyUnused((int64_t)mGLContext.get()); 757 mGLContext->MakeCurrent(); // DestroyUnused can change the current context! 758 #endif 759 760 // Default blend function implements "OVER" 761 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 762 LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); 763 mGLContext->fEnable(LOCAL_GL_BLEND); 764 765 RefPtr<CompositingRenderTarget> rt; 766 if (mCanRenderToDefaultFramebuffer) { 767 rt = CompositingRenderTargetOGL::CreateForWindow(this, rect.Size()); 768 } else if (mTarget) { 769 rt = CreateRenderTarget(rect, INIT_MODE_CLEAR); 770 } else { 771 MOZ_CRASH("Unexpected call"); 772 } 773 774 if (!rt) { 775 return Nothing(); 776 } 777 778 // We're about to actually draw a frame. 779 mFrameInProgress = true; 780 781 SetRenderTarget(rt); 782 mWindowRenderTarget = mCurrentRenderTarget; 783 784 for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) { 785 const IntRect& r = iter.Get(); 786 mCurrentFrameInvalidRegion.OrWith( 787 IntRect(r.X(), FlipY(r.YMost()), r.Width(), r.Height())); 788 } 789 // Check to see if there is any transparent dirty region that would require 790 // clearing. If not, just invalidate the framebuffer if supported. 791 // TODO: Currently we initialize the clear region to the widget bounds as 792 // SwapBuffers will update the entire framebuffer. On platforms that support 793 // damage regions, we could initialize this to mCurrentFrameInvalidRegion. 794 IntRegion regionToClear(rect); 795 regionToClear.SubOut(aOpaqueRegion); 796 GLbitfield clearBits = LOCAL_GL_DEPTH_BUFFER_BIT; 797 if (regionToClear.IsEmpty() && 798 mGLContext->IsSupported(GLFeature::invalidate_framebuffer)) { 799 GLenum attachments[] = {LOCAL_GL_COLOR}; 800 mGLContext->fInvalidateFramebuffer(LOCAL_GL_FRAMEBUFFER, 801 std::size(attachments), attachments); 802 } else { 803 clearBits |= LOCAL_GL_COLOR_BUFFER_BIT; 804 } 805 806 #if defined(MOZ_WIDGET_ANDROID) 807 if ((mSurfaceOrigin.x > 0) || (mSurfaceOrigin.y > 0)) { 808 mGLContext->fClearColor( 809 StaticPrefs::gfx_compositor_override_clear_color_r(), 810 StaticPrefs::gfx_compositor_override_clear_color_g(), 811 StaticPrefs::gfx_compositor_override_clear_color_b(), 812 StaticPrefs::gfx_compositor_override_clear_color_a()); 813 } else { 814 mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, 815 mClearColor.a); 816 } 817 #else 818 mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, 819 mClearColor.a); 820 #endif // defined(MOZ_WIDGET_ANDROID) 821 mGLContext->fClear(clearBits); 822 823 return Some(rect); 824 } 825 826 void CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect, 827 bool aCopyFromSource, 828 GLuint aSourceFrameBuffer, 829 GLuint* aFBO, GLuint* aTexture, 830 gfx::IntSize* aAllocSize) { 831 *aTexture = 832 CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer, aAllocSize); 833 mGLContext->fGenFramebuffers(1, aFBO); 834 } 835 836 GLuint CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource, 837 GLuint aSourceFrameBuffer, 838 IntSize* aAllocSize) { 839 // we're about to create a framebuffer backed by textures to use as an 840 // intermediate surface. What to do if its size (as given by aRect) would 841 // exceed the maximum texture size supported by the GL? The present code 842 // chooses the compromise of just clamping the framebuffer's size to the max 843 // supported size. This gives us a lower resolution rendering of the 844 // intermediate surface (children layers). See bug 827170 for a discussion. 845 IntRect clampedRect = aRect; 846 int32_t maxTexSize = GetMaxTextureSize(); 847 clampedRect.SetWidth(std::min(clampedRect.Width(), maxTexSize)); 848 clampedRect.SetHeight(std::min(clampedRect.Height(), maxTexSize)); 849 850 auto clampedRectWidth = clampedRect.Width(); 851 auto clampedRectHeight = clampedRect.Height(); 852 853 GLuint tex; 854 855 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); 856 mGLContext->fGenTextures(1, &tex); 857 mGLContext->fBindTexture(mFBOTextureTarget, tex); 858 859 if (aCopyFromSource) { 860 GLuint curFBO = mCurrentRenderTarget->GetFBO(); 861 if (curFBO != aSourceFrameBuffer) { 862 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer); 863 } 864 865 // We're going to create an RGBA temporary fbo. But to 866 // CopyTexImage() from the current framebuffer, the framebuffer's 867 // format has to be compatible with the new texture's. So we 868 // check the format of the framebuffer here and take a slow path 869 // if it's incompatible. 870 GLenum format = 871 GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget); 872 873 bool isFormatCompatibleWithRGBA = 874 gl()->IsGLES() ? (format == LOCAL_GL_RGBA) : true; 875 876 if (isFormatCompatibleWithRGBA) { 877 mGLContext->fCopyTexImage2D(mFBOTextureTarget, 0, LOCAL_GL_RGBA, 878 clampedRect.X(), FlipY(clampedRect.YMost()), 879 clampedRectWidth, clampedRectHeight, 0); 880 } else { 881 // Curses, incompatible formats. Take a slow path. 882 883 // RGBA 884 size_t bufferSize = clampedRectWidth * clampedRectHeight * 4; 885 auto buf = MakeUnique<uint8_t[]>(bufferSize); 886 887 mGLContext->fReadPixels(clampedRect.X(), clampedRect.Y(), 888 clampedRectWidth, clampedRectHeight, 889 LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf.get()); 890 mGLContext->fTexImage2D(mFBOTextureTarget, 0, LOCAL_GL_RGBA, 891 clampedRectWidth, clampedRectHeight, 0, 892 LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf.get()); 893 } 894 895 GLenum error = mGLContext->fGetError(); 896 if (error != LOCAL_GL_NO_ERROR) { 897 nsAutoCString msg; 898 msg.AppendPrintf( 899 "Texture initialization failed! -- error 0x%x, Source %d, Source " 900 "format %d, RGBA Compat %d", 901 error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA); 902 NS_ERROR(msg.get()); 903 } 904 } else { 905 mGLContext->fTexImage2D(mFBOTextureTarget, 0, LOCAL_GL_RGBA, 906 clampedRectWidth, clampedRectHeight, 0, 907 LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr); 908 } 909 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, 910 LOCAL_GL_LINEAR); 911 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, 912 LOCAL_GL_LINEAR); 913 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, 914 LOCAL_GL_CLAMP_TO_EDGE); 915 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, 916 LOCAL_GL_CLAMP_TO_EDGE); 917 mGLContext->fBindTexture(mFBOTextureTarget, 0); 918 919 if (aAllocSize) { 920 aAllocSize->width = clampedRectWidth; 921 aAllocSize->height = clampedRectHeight; 922 } 923 924 return tex; 925 } 926 927 ShaderConfigOGL CompositorOGL::GetShaderConfigFor(Effect* aEffect, 928 bool aDEAAEnabled, 929 bool aRoundedClip) const { 930 ShaderConfigOGL config; 931 932 switch (aEffect->mType) { 933 case EffectTypes::YCBCR: { 934 config.SetYCbCr(true); 935 EffectYCbCr* effectYCbCr = static_cast<EffectYCbCr*>(aEffect); 936 config.SetColorMultiplier( 937 RescalingFactorForColorDepth(effectYCbCr->mColorDepth)); 938 config.SetTextureTarget( 939 effectYCbCr->mTexture->AsSourceOGL()->GetTextureTarget()); 940 break; 941 } 942 case EffectTypes::NV12: 943 config.SetNV12(true); 944 if (gl()->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)) { 945 config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB); 946 } else { 947 config.SetTextureTarget(LOCAL_GL_TEXTURE_2D); 948 } 949 break; 950 default: { 951 MOZ_ASSERT(aEffect->mType == EffectTypes::RGB); 952 TexturedEffect* texturedEffect = static_cast<TexturedEffect*>(aEffect); 953 TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); 954 MOZ_ASSERT_IF( 955 source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL, 956 source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || 957 source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || 958 source->GetFormat() == gfx::SurfaceFormat::B8G8R8A8 || 959 source->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 || 960 source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16); 961 MOZ_ASSERT_IF( 962 source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB, 963 source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || 964 source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || 965 source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16 || 966 source->GetFormat() == gfx::SurfaceFormat::YUY2); 967 config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(), 968 source->GetFormat()); 969 if (!texturedEffect->mPremultiplied) { 970 config.SetNoPremultipliedAlpha(); 971 } 972 break; 973 } 974 } 975 config.SetDEAA(aDEAAEnabled); 976 config.SetRoundedClip(aRoundedClip); 977 return config; 978 } 979 980 ShaderProgramOGL* CompositorOGL::GetShaderProgramFor( 981 const ShaderConfigOGL& aConfig) { 982 ShaderProgramOGL* shader = mProgramsHolder->GetShaderProgramFor(aConfig); 983 return shader; 984 } 985 986 void CompositorOGL::ResetProgram() { mProgramsHolder->ResetCurrentProgram(); } 987 988 static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, 989 bool aIsPremultiplied = true) { 990 if (BlendOpIsMixBlendMode(aBlendMode)) { 991 // Mix-blend modes require an extra step (or more) that cannot be expressed 992 // in the fixed-function blending capabilities of opengl. We handle them 993 // separately in shaders, and the shaders assume we will use our default 994 // blend function for compositing (premultiplied OP_OVER). 995 return false; 996 } 997 if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) { 998 return false; 999 } 1000 1001 GLenum srcBlend; 1002 GLenum dstBlend; 1003 GLenum srcAlphaBlend = LOCAL_GL_ONE; 1004 GLenum dstAlphaBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA; 1005 1006 switch (aBlendMode) { 1007 case gfx::CompositionOp::OP_OVER: 1008 MOZ_ASSERT(!aIsPremultiplied); 1009 srcBlend = LOCAL_GL_SRC_ALPHA; 1010 dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA; 1011 break; 1012 case gfx::CompositionOp::OP_SOURCE: 1013 srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA; 1014 dstBlend = LOCAL_GL_ZERO; 1015 srcAlphaBlend = LOCAL_GL_ONE; 1016 dstAlphaBlend = LOCAL_GL_ZERO; 1017 break; 1018 default: 1019 MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!"); 1020 return false; 1021 } 1022 1023 aGL->fBlendFuncSeparate(srcBlend, dstBlend, srcAlphaBlend, dstAlphaBlend); 1024 return true; 1025 } 1026 1027 gfx::Point3D CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1, 1028 const gfx::Point& aPoint2) { 1029 // Return standard coefficients for a line between aPoint1 and aPoint2 1030 // for standard line equation: 1031 // 1032 // Ax + By + C = 0 1033 // 1034 // A = (p1.y – p2.y) 1035 // B = (p2.x – p1.x) 1036 // C = (p1.x * p2.y) – (p2.x * p1.y) 1037 1038 gfx::Point3D coeffecients; 1039 coeffecients.x = aPoint1.y - aPoint2.y; 1040 coeffecients.y = aPoint2.x - aPoint1.x; 1041 coeffecients.z = 1042 aPoint1.x.value * aPoint2.y.value - aPoint2.x.value * aPoint1.y.value; 1043 1044 coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x + 1045 coeffecients.y * coeffecients.y); 1046 1047 // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel 1048 // wide and included within the interior of the polygon 1049 coeffecients.z += 0.5f; 1050 1051 return coeffecients; 1052 } 1053 1054 void CompositorOGL::DrawQuad(const Rect& aRect, const IntRect& aClipRect, 1055 const EffectChain& aEffectChain, Float aOpacity, 1056 const gfx::Matrix4x4& aTransform, 1057 const gfx::Rect& aVisibleRect) { 1058 AUTO_PROFILER_LABEL("CompositorOGL::DrawQuad", GRAPHICS); 1059 1060 DrawGeometry(aRect, aRect, aClipRect, aEffectChain, aOpacity, aTransform, 1061 aVisibleRect); 1062 } 1063 1064 template <typename Geometry> 1065 void CompositorOGL::DrawGeometry(const Geometry& aGeometry, 1066 const gfx::Rect& aRect, 1067 const gfx::IntRect& aClipRect, 1068 const EffectChain& aEffectChain, 1069 gfx::Float aOpacity, 1070 const gfx::Matrix4x4& aTransform, 1071 const gfx::Rect& aVisibleRect) { 1072 MOZ_ASSERT(mFrameInProgress, "frame not started"); 1073 MOZ_ASSERT(mCurrentRenderTarget, "No destination"); 1074 1075 MakeCurrent(); 1076 1077 // Convert aClipRect into render target space, and intersect it with the 1078 // render target's clip. 1079 IntRect clipRect = aClipRect + mCurrentRenderTarget->GetClipSpaceOrigin(); 1080 if (Maybe<IntRect> rtClip = mCurrentRenderTarget->GetClipRect()) { 1081 clipRect = clipRect.Intersect(*rtClip); 1082 } 1083 1084 Rect destRect = aTransform.TransformAndClipBounds( 1085 aRect, Rect(mCurrentRenderTarget->GetRect().Intersect(clipRect))); 1086 if (destRect.IsEmpty()) { 1087 return; 1088 } 1089 1090 // Move clipRect into device space. 1091 IntPoint offset = mCurrentRenderTarget->GetOrigin(); 1092 clipRect -= offset; 1093 1094 if (!mTarget && mCurrentRenderTarget->IsWindow()) { 1095 clipRect.MoveBy(mSurfaceOrigin.x, -mSurfaceOrigin.y); 1096 } 1097 1098 ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); 1099 ScopedScissorRect autoScissorRect(mGLContext, clipRect.X(), 1100 FlipY(clipRect.Y() + clipRect.Height()), 1101 clipRect.Width(), clipRect.Height()); 1102 1103 // Only apply DEAA to quads that have been transformed such that aliasing 1104 // could be visible 1105 bool bEnableAA = StaticPrefs::layers_deaa_enabled() && 1106 !aTransform.Is2DIntegerTranslation(); 1107 1108 bool bRoundedClip = aEffectChain.mRoundedClipEffect; 1109 1110 ShaderConfigOGL config = 1111 GetShaderConfigFor(aEffectChain.mPrimaryEffect, bEnableAA, bRoundedClip); 1112 1113 config.SetOpacity(aOpacity != 1.f); 1114 ApplyPrimitiveConfig(config, aGeometry); 1115 1116 ShaderProgramOGL* program = mProgramsHolder->ActivateProgram(config); 1117 if (!program) { 1118 return; 1119 } 1120 program->SetProjectionMatrix(mProjMatrix); 1121 program->SetLayerTransform(aTransform); 1122 program->SetRenderOffset(offset.x, offset.y); 1123 1124 if (aOpacity != 1.f) program->SetLayerOpacity(aOpacity); 1125 1126 if (config.mFeatures & ENABLE_TEXTURE_RECT) { 1127 TextureSourceOGL* source = nullptr; 1128 TexturedEffect* texturedEffect = 1129 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); 1130 source = texturedEffect->mTexture->AsSourceOGL(); 1131 // This is used by IOSurface that use 0,0...w,h coordinate rather then 1132 // 0,0..1,1. 1133 program->SetTexCoordMultiplier(source->GetSize().width, 1134 source->GetSize().height); 1135 } 1136 1137 if (aEffectChain.mRoundedClipEffect) { 1138 program->SetRoundedClipRect(aEffectChain.mRoundedClipEffect->mRect); 1139 program->SetRoundedClipRadii(aEffectChain.mRoundedClipEffect->mRadii); 1140 } 1141 1142 // XXX kip - These calculations could be performed once per layer rather than 1143 // for every tile. This might belong in Compositor.cpp once DEAA 1144 // is implemented for DirectX. 1145 if (bEnableAA) { 1146 // Calculate the transformed vertices of aVisibleRect in screen space 1147 // pixels, mirroring the calculations in the vertex shader 1148 Matrix4x4 flatTransform = aTransform; 1149 flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f); 1150 flatTransform *= mProjMatrix; 1151 1152 Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f); 1153 size_t edgeCount = 0; 1154 Point3D coefficients[4]; 1155 1156 Point points[Matrix4x4::kTransformAndClipRectMaxVerts]; 1157 size_t pointCount = 1158 flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points); 1159 for (size_t i = 0; i < pointCount; i++) { 1160 points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width, 1161 (points[i].y * 0.5f + 0.5f) * mViewportSize.height); 1162 } 1163 if (pointCount > 2) { 1164 // Use shoelace formula on a triangle in the clipped quad to determine if 1165 // winding order is reversed. Iterate through the triangles until one is 1166 // found with a non-zero area. 1167 float winding = 0.0f; 1168 size_t wp = 0; 1169 while (winding == 0.0f && wp < pointCount) { 1170 int wp1 = (wp + 1) % pointCount; 1171 int wp2 = (wp + 2) % pointCount; 1172 winding = (points[wp1].x - points[wp].x).value * 1173 (points[wp1].y + points[wp].y).value + 1174 (points[wp2].x - points[wp1].x).value * 1175 (points[wp2].y + points[wp1].y).value + 1176 (points[wp].x - points[wp2].x).value * 1177 (points[wp].y + points[wp2].y).value; 1178 wp++; 1179 } 1180 bool frontFacing = winding >= 0.0f; 1181 1182 // Calculate the line coefficients used by the DEAA shader to determine 1183 // the sub-pixel coverage of the edge pixels 1184 for (size_t i = 0; i < pointCount; i++) { 1185 const Point& p1 = points[i]; 1186 const Point& p2 = points[(i + 1) % pointCount]; 1187 // Create a DEAA edge for any non-straight lines, to a maximum of 4 1188 if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) { 1189 if (frontFacing) { 1190 coefficients[edgeCount++] = GetLineCoefficients(p2, p1); 1191 } else { 1192 coefficients[edgeCount++] = GetLineCoefficients(p1, p2); 1193 } 1194 } 1195 } 1196 } 1197 1198 // The coefficients that are not needed must not cull any fragments. 1199 // We fill these unused coefficients with a clipping plane that has no 1200 // effect. 1201 for (size_t i = edgeCount; i < 4; i++) { 1202 coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height); 1203 } 1204 1205 // Set uniforms required by DEAA shader 1206 Matrix4x4 transformInverted = aTransform; 1207 transformInverted.Invert(); 1208 program->SetLayerTransformInverse(transformInverted); 1209 program->SetDEAAEdges(coefficients); 1210 program->SetVisibleCenter(aVisibleRect.Center()); 1211 program->SetViewportSize(mViewportSize); 1212 } 1213 1214 bool didSetBlendMode = false; 1215 1216 switch (aEffectChain.mPrimaryEffect->mType) { 1217 case EffectTypes::RGB: { 1218 TexturedEffect* texturedEffect = 1219 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); 1220 TextureSource* source = texturedEffect->mTexture; 1221 1222 didSetBlendMode = SetBlendMode(gl(), gfx::CompositionOp::OP_OVER, 1223 texturedEffect->mPremultiplied); 1224 1225 gfx::SamplingFilter samplingFilter = texturedEffect->mSamplingFilter; 1226 1227 source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, samplingFilter); 1228 1229 program->SetTextureUnit(0); 1230 1231 Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform(); 1232 program->SetTextureTransform(textureTransform); 1233 1234 BindAndDrawGeometryWithTextureRect( 1235 program, aGeometry, texturedEffect->mTextureCoords, source); 1236 source->AsSourceOGL()->MaybeFenceTexture(); 1237 } break; 1238 case EffectTypes::YCBCR: { 1239 EffectYCbCr* effectYCbCr = 1240 static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get()); 1241 TextureSource* sourceYCbCr = effectYCbCr->mTexture; 1242 const int Y = 0, Cb = 1, Cr = 2; 1243 TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL(); 1244 TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); 1245 TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); 1246 1247 if (!sourceY || !sourceCb || !sourceCr) { 1248 NS_WARNING("Invalid layer texture."); 1249 return; 1250 } 1251 1252 sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mSamplingFilter); 1253 sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mSamplingFilter); 1254 sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mSamplingFilter); 1255 1256 if (config.mFeatures & ENABLE_TEXTURE_RECT) { 1257 // This is used by IOSurface that use 0,0...w,h coordinate rather then 1258 // 0,0..1,1. 1259 program->SetCbCrTexCoordMultiplier(sourceCb->GetSize().width, 1260 sourceCb->GetSize().height); 1261 } 1262 1263 program->SetYCbCrTextureUnits(Y, Cb, Cr); 1264 program->SetTextureTransform(Matrix4x4()); 1265 program->SetYUVColorSpace(effectYCbCr->mYUVColorSpace); 1266 1267 BindAndDrawGeometryWithTextureRect(program, aGeometry, 1268 effectYCbCr->mTextureCoords, 1269 sourceYCbCr->GetSubSource(Y)); 1270 sourceY->MaybeFenceTexture(); 1271 sourceCb->MaybeFenceTexture(); 1272 sourceCr->MaybeFenceTexture(); 1273 } break; 1274 case EffectTypes::NV12: { 1275 EffectNV12* effectNV12 = 1276 static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get()); 1277 TextureSource* sourceNV12 = effectNV12->mTexture; 1278 const int Y = 0, CbCr = 1; 1279 TextureSourceOGL* sourceY = sourceNV12->GetSubSource(Y)->AsSourceOGL(); 1280 TextureSourceOGL* sourceCbCr = 1281 sourceNV12->GetSubSource(CbCr)->AsSourceOGL(); 1282 1283 if (!sourceY || !sourceCbCr) { 1284 NS_WARNING("Invalid layer texture."); 1285 return; 1286 } 1287 1288 sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectNV12->mSamplingFilter); 1289 sourceCbCr->BindTexture(LOCAL_GL_TEXTURE1, effectNV12->mSamplingFilter); 1290 1291 if (config.mFeatures & ENABLE_TEXTURE_RECT) { 1292 // This is used by IOSurface that use 0,0...w,h coordinate rather then 1293 // 0,0..1,1. 1294 program->SetCbCrTexCoordMultiplier(sourceCbCr->GetSize().width, 1295 sourceCbCr->GetSize().height); 1296 } 1297 1298 program->SetNV12TextureUnits(Y, CbCr); 1299 program->SetTextureTransform(Matrix4x4()); 1300 program->SetYUVColorSpace(effectNV12->mYUVColorSpace); 1301 1302 BindAndDrawGeometryWithTextureRect(program, aGeometry, 1303 effectNV12->mTextureCoords, 1304 sourceNV12->GetSubSource(Y)); 1305 sourceY->MaybeFenceTexture(); 1306 sourceCbCr->MaybeFenceTexture(); 1307 } break; 1308 default: 1309 MOZ_ASSERT(false, "Unhandled effect type"); 1310 break; 1311 } 1312 1313 if (didSetBlendMode) { 1314 gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1315 LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); 1316 } 1317 1318 // in case rendering has used some other GL context 1319 MakeCurrent(); 1320 } 1321 1322 void CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram, 1323 const gfx::Rect& aRect) { 1324 BindAndDrawQuad(aProgram, aRect); 1325 } 1326 1327 void CompositorOGL::BindAndDrawGeometry( 1328 ShaderProgramOGL* aProgram, 1329 const nsTArray<gfx::TexturedTriangle>& aTriangles) { 1330 NS_ASSERTION(aProgram->HasInitialized(), 1331 "Shader program not correctly initialized"); 1332 1333 const nsTArray<TexturedVertex> vertices = 1334 TexturedTrianglesToVertexArray(aTriangles); 1335 1336 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO); 1337 mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, 1338 vertices.Length() * sizeof(TexturedVertex), 1339 vertices.Elements(), LOCAL_GL_STREAM_DRAW); 1340 1341 const GLsizei stride = 4 * sizeof(GLfloat); 1342 InitializeVAO(kCoordinateAttributeIndex, 2, stride, 0); 1343 InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 2 * sizeof(GLfloat)); 1344 1345 mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, vertices.Length()); 1346 1347 mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex); 1348 mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex); 1349 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1350 } 1351 1352 // |aRect| is the rectangle we want to draw to. We will draw it with 1353 // up to 4 draw commands if necessary to avoid wrapping. 1354 // |aTexCoordRect| is the rectangle from the texture that we want to 1355 // draw using the given program. 1356 // |aTexture| is the texture we are drawing. Its actual size can be 1357 // larger than the rectangle given by |texCoordRect|. 1358 void CompositorOGL::BindAndDrawGeometryWithTextureRect( 1359 ShaderProgramOGL* aProg, const Rect& aRect, const Rect& aTexCoordRect, 1360 TextureSource* aTexture) { 1361 Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture); 1362 Rect layerRects[4]; 1363 Rect textureRects[4]; 1364 size_t rects = DecomposeIntoNoRepeatRects(aRect, scaledTexCoordRect, 1365 &layerRects, &textureRects); 1366 1367 BindAndDrawQuads(aProg, rects, layerRects, textureRects); 1368 } 1369 1370 void CompositorOGL::BindAndDrawGeometryWithTextureRect( 1371 ShaderProgramOGL* aProg, const nsTArray<gfx::TexturedTriangle>& aTriangles, 1372 const gfx::Rect& aTexCoordRect, TextureSource* aTexture) { 1373 BindAndDrawGeometry(aProg, aTriangles); 1374 } 1375 1376 void CompositorOGL::BindAndDrawQuads(ShaderProgramOGL* aProg, int aQuads, 1377 const Rect* aLayerRects, 1378 const Rect* aTextureRects) { 1379 NS_ASSERTION(aProg->HasInitialized(), 1380 "Shader program not correctly initialized"); 1381 1382 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); 1383 InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0); 1384 1385 aProg->SetLayerRects(aLayerRects); 1386 if (aProg->GetTextureCount() > 0) { 1387 aProg->SetTextureRects(aTextureRects); 1388 } 1389 1390 // We are using GL_TRIANGLES here because the Mac Intel drivers fail to 1391 // properly process uniform arrays with GL_TRIANGLE_STRIP. Go figure. 1392 mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads); 1393 mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex); 1394 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1395 } 1396 1397 void CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents, 1398 const GLsizei aStride, const size_t aOffset) { 1399 mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT, 1400 LOCAL_GL_FALSE, aStride, 1401 reinterpret_cast<GLvoid*>(aOffset)); 1402 mGLContext->fEnableVertexAttribArray(aAttrib); 1403 } 1404 1405 #ifdef MOZ_DUMP_PAINTING 1406 template <typename T> 1407 void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf) { 1408 if (gfxUtils::sDumpPaintFile != stderr) { 1409 gfxUtils::DumpAsDataURI(aSurf, gfxUtils::sDumpPaintFile); 1410 } else { 1411 nsCString uri = gfxUtils::GetAsDataURI(aSurf); 1412 nsPrintfCString string(R"(array["%s-%)" PRIu64 R"("]="%s";\n)", 1413 aObj->Name(), uint64_t(aObj), uri.BeginReading()); 1414 fprintf_stderr(gfxUtils::sDumpPaintFile, "%s", string.get()); 1415 } 1416 } 1417 1418 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget) { 1419 RefPtr<SourceSurface> surf = aTarget->Snapshot(); 1420 RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface(); 1421 WriteSnapshotToDumpFile_internal(aCompositor, dSurf); 1422 } 1423 #endif 1424 1425 void CompositorOGL::EndFrame() { 1426 AUTO_PROFILER_LABEL("CompositorOGL::EndFrame", GRAPHICS); 1427 1428 #ifdef MOZ_DUMP_PAINTING 1429 if (gfxEnv::MOZ_DISABLE_FORCE_PRESENT()) { 1430 LayoutDeviceIntSize size; 1431 if (mUseExternalSurfaceSize) { 1432 size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height); 1433 } else { 1434 size = mWidget->GetClientSize(); 1435 } 1436 RefPtr<DrawTarget> target = 1437 gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( 1438 IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8); 1439 if (target) { 1440 CopyToTarget(target, nsIntPoint(), Matrix()); 1441 WriteSnapshotToDumpFile(this, target); 1442 } 1443 } 1444 #endif 1445 1446 mFrameInProgress = false; 1447 mShouldInvalidateWindow = false; 1448 1449 if (mTarget) { 1450 CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix()); 1451 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1452 mTarget = nullptr; 1453 mWindowRenderTarget = nullptr; 1454 mCurrentRenderTarget = nullptr; 1455 Compositor::EndFrame(); 1456 return; 1457 } 1458 1459 mWindowRenderTarget = nullptr; 1460 mCurrentRenderTarget = nullptr; 1461 1462 if (mTexturePool) { 1463 mTexturePool->EndFrame(); 1464 } 1465 1466 InsertFrameDoneSync(); 1467 1468 mGLContext->SetDamage(mCurrentFrameInvalidRegion); 1469 mGLContext->SwapBuffers(); 1470 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1471 1472 // Unbind all textures 1473 for (GLuint i = 0; i <= 4; i++) { 1474 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i); 1475 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); 1476 if (!mGLContext->IsGLES()) { 1477 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); 1478 } 1479 } 1480 1481 mCurrentFrameInvalidRegion.SetEmpty(); 1482 1483 Compositor::EndFrame(); 1484 } 1485 1486 void CompositorOGL::InsertFrameDoneSync() { 1487 #ifdef XP_MACOSX 1488 // Only do this on macOS. 1489 // On other platforms, SwapBuffers automatically applies back-pressure. 1490 if (mThisFrameDoneSync) { 1491 mGLContext->fDeleteSync(mThisFrameDoneSync); 1492 } 1493 mThisFrameDoneSync = 1494 mGLContext->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0); 1495 #elif defined(MOZ_WIDGET_ANDROID) 1496 const auto& gle = gl::GLContextEGL::Cast(mGLContext); 1497 const auto& egl = gle->mEgl; 1498 1499 EGLSync sync = nullptr; 1500 if (AndroidHardwareBufferApi::Get()) { 1501 sync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); 1502 } 1503 if (sync) { 1504 int fenceFd = egl->fDupNativeFenceFDANDROID(sync); 1505 if (fenceFd >= 0) { 1506 mReleaseFenceFd = ipc::FileDescriptor(UniqueFileHandle(fenceFd)); 1507 } 1508 egl->fDestroySync(sync); 1509 sync = nullptr; 1510 } 1511 #endif 1512 } 1513 1514 ipc::FileDescriptor CompositorOGL::GetReleaseFence() { return mReleaseFenceFd; } 1515 1516 bool CompositorOGL::NeedToRecreateFullWindowRenderTarget() const { 1517 if (!ShouldRecordFrames()) { 1518 return false; 1519 } 1520 if (!mFullWindowRenderTarget) { 1521 return true; 1522 } 1523 IntSize windowSize = mWidget->GetClientSize().ToUnknownSize(); 1524 return mFullWindowRenderTarget->GetSize() != windowSize; 1525 } 1526 1527 void CompositorOGL::SetDestinationSurfaceSize(const IntSize& aSize) { 1528 mSurfaceSize.width = aSize.width; 1529 mSurfaceSize.height = aSize.height; 1530 } 1531 1532 void CompositorOGL::CopyToTarget(DrawTarget* aTarget, 1533 const nsIntPoint& aTopLeft, 1534 const gfx::Matrix& aTransform) { 1535 MOZ_ASSERT(aTarget); 1536 IntRect rect; 1537 if (mUseExternalSurfaceSize) { 1538 rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); 1539 } else { 1540 rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height); 1541 } 1542 GLint width = rect.Width(); 1543 GLint height = rect.Height(); 1544 1545 if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) { 1546 NS_ERROR("Widget size too big - integer overflow!"); 1547 return; 1548 } 1549 1550 RefPtr<DataSourceSurface> source = Factory::CreateDataSourceSurface( 1551 rect.Size(), gfx::SurfaceFormat::B8G8R8A8); 1552 if (NS_WARN_IF(!source)) { 1553 return; 1554 } 1555 1556 ReadPixelsIntoDataSurface(mGLContext, source); 1557 1558 // Map from GL space to Cairo space and reverse the world transform. 1559 Matrix glToCairoTransform = aTransform; 1560 glToCairoTransform.Invert(); 1561 glToCairoTransform.PreScale(1.0, -1.0); 1562 glToCairoTransform.PreTranslate(0.0, -height); 1563 1564 glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y); 1565 1566 Matrix oldMatrix = aTarget->GetTransform(); 1567 aTarget->SetTransform(glToCairoTransform); 1568 Rect floatRect = Rect(rect.X(), rect.Y(), width, height); 1569 aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), 1570 DrawOptions(1.0f, CompositionOp::OP_SOURCE)); 1571 aTarget->SetTransform(oldMatrix); 1572 aTarget->Flush(); 1573 } 1574 1575 void CompositorOGL::Pause() { 1576 #ifdef MOZ_WIDGET_ANDROID 1577 if (!gl() || gl()->IsDestroyed()) return; 1578 // ReleaseSurface internally calls MakeCurrent 1579 gl()->ReleaseSurface(); 1580 #elif defined(MOZ_WIDGET_GTK) 1581 // ReleaseSurface internally calls MakeCurrent 1582 gl()->ReleaseSurface(); 1583 #endif 1584 } 1585 1586 bool CompositorOGL::Resume() { 1587 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) || \ 1588 defined(MOZ_WIDGET_GTK) 1589 if (!gl() || gl()->IsDestroyed()) return false; 1590 1591 // RenewSurface internally calls MakeCurrent. 1592 return gl()->RenewSurface(GetWidget()); 1593 #else 1594 return true; 1595 #endif 1596 } 1597 1598 already_AddRefed<DataTextureSource> CompositorOGL::CreateDataTextureSource( 1599 TextureFlags aFlags) { 1600 if (!gl()) { 1601 return nullptr; 1602 } 1603 1604 return MakeAndAddRef<TextureImageTextureSourceOGL>(this, aFlags); 1605 } 1606 1607 int32_t CompositorOGL::GetMaxTextureSize() const { 1608 MOZ_ASSERT(mGLContext); 1609 GLint texSize = 0; 1610 mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &texSize); 1611 MOZ_ASSERT(texSize != 0); 1612 return texSize; 1613 } 1614 1615 void CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) { 1616 if (mDestroyed) { 1617 NS_WARNING("Call on destroyed layer manager"); 1618 return; 1619 } 1620 mGLContext->MakeCurrent(aFlags & ForceMakeCurrent); 1621 } 1622 1623 GLuint CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit) { 1624 if (!mTexturePool) { 1625 mTexturePool = new PerUnitTexturePoolOGL(gl()); 1626 } 1627 return mTexturePool->GetTexture(aTarget, aUnit); 1628 } 1629 1630 GLuint PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit) { 1631 if (mTextureTarget == 0) { 1632 mTextureTarget = aTarget; 1633 } 1634 MOZ_ASSERT(mTextureTarget == aTarget); 1635 1636 size_t index = aTextureUnit - LOCAL_GL_TEXTURE0; 1637 // lazily grow the array of temporary textures 1638 if (mTextures.Length() <= index) { 1639 size_t prevLength = mTextures.Length(); 1640 mTextures.SetLength(index + 1); 1641 for (unsigned int i = prevLength; i <= index; ++i) { 1642 mTextures[i] = 0; 1643 } 1644 } 1645 // lazily initialize the temporary textures 1646 if (!mTextures[index]) { 1647 if (!mGL->MakeCurrent()) { 1648 return 0; 1649 } 1650 mGL->fGenTextures(1, &mTextures[index]); 1651 mGL->fBindTexture(aTarget, mTextures[index]); 1652 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, 1653 LOCAL_GL_CLAMP_TO_EDGE); 1654 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, 1655 LOCAL_GL_CLAMP_TO_EDGE); 1656 } 1657 return mTextures[index]; 1658 } 1659 1660 void PerUnitTexturePoolOGL::DestroyTextures() { 1661 if (mGL && mGL->MakeCurrent()) { 1662 if (mTextures.Length() > 0) { 1663 mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]); 1664 } 1665 } 1666 mTextures.SetLength(0); 1667 } 1668 1669 void CompositorOGL::RegisterTextureSource(TextureSource* aTextureSource) { 1670 #ifdef MOZ_WIDGET_GTK 1671 if (mDestroyed) { 1672 return; 1673 } 1674 mRegisteredTextureSources.insert(aTextureSource); 1675 #endif 1676 } 1677 1678 void CompositorOGL::UnregisterTextureSource(TextureSource* aTextureSource) { 1679 #ifdef MOZ_WIDGET_GTK 1680 if (mDestroyed) { 1681 return; 1682 } 1683 mRegisteredTextureSources.erase(aTextureSource); 1684 #endif 1685 } 1686 1687 } // namespace layers 1688 } // namespace mozilla