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