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 "Layers.h"                 // for WriteSnapshotToDumpFile
15 #include "LayerScope.h"             // for LayerScope
16 #include "gfxCrashReporterUtils.h"  // for ScopedGfxFeatureReporter
17 #include "gfxEnv.h"                 // for gfxEnv
18 #include "gfxPlatform.h"            // for gfxPlatform
19 #include "gfxRect.h"                // for gfxRect
20 #include "gfxUtils.h"               // for gfxUtils, etc
21 #include "mozilla/ArrayUtils.h"     // for ArrayLength
22 #include "mozilla/Preferences.h"    // for Preferences
23 #include "mozilla/ProfilerLabels.h"
24 #include "mozilla/StaticPrefs_gfx.h"
25 #include "mozilla/StaticPrefs_layers.h"
26 #include "mozilla/StaticPrefs_nglayout.h"
27 #include "mozilla/gfx/BasePoint.h"  // for BasePoint
28 #include "mozilla/gfx/Matrix.h"     // for Matrix4x4, Matrix
29 #include "mozilla/gfx/Triangle.h"   // for Triangle
30 #include "mozilla/gfx/gfxVars.h"    // for gfxVars
31 #include "mozilla/layers/ImageDataSerializer.h"
32 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
33 #include "mozilla/layers/NativeLayer.h"
34 #include "mozilla/layers/CompositingRenderTargetOGL.h"
35 #include "mozilla/layers/Effects.h"      // for EffectChain, TexturedEffect, etc
36 #include "mozilla/layers/TextureHost.h"  // for TextureSource, etc
37 #include "mozilla/layers/TextureHostOGL.h"  // for TextureSourceOGL, etc
38 #include "mozilla/layers/PTextureParent.h"  // for OtherPid() on PTextureParent
39 #ifdef XP_DARWIN
40 #  include "mozilla/layers/TextureSync.h"  // for TextureSync::etc.
41 #endif
42 #include "mozilla/mozalloc.h"  // for operator delete, etc
43 #include "nsAppRunner.h"
44 #include "nsAString.h"
45 #include "nsClassHashtable.h"
46 #include "nsIConsoleService.h"      // for nsIConsoleService, etc
47 #include "nsIWidget.h"              // for nsIWidget
48 #include "nsLiteralString.h"        // for NS_LITERAL_STRING
49 #include "nsMathUtils.h"            // for NS_roundf
50 #include "nsRect.h"                 // for mozilla::gfx::IntRect
51 #include "nsServiceManagerUtils.h"  // for do_GetService
52 #include "nsString.h"               // for nsString, nsAutoCString, etc
53 #include "OGLShaderProgram.h"       // for ShaderProgramOGL, etc
54 #include "ScopedGLHelpers.h"
55 #include "GLReadTexImageHelper.h"
56 #include "GLBlitTextureImageHelper.h"
57 #include "HeapCopyOfStackArray.h"
58 #include "GLBlitHelper.h"
59 #include "mozilla/gfx/Swizzle.h"
60 #ifdef MOZ_WAYLAND
61 #  include "mozilla/widget/GtkCompositorWidget.h"
62 #endif
63 #if MOZ_WIDGET_ANDROID
64 #  include "GLContextEGL.h"
65 #  include "GLLibraryEGL.h"
66 #  include "mozilla/java/GeckoSurfaceTextureWrappers.h"
67 #  include "mozilla/layers/AndroidHardwareBuffer.h"
68 #endif
69 
70 namespace mozilla {
71 
72 using namespace gfx;
73 
74 namespace layers {
75 
76 using namespace mozilla::gl;
77 
78 static const GLuint kCoordinateAttributeIndex = 0;
79 static const GLuint kTexCoordinateAttributeIndex = 1;
80 
81 class AsyncReadbackBufferOGL final : public AsyncReadbackBuffer {
82  public:
83   AsyncReadbackBufferOGL(GLContext* aGL, const IntSize& aSize);
84 
85   bool MapAndCopyInto(DataSourceSurface* aSurface,
86                       const IntSize& aReadSize) const override;
87 
Bind() const88   void Bind() const {
89     mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mBufferHandle);
90     mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
91   }
92 
93  protected:
94   virtual ~AsyncReadbackBufferOGL();
95 
96  private:
97   GLContext* mGL;
98   GLuint mBufferHandle;
99 };
100 
AsyncReadbackBufferOGL(GLContext * aGL,const IntSize & aSize)101 AsyncReadbackBufferOGL::AsyncReadbackBufferOGL(GLContext* aGL,
102                                                const IntSize& aSize)
103     : AsyncReadbackBuffer(aSize), mGL(aGL), mBufferHandle(0) {
104   size_t bufferByteCount = mSize.width * mSize.height * 4;
105   mGL->fGenBuffers(1, &mBufferHandle);
106 
107   ScopedPackState scopedPackState(mGL);
108   Bind();
109   mGL->fBufferData(LOCAL_GL_PIXEL_PACK_BUFFER, bufferByteCount, nullptr,
110                    LOCAL_GL_STREAM_READ);
111 }
112 
~AsyncReadbackBufferOGL()113 AsyncReadbackBufferOGL::~AsyncReadbackBufferOGL() {
114   if (mGL && mGL->MakeCurrent()) {
115     mGL->fDeleteBuffers(1, &mBufferHandle);
116   }
117 }
118 
MapAndCopyInto(DataSourceSurface * aSurface,const IntSize & aReadSize) const119 bool AsyncReadbackBufferOGL::MapAndCopyInto(DataSourceSurface* aSurface,
120                                             const IntSize& aReadSize) const {
121   MOZ_RELEASE_ASSERT(aReadSize <= aSurface->GetSize());
122 
123   if (!mGL || !mGL->MakeCurrent()) {
124     return false;
125   }
126 
127   ScopedPackState scopedPackState(mGL);
128   Bind();
129 
130   const uint8_t* srcData = nullptr;
131   if (mGL->IsSupported(GLFeature::map_buffer_range)) {
132     srcData = static_cast<uint8_t*>(mGL->fMapBufferRange(
133         LOCAL_GL_PIXEL_PACK_BUFFER, 0, aReadSize.height * aReadSize.width * 4,
134         LOCAL_GL_MAP_READ_BIT));
135   } else {
136     srcData = static_cast<uint8_t*>(
137         mGL->fMapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, LOCAL_GL_READ_ONLY));
138   }
139 
140   if (!srcData) {
141     return false;
142   }
143 
144   int32_t srcStride = mSize.width * 4;  // Bind() sets an alignment of 1
145   DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::WRITE);
146   uint8_t* destData = map.GetData();
147   int32_t destStride = map.GetStride();
148   SurfaceFormat destFormat = aSurface->GetFormat();
149   for (int32_t destRow = 0; destRow < aReadSize.height; destRow++) {
150     // Turn srcData upside down during the copy.
151     int32_t srcRow = aReadSize.height - 1 - destRow;
152     const uint8_t* src = &srcData[srcRow * srcStride];
153     uint8_t* dest = &destData[destRow * destStride];
154     SwizzleData(src, srcStride, SurfaceFormat::R8G8B8A8, dest, destStride,
155                 destFormat, IntSize(aReadSize.width, 1));
156   }
157 
158   mGL->fUnmapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER);
159 
160   return true;
161 }
162 
PerUnitTexturePoolOGL(gl::GLContext * aGL)163 PerUnitTexturePoolOGL::PerUnitTexturePoolOGL(gl::GLContext* aGL)
164     : mTextureTarget(0),  // zero is never a valid texture target
165       mGL(aGL) {}
166 
~PerUnitTexturePoolOGL()167 PerUnitTexturePoolOGL::~PerUnitTexturePoolOGL() { DestroyTextures(); }
168 
BindMaskForProgram(ShaderProgramOGL * aProgram,TextureSourceOGL * aSourceMask,GLenum aTexUnit,const gfx::Matrix4x4 & aTransform)169 static void BindMaskForProgram(ShaderProgramOGL* aProgram,
170                                TextureSourceOGL* aSourceMask, GLenum aTexUnit,
171                                const gfx::Matrix4x4& aTransform) {
172   MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
173   aSourceMask->BindTexture(aTexUnit, gfx::SamplingFilter::LINEAR);
174   aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
175   aProgram->SetMaskLayerTransform(aTransform);
176 }
177 
BindBackdrop(ShaderProgramOGL * aProgram,GLuint aBackdrop,GLenum aTexUnit)178 void CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop,
179                                  GLenum aTexUnit) {
180   MOZ_ASSERT(aBackdrop);
181 
182   mGLContext->fActiveTexture(aTexUnit);
183   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aBackdrop);
184   mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
185                              LOCAL_GL_LINEAR);
186   mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
187                              LOCAL_GL_LINEAR);
188   aProgram->SetBackdropTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
189 }
190 
CompositorOGL(CompositorBridgeParent * aParent,widget::CompositorWidget * aWidget,int aSurfaceWidth,int aSurfaceHeight,bool aUseExternalSurfaceSize)191 CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent,
192                              widget::CompositorWidget* aWidget,
193                              int aSurfaceWidth, int aSurfaceHeight,
194                              bool aUseExternalSurfaceSize)
195     : Compositor(aWidget, aParent),
196       mWidgetSize(-1, -1),
197       mSurfaceSize(aSurfaceWidth, aSurfaceHeight),
198       mFBOTextureTarget(0),
199       mWindowRenderTarget(nullptr),
200       mQuadVBO(0),
201       mTriangleVBO(0),
202       mPreviousFrameDoneSync(nullptr),
203       mThisFrameDoneSync(nullptr),
204       mHasBGRA(0),
205       mUseExternalSurfaceSize(aUseExternalSurfaceSize),
206       mFrameInProgress(false),
207       mDestroyed(false),
208       mViewportSize(0, 0) {
209   if (aWidget->GetNativeLayerRoot()) {
210     // We can only render into native layers, our GLContext won't have a usable
211     // default framebuffer.
212     mCanRenderToDefaultFramebuffer = false;
213   }
214 #ifdef XP_DARWIN
215   TextureSync::RegisterTextureSourceProvider(this);
216 #endif
217   MOZ_COUNT_CTOR(CompositorOGL);
218 }
219 
~CompositorOGL()220 CompositorOGL::~CompositorOGL() {
221 #ifdef XP_DARWIN
222   TextureSync::UnregisterTextureSourceProvider(this);
223 #endif
224   MOZ_COUNT_DTOR(CompositorOGL);
225 }
226 
CreateContext()227 already_AddRefed<mozilla::gl::GLContext> CompositorOGL::CreateContext() {
228   RefPtr<GLContext> context;
229 
230   // Used by mock widget to create an offscreen context
231   nsIWidget* widget = mWidget->RealWidget();
232   void* widgetOpenGLContext =
233       widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr;
234   if (widgetOpenGLContext) {
235     GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
236     return already_AddRefed<GLContext>(alreadyRefed);
237   }
238 
239 #ifdef XP_WIN
240   if (gfxEnv::LayersPreferEGL()) {
241     printf_stderr("Trying GL layers...\n");
242     context = gl::GLContextProviderEGL::CreateForCompositorWidget(
243         mWidget, /* aHardwareWebRender */ false, /* aForceAccelerated */ false);
244   }
245 #endif
246 
247   // Allow to create offscreen GL context for main Layer Manager
248   if (!context && gfxEnv::LayersPreferOffscreen()) {
249     nsCString discardFailureId;
250     context = GLContextProvider::CreateHeadless(
251         {CreateContextFlags::REQUIRE_COMPAT_PROFILE}, &discardFailureId);
252     if (!context->CreateOffscreenDefaultFb(mSurfaceSize)) {
253       context = nullptr;
254     }
255   }
256 
257   if (!context) {
258     context = gl::GLContextProvider::CreateForCompositorWidget(
259         mWidget,
260         /* aHardwareWebRender */ false,
261         gfxVars::RequiresAcceleratedGLContextForCompositorOGL());
262   }
263 
264   if (!context) {
265     NS_WARNING("Failed to create CompositorOGL context");
266   }
267 
268   return context.forget();
269 }
270 
Destroy()271 void CompositorOGL::Destroy() {
272   Compositor::Destroy();
273 
274   if (mTexturePool) {
275     mTexturePool->Clear();
276     mTexturePool = nullptr;
277   }
278 
279 #ifdef XP_DARWIN
280   mMaybeUnlockBeforeNextComposition.Clear();
281 #endif
282 
283   if (!mDestroyed) {
284     mDestroyed = true;
285     CleanupResources();
286   }
287 }
288 
CleanupResources()289 void CompositorOGL::CleanupResources() {
290   if (!mGLContext) return;
291 
292   if (mSurfacePoolHandle) {
293     mSurfacePoolHandle->Pool()->DestroyGLResourcesForContext(mGLContext);
294     mSurfacePoolHandle = nullptr;
295   }
296 
297   RefPtr<GLContext> ctx = mGLContext->GetSharedContext();
298   if (!ctx) {
299     ctx = mGLContext;
300   }
301 
302   if (!ctx->MakeCurrent()) {
303     // Leak resources!
304     mQuadVBO = 0;
305     mTriangleVBO = 0;
306     mPreviousFrameDoneSync = nullptr;
307     mThisFrameDoneSync = nullptr;
308     mProgramsHolder = nullptr;
309     mGLContext = nullptr;
310     mNativeLayersReferenceRT = nullptr;
311     mFullWindowRenderTarget = nullptr;
312     return;
313   }
314 
315   mProgramsHolder = nullptr;
316   mNativeLayersReferenceRT = nullptr;
317   mFullWindowRenderTarget = nullptr;
318 
319 #ifdef MOZ_WIDGET_GTK
320   // TextureSources might hold RefPtr<gl::GLContext>.
321   // All of them needs to be released to destroy GLContext.
322   // GLContextGLX has to be destroyed before related gtk window is destroyed.
323   for (auto textureSource : mRegisteredTextureSources) {
324     textureSource->DeallocateDeviceData();
325   }
326   mRegisteredTextureSources.clear();
327 #endif
328 
329   ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
330 
331   if (mQuadVBO) {
332     ctx->fDeleteBuffers(1, &mQuadVBO);
333     mQuadVBO = 0;
334   }
335 
336   if (mTriangleVBO) {
337     ctx->fDeleteBuffers(1, &mTriangleVBO);
338     mTriangleVBO = 0;
339   }
340 
341   mGLContext->MakeCurrent();
342 
343   if (mPreviousFrameDoneSync) {
344     mGLContext->fDeleteSync(mPreviousFrameDoneSync);
345     mPreviousFrameDoneSync = nullptr;
346   }
347 
348   if (mThisFrameDoneSync) {
349     mGLContext->fDeleteSync(mThisFrameDoneSync);
350     mThisFrameDoneSync = nullptr;
351   }
352 
353   mBlitTextureImageHelper = nullptr;
354 
355   if (mOwnsGLContext) {
356     // On the main thread the Widget will be destroyed soon and calling
357     // MakeCurrent after that could cause a crash (at least with GLX, see bug
358     // 1059793), unless context is marked as destroyed. There may be some
359     // textures still alive that will try to call MakeCurrent on the context so
360     // let's make sure it is marked destroyed now.
361     mGLContext->MarkDestroyed();
362   }
363 
364   mGLContext = nullptr;
365 }
366 
Initialize(GLContext * aGLContext,RefPtr<ShaderProgramOGLsHolder> aProgramsHolder,nsCString * const out_failureReason)367 bool CompositorOGL::Initialize(GLContext* aGLContext,
368                                RefPtr<ShaderProgramOGLsHolder> aProgramsHolder,
369                                nsCString* const out_failureReason) {
370   MOZ_ASSERT(!mDestroyed);
371   MOZ_ASSERT(!mGLContext);
372 
373   mGLContext = aGLContext;
374   mProgramsHolder = aProgramsHolder;
375   mOwnsGLContext = false;
376 
377   return Initialize(out_failureReason);
378 }
379 
Initialize(nsCString * const out_failureReason)380 bool CompositorOGL::Initialize(nsCString* const out_failureReason) {
381   ScopedGfxFeatureReporter reporter("GL Layers");
382 
383   // Do not allow double initialization
384   MOZ_ASSERT(mGLContext == nullptr || !mOwnsGLContext,
385              "Don't reinitialize CompositorOGL");
386 
387   if (!mGLContext) {
388     MOZ_ASSERT(mOwnsGLContext);
389     mGLContext = CreateContext();
390   }
391 
392 #ifdef MOZ_WIDGET_ANDROID
393   if (!mGLContext) {
394     *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_ANDROID_CONTEXT";
395     MOZ_CRASH("We need a context on Android");
396   }
397 #endif
398 
399   if (!mGLContext) {
400     *out_failureReason = "FEATURE_FAILURE_OPENGL_CREATE_CONTEXT";
401     return false;
402   }
403 
404   if (!mProgramsHolder) {
405     mProgramsHolder = new ShaderProgramOGLsHolder(mGLContext);
406   }
407 
408   MakeCurrent();
409 
410   mHasBGRA = mGLContext->IsExtensionSupported(
411                  gl::GLContext::EXT_texture_format_BGRA8888) ||
412              mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
413 
414   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
415                                  LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
416   mGLContext->fEnable(LOCAL_GL_BLEND);
417 
418   // initialise a common shader to check that we can actually compile a shader
419   RefPtr<EffectSolidColor> effect =
420       new EffectSolidColor(DeviceColor(0, 0, 0, 0));
421   ShaderConfigOGL config = GetShaderConfigFor(effect);
422   if (!GetShaderProgramFor(config)) {
423     *out_failureReason = "FEATURE_FAILURE_OPENGL_COMPILE_SHADER";
424     return false;
425   }
426 
427   if (mGLContext->WorkAroundDriverBugs()) {
428     /**
429      * We'll test the ability here to bind NPOT textures to a framebuffer, if
430      * this fails we'll try ARB_texture_rectangle.
431      */
432 
433     GLenum textureTargets[] = {LOCAL_GL_TEXTURE_2D, LOCAL_GL_NONE};
434 
435     if (!mGLContext->IsGLES()) {
436       // No TEXTURE_RECTANGLE_ARB available on ES2
437       textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
438     }
439 
440     mFBOTextureTarget = LOCAL_GL_NONE;
441 
442     GLuint testFBO = 0;
443     mGLContext->fGenFramebuffers(1, &testFBO);
444     GLuint testTexture = 0;
445 
446     for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
447       GLenum target = textureTargets[i];
448       if (!target) continue;
449 
450       mGLContext->fGenTextures(1, &testTexture);
451       mGLContext->fBindTexture(target, testTexture);
452       mGLContext->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER,
453                                  LOCAL_GL_NEAREST);
454       mGLContext->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER,
455                                  LOCAL_GL_NEAREST);
456       mGLContext->fTexImage2D(
457           target, 0, LOCAL_GL_RGBA, 5, 3, /* sufficiently NPOT */
458           0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
459 
460       // unbind this texture, in preparation for binding it to the FBO
461       mGLContext->fBindTexture(target, 0);
462 
463       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
464       mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
465                                         LOCAL_GL_COLOR_ATTACHMENT0, target,
466                                         testTexture, 0);
467 
468       if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
469           LOCAL_GL_FRAMEBUFFER_COMPLETE) {
470         mFBOTextureTarget = target;
471         mGLContext->fDeleteTextures(1, &testTexture);
472         break;
473       }
474 
475       mGLContext->fDeleteTextures(1, &testTexture);
476     }
477 
478     if (testFBO) {
479       mGLContext->fDeleteFramebuffers(1, &testFBO);
480     }
481 
482     if (mFBOTextureTarget == LOCAL_GL_NONE) {
483       /* Unable to find a texture target that works with FBOs and NPOT textures
484        */
485       *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET";
486       return false;
487     }
488   } else {
489     // not trying to work around driver bugs, so TEXTURE_2D should just work
490     mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
491   }
492 
493   // back to default framebuffer, to avoid confusion
494   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
495 
496   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
497     /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
498      * extension -- the EXT variant does not provide support for
499      * texture rectangle access inside GLSL (sampler2DRect,
500      * texture2DRect).
501      */
502     if (!mGLContext->IsExtensionSupported(
503             gl::GLContext::ARB_texture_rectangle)) {
504       *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
505       return false;
506     }
507   }
508 
509   // Create a VBO for triangle vertices.
510   mGLContext->fGenBuffers(1, &mTriangleVBO);
511 
512   /* Create a simple quad VBO */
513   mGLContext->fGenBuffers(1, &mQuadVBO);
514 
515   // 4 quads, with the number of the quad (vertexID) encoded in w.
516   GLfloat vertices[] = {
517       0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
518       1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
519 
520       0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
521       1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
522 
523       0.0f, 0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 2.0f,
524       1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 2.0f,
525 
526       0.0f, 0.0f, 0.0f, 3.0f, 1.0f, 0.0f, 0.0f, 3.0f, 0.0f, 1.0f, 0.0f, 3.0f,
527       1.0f, 0.0f, 0.0f, 3.0f, 0.0f, 1.0f, 0.0f, 3.0f, 1.0f, 1.0f, 0.0f, 3.0f,
528   };
529   HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
530 
531   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
532   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, verticesOnHeap.ByteLength(),
533                           verticesOnHeap.Data(), LOCAL_GL_STATIC_DRAW);
534   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
535 
536   nsCOMPtr<nsIConsoleService> console(
537       do_GetService(NS_CONSOLESERVICE_CONTRACTID));
538 
539   if (console) {
540     nsString msg;
541     msg += nsLiteralString(
542         u"OpenGL compositor Initialized Succesfully.\nVersion: ");
543     msg += NS_ConvertUTF8toUTF16(nsDependentCString(
544         (const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
545     msg += u"\nVendor: "_ns;
546     msg += NS_ConvertUTF8toUTF16(nsDependentCString(
547         (const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
548     msg += u"\nRenderer: "_ns;
549     msg += NS_ConvertUTF8toUTF16(nsDependentCString(
550         (const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
551     msg += u"\nFBO Texture Target: "_ns;
552     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
553       msg += u"TEXTURE_2D"_ns;
554     else
555       msg += u"TEXTURE_RECTANGLE"_ns;
556     console->LogStringMessage(msg.get());
557   }
558 
559   reporter.SetSuccessful();
560 
561   return true;
562 }
563 
564 /*
565  * Returns a size that is equal to, or larger than and closest to,
566  * aSize where both width and height are powers of two.
567  * If the OpenGL setup is capable of using non-POT textures,
568  * then it will just return aSize.
569  */
CalculatePOTSize(const IntSize & aSize,GLContext * gl)570 static IntSize CalculatePOTSize(const IntSize& aSize, GLContext* gl) {
571   if (CanUploadNonPowerOfTwo(gl)) return aSize;
572 
573   return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height));
574 }
575 
GetTextureCoordinates(gfx::Rect textureRect,TextureSource * aTexture)576 gfx::Rect CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect,
577                                                TextureSource* aTexture) {
578   // If the OpenGL setup does not support non-power-of-two textures then the
579   // texture's width and height will have been increased to the next
580   // power-of-two (unless already a power of two). In that case we must scale
581   // the texture coordinates to account for that.
582   if (!CanUploadNonPowerOfTwo(mGLContext)) {
583     const IntSize& textureSize = aTexture->GetSize();
584     const IntSize potSize = CalculatePOTSize(textureSize, mGLContext);
585     if (potSize != textureSize) {
586       const float xScale = (float)textureSize.width / (float)potSize.width;
587       const float yScale = (float)textureSize.height / (float)potSize.height;
588       textureRect.Scale(xScale, yScale);
589     }
590   }
591 
592   return textureRect;
593 }
594 
PrepareViewport(CompositingRenderTargetOGL * aRenderTarget)595 void CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget) {
596   MOZ_ASSERT(aRenderTarget);
597   // Logical surface size.
598   const gfx::IntSize& size = aRenderTarget->GetSize();
599   // Physical surface size.
600   const gfx::IntSize& phySize = aRenderTarget->GetPhysicalSize();
601 
602   // Set the viewport correctly.
603   mGLContext->fViewport(mSurfaceOrigin.x, mSurfaceOrigin.y, phySize.width,
604                         phySize.height);
605 
606   mViewportSize = size;
607 
608   if (!aRenderTarget->HasComplexProjection()) {
609     // We flip the view matrix around so that everything is right-side up; we're
610     // drawing directly into the window's back buffer, so this keeps things
611     // looking correct.
612     // XXX: We keep track of whether the window size changed, so we could skip
613     // this update if it hadn't changed since the last call.
614 
615     // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
616     // 2, 2) and flip the contents.
617     Matrix viewMatrix;
618     viewMatrix.PreTranslate(-1.0, 1.0);
619     viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
620     viewMatrix.PreScale(1.0f, -1.0f);
621 
622     MOZ_ASSERT(mCurrentRenderTarget, "No destination");
623 
624     Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
625     matrix3d._33 = 0.0f;
626     mProjMatrix = matrix3d;
627     mGLContext->fDepthRange(0.0f, 1.0f);
628   } else {
629     bool depthEnable;
630     float zNear, zFar;
631     aRenderTarget->GetProjection(mProjMatrix, depthEnable, zNear, zFar);
632     mGLContext->fDepthRange(zNear, zFar);
633   }
634 }
635 
CreateRenderTarget(const IntRect & aRect,SurfaceInitMode aInit)636 already_AddRefed<CompositingRenderTarget> CompositorOGL::CreateRenderTarget(
637     const IntRect& aRect, SurfaceInitMode aInit) {
638   MOZ_ASSERT(!aRect.IsZeroArea(),
639              "Trying to create a render target of invalid size");
640 
641   if (aRect.IsZeroArea()) {
642     return nullptr;
643   }
644 
645   if (!gl()) {
646     // CompositingRenderTargetOGL does not work without a gl context.
647     return nullptr;
648   }
649 
650   GLuint tex = 0;
651   GLuint fbo = 0;
652   IntRect rect = aRect;
653   IntSize fboSize;
654   CreateFBOWithTexture(rect, false, 0, &fbo, &tex, &fboSize);
655   return CompositingRenderTargetOGL::CreateForNewFBOAndTakeOwnership(
656       this, tex, fbo, aRect, aRect.TopLeft(), aRect.Size(), mFBOTextureTarget,
657       aInit);
658 }
659 
660 already_AddRefed<CompositingRenderTarget>
CreateRenderTargetFromSource(const IntRect & aRect,const CompositingRenderTarget * aSource,const IntPoint & aSourcePoint)661 CompositorOGL::CreateRenderTargetFromSource(
662     const IntRect& aRect, const CompositingRenderTarget* aSource,
663     const IntPoint& aSourcePoint) {
664   MOZ_ASSERT(!aRect.IsZeroArea(),
665              "Trying to create a render target of invalid size");
666   MOZ_RELEASE_ASSERT(aSource, "Source needs to be non-null");
667 
668   if (aRect.IsZeroArea()) {
669     return nullptr;
670   }
671 
672   if (!gl()) {
673     return nullptr;
674   }
675 
676   GLuint tex = 0;
677   GLuint fbo = 0;
678   const CompositingRenderTargetOGL* sourceSurface =
679       static_cast<const CompositingRenderTargetOGL*>(aSource);
680   IntRect sourceRect(aSourcePoint, aRect.Size());
681   CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(), &fbo, &tex);
682 
683   return CompositingRenderTargetOGL::CreateForNewFBOAndTakeOwnership(
684       this, tex, fbo, aRect, aRect.TopLeft(), sourceRect.Size(),
685       mFBOTextureTarget, INIT_MODE_NONE);
686 }
687 
SetRenderTarget(CompositingRenderTarget * aSurface)688 void CompositorOGL::SetRenderTarget(CompositingRenderTarget* aSurface) {
689   MOZ_ASSERT(aSurface);
690   CompositingRenderTargetOGL* surface =
691       static_cast<CompositingRenderTargetOGL*>(aSurface);
692   if (mCurrentRenderTarget != surface) {
693     mCurrentRenderTarget = surface;
694     surface->BindRenderTarget();
695   }
696 
697   PrepareViewport(mCurrentRenderTarget);
698 }
699 
700 already_AddRefed<CompositingRenderTarget>
GetCurrentRenderTarget() const701 CompositorOGL::GetCurrentRenderTarget() const {
702   return do_AddRef(mCurrentRenderTarget);
703 }
704 
GetWindowRenderTarget() const705 already_AddRefed<CompositingRenderTarget> CompositorOGL::GetWindowRenderTarget()
706     const {
707   return do_AddRef(mWindowRenderTarget);
708 }
709 
CreateAsyncReadbackBuffer(const IntSize & aSize)710 already_AddRefed<AsyncReadbackBuffer> CompositorOGL::CreateAsyncReadbackBuffer(
711     const IntSize& aSize) {
712   return MakeAndAddRef<AsyncReadbackBufferOGL>(mGLContext, aSize);
713 }
714 
ReadbackRenderTarget(CompositingRenderTarget * aSource,AsyncReadbackBuffer * aDest)715 bool CompositorOGL::ReadbackRenderTarget(CompositingRenderTarget* aSource,
716                                          AsyncReadbackBuffer* aDest) {
717   IntSize size = aSource->GetSize();
718   MOZ_RELEASE_ASSERT(aDest->GetSize() == size);
719 
720   RefPtr<CompositingRenderTarget> previousTarget = GetCurrentRenderTarget();
721   if (previousTarget != aSource) {
722     SetRenderTarget(aSource);
723   }
724 
725   ScopedPackState scopedPackState(mGLContext);
726   static_cast<AsyncReadbackBufferOGL*>(aDest)->Bind();
727 
728   mGLContext->fReadPixels(0, 0, size.width, size.height, LOCAL_GL_RGBA,
729                           LOCAL_GL_UNSIGNED_BYTE, 0);
730 
731   if (previousTarget != aSource) {
732     SetRenderTarget(previousTarget);
733   }
734   return true;
735 }
736 
BlitRenderTarget(CompositingRenderTarget * aSource,const gfx::IntSize & aSourceSize,const gfx::IntSize & aDestSize)737 bool CompositorOGL::BlitRenderTarget(CompositingRenderTarget* aSource,
738                                      const gfx::IntSize& aSourceSize,
739                                      const gfx::IntSize& aDestSize) {
740   if (!mGLContext->IsSupported(GLFeature::framebuffer_blit)) {
741     return false;
742   }
743   CompositingRenderTargetOGL* source =
744       static_cast<CompositingRenderTargetOGL*>(aSource);
745   GLuint srcFBO = source->GetFBO();
746   GLuint destFBO = mCurrentRenderTarget->GetFBO();
747   mGLContext->BlitHelper()->BlitFramebufferToFramebuffer(
748       srcFBO, destFBO, IntRect(IntPoint(), aSourceSize),
749       IntRect(IntPoint(), aDestSize), LOCAL_GL_LINEAR);
750   return true;
751 }
752 
GetFrameBufferInternalFormat(GLContext * gl,GLuint aFrameBuffer,mozilla::widget::CompositorWidget * aWidget)753 static GLenum GetFrameBufferInternalFormat(
754     GLContext* gl, GLuint aFrameBuffer,
755     mozilla::widget::CompositorWidget* aWidget) {
756   if (aFrameBuffer == 0) {  // default framebuffer
757     return aWidget->GetGLFrameBufferFormat();
758   }
759   return LOCAL_GL_RGBA;
760 }
761 
ClearRect(const gfx::Rect & aRect)762 void CompositorOGL::ClearRect(const gfx::Rect& aRect) {
763   // Map aRect to OGL coordinates, origin:bottom-left
764   GLint y = mViewportSize.height - aRect.YMost();
765 
766   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
767   ScopedScissorRect autoScissorRect(mGLContext, aRect.X(), y, aRect.Width(),
768                                     aRect.Height());
769   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
770   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
771 }
772 
773 already_AddRefed<CompositingRenderTargetOGL>
RenderTargetForNativeLayer(NativeLayer * aNativeLayer,const IntRegion & aInvalidRegion)774 CompositorOGL::RenderTargetForNativeLayer(NativeLayer* aNativeLayer,
775                                           const IntRegion& aInvalidRegion) {
776   if (aInvalidRegion.IsEmpty()) {
777     return nullptr;
778   }
779 
780   aNativeLayer->SetSurfaceIsFlipped(true);
781 
782   IntRect layerRect = aNativeLayer->GetRect();
783   IntRegion invalidRelativeToLayer =
784       aInvalidRegion.MovedBy(-layerRect.TopLeft());
785   Maybe<GLuint> fbo = aNativeLayer->NextSurfaceAsFramebuffer(
786       gfx::IntRect({}, aNativeLayer->GetSize()), invalidRelativeToLayer, false);
787   if (!fbo) {
788     return nullptr;
789   }
790 
791   RefPtr<CompositingRenderTargetOGL> rt =
792       CompositingRenderTargetOGL::CreateForExternallyOwnedFBO(
793           this, *fbo, layerRect, IntPoint());
794 
795   // Clip the render target to the invalid rect. This conserves memory bandwidth
796   // and power.
797   IntRect invalidRect = aInvalidRegion.GetBounds();
798   rt->SetClipRect(invalidRect == layerRect ? Nothing() : Some(invalidRect));
799 
800   return rt.forget();
801 }
802 
BeginFrameForWindow(const nsIntRegion & aInvalidRegion,const Maybe<IntRect> & aClipRect,const IntRect & aRenderBounds,const nsIntRegion & aOpaqueRegion)803 Maybe<IntRect> CompositorOGL::BeginFrameForWindow(
804     const nsIntRegion& aInvalidRegion, const Maybe<IntRect>& aClipRect,
805     const IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion) {
806   MOZ_RELEASE_ASSERT(!mTarget, "mTarget not cleared properly");
807   return BeginFrame(aInvalidRegion, aClipRect, aRenderBounds, aOpaqueRegion);
808 }
809 
BeginFrameForTarget(const nsIntRegion & aInvalidRegion,const Maybe<IntRect> & aClipRect,const IntRect & aRenderBounds,const nsIntRegion & aOpaqueRegion,DrawTarget * aTarget,const IntRect & aTargetBounds)810 Maybe<IntRect> CompositorOGL::BeginFrameForTarget(
811     const nsIntRegion& aInvalidRegion, const Maybe<IntRect>& aClipRect,
812     const IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion,
813     DrawTarget* aTarget, const IntRect& aTargetBounds) {
814   MOZ_RELEASE_ASSERT(!mTarget, "mTarget not cleared properly");
815   mTarget = aTarget;  // Will be cleared in EndFrame().
816   mTargetBounds = aTargetBounds;
817   Maybe<IntRect> result =
818       BeginFrame(aInvalidRegion, aClipRect, aRenderBounds, aOpaqueRegion);
819   if (!result) {
820     // Composition has been aborted. Reset mTarget.
821     mTarget = nullptr;
822   }
823   return result;
824 }
825 
BeginFrameForNativeLayers()826 void CompositorOGL::BeginFrameForNativeLayers() {
827   MakeCurrent();
828   mPixelsPerFrame = 0;
829   mPixelsFilled = 0;
830 
831   // Default blend function implements "OVER"
832   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
833                                  LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
834   mGLContext->fEnable(LOCAL_GL_BLEND);
835 
836   mFrameInProgress = true;
837   mShouldInvalidateWindow = NeedToRecreateFullWindowRenderTarget();
838 
839   // Make a 1x1 dummy render target so that GetCurrentRenderTarget() returns
840   // something non-null even outside of calls to
841   // Begin/EndRenderingToNativeLayer.
842   if (!mNativeLayersReferenceRT) {
843     mNativeLayersReferenceRT =
844         CreateRenderTarget(IntRect(0, 0, 1, 1), INIT_MODE_CLEAR);
845   }
846   SetRenderTarget(mNativeLayersReferenceRT);
847   mWindowRenderTarget = mFullWindowRenderTarget;
848 }
849 
BeginRenderingToNativeLayer(const nsIntRegion & aInvalidRegion,const Maybe<gfx::IntRect> & aClipRect,const nsIntRegion & aOpaqueRegion,NativeLayer * aNativeLayer)850 Maybe<gfx::IntRect> CompositorOGL::BeginRenderingToNativeLayer(
851     const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
852     const nsIntRegion& aOpaqueRegion, NativeLayer* aNativeLayer) {
853   MOZ_RELEASE_ASSERT(aNativeLayer);
854   MOZ_RELEASE_ASSERT(mCurrentRenderTarget == mNativeLayersReferenceRT,
855                      "Please restore the current render target to the one that "
856                      "was in place after the call to BeginFrameForNativeLayers "
857                      "before calling BeginRenderingToNativeLayer.");
858 
859   IntRect rect = aNativeLayer->GetRect();
860   IntRegion layerInvalid;
861   if (mShouldInvalidateWindow) {
862     layerInvalid = rect;
863   } else {
864     layerInvalid.And(aInvalidRegion, rect);
865   }
866 
867   RefPtr<CompositingRenderTarget> rt =
868       RenderTargetForNativeLayer(aNativeLayer, layerInvalid);
869   if (!rt) {
870     return Nothing();
871   }
872   SetRenderTarget(rt);
873   mCurrentNativeLayer = aNativeLayer;
874 
875   mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b,
876                           mClearColor.a);
877   if (const Maybe<IntRect>& rtClip = mCurrentRenderTarget->GetClipRect()) {
878     // We need to apply a scissor rect during the clear. And since clears with
879     // scissor rects are usually treated differently by the GPU than regular
880     // clears, let's try to clear as little as possible in order to conserve
881     // memory bandwidth.
882     IntRegion clearRegion;
883     clearRegion.Sub(*rtClip, aOpaqueRegion);
884     if (!clearRegion.IsEmpty()) {
885       IntRect clearRect =
886           clearRegion.GetBounds() - mCurrentRenderTarget->GetOrigin();
887       ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST,
888                                            true);
889       ScopedScissorRect autoScissorRect(mGLContext, clearRect.x,
890                                         FlipY(clearRect.YMost()),
891                                         clearRect.Width(), clearRect.Height());
892       mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
893     }
894     mPixelsPerFrame += rtClip->Area();
895   } else {
896     mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
897     mPixelsPerFrame += rect.Area();
898   }
899 
900   return Some(rect);
901 }
902 
NormalDrawingDone()903 void CompositorOGL::NormalDrawingDone() {
904   // Now is a good time to update mFullWindowRenderTarget.
905   if (!mCurrentNativeLayer) {
906     return;
907   }
908 
909   if (!mGLContext->IsSupported(GLFeature::framebuffer_blit)) {
910     return;
911   }
912 
913   if (!ShouldRecordFrames()) {
914     // If we are no longer recording a profile, we can drop the render target if
915     // it exists.
916     mWindowRenderTarget = nullptr;
917     mFullWindowRenderTarget = nullptr;
918     return;
919   }
920 
921   if (NeedToRecreateFullWindowRenderTarget()) {
922     // We have either (1) just started recording and not yet allocated a
923     // buffer or (2) are already recording and have resized the window. In
924     // either case, we need a new render target.
925     IntRect windowRect(IntPoint(0, 0),
926                        mWidget->GetClientSize().ToUnknownSize());
927     RefPtr<CompositingRenderTarget> rt =
928         CreateRenderTarget(windowRect, INIT_MODE_NONE);
929     mFullWindowRenderTarget =
930         static_cast<CompositingRenderTargetOGL*>(rt.get());
931     mWindowRenderTarget = mFullWindowRenderTarget;
932 
933     // Initialize the render target by binding it.
934     RefPtr<CompositingRenderTarget> previousTarget = mCurrentRenderTarget;
935     SetRenderTarget(mFullWindowRenderTarget);
936     SetRenderTarget(previousTarget);
937   }
938 
939   // Copy the appropriate rectangle from the layer to mFullWindowRenderTarget.
940   RefPtr<CompositingRenderTargetOGL> layerRT = mCurrentRenderTarget;
941   IntRect copyRect = layerRT->GetClipRect().valueOr(layerRT->GetRect());
942   IntRect sourceRect = copyRect - layerRT->GetOrigin();
943   sourceRect.y = layerRT->GetSize().height - sourceRect.YMost();
944   IntRect destRect = copyRect;
945   destRect.y = mFullWindowRenderTarget->GetSize().height - destRect.YMost();
946   GLuint sourceFBO = layerRT->GetFBO();
947   GLuint destFBO = mFullWindowRenderTarget->GetFBO();
948   mGLContext->BlitHelper()->BlitFramebufferToFramebuffer(
949       sourceFBO, destFBO, sourceRect, destRect, LOCAL_GL_NEAREST);
950 }
951 
EndRenderingToNativeLayer()952 void CompositorOGL::EndRenderingToNativeLayer() {
953   MOZ_RELEASE_ASSERT(mCurrentNativeLayer,
954                      "EndRenderingToNativeLayer not paired with a call to "
955                      "BeginRenderingToNativeLayer?");
956 
957   if (StaticPrefs::nglayout_debug_widget_update_flashing()) {
958     float r = float(rand()) / float(RAND_MAX);
959     float g = float(rand()) / float(RAND_MAX);
960     float b = float(rand()) / float(RAND_MAX);
961     EffectChain effectChain;
962     effectChain.mPrimaryEffect =
963         new EffectSolidColor(DeviceColor(r, g, b, 0.2f));
964     // If we're clipping the render target to the invalid rect, then the
965     // current render target is still clipped, so just fill the bounds.
966     IntRect rect = mCurrentRenderTarget->GetRect();
967     DrawQuad(Rect(rect), rect - rect.TopLeft(), effectChain, 1.0, Matrix4x4(),
968              Rect(rect));
969   }
970 
971   mCurrentRenderTarget->SetClipRect(Nothing());
972   SetRenderTarget(mNativeLayersReferenceRT);
973 
974   mCurrentNativeLayer->NotifySurfaceReady();
975   mCurrentNativeLayer = nullptr;
976 }
977 
BeginFrame(const nsIntRegion & aInvalidRegion,const Maybe<IntRect> & aClipRect,const IntRect & aRenderBounds,const nsIntRegion & aOpaqueRegion)978 Maybe<IntRect> CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
979                                          const Maybe<IntRect>& aClipRect,
980                                          const IntRect& aRenderBounds,
981                                          const nsIntRegion& aOpaqueRegion) {
982   AUTO_PROFILER_LABEL("CompositorOGL::BeginFrame", GRAPHICS);
983 
984   MOZ_ASSERT(!mFrameInProgress,
985              "frame still in progress (should have called EndFrame");
986 
987   IntRect rect;
988   if (mUseExternalSurfaceSize) {
989     rect = IntRect(IntPoint(), mSurfaceSize);
990   } else {
991     rect = aRenderBounds;
992   }
993 
994   // We can't draw anything to something with no area
995   // so just return
996   if (rect.IsZeroArea()) {
997     return Nothing();
998   }
999 
1000   // If the widget size changed, we have to force a MakeCurrent
1001   // to make sure that GL sees the updated widget size.
1002   if (mWidgetSize.ToUnknownSize() != rect.Size()) {
1003     MakeCurrent(ForceMakeCurrent);
1004 
1005     mWidgetSize = LayoutDeviceIntSize::FromUnknownSize(rect.Size());
1006 #ifdef MOZ_WAYLAND
1007     if (mWidget && mWidget->AsGTK()) {
1008       mWidget->AsGTK()->SetEGLNativeWindowSize(mWidgetSize);
1009     }
1010 #endif
1011   } else {
1012     MakeCurrent();
1013   }
1014 
1015   mPixelsPerFrame = rect.Area();
1016   mPixelsFilled = 0;
1017 
1018 #ifdef MOZ_WIDGET_ANDROID
1019   java::GeckoSurfaceTexture::DestroyUnused((int64_t)mGLContext.get());
1020   mGLContext->MakeCurrent();  // DestroyUnused can change the current context!
1021 #endif
1022 
1023   // Default blend function implements "OVER"
1024   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1025                                  LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1026   mGLContext->fEnable(LOCAL_GL_BLEND);
1027 
1028   RefPtr<CompositingRenderTarget> rt;
1029   if (mCanRenderToDefaultFramebuffer) {
1030     rt = CompositingRenderTargetOGL::CreateForWindow(this, rect.Size());
1031   } else if (mTarget) {
1032     rt = CreateRenderTarget(rect, INIT_MODE_CLEAR);
1033   } else {
1034     MOZ_CRASH("Unexpected call");
1035   }
1036 
1037   if (!rt) {
1038     return Nothing();
1039   }
1040 
1041   // We're about to actually draw a frame.
1042   mFrameInProgress = true;
1043 
1044   SetRenderTarget(rt);
1045   mWindowRenderTarget = mCurrentRenderTarget;
1046 
1047   for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
1048     const IntRect& r = iter.Get();
1049     mCurrentFrameInvalidRegion.OrWith(
1050         IntRect(r.X(), FlipY(r.YMost()), r.Width(), r.Height()));
1051   }
1052   // Check to see if there is any transparent dirty region that would require
1053   // clearing. If not, just invalidate the framebuffer if supported.
1054   // TODO: Currently we initialize the clear region to the widget bounds as
1055   // SwapBuffers will update the entire framebuffer. On platforms that support
1056   // damage regions, we could initialize this to mCurrentFrameInvalidRegion.
1057   IntRegion regionToClear(rect);
1058   regionToClear.SubOut(aOpaqueRegion);
1059   GLbitfield clearBits = LOCAL_GL_DEPTH_BUFFER_BIT;
1060   if (regionToClear.IsEmpty() &&
1061       mGLContext->IsSupported(GLFeature::invalidate_framebuffer)) {
1062     GLenum attachments[] = {LOCAL_GL_COLOR};
1063     mGLContext->fInvalidateFramebuffer(
1064         LOCAL_GL_FRAMEBUFFER, MOZ_ARRAY_LENGTH(attachments), attachments);
1065   } else {
1066     clearBits |= LOCAL_GL_COLOR_BUFFER_BIT;
1067   }
1068 
1069 #if defined(MOZ_WIDGET_ANDROID)
1070   if ((mSurfaceOrigin.x > 0) || (mSurfaceOrigin.y > 0)) {
1071     mGLContext->fClearColor(
1072         StaticPrefs::gfx_compositor_override_clear_color_r(),
1073         StaticPrefs::gfx_compositor_override_clear_color_g(),
1074         StaticPrefs::gfx_compositor_override_clear_color_b(),
1075         StaticPrefs::gfx_compositor_override_clear_color_a());
1076   } else {
1077     mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b,
1078                             mClearColor.a);
1079   }
1080 #else
1081   mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b,
1082                           mClearColor.a);
1083 #endif  // defined(MOZ_WIDGET_ANDROID)
1084   mGLContext->fClear(clearBits);
1085 
1086   return Some(rect);
1087 }
1088 
CreateFBOWithTexture(const gfx::IntRect & aRect,bool aCopyFromSource,GLuint aSourceFrameBuffer,GLuint * aFBO,GLuint * aTexture,gfx::IntSize * aAllocSize)1089 void CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect,
1090                                          bool aCopyFromSource,
1091                                          GLuint aSourceFrameBuffer,
1092                                          GLuint* aFBO, GLuint* aTexture,
1093                                          gfx::IntSize* aAllocSize) {
1094   *aTexture =
1095       CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer, aAllocSize);
1096   mGLContext->fGenFramebuffers(1, aFBO);
1097 }
1098 
1099 // Should be called after calls to fReadPixels or fCopyTexImage2D, and other
1100 // GL read calls.
WorkAroundAppleIntelHD3000GraphicsGLDriverBug(GLContext * aGL)1101 static void WorkAroundAppleIntelHD3000GraphicsGLDriverBug(GLContext* aGL) {
1102 #ifdef XP_MACOSX
1103   if (aGL->WorkAroundDriverBugs() &&
1104       aGL->Renderer() == GLRenderer::IntelHD3000) {
1105     // Work around a bug in the Apple Intel HD Graphics 3000 driver (bug
1106     // 1586627, filed with Apple as FB7379358). This bug has been found present
1107     // on 10.9.3 and on 10.13.6, so it likely affects all shipped versions of
1108     // this driver. (macOS 10.14 does not support this GPU.)
1109     // The bug manifests as follows: Reading from a framebuffer puts that
1110     // framebuffer into a state such that deleting that framebuffer can break
1111     // other framebuffers in certain cases. More specifically, if you have two
1112     // framebuffers A and B, the following sequence of events breaks subsequent
1113     // drawing to B:
1114     //  1. A becomes "most recently read-from framebuffer".
1115     //  2. B is drawn to.
1116     //  3. A is deleted, and other GL state (such as GL_SCISSOR enabled state)
1117     //     is touched.
1118     //  4. B is drawn to again.
1119     // Now all draws to framebuffer B, including the draw from step 4, will
1120     // render at the wrong position and upside down.
1121     //
1122     // When AfterGLReadCall() is called, the currently bound framebuffer is the
1123     // framebuffer that has been read from most recently. So in the presence of
1124     // this bug, deleting this framebuffer has now become dangerous. We work
1125     // around the bug by creating a new short-lived framebuffer, making that new
1126     // framebuffer the most recently read-from framebuffer (using
1127     // glCopyTexImage2D), and then deleting it under controlled circumstances.
1128     // This deletion is not affected by the bug because our deletion call is not
1129     // interleaved with draw calls to another framebuffer and a touching of the
1130     // GL scissor enabled state.
1131 
1132     ScopedTexture texForReading(aGL);
1133     {
1134       // Initialize a 1x1 texture.
1135       ScopedBindTexture autoBindTexForReading(aGL, texForReading);
1136       aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1, 0,
1137                        LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
1138       aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
1139                           LOCAL_GL_LINEAR);
1140       aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
1141                           LOCAL_GL_LINEAR);
1142     }
1143     // Make a framebuffer around the texture.
1144     ScopedFramebufferForTexture autoFBForReading(aGL, texForReading);
1145     if (autoFBForReading.IsComplete()) {
1146       // "Read" from the framebuffer, by initializing a new texture using
1147       // glCopyTexImage2D. This flips the bad bit on autoFBForReading.FB().
1148       ScopedBindFramebuffer autoFB(aGL, autoFBForReading.FB());
1149       ScopedTexture texReadingDest(aGL);
1150       ScopedBindTexture autoBindTexReadingDest(aGL, texReadingDest);
1151       aGL->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 0, 0, 1, 1,
1152                            0);
1153     }
1154     // When autoFBForReading goes out of scope, the "poisoned" framebuffer is
1155     // deleted, and the bad state seems to go away along with it.
1156   }
1157 #endif
1158 }
1159 
CreateTexture(const IntRect & aRect,bool aCopyFromSource,GLuint aSourceFrameBuffer,IntSize * aAllocSize)1160 GLuint CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource,
1161                                     GLuint aSourceFrameBuffer,
1162                                     IntSize* aAllocSize) {
1163   // we're about to create a framebuffer backed by textures to use as an
1164   // intermediate surface. What to do if its size (as given by aRect) would
1165   // exceed the maximum texture size supported by the GL? The present code
1166   // chooses the compromise of just clamping the framebuffer's size to the max
1167   // supported size. This gives us a lower resolution rendering of the
1168   // intermediate surface (children layers). See bug 827170 for a discussion.
1169   IntRect clampedRect = aRect;
1170   int32_t maxTexSize = GetMaxTextureSize();
1171   clampedRect.SetWidth(std::min(clampedRect.Width(), maxTexSize));
1172   clampedRect.SetHeight(std::min(clampedRect.Height(), maxTexSize));
1173 
1174   auto clampedRectWidth = clampedRect.Width();
1175   auto clampedRectHeight = clampedRect.Height();
1176 
1177   GLuint tex;
1178 
1179   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
1180   mGLContext->fGenTextures(1, &tex);
1181   mGLContext->fBindTexture(mFBOTextureTarget, tex);
1182 
1183   if (aCopyFromSource) {
1184     GLuint curFBO = mCurrentRenderTarget->GetFBO();
1185     if (curFBO != aSourceFrameBuffer) {
1186       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
1187     }
1188 
1189     // We're going to create an RGBA temporary fbo.  But to
1190     // CopyTexImage() from the current framebuffer, the framebuffer's
1191     // format has to be compatible with the new texture's.  So we
1192     // check the format of the framebuffer here and take a slow path
1193     // if it's incompatible.
1194     GLenum format =
1195         GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
1196 
1197     bool isFormatCompatibleWithRGBA =
1198         gl()->IsGLES() ? (format == LOCAL_GL_RGBA) : true;
1199 
1200     if (isFormatCompatibleWithRGBA) {
1201       mGLContext->fCopyTexImage2D(mFBOTextureTarget, 0, LOCAL_GL_RGBA,
1202                                   clampedRect.X(), FlipY(clampedRect.YMost()),
1203                                   clampedRectWidth, clampedRectHeight, 0);
1204       WorkAroundAppleIntelHD3000GraphicsGLDriverBug(mGLContext);
1205     } else {
1206       // Curses, incompatible formats.  Take a slow path.
1207 
1208       // RGBA
1209       size_t bufferSize = clampedRectWidth * clampedRectHeight * 4;
1210       auto buf = MakeUnique<uint8_t[]>(bufferSize);
1211 
1212       mGLContext->fReadPixels(clampedRect.X(), clampedRect.Y(),
1213                               clampedRectWidth, clampedRectHeight,
1214                               LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf.get());
1215       WorkAroundAppleIntelHD3000GraphicsGLDriverBug(mGLContext);
1216       mGLContext->fTexImage2D(mFBOTextureTarget, 0, LOCAL_GL_RGBA,
1217                               clampedRectWidth, clampedRectHeight, 0,
1218                               LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf.get());
1219     }
1220 
1221     GLenum error = mGLContext->fGetError();
1222     if (error != LOCAL_GL_NO_ERROR) {
1223       nsAutoCString msg;
1224       msg.AppendPrintf(
1225           "Texture initialization failed! -- error 0x%x, Source %d, Source "
1226           "format %d,  RGBA Compat %d",
1227           error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
1228       NS_ERROR(msg.get());
1229     }
1230   } else {
1231     mGLContext->fTexImage2D(mFBOTextureTarget, 0, LOCAL_GL_RGBA,
1232                             clampedRectWidth, clampedRectHeight, 0,
1233                             LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
1234   }
1235   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
1236                              LOCAL_GL_LINEAR);
1237   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
1238                              LOCAL_GL_LINEAR);
1239   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
1240                              LOCAL_GL_CLAMP_TO_EDGE);
1241   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
1242                              LOCAL_GL_CLAMP_TO_EDGE);
1243   mGLContext->fBindTexture(mFBOTextureTarget, 0);
1244 
1245   if (aAllocSize) {
1246     aAllocSize->width = clampedRectWidth;
1247     aAllocSize->height = clampedRectHeight;
1248   }
1249 
1250   return tex;
1251 }
1252 
GetShaderConfigFor(Effect * aEffect,TextureSourceOGL * aSourceMask,gfx::CompositionOp aOp,bool aColorMatrix,bool aDEAAEnabled) const1253 ShaderConfigOGL CompositorOGL::GetShaderConfigFor(Effect* aEffect,
1254                                                   TextureSourceOGL* aSourceMask,
1255                                                   gfx::CompositionOp aOp,
1256                                                   bool aColorMatrix,
1257                                                   bool aDEAAEnabled) const {
1258   ShaderConfigOGL config;
1259 
1260   switch (aEffect->mType) {
1261     case EffectTypes::SOLID_COLOR:
1262       config.SetRenderColor(true);
1263       break;
1264     case EffectTypes::YCBCR: {
1265       config.SetYCbCr(true);
1266       EffectYCbCr* effectYCbCr = static_cast<EffectYCbCr*>(aEffect);
1267       config.SetColorMultiplier(
1268           RescalingFactorForColorDepth(effectYCbCr->mColorDepth));
1269       config.SetTextureTarget(
1270           effectYCbCr->mTexture->AsSourceOGL()->GetTextureTarget());
1271       break;
1272     }
1273     case EffectTypes::NV12:
1274       config.SetNV12(true);
1275       if (gl()->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)) {
1276         config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
1277       } else {
1278         config.SetTextureTarget(LOCAL_GL_TEXTURE_2D);
1279       }
1280       break;
1281     case EffectTypes::COMPONENT_ALPHA: {
1282       config.SetComponentAlpha(true);
1283       EffectComponentAlpha* effectComponentAlpha =
1284           static_cast<EffectComponentAlpha*>(aEffect);
1285       gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
1286       config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
1287                        format == gfx::SurfaceFormat::B8G8R8X8);
1288       TextureSourceOGL* source = effectComponentAlpha->mOnWhite->AsSourceOGL();
1289       config.SetTextureTarget(source->GetTextureTarget());
1290       break;
1291     }
1292     case EffectTypes::RENDER_TARGET:
1293       config.SetTextureTarget(mFBOTextureTarget);
1294       break;
1295     default: {
1296       MOZ_ASSERT(aEffect->mType == EffectTypes::RGB);
1297       TexturedEffect* texturedEffect = static_cast<TexturedEffect*>(aEffect);
1298       TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
1299       MOZ_ASSERT_IF(
1300           source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
1301           source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
1302               source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
1303               source->GetFormat() == gfx::SurfaceFormat::B8G8R8A8 ||
1304               source->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 ||
1305               source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16);
1306       MOZ_ASSERT_IF(
1307           source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
1308           source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
1309               source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
1310               source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16 ||
1311               source->GetFormat() == gfx::SurfaceFormat::YUV422);
1312       config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
1313                                                source->GetFormat());
1314       if (!texturedEffect->mPremultiplied) {
1315         config.SetNoPremultipliedAlpha();
1316       }
1317       break;
1318     }
1319   }
1320   config.SetColorMatrix(aColorMatrix);
1321   config.SetMask(!!aSourceMask);
1322   if (aSourceMask) {
1323     config.SetMaskTextureTarget(aSourceMask->GetTextureTarget());
1324   }
1325   config.SetDEAA(aDEAAEnabled);
1326   config.SetCompositionOp(aOp);
1327   return config;
1328 }
1329 
GetShaderProgramFor(const ShaderConfigOGL & aConfig)1330 ShaderProgramOGL* CompositorOGL::GetShaderProgramFor(
1331     const ShaderConfigOGL& aConfig) {
1332   ShaderProgramOGL* shader = mProgramsHolder->GetShaderProgramFor(aConfig);
1333   return shader;
1334 }
1335 
ResetProgram()1336 void CompositorOGL::ResetProgram() { mProgramsHolder->ResetCurrentProgram(); }
1337 
SetBlendMode(GLContext * aGL,gfx::CompositionOp aBlendMode,bool aIsPremultiplied=true)1338 static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode,
1339                          bool aIsPremultiplied = true) {
1340   if (BlendOpIsMixBlendMode(aBlendMode)) {
1341     // Mix-blend modes require an extra step (or more) that cannot be expressed
1342     // in the fixed-function blending capabilities of opengl. We handle them
1343     // separately in shaders, and the shaders assume we will use our default
1344     // blend function for compositing (premultiplied OP_OVER).
1345     return false;
1346   }
1347   if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
1348     return false;
1349   }
1350 
1351   GLenum srcBlend;
1352   GLenum dstBlend;
1353   GLenum srcAlphaBlend = LOCAL_GL_ONE;
1354   GLenum dstAlphaBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
1355 
1356   switch (aBlendMode) {
1357     case gfx::CompositionOp::OP_OVER:
1358       MOZ_ASSERT(!aIsPremultiplied);
1359       srcBlend = LOCAL_GL_SRC_ALPHA;
1360       dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
1361       break;
1362     case gfx::CompositionOp::OP_SOURCE:
1363       srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA;
1364       dstBlend = LOCAL_GL_ZERO;
1365       srcAlphaBlend = LOCAL_GL_ONE;
1366       dstAlphaBlend = LOCAL_GL_ZERO;
1367       break;
1368     default:
1369       MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!");
1370       return false;
1371   }
1372 
1373   aGL->fBlendFuncSeparate(srcBlend, dstBlend, srcAlphaBlend, dstAlphaBlend);
1374   return true;
1375 }
1376 
GetLineCoefficients(const gfx::Point & aPoint1,const gfx::Point & aPoint2)1377 gfx::Point3D CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1,
1378                                                 const gfx::Point& aPoint2) {
1379   // Return standard coefficients for a line between aPoint1 and aPoint2
1380   // for standard line equation:
1381   //
1382   // Ax + By + C = 0
1383   //
1384   // A = (p1.y – p2.y)
1385   // B = (p2.x – p1.x)
1386   // C = (p1.x * p2.y) – (p2.x * p1.y)
1387 
1388   gfx::Point3D coeffecients;
1389   coeffecients.x = aPoint1.y - aPoint2.y;
1390   coeffecients.y = aPoint2.x - aPoint1.x;
1391   coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y;
1392 
1393   coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x +
1394                                coeffecients.y * coeffecients.y);
1395 
1396   // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel
1397   // wide and included within the interior of the polygon
1398   coeffecients.z += 0.5f;
1399 
1400   return coeffecients;
1401 }
1402 
DrawQuad(const Rect & aRect,const IntRect & aClipRect,const EffectChain & aEffectChain,Float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::Rect & aVisibleRect)1403 void CompositorOGL::DrawQuad(const Rect& aRect, const IntRect& aClipRect,
1404                              const EffectChain& aEffectChain, Float aOpacity,
1405                              const gfx::Matrix4x4& aTransform,
1406                              const gfx::Rect& aVisibleRect) {
1407   AUTO_PROFILER_LABEL("CompositorOGL::DrawQuad", GRAPHICS);
1408 
1409   DrawGeometry(aRect, aRect, aClipRect, aEffectChain, aOpacity, aTransform,
1410                aVisibleRect);
1411 }
1412 
DrawTriangles(const nsTArray<gfx::TexturedTriangle> & aTriangles,const gfx::Rect & aRect,const gfx::IntRect & aClipRect,const EffectChain & aEffectChain,gfx::Float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::Rect & aVisibleRect)1413 void CompositorOGL::DrawTriangles(
1414     const nsTArray<gfx::TexturedTriangle>& aTriangles, const gfx::Rect& aRect,
1415     const gfx::IntRect& aClipRect, const EffectChain& aEffectChain,
1416     gfx::Float aOpacity, const gfx::Matrix4x4& aTransform,
1417     const gfx::Rect& aVisibleRect) {
1418   AUTO_PROFILER_LABEL("CompositorOGL::DrawTriangles", GRAPHICS);
1419 
1420   DrawGeometry(aTriangles, aRect, aClipRect, aEffectChain, aOpacity, aTransform,
1421                aVisibleRect);
1422 }
1423 
1424 template <typename Geometry>
DrawGeometry(const Geometry & aGeometry,const gfx::Rect & aRect,const gfx::IntRect & aClipRect,const EffectChain & aEffectChain,gfx::Float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::Rect & aVisibleRect)1425 void CompositorOGL::DrawGeometry(const Geometry& aGeometry,
1426                                  const gfx::Rect& aRect,
1427                                  const gfx::IntRect& aClipRect,
1428                                  const EffectChain& aEffectChain,
1429                                  gfx::Float aOpacity,
1430                                  const gfx::Matrix4x4& aTransform,
1431                                  const gfx::Rect& aVisibleRect) {
1432   MOZ_ASSERT(mFrameInProgress, "frame not started");
1433   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
1434 
1435   MakeCurrent();
1436 
1437   // Convert aClipRect into render target space, and intersect it with the
1438   // render target's clip.
1439   IntRect clipRect = aClipRect + mCurrentRenderTarget->GetClipSpaceOrigin();
1440   if (Maybe<IntRect> rtClip = mCurrentRenderTarget->GetClipRect()) {
1441     clipRect = clipRect.Intersect(*rtClip);
1442   }
1443 
1444   Rect destRect = aTransform.TransformAndClipBounds(
1445       aRect, Rect(mCurrentRenderTarget->GetRect().Intersect(clipRect)));
1446   if (destRect.IsEmpty()) {
1447     return;
1448   }
1449 
1450   // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
1451   //      quads. Fix me.
1452   mPixelsFilled += destRect.Area();
1453 
1454   LayerScope::DrawBegin();
1455 
1456   EffectMask* effectMask;
1457   Rect maskBounds;
1458   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
1459     effectMask = static_cast<EffectMask*>(
1460         aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
1461 
1462     // We're assuming that the gl backend won't cheat and use NPOT
1463     // textures when glContext says it can't (which seems to happen
1464     // on a mac when you force POT textures)
1465     IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
1466 
1467     const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
1468     NS_ASSERTION(maskTransform.Is2D(),
1469                  "How did we end up with a 3D transform here?!");
1470     maskBounds = Rect(Point(), Size(maskSize));
1471     maskBounds = maskTransform.As2D().TransformBounds(maskBounds);
1472 
1473     clipRect = clipRect.Intersect(RoundedOut(maskBounds));
1474   }
1475 
1476   // Move clipRect into device space.
1477   IntPoint offset = mCurrentRenderTarget->GetOrigin();
1478   clipRect -= offset;
1479 
1480   if (!mTarget && mCurrentRenderTarget->IsWindow()) {
1481     clipRect.MoveBy(mSurfaceOrigin.x, -mSurfaceOrigin.y);
1482   }
1483 
1484   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
1485   ScopedScissorRect autoScissorRect(mGLContext, clipRect.X(),
1486                                     FlipY(clipRect.Y() + clipRect.Height()),
1487                                     clipRect.Width(), clipRect.Height());
1488 
1489   MaskType maskType;
1490   TextureSourceOGL* sourceMask = nullptr;
1491   gfx::Matrix4x4 maskQuadTransform;
1492   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
1493     sourceMask = effectMask->mMaskTexture->AsSourceOGL();
1494 
1495     // NS_ASSERTION(textureMask->IsAlpha(),
1496     //              "OpenGL mask layers must be backed by alpha surfaces");
1497 
1498     maskQuadTransform._11 = 1.0f / maskBounds.Width();
1499     maskQuadTransform._22 = 1.0f / maskBounds.Height();
1500     maskQuadTransform._41 = float(-maskBounds.X()) / maskBounds.Width();
1501     maskQuadTransform._42 = float(-maskBounds.Y()) / maskBounds.Height();
1502 
1503     maskType = MaskType::Mask;
1504   } else {
1505     maskType = MaskType::MaskNone;
1506   }
1507 
1508   // Determine the color if this is a color shader and fold the opacity into
1509   // the color since color shaders don't have an opacity uniform.
1510   DeviceColor color;
1511   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::SOLID_COLOR) {
1512     EffectSolidColor* effectSolidColor =
1513         static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
1514     color = effectSolidColor->mColor;
1515 
1516     Float opacity = aOpacity * color.a;
1517     color.r *= opacity;
1518     color.g *= opacity;
1519     color.b *= opacity;
1520     color.a = opacity;
1521 
1522     // We can fold opacity into the color, so no need to consider it further.
1523     aOpacity = 1.f;
1524   }
1525 
1526   bool createdMixBlendBackdropTexture = false;
1527   GLuint mixBlendBackdrop = 0;
1528   gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
1529 
1530   if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
1531     EffectBlendMode* blendEffect = static_cast<EffectBlendMode*>(
1532         aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
1533     blendMode = blendEffect->mBlendMode;
1534   }
1535 
1536   // Only apply DEAA to quads that have been transformed such that aliasing
1537   // could be visible
1538   bool bEnableAA = StaticPrefs::layers_deaa_enabled() &&
1539                    !aTransform.Is2DIntegerTranslation();
1540 
1541   bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
1542   ShaderConfigOGL config =
1543       GetShaderConfigFor(aEffectChain.mPrimaryEffect, sourceMask, blendMode,
1544                          colorMatrix, bEnableAA);
1545 
1546   config.SetOpacity(aOpacity != 1.f);
1547   ApplyPrimitiveConfig(config, aGeometry);
1548 
1549   ShaderProgramOGL* program = mProgramsHolder->ActivateProgram(config);
1550   if (!program) {
1551     return;
1552   }
1553   program->SetProjectionMatrix(mProjMatrix);
1554   program->SetLayerTransform(aTransform);
1555   LayerScope::SetLayerTransform(aTransform);
1556 
1557   if (colorMatrix) {
1558     EffectColorMatrix* effectColorMatrix = static_cast<EffectColorMatrix*>(
1559         aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
1560     program->SetColorMatrix(effectColorMatrix->mColorMatrix);
1561   }
1562 
1563   if (BlendOpIsMixBlendMode(blendMode)) {
1564     gfx::Matrix4x4 backdropTransform;
1565 
1566     if (gl()->IsExtensionSupported(GLContext::NV_texture_barrier)) {
1567       // The NV_texture_barrier extension lets us read directly from the
1568       // backbuffer. Let's do that.
1569       // We need to tell OpenGL about this, so that it can make sure everything
1570       // on the GPU is happening in the right order.
1571       gl()->fTextureBarrier();
1572       mixBlendBackdrop = mCurrentRenderTarget->GetTextureHandle();
1573     } else {
1574       gfx::IntRect rect = ComputeBackdropCopyRect(aRect, clipRect, aTransform,
1575                                                   &backdropTransform);
1576       mixBlendBackdrop =
1577           CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
1578       createdMixBlendBackdropTexture = true;
1579     }
1580     program->SetBackdropTransform(backdropTransform);
1581   }
1582 
1583   program->SetRenderOffset(offset.x, offset.y);
1584   LayerScope::SetRenderOffset(offset.x, offset.y);
1585 
1586   if (aOpacity != 1.f) program->SetLayerOpacity(aOpacity);
1587 
1588   if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1589     TextureSourceOGL* source = nullptr;
1590     if (aEffectChain.mPrimaryEffect->mType == EffectTypes::COMPONENT_ALPHA) {
1591       EffectComponentAlpha* effectComponentAlpha =
1592           static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1593       source = effectComponentAlpha->mOnWhite->AsSourceOGL();
1594     } else {
1595       TexturedEffect* texturedEffect =
1596           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
1597       source = texturedEffect->mTexture->AsSourceOGL();
1598     }
1599     // This is used by IOSurface that use 0,0...w,h coordinate rather then
1600     // 0,0..1,1.
1601     program->SetTexCoordMultiplier(source->GetSize().width,
1602                                    source->GetSize().height);
1603   }
1604 
1605   if (sourceMask && config.mFeatures & ENABLE_MASK_TEXTURE_RECT) {
1606     program->SetMaskCoordMultiplier(sourceMask->GetSize().width,
1607                                     sourceMask->GetSize().height);
1608   }
1609 
1610   // XXX kip - These calculations could be performed once per layer rather than
1611   //           for every tile.  This might belong in Compositor.cpp once DEAA
1612   //           is implemented for DirectX.
1613   if (bEnableAA) {
1614     // Calculate the transformed vertices of aVisibleRect in screen space
1615     // pixels, mirroring the calculations in the vertex shader
1616     Matrix4x4 flatTransform = aTransform;
1617     flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f);
1618     flatTransform *= mProjMatrix;
1619 
1620     Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f);
1621     size_t edgeCount = 0;
1622     Point3D coefficients[4];
1623 
1624     Point points[Matrix4x4::kTransformAndClipRectMaxVerts];
1625     size_t pointCount =
1626         flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points);
1627     for (size_t i = 0; i < pointCount; i++) {
1628       points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width,
1629                         (points[i].y * 0.5f + 0.5f) * mViewportSize.height);
1630     }
1631     if (pointCount > 2) {
1632       // Use shoelace formula on a triangle in the clipped quad to determine if
1633       // winding order is reversed.  Iterate through the triangles until one is
1634       // found with a non-zero area.
1635       float winding = 0.0f;
1636       size_t wp = 0;
1637       while (winding == 0.0f && wp < pointCount) {
1638         int wp1 = (wp + 1) % pointCount;
1639         int wp2 = (wp + 2) % pointCount;
1640         winding =
1641             (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) +
1642             (points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) +
1643             (points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y);
1644         wp++;
1645       }
1646       bool frontFacing = winding >= 0.0f;
1647 
1648       // Calculate the line coefficients used by the DEAA shader to determine
1649       // the sub-pixel coverage of the edge pixels
1650       for (size_t i = 0; i < pointCount; i++) {
1651         const Point& p1 = points[i];
1652         const Point& p2 = points[(i + 1) % pointCount];
1653         // Create a DEAA edge for any non-straight lines, to a maximum of 4
1654         if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) {
1655           if (frontFacing) {
1656             coefficients[edgeCount++] = GetLineCoefficients(p2, p1);
1657           } else {
1658             coefficients[edgeCount++] = GetLineCoefficients(p1, p2);
1659           }
1660         }
1661       }
1662     }
1663 
1664     // The coefficients that are not needed must not cull any fragments.
1665     // We fill these unused coefficients with a clipping plane that has no
1666     // effect.
1667     for (size_t i = edgeCount; i < 4; i++) {
1668       coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height);
1669     }
1670 
1671     // Set uniforms required by DEAA shader
1672     Matrix4x4 transformInverted = aTransform;
1673     transformInverted.Invert();
1674     program->SetLayerTransformInverse(transformInverted);
1675     program->SetDEAAEdges(coefficients);
1676     program->SetVisibleCenter(aVisibleRect.Center());
1677     program->SetViewportSize(mViewportSize);
1678   }
1679 
1680   bool didSetBlendMode = false;
1681 
1682   switch (aEffectChain.mPrimaryEffect->mType) {
1683     case EffectTypes::SOLID_COLOR: {
1684       program->SetRenderColor(color);
1685 
1686       if (maskType != MaskType::MaskNone) {
1687         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0,
1688                            maskQuadTransform);
1689       }
1690       if (mixBlendBackdrop) {
1691         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1);
1692       }
1693 
1694       didSetBlendMode = SetBlendMode(gl(), blendMode);
1695 
1696       BindAndDrawGeometry(program, aGeometry);
1697     } break;
1698 
1699     case EffectTypes::RGB: {
1700       TexturedEffect* texturedEffect =
1701           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
1702       TextureSource* source = texturedEffect->mTexture;
1703 
1704       didSetBlendMode =
1705           SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied);
1706 
1707       gfx::SamplingFilter samplingFilter = texturedEffect->mSamplingFilter;
1708 
1709       source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, samplingFilter);
1710 
1711       program->SetTextureUnit(0);
1712 
1713       Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform();
1714       program->SetTextureTransform(textureTransform);
1715 
1716       if (maskType != MaskType::MaskNone) {
1717         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1,
1718                            maskQuadTransform);
1719       }
1720       if (mixBlendBackdrop) {
1721         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
1722       }
1723 
1724       BindAndDrawGeometryWithTextureRect(
1725           program, aGeometry, texturedEffect->mTextureCoords, source);
1726       source->AsSourceOGL()->MaybeFenceTexture();
1727     } break;
1728     case EffectTypes::YCBCR: {
1729       EffectYCbCr* effectYCbCr =
1730           static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
1731       TextureSource* sourceYCbCr = effectYCbCr->mTexture;
1732       const int Y = 0, Cb = 1, Cr = 2;
1733       TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
1734       TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
1735       TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
1736 
1737       if (!sourceY || !sourceCb || !sourceCr) {
1738         NS_WARNING("Invalid layer texture.");
1739         return;
1740       }
1741 
1742       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mSamplingFilter);
1743       sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mSamplingFilter);
1744       sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mSamplingFilter);
1745 
1746       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1747         // This is used by IOSurface that use 0,0...w,h coordinate rather then
1748         // 0,0..1,1.
1749         program->SetCbCrTexCoordMultiplier(sourceCb->GetSize().width,
1750                                            sourceCb->GetSize().height);
1751       }
1752 
1753       program->SetYCbCrTextureUnits(Y, Cb, Cr);
1754       program->SetTextureTransform(Matrix4x4());
1755       program->SetYUVColorSpace(effectYCbCr->mYUVColorSpace);
1756 
1757       if (maskType != MaskType::MaskNone) {
1758         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3,
1759                            maskQuadTransform);
1760       }
1761       if (mixBlendBackdrop) {
1762         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4);
1763       }
1764       didSetBlendMode = SetBlendMode(gl(), blendMode);
1765       BindAndDrawGeometryWithTextureRect(program, aGeometry,
1766                                          effectYCbCr->mTextureCoords,
1767                                          sourceYCbCr->GetSubSource(Y));
1768       sourceY->MaybeFenceTexture();
1769       sourceCb->MaybeFenceTexture();
1770       sourceCr->MaybeFenceTexture();
1771     } break;
1772     case EffectTypes::NV12: {
1773       EffectNV12* effectNV12 =
1774           static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get());
1775       TextureSource* sourceNV12 = effectNV12->mTexture;
1776       const int Y = 0, CbCr = 1;
1777       TextureSourceOGL* sourceY = sourceNV12->GetSubSource(Y)->AsSourceOGL();
1778       TextureSourceOGL* sourceCbCr =
1779           sourceNV12->GetSubSource(CbCr)->AsSourceOGL();
1780 
1781       if (!sourceY || !sourceCbCr) {
1782         NS_WARNING("Invalid layer texture.");
1783         return;
1784       }
1785 
1786       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectNV12->mSamplingFilter);
1787       sourceCbCr->BindTexture(LOCAL_GL_TEXTURE1, effectNV12->mSamplingFilter);
1788 
1789       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1790         // This is used by IOSurface that use 0,0...w,h coordinate rather then
1791         // 0,0..1,1.
1792         program->SetCbCrTexCoordMultiplier(sourceCbCr->GetSize().width,
1793                                            sourceCbCr->GetSize().height);
1794       }
1795 
1796       program->SetNV12TextureUnits(Y, CbCr);
1797       program->SetTextureTransform(Matrix4x4());
1798       program->SetYUVColorSpace(effectNV12->mYUVColorSpace);
1799 
1800       if (maskType != MaskType::MaskNone) {
1801         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2,
1802                            maskQuadTransform);
1803       }
1804       if (mixBlendBackdrop) {
1805         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3);
1806       }
1807       didSetBlendMode = SetBlendMode(gl(), blendMode);
1808       BindAndDrawGeometryWithTextureRect(program, aGeometry,
1809                                          effectNV12->mTextureCoords,
1810                                          sourceNV12->GetSubSource(Y));
1811       sourceY->MaybeFenceTexture();
1812       sourceCbCr->MaybeFenceTexture();
1813     } break;
1814     case EffectTypes::RENDER_TARGET: {
1815       EffectRenderTarget* effectRenderTarget =
1816           static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
1817       RefPtr<CompositingRenderTargetOGL> surface =
1818           static_cast<CompositingRenderTargetOGL*>(
1819               effectRenderTarget->mRenderTarget.get());
1820 
1821       surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
1822 
1823       // Drawing is always flipped, but when copying between surfaces we want to
1824       // avoid this, so apply a flip here to cancel the other one out.
1825       Matrix transform;
1826       transform.PreTranslate(0.0, 1.0);
1827       transform.PreScale(1.0f, -1.0f);
1828       program->SetTextureTransform(Matrix4x4::From2D(transform));
1829       program->SetTextureUnit(0);
1830 
1831       if (maskType != MaskType::MaskNone) {
1832         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1,
1833                            maskQuadTransform);
1834       }
1835       if (mixBlendBackdrop) {
1836         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
1837       }
1838 
1839       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1840         // 2DRect case, get the multiplier right for a sampler2DRect
1841         program->SetTexCoordMultiplier(surface->GetSize().width,
1842                                        surface->GetSize().height);
1843       }
1844 
1845       // Drawing is always flipped, but when copying between surfaces we want to
1846       // avoid this. Pass true for the flip parameter to introduce a second flip
1847       // that cancels the other one out.
1848       didSetBlendMode = SetBlendMode(gl(), blendMode);
1849       BindAndDrawGeometry(program, aGeometry);
1850     } break;
1851     case EffectTypes::COMPONENT_ALPHA: {
1852       MOZ_ASSERT(LayerManager::LayersComponentAlphaEnabled());
1853       MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER,
1854                  "Can't support blend modes with component alpha!");
1855       EffectComponentAlpha* effectComponentAlpha =
1856           static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1857       TextureSourceOGL* sourceOnWhite =
1858           effectComponentAlpha->mOnWhite->AsSourceOGL();
1859       TextureSourceOGL* sourceOnBlack =
1860           effectComponentAlpha->mOnBlack->AsSourceOGL();
1861 
1862       if (!sourceOnBlack->IsValid() || !sourceOnWhite->IsValid()) {
1863         NS_WARNING("Invalid layer texture for component alpha");
1864         return;
1865       }
1866 
1867       sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0,
1868                                  effectComponentAlpha->mSamplingFilter);
1869       sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1,
1870                                  effectComponentAlpha->mSamplingFilter);
1871 
1872       program->SetBlackTextureUnit(0);
1873       program->SetWhiteTextureUnit(1);
1874       program->SetTextureTransform(Matrix4x4());
1875 
1876       if (maskType != MaskType::MaskNone) {
1877         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2,
1878                            maskQuadTransform);
1879       }
1880       // Pass 1.
1881       gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
1882                                LOCAL_GL_ONE, LOCAL_GL_ONE);
1883       program->SetTexturePass2(false);
1884       BindAndDrawGeometryWithTextureRect(program, aGeometry,
1885                                          effectComponentAlpha->mTextureCoords,
1886                                          effectComponentAlpha->mOnBlack);
1887 
1888       // Pass 2.
1889       gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE, LOCAL_GL_ONE,
1890                                LOCAL_GL_ONE);
1891       program->SetTexturePass2(true);
1892       BindAndDrawGeometryWithTextureRect(program, aGeometry,
1893                                          effectComponentAlpha->mTextureCoords,
1894                                          effectComponentAlpha->mOnBlack);
1895 
1896       mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1897                                      LOCAL_GL_ONE,
1898                                      LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1899 
1900       sourceOnBlack->MaybeFenceTexture();
1901       sourceOnWhite->MaybeFenceTexture();
1902     } break;
1903     default:
1904       MOZ_ASSERT(false, "Unhandled effect type");
1905       break;
1906   }
1907 
1908   if (didSetBlendMode) {
1909     gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1910                              LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1911   }
1912   if (createdMixBlendBackdropTexture) {
1913     gl()->fDeleteTextures(1, &mixBlendBackdrop);
1914   }
1915 
1916   // in case rendering has used some other GL context
1917   MakeCurrent();
1918 
1919   LayerScope::DrawEnd(mGLContext, aEffectChain, aRect.Width(), aRect.Height());
1920 }
1921 
BindAndDrawGeometry(ShaderProgramOGL * aProgram,const gfx::Rect & aRect)1922 void CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
1923                                         const gfx::Rect& aRect) {
1924   BindAndDrawQuad(aProgram, aRect);
1925 }
1926 
BindAndDrawGeometry(ShaderProgramOGL * aProgram,const nsTArray<gfx::TexturedTriangle> & aTriangles)1927 void CompositorOGL::BindAndDrawGeometry(
1928     ShaderProgramOGL* aProgram,
1929     const nsTArray<gfx::TexturedTriangle>& aTriangles) {
1930   NS_ASSERTION(aProgram->HasInitialized(),
1931                "Shader program not correctly initialized");
1932 
1933   const nsTArray<TexturedVertex> vertices =
1934       TexturedTrianglesToVertexArray(aTriangles);
1935 
1936   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO);
1937   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
1938                           vertices.Length() * sizeof(TexturedVertex),
1939                           vertices.Elements(), LOCAL_GL_STREAM_DRAW);
1940 
1941   const GLsizei stride = 4 * sizeof(GLfloat);
1942   InitializeVAO(kCoordinateAttributeIndex, 2, stride, 0);
1943   InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 2 * sizeof(GLfloat));
1944 
1945   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, vertices.Length());
1946 
1947   mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
1948   mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex);
1949   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1950 }
1951 
1952 // |aRect| is the rectangle we want to draw to. We will draw it with
1953 // up to 4 draw commands if necessary to avoid wrapping.
1954 // |aTexCoordRect| is the rectangle from the texture that we want to
1955 // draw using the given program.
1956 // |aTexture| is the texture we are drawing. Its actual size can be
1957 // larger than the rectangle given by |texCoordRect|.
BindAndDrawGeometryWithTextureRect(ShaderProgramOGL * aProg,const Rect & aRect,const Rect & aTexCoordRect,TextureSource * aTexture)1958 void CompositorOGL::BindAndDrawGeometryWithTextureRect(
1959     ShaderProgramOGL* aProg, const Rect& aRect, const Rect& aTexCoordRect,
1960     TextureSource* aTexture) {
1961   Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture);
1962   Rect layerRects[4];
1963   Rect textureRects[4];
1964   size_t rects = DecomposeIntoNoRepeatRects(aRect, scaledTexCoordRect,
1965                                             &layerRects, &textureRects);
1966 
1967   BindAndDrawQuads(aProg, rects, layerRects, textureRects);
1968 }
1969 
BindAndDrawGeometryWithTextureRect(ShaderProgramOGL * aProg,const nsTArray<gfx::TexturedTriangle> & aTriangles,const gfx::Rect & aTexCoordRect,TextureSource * aTexture)1970 void CompositorOGL::BindAndDrawGeometryWithTextureRect(
1971     ShaderProgramOGL* aProg, const nsTArray<gfx::TexturedTriangle>& aTriangles,
1972     const gfx::Rect& aTexCoordRect, TextureSource* aTexture) {
1973   BindAndDrawGeometry(aProg, aTriangles);
1974 }
1975 
BindAndDrawQuads(ShaderProgramOGL * aProg,int aQuads,const Rect * aLayerRects,const Rect * aTextureRects)1976 void CompositorOGL::BindAndDrawQuads(ShaderProgramOGL* aProg, int aQuads,
1977                                      const Rect* aLayerRects,
1978                                      const Rect* aTextureRects) {
1979   NS_ASSERTION(aProg->HasInitialized(),
1980                "Shader program not correctly initialized");
1981 
1982   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
1983   InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0);
1984 
1985   aProg->SetLayerRects(aLayerRects);
1986   if (aProg->GetTextureCount() > 0) {
1987     aProg->SetTextureRects(aTextureRects);
1988   }
1989 
1990   // We are using GL_TRIANGLES here because the Mac Intel drivers fail to
1991   // properly process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
1992   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
1993   mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
1994   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1995   LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
1996 }
1997 
InitializeVAO(const GLuint aAttrib,const GLint aComponents,const GLsizei aStride,const size_t aOffset)1998 void CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents,
1999                                   const GLsizei aStride, const size_t aOffset) {
2000   mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT,
2001                                    LOCAL_GL_FALSE, aStride,
2002                                    reinterpret_cast<GLvoid*>(aOffset));
2003   mGLContext->fEnableVertexAttribArray(aAttrib);
2004 }
2005 
EndFrame()2006 void CompositorOGL::EndFrame() {
2007   AUTO_PROFILER_LABEL("CompositorOGL::EndFrame", GRAPHICS);
2008 
2009 #ifdef MOZ_DUMP_PAINTING
2010   if (gfxEnv::DumpCompositorTextures()) {
2011     LayoutDeviceIntSize size;
2012     if (mUseExternalSurfaceSize) {
2013       size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height);
2014     } else {
2015       size = mWidget->GetClientSize();
2016     }
2017     RefPtr<DrawTarget> target =
2018         gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
2019             IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
2020     if (target) {
2021       CopyToTarget(target, nsIntPoint(), Matrix());
2022       WriteSnapshotToDumpFile(this, target);
2023     }
2024   }
2025 #endif
2026 
2027   mFrameInProgress = false;
2028   mShouldInvalidateWindow = false;
2029 
2030   if (mTarget) {
2031     CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix());
2032     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
2033     mTarget = nullptr;
2034     mWindowRenderTarget = nullptr;
2035     mCurrentRenderTarget = nullptr;
2036     Compositor::EndFrame();
2037     return;
2038   }
2039 
2040   mWindowRenderTarget = nullptr;
2041   mCurrentRenderTarget = nullptr;
2042 
2043   if (mTexturePool) {
2044     mTexturePool->EndFrame();
2045   }
2046 
2047   InsertFrameDoneSync();
2048 
2049   mGLContext->SetDamage(mCurrentFrameInvalidRegion);
2050   mGLContext->SwapBuffers();
2051   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
2052 
2053   // Unbind all textures
2054   for (GLuint i = 0; i <= 4; i++) {
2055     mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
2056     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
2057     if (!mGLContext->IsGLES()) {
2058       mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
2059     }
2060   }
2061 
2062   mCurrentFrameInvalidRegion.SetEmpty();
2063 
2064   Compositor::EndFrame();
2065 }
2066 
InsertFrameDoneSync()2067 void CompositorOGL::InsertFrameDoneSync() {
2068 #ifdef XP_MACOSX
2069   // Only do this on macOS.
2070   // On other platforms, SwapBuffers automatically applies back-pressure.
2071   if (mThisFrameDoneSync) {
2072     mGLContext->fDeleteSync(mThisFrameDoneSync);
2073   }
2074   mThisFrameDoneSync =
2075       mGLContext->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
2076 #elif defined(MOZ_WIDGET_ANDROID)
2077   const auto& gle = gl::GLContextEGL::Cast(mGLContext);
2078   const auto& egl = gle->mEgl;
2079 
2080   EGLSync sync = nullptr;
2081   if (AndroidHardwareBufferApi::Get()) {
2082     sync = egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
2083   }
2084   if (sync) {
2085     int fenceFd = egl->fDupNativeFenceFDANDROID(sync);
2086     if (fenceFd >= 0) {
2087       mReleaseFenceFd = ipc::FileDescriptor(UniqueFileHandle(fenceFd));
2088     }
2089     egl->fDestroySync(sync);
2090     sync = nullptr;
2091   }
2092 #endif
2093 }
2094 
WaitForGPU()2095 void CompositorOGL::WaitForGPU() {
2096   if (mPreviousFrameDoneSync) {
2097     AUTO_PROFILER_LABEL("Waiting for GPU to finish previous frame", GRAPHICS);
2098     mGLContext->fClientWaitSync(mPreviousFrameDoneSync,
2099                                 LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT,
2100                                 LOCAL_GL_TIMEOUT_IGNORED);
2101     mGLContext->fDeleteSync(mPreviousFrameDoneSync);
2102   }
2103   mPreviousFrameDoneSync = mThisFrameDoneSync;
2104   mThisFrameDoneSync = nullptr;
2105 }
2106 
GetReleaseFence()2107 ipc::FileDescriptor CompositorOGL::GetReleaseFence() { return mReleaseFenceFd; }
2108 
GetSurfacePoolHandle()2109 RefPtr<SurfacePoolHandle> CompositorOGL::GetSurfacePoolHandle() {
2110 #ifdef XP_MACOSX
2111   if (!mSurfacePoolHandle) {
2112     mSurfacePoolHandle = SurfacePool::Create(0)->GetHandleForGL(mGLContext);
2113   }
2114 #endif
2115   return mSurfacePoolHandle;
2116 }
2117 
NeedToRecreateFullWindowRenderTarget() const2118 bool CompositorOGL::NeedToRecreateFullWindowRenderTarget() const {
2119   if (!ShouldRecordFrames()) {
2120     return false;
2121   }
2122   if (!mFullWindowRenderTarget) {
2123     return true;
2124   }
2125   IntSize windowSize = mWidget->GetClientSize().ToUnknownSize();
2126   return mFullWindowRenderTarget->GetSize() != windowSize;
2127 }
2128 
SetDestinationSurfaceSize(const IntSize & aSize)2129 void CompositorOGL::SetDestinationSurfaceSize(const IntSize& aSize) {
2130   mSurfaceSize.width = aSize.width;
2131   mSurfaceSize.height = aSize.height;
2132 }
2133 
CopyToTarget(DrawTarget * aTarget,const nsIntPoint & aTopLeft,const gfx::Matrix & aTransform)2134 void CompositorOGL::CopyToTarget(DrawTarget* aTarget,
2135                                  const nsIntPoint& aTopLeft,
2136                                  const gfx::Matrix& aTransform) {
2137   MOZ_ASSERT(aTarget);
2138   IntRect rect;
2139   if (mUseExternalSurfaceSize) {
2140     rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
2141   } else {
2142     rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
2143   }
2144   GLint width = rect.Width();
2145   GLint height = rect.Height();
2146 
2147   if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
2148     NS_ERROR("Widget size too big - integer overflow!");
2149     return;
2150   }
2151 
2152   RefPtr<DataSourceSurface> source = Factory::CreateDataSourceSurface(
2153       rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
2154   if (NS_WARN_IF(!source)) {
2155     return;
2156   }
2157 
2158   ReadPixelsIntoDataSurface(mGLContext, source);
2159 
2160   // Map from GL space to Cairo space and reverse the world transform.
2161   Matrix glToCairoTransform = aTransform;
2162   glToCairoTransform.Invert();
2163   glToCairoTransform.PreScale(1.0, -1.0);
2164   glToCairoTransform.PreTranslate(0.0, -height);
2165 
2166   glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y);
2167 
2168   Matrix oldMatrix = aTarget->GetTransform();
2169   aTarget->SetTransform(glToCairoTransform);
2170   Rect floatRect = Rect(rect.X(), rect.Y(), width, height);
2171   aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(),
2172                        DrawOptions(1.0f, CompositionOp::OP_SOURCE));
2173   aTarget->SetTransform(oldMatrix);
2174   aTarget->Flush();
2175 }
2176 
Pause()2177 void CompositorOGL::Pause() {
2178 #ifdef MOZ_WIDGET_ANDROID
2179   if (!gl() || gl()->IsDestroyed()) return;
2180   // ReleaseSurface internally calls MakeCurrent
2181   gl()->ReleaseSurface();
2182 #elif defined(MOZ_WAYLAND)
2183   // ReleaseSurface internally calls MakeCurrent
2184   gl()->ReleaseSurface();
2185 #endif
2186 }
2187 
Resume()2188 bool CompositorOGL::Resume() {
2189 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) || \
2190     defined(MOZ_WAYLAND)
2191   if (!gl() || gl()->IsDestroyed()) return false;
2192 
2193   // RenewSurface internally calls MakeCurrent.
2194   return gl()->RenewSurface(GetWidget());
2195 #endif
2196   return true;
2197 }
2198 
CreateDataTextureSource(TextureFlags aFlags)2199 already_AddRefed<DataTextureSource> CompositorOGL::CreateDataTextureSource(
2200     TextureFlags aFlags) {
2201   if (!gl()) {
2202     return nullptr;
2203   }
2204 
2205   return MakeAndAddRef<TextureImageTextureSourceOGL>(this, aFlags);
2206 }
2207 
2208 already_AddRefed<DataTextureSource>
CreateDataTextureSourceAroundYCbCr(TextureHost * aTexture)2209 CompositorOGL::CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture) {
2210   if (!gl()) {
2211     return nullptr;
2212   }
2213 
2214   BufferTextureHost* bufferTexture = aTexture->AsBufferTextureHost();
2215   MOZ_ASSERT(bufferTexture);
2216 
2217   if (!bufferTexture) {
2218     return nullptr;
2219   }
2220 
2221   uint8_t* buf = bufferTexture->GetBuffer();
2222   const BufferDescriptor& buffDesc = bufferTexture->GetBufferDescriptor();
2223   const YCbCrDescriptor& desc = buffDesc.get_YCbCrDescriptor();
2224 
2225   RefPtr<gfx::DataSourceSurface> tempY =
2226       gfx::Factory::CreateWrappingDataSourceSurface(
2227           ImageDataSerializer::GetYChannel(buf, desc), desc.yStride(),
2228           desc.ySize(), SurfaceFormatForColorDepth(desc.colorDepth()));
2229   if (!tempY) {
2230     return nullptr;
2231   }
2232   RefPtr<gfx::DataSourceSurface> tempCb =
2233       gfx::Factory::CreateWrappingDataSourceSurface(
2234           ImageDataSerializer::GetCbChannel(buf, desc), desc.cbCrStride(),
2235           desc.cbCrSize(), SurfaceFormatForColorDepth(desc.colorDepth()));
2236   if (!tempCb) {
2237     return nullptr;
2238   }
2239   RefPtr<gfx::DataSourceSurface> tempCr =
2240       gfx::Factory::CreateWrappingDataSourceSurface(
2241           ImageDataSerializer::GetCrChannel(buf, desc), desc.cbCrStride(),
2242           desc.cbCrSize(), SurfaceFormatForColorDepth(desc.colorDepth()));
2243   if (!tempCr) {
2244     return nullptr;
2245   }
2246 
2247   RefPtr<DirectMapTextureSource> srcY = new DirectMapTextureSource(this, tempY);
2248   RefPtr<DirectMapTextureSource> srcU =
2249       new DirectMapTextureSource(this, tempCb);
2250   RefPtr<DirectMapTextureSource> srcV =
2251       new DirectMapTextureSource(this, tempCr);
2252 
2253   srcY->SetNextSibling(srcU);
2254   srcU->SetNextSibling(srcV);
2255 
2256   return srcY.forget();
2257 }
2258 
2259 #ifdef XP_DARWIN
MaybeUnlockBeforeNextComposition(TextureHost * aTextureHost)2260 void CompositorOGL::MaybeUnlockBeforeNextComposition(
2261     TextureHost* aTextureHost) {
2262   auto bufferTexture = aTextureHost->AsBufferTextureHost();
2263   if (bufferTexture) {
2264     mMaybeUnlockBeforeNextComposition.AppendElement(bufferTexture);
2265   }
2266 }
2267 
TryUnlockTextures()2268 void CompositorOGL::TryUnlockTextures() {
2269   nsClassHashtable<nsUint32HashKey, nsTArray<uint64_t>>
2270       texturesIdsToUnlockByPid;
2271   for (auto& texture : mMaybeUnlockBeforeNextComposition) {
2272     if (texture->IsDirectMap() && texture->CanUnlock()) {
2273       texture->ReadUnlock();
2274       auto actor = texture->GetIPDLActor();
2275       if (actor) {
2276         base::ProcessId pid = actor->OtherPid();
2277         nsTArray<uint64_t>* textureIds =
2278             texturesIdsToUnlockByPid.GetOrInsertNew(pid);
2279         textureIds->AppendElement(TextureHost::GetTextureSerial(actor));
2280       }
2281     }
2282   }
2283   mMaybeUnlockBeforeNextComposition.Clear();
2284   for (const auto& entry : texturesIdsToUnlockByPid) {
2285     TextureSync::SetTexturesUnlocked(entry.GetKey(), *entry.GetWeak());
2286   }
2287 }
2288 #endif
2289 
2290 already_AddRefed<DataTextureSource>
CreateDataTextureSourceAround(gfx::DataSourceSurface * aSurface)2291 CompositorOGL::CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) {
2292   if (!gl()) {
2293     return nullptr;
2294   }
2295 
2296   return MakeAndAddRef<DirectMapTextureSource>(this, aSurface);
2297 }
2298 
SupportsPartialTextureUpdate()2299 bool CompositorOGL::SupportsPartialTextureUpdate() {
2300   return ShouldUploadSubTextures(mGLContext);
2301 }
2302 
GetMaxTextureSize() const2303 int32_t CompositorOGL::GetMaxTextureSize() const {
2304   MOZ_ASSERT(mGLContext);
2305   GLint texSize = 0;
2306   mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &texSize);
2307   MOZ_ASSERT(texSize != 0);
2308   return texSize;
2309 }
2310 
MakeCurrent(MakeCurrentFlags aFlags)2311 void CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
2312   if (mDestroyed) {
2313     NS_WARNING("Call on destroyed layer manager");
2314     return;
2315   }
2316   mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
2317 }
2318 
BlitTextureImageHelper()2319 GLBlitTextureImageHelper* CompositorOGL::BlitTextureImageHelper() {
2320   if (!mBlitTextureImageHelper) {
2321     mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
2322   }
2323 
2324   return mBlitTextureImageHelper.get();
2325 }
2326 
GetTemporaryTexture(GLenum aTarget,GLenum aUnit)2327 GLuint CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit) {
2328   if (!mTexturePool) {
2329     mTexturePool = new PerUnitTexturePoolOGL(gl());
2330   }
2331   return mTexturePool->GetTexture(aTarget, aUnit);
2332 }
2333 
SupportsTextureDirectMapping()2334 bool CompositorOGL::SupportsTextureDirectMapping() {
2335   if (!StaticPrefs::gfx_allow_texture_direct_mapping_AtStartup()) {
2336     return false;
2337   }
2338 
2339   if (mGLContext) {
2340     mGLContext->MakeCurrent();
2341     return mGLContext->IsExtensionSupported(
2342                gl::GLContext::APPLE_client_storage) &&
2343            mGLContext->IsExtensionSupported(gl::GLContext::APPLE_texture_range);
2344   }
2345 
2346   return false;
2347 }
2348 
GetTexture(GLenum aTarget,GLenum aTextureUnit)2349 GLuint PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit) {
2350   if (mTextureTarget == 0) {
2351     mTextureTarget = aTarget;
2352   }
2353   MOZ_ASSERT(mTextureTarget == aTarget);
2354 
2355   size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
2356   // lazily grow the array of temporary textures
2357   if (mTextures.Length() <= index) {
2358     size_t prevLength = mTextures.Length();
2359     mTextures.SetLength(index + 1);
2360     for (unsigned int i = prevLength; i <= index; ++i) {
2361       mTextures[i] = 0;
2362     }
2363   }
2364   // lazily initialize the temporary textures
2365   if (!mTextures[index]) {
2366     if (!mGL->MakeCurrent()) {
2367       return 0;
2368     }
2369     mGL->fGenTextures(1, &mTextures[index]);
2370     mGL->fBindTexture(aTarget, mTextures[index]);
2371     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S,
2372                         LOCAL_GL_CLAMP_TO_EDGE);
2373     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T,
2374                         LOCAL_GL_CLAMP_TO_EDGE);
2375   }
2376   return mTextures[index];
2377 }
2378 
DestroyTextures()2379 void PerUnitTexturePoolOGL::DestroyTextures() {
2380   if (mGL && mGL->MakeCurrent()) {
2381     if (mTextures.Length() > 0) {
2382       mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
2383     }
2384   }
2385   mTextures.SetLength(0);
2386 }
2387 
SupportsLayerGeometry() const2388 bool CompositorOGL::SupportsLayerGeometry() const {
2389   return StaticPrefs::layers_geometry_opengl_enabled();
2390 }
2391 
RegisterTextureSource(TextureSource * aTextureSource)2392 void CompositorOGL::RegisterTextureSource(TextureSource* aTextureSource) {
2393 #ifdef MOZ_WIDGET_GTK
2394   if (mDestroyed) {
2395     return;
2396   }
2397   mRegisteredTextureSources.insert(aTextureSource);
2398 #endif
2399 }
2400 
UnregisterTextureSource(TextureSource * aTextureSource)2401 void CompositorOGL::UnregisterTextureSource(TextureSource* aTextureSource) {
2402 #ifdef MOZ_WIDGET_GTK
2403   if (mDestroyed) {
2404     return;
2405   }
2406   mRegisteredTextureSources.erase(aTextureSource);
2407 #endif
2408 }
2409 
2410 }  // namespace layers
2411 }  // namespace mozilla
2412