1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "CompositorOGL.h"
7 #include <stddef.h>                     // for size_t
8 #include <stdint.h>                     // for uint32_t, uint8_t
9 #include <stdlib.h>                     // for free, malloc
10 #include "GLContextProvider.h"          // for GLContextProvider
11 #include "GLContext.h"                  // for GLContext
12 #include "GLUploadHelpers.h"
13 #include "Layers.h"                     // for WriteSnapshotToDumpFile
14 #include "LayerScope.h"                 // for LayerScope
15 #include "gfxCrashReporterUtils.h"      // for ScopedGfxFeatureReporter
16 #include "gfxEnv.h"                     // for gfxEnv
17 #include "gfxPlatform.h"                // for gfxPlatform
18 #include "gfxPrefs.h"                   // for gfxPrefs
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/gfx/BasePoint.h"      // for BasePoint
24 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4, Matrix
25 #include "mozilla/gfx/Triangle.h"       // for Triangle
26 #include "mozilla/gfx/gfxVars.h"        // for gfxVars
27 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
28 #include "mozilla/layers/CompositingRenderTargetOGL.h"
29 #include "mozilla/layers/Effects.h"     // for EffectChain, TexturedEffect, etc
30 #include "mozilla/layers/TextureHost.h"  // for TextureSource, etc
31 #include "mozilla/layers/TextureHostOGL.h"  // for TextureSourceOGL, etc
32 #include "mozilla/mozalloc.h"           // for operator delete, etc
33 #include "nsAppRunner.h"
34 #include "nsAString.h"
35 #include "nsIConsoleService.h"          // for nsIConsoleService, etc
36 #include "nsIWidget.h"                  // for nsIWidget
37 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
38 #include "nsMathUtils.h"                // for NS_roundf
39 #include "nsRect.h"                     // for mozilla::gfx::IntRect
40 #include "nsServiceManagerUtils.h"      // for do_GetService
41 #include "nsString.h"                   // for nsString, nsAutoCString, etc
42 #include "ScopedGLHelpers.h"
43 #include "GLReadTexImageHelper.h"
44 #include "GLBlitTextureImageHelper.h"
45 #include "HeapCopyOfStackArray.h"
46 
47 #if MOZ_WIDGET_ANDROID
48 #include "TexturePoolOGL.h"
49 #endif
50 
51 #include "GeckoProfiler.h"
52 
53 namespace mozilla {
54 
55 using namespace std;
56 using namespace gfx;
57 
58 namespace layers {
59 
60 using namespace mozilla::gl;
61 
62 static const GLuint kCoordinateAttributeIndex = 0;
63 static const GLuint kTexCoordinateAttributeIndex = 1;
64 
65 static void
BindMaskForProgram(ShaderProgramOGL * aProgram,TextureSourceOGL * aSourceMask,GLenum aTexUnit,const gfx::Matrix4x4 & aTransform)66 BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
67                    GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
68 {
69   MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
70   aSourceMask->BindTexture(aTexUnit, gfx::SamplingFilter::LINEAR);
71   aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
72   aProgram->SetMaskLayerTransform(aTransform);
73 }
74 
75 void
BindBackdrop(ShaderProgramOGL * aProgram,GLuint aBackdrop,GLenum aTexUnit)76 CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit)
77 {
78   MOZ_ASSERT(aBackdrop);
79 
80   mGLContext->fActiveTexture(aTexUnit);
81   mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aBackdrop);
82   mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
83   mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
84   aProgram->SetBackdropTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
85 }
86 
CompositorOGL(CompositorBridgeParent * aParent,widget::CompositorWidget * aWidget,int aSurfaceWidth,int aSurfaceHeight,bool aUseExternalSurfaceSize)87 CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent,
88                              widget::CompositorWidget* aWidget,
89                              int aSurfaceWidth, int aSurfaceHeight,
90                              bool aUseExternalSurfaceSize)
91   : Compositor(aWidget, aParent)
92   , mWidgetSize(-1, -1)
93   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
94   , mHasBGRA(0)
95   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
96   , mFrameInProgress(false)
97   , mDestroyed(false)
98   , mViewportSize(0, 0)
99   , mCurrentProgram(nullptr)
100 {
101   MOZ_COUNT_CTOR(CompositorOGL);
102 }
103 
~CompositorOGL()104 CompositorOGL::~CompositorOGL()
105 {
106   MOZ_COUNT_DTOR(CompositorOGL);
107   Destroy();
108 }
109 
110 already_AddRefed<mozilla::gl::GLContext>
CreateContext()111 CompositorOGL::CreateContext()
112 {
113   RefPtr<GLContext> context;
114 
115   // Used by mock widget to create an offscreen context
116   nsIWidget* widget = mWidget->RealWidget();
117   void* widgetOpenGLContext = widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr;
118   if (widgetOpenGLContext) {
119     GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext);
120     return already_AddRefed<GLContext>(alreadyRefed);
121   }
122 
123 #ifdef XP_WIN
124   if (gfxEnv::LayersPreferEGL()) {
125     printf_stderr("Trying GL layers...\n");
126     context = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, false);
127   }
128 #endif
129 
130   // Allow to create offscreen GL context for main Layer Manager
131   if (!context && gfxEnv::LayersPreferOffscreen()) {
132     SurfaceCaps caps = SurfaceCaps::ForRGB();
133     caps.preserve = false;
134     caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
135 
136     nsCString discardFailureId;
137     context = GLContextProvider::CreateOffscreen(mSurfaceSize,
138                                                  caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE,
139                                                  &discardFailureId);
140   }
141 
142   if (!context) {
143     context = gl::GLContextProvider::CreateForCompositorWidget(mWidget,
144                 gfxVars::RequiresAcceleratedGLContextForCompositorOGL());
145   }
146 
147   if (!context) {
148     NS_WARNING("Failed to create CompositorOGL context");
149   }
150 
151   return context.forget();
152 }
153 
154 void
Destroy()155 CompositorOGL::Destroy()
156 {
157   Compositor::Destroy();
158 
159   if (mTexturePool) {
160     mTexturePool->Clear();
161     mTexturePool = nullptr;
162   }
163 
164   if (!mDestroyed) {
165     mDestroyed = true;
166     CleanupResources();
167   }
168 }
169 
170 void
CleanupResources()171 CompositorOGL::CleanupResources()
172 {
173   if (!mGLContext)
174     return;
175 
176   RefPtr<GLContext> ctx = mGLContext->GetSharedContext();
177   if (!ctx) {
178     ctx = mGLContext;
179   }
180 
181   if (!ctx->MakeCurrent()) {
182     // Leak resources!
183     mQuadVBO = 0;
184     mTriangleVBO = 0;
185     mGLContext = nullptr;
186     mPrograms.clear();
187     return;
188   }
189 
190   for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
191        iter != mPrograms.end();
192        iter++) {
193     delete iter->second;
194   }
195   mPrograms.clear();
196 
197   ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
198 
199   if (mQuadVBO) {
200     ctx->fDeleteBuffers(1, &mQuadVBO);
201     mQuadVBO = 0;
202   }
203 
204   if (mTriangleVBO) {
205     ctx->fDeleteBuffers(1, &mTriangleVBO);
206     mTriangleVBO = 0;
207   }
208 
209   mGLContext->MakeCurrent();
210 
211   mBlitTextureImageHelper = nullptr;
212 
213   mContextStateTracker.DestroyOGL(mGLContext);
214 
215   // On the main thread the Widget will be destroyed soon and calling MakeCurrent
216   // after that could cause a crash (at least with GLX, see bug 1059793), unless
217   // context is marked as destroyed.
218   // There may be some textures still alive that will try to call MakeCurrent on
219   // the context so let's make sure it is marked destroyed now.
220   mGLContext->MarkDestroyed();
221 
222   mGLContext = nullptr;
223 }
224 
225 bool
Initialize(nsCString * const out_failureReason)226 CompositorOGL::Initialize(nsCString* const out_failureReason)
227 {
228   ScopedGfxFeatureReporter reporter("GL Layers");
229 
230   // Do not allow double initialization
231   MOZ_ASSERT(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
232 
233   mGLContext = CreateContext();
234 
235 #ifdef MOZ_WIDGET_ANDROID
236   if (!mGLContext){
237     *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_ANDROID_CONTEXT";
238     NS_RUNTIMEABORT("We need a context on Android");
239   }
240 #endif
241 
242   if (!mGLContext){
243     *out_failureReason = "FEATURE_FAILURE_OPENGL_CREATE_CONTEXT";
244     return false;
245   }
246 
247   MakeCurrent();
248 
249   mHasBGRA =
250     mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
251     mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
252 
253   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
254                                  LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
255   mGLContext->fEnable(LOCAL_GL_BLEND);
256 
257   // initialise a common shader to check that we can actually compile a shader
258   RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
259   ShaderConfigOGL config = GetShaderConfigFor(effect);
260   if (!GetShaderProgramFor(config)) {
261     *out_failureReason = "FEATURE_FAILURE_OPENGL_COMPILE_SHADER";
262     return false;
263   }
264 
265   if (mGLContext->WorkAroundDriverBugs()) {
266     /**
267     * We'll test the ability here to bind NPOT textures to a framebuffer, if
268     * this fails we'll try ARB_texture_rectangle.
269     */
270 
271     GLenum textureTargets[] = {
272       LOCAL_GL_TEXTURE_2D,
273       LOCAL_GL_NONE
274     };
275 
276     if (!mGLContext->IsGLES()) {
277       // No TEXTURE_RECTANGLE_ARB available on ES2
278       textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
279     }
280 
281     mFBOTextureTarget = LOCAL_GL_NONE;
282 
283     GLuint testFBO = 0;
284     mGLContext->fGenFramebuffers(1, &testFBO);
285     GLuint testTexture = 0;
286 
287     for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
288       GLenum target = textureTargets[i];
289       if (!target)
290           continue;
291 
292       mGLContext->fGenTextures(1, &testTexture);
293       mGLContext->fBindTexture(target, testTexture);
294       mGLContext->fTexParameteri(target,
295                                 LOCAL_GL_TEXTURE_MIN_FILTER,
296                                 LOCAL_GL_NEAREST);
297       mGLContext->fTexParameteri(target,
298                                 LOCAL_GL_TEXTURE_MAG_FILTER,
299                                 LOCAL_GL_NEAREST);
300       mGLContext->fTexImage2D(target,
301                               0,
302                               LOCAL_GL_RGBA,
303                               5, 3, /* sufficiently NPOT */
304                               0,
305                               LOCAL_GL_RGBA,
306                               LOCAL_GL_UNSIGNED_BYTE,
307                               nullptr);
308 
309       // unbind this texture, in preparation for binding it to the FBO
310       mGLContext->fBindTexture(target, 0);
311 
312       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
313       mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
314                                         LOCAL_GL_COLOR_ATTACHMENT0,
315                                         target,
316                                         testTexture,
317                                         0);
318 
319       if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
320           LOCAL_GL_FRAMEBUFFER_COMPLETE)
321       {
322         mFBOTextureTarget = target;
323         mGLContext->fDeleteTextures(1, &testTexture);
324         break;
325       }
326 
327       mGLContext->fDeleteTextures(1, &testTexture);
328     }
329 
330     if (testFBO) {
331       mGLContext->fDeleteFramebuffers(1, &testFBO);
332     }
333 
334     if (mFBOTextureTarget == LOCAL_GL_NONE) {
335       /* Unable to find a texture target that works with FBOs and NPOT textures */
336       *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET";
337       return false;
338     }
339   } else {
340     // not trying to work around driver bugs, so TEXTURE_2D should just work
341     mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
342   }
343 
344   // back to default framebuffer, to avoid confusion
345   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
346 
347   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
348     /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
349      * extension -- the EXT variant does not provide support for
350      * texture rectangle access inside GLSL (sampler2DRect,
351      * texture2DRect).
352      */
353     if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){
354       *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
355       return false;
356     }
357   }
358 
359   // Create a VBO for triangle vertices.
360   mGLContext->fGenBuffers(1, &mTriangleVBO);
361 
362   /* Create a simple quad VBO */
363   mGLContext->fGenBuffers(1, &mQuadVBO);
364 
365   // 4 quads, with the number of the quad (vertexID) encoded in w.
366   GLfloat vertices[] = {
367     0.0f, 0.0f, 0.0f, 0.0f,
368     1.0f, 0.0f, 0.0f, 0.0f,
369     0.0f, 1.0f, 0.0f, 0.0f,
370     1.0f, 0.0f, 0.0f, 0.0f,
371     0.0f, 1.0f, 0.0f, 0.0f,
372     1.0f, 1.0f, 0.0f, 0.0f,
373 
374     0.0f, 0.0f, 0.0f, 1.0f,
375     1.0f, 0.0f, 0.0f, 1.0f,
376     0.0f, 1.0f, 0.0f, 1.0f,
377     1.0f, 0.0f, 0.0f, 1.0f,
378     0.0f, 1.0f, 0.0f, 1.0f,
379     1.0f, 1.0f, 0.0f, 1.0f,
380 
381     0.0f, 0.0f, 0.0f, 2.0f,
382     1.0f, 0.0f, 0.0f, 2.0f,
383     0.0f, 1.0f, 0.0f, 2.0f,
384     1.0f, 0.0f, 0.0f, 2.0f,
385     0.0f, 1.0f, 0.0f, 2.0f,
386     1.0f, 1.0f, 0.0f, 2.0f,
387 
388     0.0f, 0.0f, 0.0f, 3.0f,
389     1.0f, 0.0f, 0.0f, 3.0f,
390     0.0f, 1.0f, 0.0f, 3.0f,
391     1.0f, 0.0f, 0.0f, 3.0f,
392     0.0f, 1.0f, 0.0f, 3.0f,
393     1.0f, 1.0f, 0.0f, 3.0f,
394   };
395   HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
396 
397   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
398   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
399                           verticesOnHeap.ByteLength(),
400                           verticesOnHeap.Data(),
401                           LOCAL_GL_STATIC_DRAW);
402   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
403 
404   nsCOMPtr<nsIConsoleService>
405     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
406 
407   if (console) {
408     nsString msg;
409     msg +=
410       NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
411     msg += NS_ConvertUTF8toUTF16(
412       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
413     msg += NS_LITERAL_STRING("\nVendor: ");
414     msg += NS_ConvertUTF8toUTF16(
415       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
416     msg += NS_LITERAL_STRING("\nRenderer: ");
417     msg += NS_ConvertUTF8toUTF16(
418       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
419     msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
420     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
421       msg += NS_LITERAL_STRING("TEXTURE_2D");
422     else
423       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
424     console->LogStringMessage(msg.get());
425   }
426 
427   reporter.SetSuccessful();
428 
429   return true;
430 }
431 
432 /*
433  * Returns a size that is equal to, or larger than and closest to,
434  * aSize where both width and height are powers of two.
435  * If the OpenGL setup is capable of using non-POT textures,
436  * then it will just return aSize.
437  */
438 static IntSize
CalculatePOTSize(const IntSize & aSize,GLContext * gl)439 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
440 {
441   if (CanUploadNonPowerOfTwo(gl))
442     return aSize;
443 
444   return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height));
445 }
446 
447 gfx::Rect
GetTextureCoordinates(gfx::Rect textureRect,TextureSource * aTexture)448 CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect, TextureSource* aTexture)
449 {
450   // If the OpenGL setup does not support non-power-of-two textures then the
451   // texture's width and height will have been increased to the next
452   // power-of-two (unless already a power of two). In that case we must scale
453   // the texture coordinates to account for that.
454   if (!CanUploadNonPowerOfTwo(mGLContext)) {
455     const IntSize& textureSize = aTexture->GetSize();
456     const IntSize potSize = CalculatePOTSize(textureSize, mGLContext);
457     if (potSize != textureSize) {
458       const float xScale = (float)textureSize.width / (float)potSize.width;
459       const float yScale = (float)textureSize.height / (float)potSize.height;
460       textureRect.Scale(xScale, yScale);
461     }
462   }
463 
464   return textureRect;
465 }
466 
467 void
PrepareViewport(CompositingRenderTargetOGL * aRenderTarget)468 CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget)
469 {
470   MOZ_ASSERT(aRenderTarget);
471   // Logical surface size.
472   const gfx::IntSize& size = aRenderTarget->mInitParams.mSize;
473   // Physical surface size.
474   const gfx::IntSize& phySize = aRenderTarget->mInitParams.mPhySize;
475 
476   // Set the viewport correctly.
477   mGLContext->fViewport(0, 0, phySize.width, phySize.height);
478 
479   mViewportSize = size;
480 
481   if (!aRenderTarget->HasComplexProjection()) {
482     // We flip the view matrix around so that everything is right-side up; we're
483     // drawing directly into the window's back buffer, so this keeps things
484     // looking correct.
485     // XXX: We keep track of whether the window size changed, so we could skip
486     // this update if it hadn't changed since the last call.
487 
488     // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
489     // 2, 2) and flip the contents.
490     Matrix viewMatrix;
491     if (mGLContext->IsOffscreen() && !gIsGtest) {
492       // In case of rendering via GL Offscreen context, disable Y-Flipping
493       viewMatrix.PreTranslate(-1.0, -1.0);
494       viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
495     } else {
496       viewMatrix.PreTranslate(-1.0, 1.0);
497       viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height));
498       viewMatrix.PreScale(1.0f, -1.0f);
499     }
500 
501     MOZ_ASSERT(mCurrentRenderTarget, "No destination");
502     // If we're drawing directly to the window then we want to offset
503     // drawing by the render offset.
504     if (!mTarget && mCurrentRenderTarget->IsWindow()) {
505       viewMatrix.PreTranslate(mRenderOffset.x, mRenderOffset.y);
506     }
507 
508     Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
509     matrix3d._33 = 0.0f;
510     mProjMatrix = matrix3d;
511     mGLContext->fDepthRange(0.0f, 1.0f);
512   } else {
513     // XXX take into account mRenderOffset
514     bool depthEnable;
515     float zNear, zFar;
516     aRenderTarget->GetProjection(mProjMatrix, depthEnable, zNear, zFar);
517     mGLContext->fDepthRange(zNear, zFar);
518   }
519 }
520 
521 already_AddRefed<CompositingRenderTarget>
CreateRenderTarget(const IntRect & aRect,SurfaceInitMode aInit)522 CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
523 {
524   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
525 
526   if (aRect.width * aRect.height == 0) {
527     return nullptr;
528   }
529 
530   if (!gl()) {
531     // CompositingRenderTargetOGL does not work without a gl context.
532     return nullptr;
533   }
534 
535   GLuint tex = 0;
536   GLuint fbo = 0;
537   IntRect rect = aRect;
538   IntSize FBOSize;
539   CreateFBOWithTexture(rect, false, 0, &fbo, &tex, &FBOSize);
540   RefPtr<CompositingRenderTargetOGL> surface
541     = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
542   surface->Initialize(aRect.Size(), FBOSize, mFBOTextureTarget, aInit);
543   return surface.forget();
544 }
545 
546 already_AddRefed<CompositingRenderTarget>
CreateRenderTargetFromSource(const IntRect & aRect,const CompositingRenderTarget * aSource,const IntPoint & aSourcePoint)547 CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
548                                             const CompositingRenderTarget *aSource,
549                                             const IntPoint &aSourcePoint)
550 {
551   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
552 
553   if (aRect.width * aRect.height == 0) {
554     return nullptr;
555   }
556 
557   if (!gl()) {
558     return nullptr;
559   }
560 
561   GLuint tex = 0;
562   GLuint fbo = 0;
563   const CompositingRenderTargetOGL* sourceSurface
564     = static_cast<const CompositingRenderTargetOGL*>(aSource);
565   IntRect sourceRect(aSourcePoint, aRect.Size());
566   if (aSource) {
567     CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
568                          &fbo, &tex);
569   } else {
570     CreateFBOWithTexture(sourceRect, true, 0,
571                          &fbo, &tex);
572   }
573 
574   RefPtr<CompositingRenderTargetOGL> surface
575     = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
576   surface->Initialize(aRect.Size(),
577                       sourceRect.Size(),
578                       mFBOTextureTarget,
579                       INIT_MODE_NONE);
580   return surface.forget();
581 }
582 
583 void
SetRenderTarget(CompositingRenderTarget * aSurface)584 CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
585 {
586   MOZ_ASSERT(aSurface);
587   CompositingRenderTargetOGL* surface
588     = static_cast<CompositingRenderTargetOGL*>(aSurface);
589   if (mCurrentRenderTarget != surface) {
590     mCurrentRenderTarget = surface;
591     if (mCurrentRenderTarget) {
592       mContextStateTracker.PopOGLSection(gl(), "Frame");
593     }
594     mContextStateTracker.PushOGLSection(gl(), "Frame");
595     surface->BindRenderTarget();
596   }
597 
598   PrepareViewport(mCurrentRenderTarget);
599 }
600 
601 CompositingRenderTarget*
GetCurrentRenderTarget() const602 CompositorOGL::GetCurrentRenderTarget() const
603 {
604   return mCurrentRenderTarget;
605 }
606 
607 static GLenum
GetFrameBufferInternalFormat(GLContext * gl,GLuint aFrameBuffer,mozilla::widget::CompositorWidget * aWidget)608 GetFrameBufferInternalFormat(GLContext* gl,
609                              GLuint aFrameBuffer,
610                              mozilla::widget::CompositorWidget* aWidget)
611 {
612   if (aFrameBuffer == 0) { // default framebuffer
613     return aWidget->GetGLFrameBufferFormat();
614   }
615   return LOCAL_GL_RGBA;
616 }
617 
618 void
ClearRect(const gfx::Rect & aRect)619 CompositorOGL::ClearRect(const gfx::Rect& aRect)
620 {
621   // Map aRect to OGL coordinates, origin:bottom-left
622   GLint y = mViewportSize.height - (aRect.y + aRect.height);
623 
624   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
625   ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
626   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
627   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
628 }
629 
630 void
BeginFrame(const nsIntRegion & aInvalidRegion,const IntRect * aClipRectIn,const IntRect & aRenderBounds,const nsIntRegion & aOpaqueRegion,IntRect * aClipRectOut,IntRect * aRenderBoundsOut)631 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
632                           const IntRect *aClipRectIn,
633                           const IntRect& aRenderBounds,
634                           const nsIntRegion& aOpaqueRegion,
635                           IntRect *aClipRectOut,
636                           IntRect *aRenderBoundsOut)
637 {
638   PROFILER_LABEL("CompositorOGL", "BeginFrame",
639     js::ProfileEntry::Category::GRAPHICS);
640 
641   MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
642 
643   gfx::IntRect rect;
644   if (mUseExternalSurfaceSize) {
645     rect = gfx::IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
646   } else {
647     rect = gfx::IntRect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
648   }
649 
650   if (aRenderBoundsOut) {
651     *aRenderBoundsOut = rect;
652   }
653 
654   GLint width = rect.width;
655   GLint height = rect.height;
656 
657   // We can't draw anything to something with no area
658   // so just return
659   if (width == 0 || height == 0)
660     return;
661 
662   // We're about to actually draw a frame.
663   mFrameInProgress = true;
664 
665   // If the widget size changed, we have to force a MakeCurrent
666   // to make sure that GL sees the updated widget size.
667   if (mWidgetSize.width != width ||
668       mWidgetSize.height != height)
669   {
670     MakeCurrent(ForceMakeCurrent);
671 
672     mWidgetSize.width = width;
673     mWidgetSize.height = height;
674   } else {
675     MakeCurrent();
676   }
677 
678   mPixelsPerFrame = width * height;
679   mPixelsFilled = 0;
680 
681 #ifdef MOZ_WIDGET_ANDROID
682   TexturePoolOGL::Fill(gl());
683 #endif
684 
685   // Default blend function implements "OVER"
686   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
687                                  LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
688   mGLContext->fEnable(LOCAL_GL_BLEND);
689 
690   RefPtr<CompositingRenderTargetOGL> rt =
691     CompositingRenderTargetOGL::RenderTargetForWindow(this,
692                                                       IntSize(width, height));
693   SetRenderTarget(rt);
694 
695 #ifdef DEBUG
696   mWindowRenderTarget = mCurrentRenderTarget;
697 #endif
698 
699   if (aClipRectOut && !aClipRectIn) {
700     aClipRectOut->SetRect(0, 0, width, height);
701   }
702 
703   mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a);
704   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
705 }
706 
707 void
CreateFBOWithTexture(const gfx::IntRect & aRect,bool aCopyFromSource,GLuint aSourceFrameBuffer,GLuint * aFBO,GLuint * aTexture,gfx::IntSize * aAllocSize)708 CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect,
709                                     bool aCopyFromSource,
710                                     GLuint aSourceFrameBuffer,
711                                     GLuint *aFBO, GLuint *aTexture,
712                                     gfx::IntSize* aAllocSize)
713 {
714   *aTexture = CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer,
715                             aAllocSize);
716   mGLContext->fGenFramebuffers(1, aFBO);
717 }
718 
719 GLuint
CreateTexture(const IntRect & aRect,bool aCopyFromSource,GLuint aSourceFrameBuffer,IntSize * aAllocSize)720 CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource,
721                              GLuint aSourceFrameBuffer, IntSize* aAllocSize)
722 {
723   // we're about to create a framebuffer backed by textures to use as an intermediate
724   // surface. What to do if its size (as given by aRect) would exceed the
725   // maximum texture size supported by the GL? The present code chooses the compromise
726   // of just clamping the framebuffer's size to the max supported size.
727   // This gives us a lower resolution rendering of the intermediate surface (children layers).
728   // See bug 827170 for a discussion.
729   IntRect clampedRect = aRect;
730   int32_t maxTexSize = GetMaxTextureSize();
731   clampedRect.width = std::min(clampedRect.width, maxTexSize);
732   clampedRect.height = std::min(clampedRect.height, maxTexSize);
733 
734   GLuint tex;
735 
736   mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
737   mGLContext->fGenTextures(1, &tex);
738   mGLContext->fBindTexture(mFBOTextureTarget, tex);
739 
740   if (aCopyFromSource) {
741     GLuint curFBO = mCurrentRenderTarget->GetFBO();
742     if (curFBO != aSourceFrameBuffer) {
743       mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
744     }
745 
746     // We're going to create an RGBA temporary fbo.  But to
747     // CopyTexImage() from the current framebuffer, the framebuffer's
748     // format has to be compatible with the new texture's.  So we
749     // check the format of the framebuffer here and take a slow path
750     // if it's incompatible.
751     GLenum format =
752       GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
753 
754     bool isFormatCompatibleWithRGBA
755         = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
756                           : true;
757 
758     if (isFormatCompatibleWithRGBA) {
759       mGLContext->fCopyTexImage2D(mFBOTextureTarget,
760                                   0,
761                                   LOCAL_GL_RGBA,
762                                   clampedRect.x, FlipY(clampedRect.y + clampedRect.height),
763                                   clampedRect.width, clampedRect.height,
764                                   0);
765     } else {
766       // Curses, incompatible formats.  Take a slow path.
767 
768       // RGBA
769       size_t bufferSize = clampedRect.width * clampedRect.height * 4;
770       auto buf = MakeUnique<uint8_t[]>(bufferSize);
771 
772       mGLContext->fReadPixels(clampedRect.x, clampedRect.y,
773                               clampedRect.width, clampedRect.height,
774                               LOCAL_GL_RGBA,
775                               LOCAL_GL_UNSIGNED_BYTE,
776                               buf.get());
777       mGLContext->fTexImage2D(mFBOTextureTarget,
778                               0,
779                               LOCAL_GL_RGBA,
780                               clampedRect.width, clampedRect.height,
781                               0,
782                               LOCAL_GL_RGBA,
783                               LOCAL_GL_UNSIGNED_BYTE,
784                               buf.get());
785     }
786 
787     GLenum error = mGLContext->fGetError();
788     if (error != LOCAL_GL_NO_ERROR) {
789       nsAutoCString msg;
790       msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d,  RGBA Compat %d",
791                        error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
792       NS_ERROR(msg.get());
793     }
794   } else {
795     mGLContext->fTexImage2D(mFBOTextureTarget,
796                             0,
797                             LOCAL_GL_RGBA,
798                             clampedRect.width, clampedRect.height,
799                             0,
800                             LOCAL_GL_RGBA,
801                             LOCAL_GL_UNSIGNED_BYTE,
802                             nullptr);
803   }
804   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
805                              LOCAL_GL_LINEAR);
806   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
807                              LOCAL_GL_LINEAR);
808   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
809                              LOCAL_GL_CLAMP_TO_EDGE);
810   mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
811                              LOCAL_GL_CLAMP_TO_EDGE);
812   mGLContext->fBindTexture(mFBOTextureTarget, 0);
813 
814   if (aAllocSize) {
815     aAllocSize->width = clampedRect.width;
816     aAllocSize->height = clampedRect.height;
817   }
818 
819   return tex;
820 }
821 
822 ShaderConfigOGL
GetShaderConfigFor(Effect * aEffect,MaskType aMask,gfx::CompositionOp aOp,bool aColorMatrix,bool aDEAAEnabled) const823 CompositorOGL::GetShaderConfigFor(Effect *aEffect,
824                                   MaskType aMask,
825                                   gfx::CompositionOp aOp,
826                                   bool aColorMatrix,
827                                   bool aDEAAEnabled) const
828 {
829   ShaderConfigOGL config;
830 
831   switch(aEffect->mType) {
832   case EffectTypes::SOLID_COLOR:
833     config.SetRenderColor(true);
834     break;
835   case EffectTypes::YCBCR:
836     config.SetYCbCr(true);
837     break;
838   case EffectTypes::NV12:
839     config.SetNV12(true);
840     config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB);
841     break;
842   case EffectTypes::COMPONENT_ALPHA:
843   {
844     config.SetComponentAlpha(true);
845     EffectComponentAlpha* effectComponentAlpha =
846       static_cast<EffectComponentAlpha*>(aEffect);
847     gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
848     config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
849                      format == gfx::SurfaceFormat::B8G8R8X8);
850     TextureSourceOGL* source = effectComponentAlpha->mOnWhite->AsSourceOGL();
851     config.SetTextureTarget(source->GetTextureTarget());
852     break;
853   }
854   case EffectTypes::RENDER_TARGET:
855     config.SetTextureTarget(mFBOTextureTarget);
856     break;
857   default:
858   {
859     MOZ_ASSERT(aEffect->mType == EffectTypes::RGB);
860     TexturedEffect* texturedEffect =
861         static_cast<TexturedEffect*>(aEffect);
862     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
863     MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
864                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
865                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8);
866     MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
867                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
868                   source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
869                   source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16 ||
870                   source->GetFormat() == gfx::SurfaceFormat::YUV422 );
871     config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
872                                              source->GetFormat());
873     if (!texturedEffect->mPremultiplied) {
874       config.SetNoPremultipliedAlpha();
875     }
876     break;
877   }
878   }
879   config.SetColorMatrix(aColorMatrix);
880   config.SetMask(aMask == MaskType::Mask);
881   config.SetDEAA(aDEAAEnabled);
882   config.SetCompositionOp(aOp);
883   return config;
884 }
885 
886 ShaderProgramOGL*
GetShaderProgramFor(const ShaderConfigOGL & aConfig)887 CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
888 {
889   std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
890   if (iter != mPrograms.end())
891     return iter->second;
892 
893   ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
894   ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
895   if (!shader->Initialize()) {
896     delete shader;
897     return nullptr;
898   }
899 
900   mPrograms[aConfig] = shader;
901   return shader;
902 }
903 
904 void
ActivateProgram(ShaderProgramOGL * aProg)905 CompositorOGL::ActivateProgram(ShaderProgramOGL* aProg)
906 {
907   if (mCurrentProgram != aProg) {
908     gl()->fUseProgram(aProg->GetProgram());
909     mCurrentProgram = aProg;
910   }
911 }
912 
913 void
ResetProgram()914 CompositorOGL::ResetProgram()
915 {
916   mCurrentProgram = nullptr;
917 }
918 
SetBlendMode(GLContext * aGL,gfx::CompositionOp aBlendMode,bool aIsPremultiplied=true)919 static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true)
920 {
921   if (BlendOpIsMixBlendMode(aBlendMode)) {
922     // Mix-blend modes require an extra step (or more) that cannot be expressed
923     // in the fixed-function blending capabilities of opengl. We handle them
924     // separately in shaders, and the shaders assume we will use our default
925     // blend function for compositing (premultiplied OP_OVER).
926     return false;
927   }
928   if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
929     return false;
930   }
931 
932   GLenum srcBlend;
933   GLenum dstBlend;
934   GLenum srcAlphaBlend = LOCAL_GL_ONE;
935   GLenum dstAlphaBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
936 
937   switch (aBlendMode) {
938     case gfx::CompositionOp::OP_OVER:
939       MOZ_ASSERT(!aIsPremultiplied);
940       srcBlend = LOCAL_GL_SRC_ALPHA;
941       dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA;
942       break;
943     case gfx::CompositionOp::OP_SOURCE:
944       srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA;
945       dstBlend = LOCAL_GL_ZERO;
946       srcAlphaBlend = LOCAL_GL_ONE;
947       dstAlphaBlend = LOCAL_GL_ZERO;
948       break;
949     default:
950       MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!");
951       return false;
952   }
953 
954   aGL->fBlendFuncSeparate(srcBlend, dstBlend,
955                           srcAlphaBlend, dstAlphaBlend);
956   return true;
957 }
958 
959 gfx::Point3D
GetLineCoefficients(const gfx::Point & aPoint1,const gfx::Point & aPoint2)960 CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1,
961                                    const gfx::Point& aPoint2)
962 {
963   // Return standard coefficients for a line between aPoint1 and aPoint2
964   // for standard line equation:
965   //
966   // Ax + By + C = 0
967   //
968   // A = (p1.y – p2.y)
969   // B = (p2.x – p1.x)
970   // C = (p1.x * p2.y) – (p2.x * p1.y)
971 
972   gfx::Point3D coeffecients;
973   coeffecients.x = aPoint1.y - aPoint2.y;
974   coeffecients.y = aPoint2.x - aPoint1.x;
975   coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y;
976 
977   coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x +
978                                coeffecients.y * coeffecients.y);
979 
980   // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel
981   // wide and included within the interior of the polygon
982   coeffecients.z += 0.5f;
983 
984   return coeffecients;
985 }
986 
987 void
DrawQuad(const Rect & aRect,const IntRect & aClipRect,const EffectChain & aEffectChain,Float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::Rect & aVisibleRect)988 CompositorOGL::DrawQuad(const Rect& aRect,
989                         const IntRect& aClipRect,
990                         const EffectChain &aEffectChain,
991                         Float aOpacity,
992                         const gfx::Matrix4x4& aTransform,
993                         const gfx::Rect& aVisibleRect)
994 {
995   PROFILER_LABEL("CompositorOGL", "DrawQuad",
996     js::ProfileEntry::Category::GRAPHICS);
997 
998   DrawGeometry(aRect, aClipRect, aEffectChain,
999                aOpacity, aTransform, aVisibleRect);
1000 }
1001 
1002 void
DrawTriangle(const gfx::TexturedTriangle & aTriangle,const gfx::IntRect & aClipRect,const EffectChain & aEffectChain,gfx::Float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::Rect & aVisibleRect)1003 CompositorOGL::DrawTriangle(const gfx::TexturedTriangle& aTriangle,
1004                             const gfx::IntRect& aClipRect,
1005                             const EffectChain& aEffectChain,
1006                             gfx::Float aOpacity,
1007                             const gfx::Matrix4x4& aTransform,
1008                             const gfx::Rect& aVisibleRect)
1009 {
1010   PROFILER_LABEL("CompositorOGL", "DrawTriangle",
1011     js::ProfileEntry::Category::GRAPHICS);
1012 
1013   DrawGeometry(aTriangle, aClipRect, aEffectChain,
1014                aOpacity, aTransform, aVisibleRect);
1015 }
1016 
1017 template<typename Geometry>
1018 void
DrawGeometry(const Geometry & aGeometry,const IntRect & aClipRect,const EffectChain & aEffectChain,Float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::Rect & aVisibleRect)1019 CompositorOGL::DrawGeometry(const Geometry& aGeometry,
1020                             const IntRect& aClipRect,
1021                             const EffectChain &aEffectChain,
1022                             Float aOpacity,
1023                             const gfx::Matrix4x4& aTransform,
1024                             const gfx::Rect& aVisibleRect)
1025 {
1026   MOZ_ASSERT(mFrameInProgress, "frame not started");
1027   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
1028 
1029   MakeCurrent();
1030 
1031   IntPoint offset = mCurrentRenderTarget->GetOrigin();
1032   IntSize size = mCurrentRenderTarget->GetSize();
1033 
1034   Rect renderBound(0, 0, size.width, size.height);
1035   renderBound.IntersectRect(renderBound, Rect(aClipRect));
1036   renderBound.MoveBy(offset);
1037 
1038   Rect destRect = aTransform.TransformAndClipBounds(aGeometry, renderBound);
1039 
1040   // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
1041   //      quads. Fix me.
1042   mPixelsFilled += destRect.width * destRect.height;
1043 
1044   // Do a simple culling if this rect is out of target buffer.
1045   // Inflate a small size to avoid some numerical imprecision issue.
1046   destRect.Inflate(1, 1);
1047   destRect.MoveBy(-offset);
1048   renderBound = Rect(0, 0, size.width, size.height);
1049   if (!renderBound.Intersects(destRect)) {
1050     return;
1051   }
1052 
1053   LayerScope::DrawBegin();
1054 
1055   IntRect clipRect = aClipRect;
1056   // aClipRect is in destination coordinate space (after all
1057   // transforms and offsets have been applied) so if our
1058   // drawing is going to be shifted by mRenderOffset then we need
1059   // to shift the clip rect by the same amount.
1060   if (!mTarget && mCurrentRenderTarget->IsWindow()) {
1061     clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
1062   }
1063 
1064   ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
1065   ScopedScissorRect autoScissorRect(mGLContext, clipRect.x, FlipY(clipRect.y + clipRect.height),
1066                                     clipRect.width, clipRect.height);
1067 
1068   MaskType maskType;
1069   EffectMask* effectMask;
1070   TextureSourceOGL* sourceMask = nullptr;
1071   gfx::Matrix4x4 maskQuadTransform;
1072   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
1073     effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
1074     sourceMask = effectMask->mMaskTexture->AsSourceOGL();
1075 
1076     // NS_ASSERTION(textureMask->IsAlpha(),
1077     //              "OpenGL mask layers must be backed by alpha surfaces");
1078 
1079     // We're assuming that the gl backend won't cheat and use NPOT
1080     // textures when glContext says it can't (which seems to happen
1081     // on a mac when you force POT textures)
1082     IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
1083 
1084     const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
1085     NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
1086     Rect bounds = Rect(Point(), Size(maskSize));
1087     bounds = maskTransform.As2D().TransformBounds(bounds);
1088 
1089     maskQuadTransform._11 = 1.0f/bounds.width;
1090     maskQuadTransform._22 = 1.0f/bounds.height;
1091     maskQuadTransform._41 = float(-bounds.x)/bounds.width;
1092     maskQuadTransform._42 = float(-bounds.y)/bounds.height;
1093 
1094     maskType = MaskType::Mask;
1095   } else {
1096     maskType = MaskType::MaskNone;
1097   }
1098 
1099   // Determine the color if this is a color shader and fold the opacity into
1100   // the color since color shaders don't have an opacity uniform.
1101   Color color;
1102   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::SOLID_COLOR) {
1103     EffectSolidColor* effectSolidColor =
1104       static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
1105     color = effectSolidColor->mColor;
1106 
1107     Float opacity = aOpacity * color.a;
1108     color.r *= opacity;
1109     color.g *= opacity;
1110     color.b *= opacity;
1111     color.a = opacity;
1112 
1113     // We can fold opacity into the color, so no need to consider it further.
1114     aOpacity = 1.f;
1115   }
1116 
1117   bool createdMixBlendBackdropTexture = false;
1118   GLuint mixBlendBackdrop = 0;
1119   gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
1120 
1121   if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
1122     EffectBlendMode *blendEffect =
1123       static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
1124     blendMode = blendEffect->mBlendMode;
1125   }
1126 
1127   // Only apply DEAA to quads that have been transformed such that aliasing
1128   // could be visible
1129   bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
1130                    !aTransform.Is2DIntegerTranslation();
1131 
1132   bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
1133   ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect,
1134                                               maskType, blendMode, colorMatrix,
1135                                               bEnableAA);
1136 
1137   config.SetOpacity(aOpacity != 1.f);
1138   ApplyPrimitiveConfig(config, aGeometry);
1139 
1140   ShaderProgramOGL *program = GetShaderProgramFor(config);
1141   ActivateProgram(program);
1142   program->SetProjectionMatrix(mProjMatrix);
1143   program->SetLayerTransform(aTransform);
1144   LayerScope::SetLayerTransform(aTransform);
1145 
1146   if (colorMatrix) {
1147       EffectColorMatrix* effectColorMatrix =
1148         static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
1149       program->SetColorMatrix(effectColorMatrix->mColorMatrix);
1150   }
1151 
1152   if (BlendOpIsMixBlendMode(blendMode)) {
1153     gfx::Matrix4x4 backdropTransform;
1154 
1155     if (gl()->IsExtensionSupported(GLContext::NV_texture_barrier)) {
1156       // The NV_texture_barrier extension lets us read directly from the
1157       // backbuffer. Let's do that.
1158       // We need to tell OpenGL about this, so that it can make sure everything
1159       // on the GPU is happening in the right order.
1160       gl()->fTextureBarrier();
1161       mixBlendBackdrop = mCurrentRenderTarget->GetTextureHandle();
1162     } else {
1163       gfx::IntRect rect = ComputeBackdropCopyRect(aGeometry, aClipRect,
1164                                                   aTransform, &backdropTransform);
1165       mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
1166       createdMixBlendBackdropTexture = true;
1167     }
1168     program->SetBackdropTransform(backdropTransform);
1169   }
1170 
1171   program->SetRenderOffset(offset.x, offset.y);
1172   LayerScope::SetRenderOffset(offset.x, offset.y);
1173 
1174   if (aOpacity != 1.f)
1175     program->SetLayerOpacity(aOpacity);
1176 
1177   if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1178     TextureSourceOGL* source = nullptr;
1179     if (aEffectChain.mPrimaryEffect->mType == EffectTypes::COMPONENT_ALPHA) {
1180       EffectComponentAlpha* effectComponentAlpha =
1181         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1182       source = effectComponentAlpha->mOnWhite->AsSourceOGL();
1183     } else {
1184       TexturedEffect* texturedEffect =
1185         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
1186       source = texturedEffect->mTexture->AsSourceOGL();
1187     }
1188     // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
1189     program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
1190   }
1191 
1192   // XXX kip - These calculations could be performed once per layer rather than
1193   //           for every tile.  This might belong in Compositor.cpp once DEAA
1194   //           is implemented for DirectX.
1195   if (bEnableAA) {
1196     // Calculate the transformed vertices of aVisibleRect in screen space
1197     // pixels, mirroring the calculations in the vertex shader
1198     Matrix4x4 flatTransform = aTransform;
1199     flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f);
1200     flatTransform *= mProjMatrix;
1201 
1202     Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f);
1203     size_t edgeCount = 0;
1204     Point3D coefficients[4];
1205 
1206     Point points[Matrix4x4::kTransformAndClipRectMaxVerts];
1207     size_t pointCount = flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points);
1208     for (size_t i = 0; i < pointCount; i++) {
1209       points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width,
1210                         (points[i].y * 0.5f + 0.5f) * mViewportSize.height);
1211     }
1212     if (pointCount > 2) {
1213       // Use shoelace formula on a triangle in the clipped quad to determine if
1214       // winding order is reversed.  Iterate through the triangles until one is
1215       // found with a non-zero area.
1216       float winding = 0.0f;
1217       size_t wp = 0;
1218       while (winding == 0.0f && wp < pointCount) {
1219         int wp1 = (wp + 1) % pointCount;
1220         int wp2 = (wp + 2) % pointCount;
1221         winding = (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) +
1222                   (points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) +
1223                   (points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y);
1224         wp++;
1225       }
1226       bool frontFacing = winding >= 0.0f;
1227 
1228       // Calculate the line coefficients used by the DEAA shader to determine the
1229       // sub-pixel coverage of the edge pixels
1230       for (size_t i=0; i<pointCount; i++) {
1231         const Point& p1 = points[i];
1232         const Point& p2 = points[(i + 1) % pointCount];
1233         // Create a DEAA edge for any non-straight lines, to a maximum of 4
1234         if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) {
1235           if (frontFacing) {
1236             coefficients[edgeCount++] = GetLineCoefficients(p2, p1);
1237           } else {
1238             coefficients[edgeCount++] = GetLineCoefficients(p1, p2);
1239           }
1240         }
1241       }
1242     }
1243 
1244     // The coefficients that are not needed must not cull any fragments.
1245     // We fill these unused coefficients with a clipping plane that has no
1246     // effect.
1247     for (size_t i = edgeCount; i < 4; i++) {
1248       coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height);
1249     }
1250 
1251     // Set uniforms required by DEAA shader
1252     Matrix4x4 transformInverted = aTransform;
1253     transformInverted.Invert();
1254     program->SetLayerTransformInverse(transformInverted);
1255     program->SetDEAAEdges(coefficients);
1256     program->SetVisibleCenter(aVisibleRect.Center());
1257     program->SetViewportSize(mViewportSize);
1258   }
1259 
1260   bool didSetBlendMode = false;
1261 
1262   switch (aEffectChain.mPrimaryEffect->mType) {
1263     case EffectTypes::SOLID_COLOR: {
1264       program->SetRenderColor(color);
1265 
1266       if (maskType != MaskType::MaskNone) {
1267         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
1268       }
1269       if (mixBlendBackdrop) {
1270         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1);
1271       }
1272 
1273       didSetBlendMode = SetBlendMode(gl(), blendMode);
1274 
1275       BindAndDrawGeometry(program, aGeometry);
1276     }
1277     break;
1278 
1279   case EffectTypes::RGB: {
1280       TexturedEffect* texturedEffect =
1281           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
1282       TextureSource *source = texturedEffect->mTexture;
1283 
1284       didSetBlendMode = SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied);
1285 
1286       gfx::SamplingFilter samplingFilter = texturedEffect->mSamplingFilter;
1287 
1288       source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, samplingFilter);
1289 
1290       program->SetTextureUnit(0);
1291 
1292       Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform();
1293       program->SetTextureTransform(textureTransform);
1294 
1295       if (maskType != MaskType::MaskNone) {
1296         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
1297       }
1298       if (mixBlendBackdrop) {
1299         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
1300       }
1301 
1302       BindAndDrawGeometryWithTextureRect(program, aGeometry,
1303                                          texturedEffect->mTextureCoords, source);
1304     }
1305     break;
1306   case EffectTypes::YCBCR: {
1307       EffectYCbCr* effectYCbCr =
1308         static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
1309       TextureSource* sourceYCbCr = effectYCbCr->mTexture;
1310       const int Y = 0, Cb = 1, Cr = 2;
1311       TextureSourceOGL* sourceY =  sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
1312       TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
1313       TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
1314 
1315       if (!sourceY || !sourceCb || !sourceCr) {
1316         NS_WARNING("Invalid layer texture.");
1317         return;
1318       }
1319 
1320       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mSamplingFilter);
1321       sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mSamplingFilter);
1322       sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mSamplingFilter);
1323 
1324       program->SetYCbCrTextureUnits(Y, Cb, Cr);
1325       program->SetTextureTransform(Matrix4x4());
1326       program->SetYUVColorSpace(effectYCbCr->mYUVColorSpace);
1327 
1328       if (maskType != MaskType::MaskNone) {
1329         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
1330       }
1331       if (mixBlendBackdrop) {
1332         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4);
1333       }
1334       didSetBlendMode = SetBlendMode(gl(), blendMode);
1335       BindAndDrawGeometryWithTextureRect(program,
1336                                          aGeometry,
1337                                          effectYCbCr->mTextureCoords,
1338                                          sourceYCbCr->GetSubSource(Y));
1339     }
1340     break;
1341   case EffectTypes::NV12: {
1342       EffectNV12* effectNV12 =
1343         static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get());
1344       TextureSource* sourceNV12 = effectNV12->mTexture;
1345       const int Y = 0, CbCr = 1;
1346       TextureSourceOGL* sourceY =  sourceNV12->GetSubSource(Y)->AsSourceOGL();
1347       TextureSourceOGL* sourceCbCr = sourceNV12->GetSubSource(CbCr)->AsSourceOGL();
1348 
1349       if (!sourceY || !sourceCbCr) {
1350         NS_WARNING("Invalid layer texture.");
1351         return;
1352       }
1353 
1354       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectNV12->mSamplingFilter);
1355       sourceCbCr->BindTexture(LOCAL_GL_TEXTURE1, effectNV12->mSamplingFilter);
1356 
1357       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1358         // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
1359         program->SetCbCrTexCoordMultiplier(sourceCbCr->GetSize().width, sourceCbCr->GetSize().height);
1360       }
1361 
1362       program->SetNV12TextureUnits(Y, CbCr);
1363       program->SetTextureTransform(Matrix4x4());
1364 
1365       if (maskType != MaskType::MaskNone) {
1366         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
1367       }
1368       if (mixBlendBackdrop) {
1369         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3);
1370       }
1371       didSetBlendMode = SetBlendMode(gl(), blendMode);
1372       BindAndDrawGeometryWithTextureRect(program,
1373                                          aGeometry,
1374                                          effectNV12->mTextureCoords,
1375                                          sourceNV12->GetSubSource(Y));
1376     }
1377     break;
1378   case EffectTypes::RENDER_TARGET: {
1379       EffectRenderTarget* effectRenderTarget =
1380         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
1381       RefPtr<CompositingRenderTargetOGL> surface
1382         = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
1383 
1384       surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
1385 
1386       // Drawing is always flipped, but when copying between surfaces we want to avoid
1387       // this, so apply a flip here to cancel the other one out.
1388       Matrix transform;
1389       transform.PreTranslate(0.0, 1.0);
1390       transform.PreScale(1.0f, -1.0f);
1391       program->SetTextureTransform(Matrix4x4::From2D(transform));
1392       program->SetTextureUnit(0);
1393 
1394       if (maskType != MaskType::MaskNone) {
1395         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
1396       }
1397       if (mixBlendBackdrop) {
1398         BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2);
1399       }
1400 
1401       if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1402         // 2DRect case, get the multiplier right for a sampler2DRect
1403         program->SetTexCoordMultiplier(surface->GetSize().width,
1404                                        surface->GetSize().height);
1405       }
1406 
1407       // Drawing is always flipped, but when copying between surfaces we want to avoid
1408       // this. Pass true for the flip parameter to introduce a second flip
1409       // that cancels the other one out.
1410       didSetBlendMode = SetBlendMode(gl(), blendMode);
1411       BindAndDrawGeometry(program, aGeometry);
1412     }
1413     break;
1414   case EffectTypes::COMPONENT_ALPHA: {
1415       MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
1416       MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER, "Can't support blend modes with component alpha!");
1417       EffectComponentAlpha* effectComponentAlpha =
1418         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1419       TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
1420       TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
1421 
1422       if (!sourceOnBlack->IsValid() ||
1423           !sourceOnWhite->IsValid()) {
1424         NS_WARNING("Invalid layer texture for component alpha");
1425         return;
1426       }
1427 
1428       sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mSamplingFilter);
1429       sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mSamplingFilter);
1430 
1431       program->SetBlackTextureUnit(0);
1432       program->SetWhiteTextureUnit(1);
1433       program->SetTextureTransform(Matrix4x4());
1434 
1435       if (maskType != MaskType::MaskNone) {
1436         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
1437       }
1438       // Pass 1.
1439       gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
1440                                LOCAL_GL_ONE, LOCAL_GL_ONE);
1441       program->SetTexturePass2(false);
1442       BindAndDrawGeometryWithTextureRect(program,
1443                                          aGeometry,
1444                                          effectComponentAlpha->mTextureCoords,
1445                                          effectComponentAlpha->mOnBlack);
1446 
1447       // Pass 2.
1448       gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
1449                                LOCAL_GL_ONE, LOCAL_GL_ONE);
1450       program->SetTexturePass2(true);
1451       BindAndDrawGeometryWithTextureRect(program,
1452                                          aGeometry,
1453                                          effectComponentAlpha->mTextureCoords,
1454                                          effectComponentAlpha->mOnBlack);
1455 
1456       mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1457                                      LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1458     }
1459     break;
1460   default:
1461     MOZ_ASSERT(false, "Unhandled effect type");
1462     break;
1463   }
1464 
1465   if (didSetBlendMode) {
1466     gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1467                              LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
1468   }
1469   if (createdMixBlendBackdropTexture) {
1470     gl()->fDeleteTextures(1, &mixBlendBackdrop);
1471   }
1472 
1473   // in case rendering has used some other GL context
1474   MakeCurrent();
1475 
1476   LayerScope::DrawEnd(mGLContext, aEffectChain,
1477                       aGeometry.width, aGeometry.height);
1478 }
1479 
1480 void
BindAndDrawGeometry(ShaderProgramOGL * aProgram,const gfx::Rect & aRect,const gfx::Rect & aTextureRect)1481 CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
1482                                    const gfx::Rect& aRect,
1483                                    const gfx::Rect& aTextureRect)
1484 {
1485   BindAndDrawQuad(aProgram, aRect, aTextureRect);
1486 }
1487 
1488 void
BindAndDrawGeometry(ShaderProgramOGL * aProgram,const gfx::TexturedTriangle & aTriangle,const gfx::Rect & aTextureRect)1489 CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram,
1490                                    const gfx::TexturedTriangle& aTriangle,
1491                                    const gfx::Rect& aTextureRect)
1492 {
1493   NS_ASSERTION(aProgram->HasInitialized(), "Shader program not correctly initialized");
1494 
1495   const gfx::TexturedTriangle& t = aTriangle;
1496   const gfx::Triangle& tex = t.textureCoords;
1497 
1498   GLfloat vertices[] = {
1499     t.p1.x, t.p1.y, 0.0f, 1.0f, tex.p1.x, tex.p1.y,
1500     t.p2.x, t.p2.y, 0.0f, 1.0f, tex.p2.x, tex.p2.y,
1501     t.p3.x, t.p3.y, 0.0f, 1.0f, tex.p3.x, tex.p3.y
1502   };
1503 
1504   HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
1505   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO);
1506   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
1507                           verticesOnHeap.ByteLength(),
1508                           verticesOnHeap.Data(),
1509                           LOCAL_GL_STREAM_DRAW);
1510 
1511   const GLsizei stride = 6 * sizeof(GLfloat);
1512   InitializeVAO(kCoordinateAttributeIndex, 4, stride, 0);
1513   InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 4 * sizeof(GLfloat));
1514 
1515   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 3);
1516 
1517   mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
1518   mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex);
1519   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1520 }
1521 
1522 // |aRect| is the rectangle we want to draw to. We will draw it with
1523 // up to 4 draw commands if necessary to avoid wrapping.
1524 // |aTexCoordRect| is the rectangle from the texture that we want to
1525 // draw using the given program.
1526 // |aTexture| is the texture we are drawing. Its actual size can be
1527 // larger than the rectangle given by |texCoordRect|.
1528 void
BindAndDrawGeometryWithTextureRect(ShaderProgramOGL * aProg,const Rect & aRect,const Rect & aTexCoordRect,TextureSource * aTexture)1529 CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
1530                                                   const Rect& aRect,
1531                                                   const Rect& aTexCoordRect,
1532                                                   TextureSource *aTexture)
1533 {
1534   Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture);
1535   Rect layerRects[4];
1536   Rect textureRects[4];
1537   size_t rects = DecomposeIntoNoRepeatRects(aRect,
1538                                             scaledTexCoordRect,
1539                                             &layerRects,
1540                                             &textureRects);
1541 
1542   BindAndDrawQuads(aProg, rects, layerRects, textureRects);
1543 }
1544 
1545 void
BindAndDrawGeometryWithTextureRect(ShaderProgramOGL * aProg,const gfx::TexturedTriangle & aTriangle,const gfx::Rect & aTexCoordRect,TextureSource * aTexture)1546 CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg,
1547                                                   const gfx::TexturedTriangle& aTriangle,
1548                                                   const gfx::Rect& aTexCoordRect,
1549                                                   TextureSource *aTexture)
1550 {
1551   BindAndDrawGeometry(aProg, aTriangle,
1552                       GetTextureCoordinates(aTexCoordRect, aTexture));
1553 }
1554 
1555 void
BindAndDrawQuads(ShaderProgramOGL * aProg,int aQuads,const Rect * aLayerRects,const Rect * aTextureRects)1556 CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
1557                                 int aQuads,
1558                                 const Rect* aLayerRects,
1559                                 const Rect* aTextureRects)
1560 {
1561   NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
1562 
1563   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
1564   InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0);
1565 
1566   aProg->SetLayerRects(aLayerRects);
1567   if (aProg->GetTextureCount() > 0) {
1568     aProg->SetTextureRects(aTextureRects);
1569   }
1570 
1571   // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly
1572   // process uniform arrays with GL_TRIANGLE_STRIP. Go figure.
1573   mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads);
1574   mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex);
1575   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1576   LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects);
1577 }
1578 
1579 void
InitializeVAO(const GLuint aAttrib,const GLint aComponents,const GLsizei aStride,const size_t aOffset)1580 CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents,
1581                              const GLsizei aStride, const size_t aOffset)
1582 {
1583   mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT,
1584                                    LOCAL_GL_FALSE, aStride,
1585                                    reinterpret_cast<GLvoid*>(aOffset));
1586   mGLContext->fEnableVertexAttribArray(aAttrib);
1587 }
1588 
1589 void
EndFrame()1590 CompositorOGL::EndFrame()
1591 {
1592   PROFILER_LABEL("CompositorOGL", "EndFrame",
1593     js::ProfileEntry::Category::GRAPHICS);
1594 
1595   MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
1596 
1597 #ifdef MOZ_DUMP_PAINTING
1598   if (gfxEnv::DumpCompositorTextures()) {
1599     LayoutDeviceIntSize size;
1600     if (mUseExternalSurfaceSize) {
1601       size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height);
1602     } else {
1603       size = mWidget->GetClientSize();
1604     }
1605     RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
1606     if (target) {
1607       CopyToTarget(target, nsIntPoint(), Matrix());
1608       WriteSnapshotToDumpFile(this, target);
1609     }
1610   }
1611 #endif
1612 
1613   mContextStateTracker.PopOGLSection(gl(), "Frame");
1614 
1615   mFrameInProgress = false;
1616 
1617   if (mTarget) {
1618     CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix());
1619     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1620     mCurrentRenderTarget = nullptr;
1621     Compositor::EndFrame();
1622     return;
1623   }
1624 
1625   mCurrentRenderTarget = nullptr;
1626 
1627   if (mTexturePool) {
1628     mTexturePool->EndFrame();
1629   }
1630 
1631   mGLContext->SwapBuffers();
1632   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1633 
1634   // Unbind all textures
1635   for (GLuint i = 0; i <= 4; i++) {
1636     mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
1637     mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
1638     if (!mGLContext->IsGLES()) {
1639       mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
1640     }
1641   }
1642 
1643   Compositor::EndFrame();
1644 }
1645 
1646 void
EndFrameForExternalComposition(const gfx::Matrix & aTransform)1647 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
1648 {
1649   MOZ_ASSERT(!mTarget);
1650   if (mTexturePool) {
1651     mTexturePool->EndFrame();
1652   }
1653 }
1654 
1655 void
SetDestinationSurfaceSize(const IntSize & aSize)1656 CompositorOGL::SetDestinationSurfaceSize(const IntSize& aSize)
1657 {
1658   mSurfaceSize.width = aSize.width;
1659   mSurfaceSize.height = aSize.height;
1660 }
1661 
1662 void
CopyToTarget(DrawTarget * aTarget,const nsIntPoint & aTopLeft,const gfx::Matrix & aTransform)1663 CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform)
1664 {
1665   MOZ_ASSERT(aTarget);
1666   IntRect rect;
1667   if (mUseExternalSurfaceSize) {
1668     rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
1669   } else {
1670     rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
1671   }
1672   GLint width = rect.width;
1673   GLint height = rect.height;
1674 
1675   if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
1676     NS_ERROR("Widget size too big - integer overflow!");
1677     return;
1678   }
1679 
1680   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
1681 
1682   if (!mGLContext->IsGLES()) {
1683     // GLES2 promises that binding to any custom FBO will attach
1684     // to GL_COLOR_ATTACHMENT0 attachment point.
1685     mGLContext->fReadBuffer(LOCAL_GL_BACK);
1686   }
1687 
1688   RefPtr<DataSourceSurface> source =
1689         Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
1690   if (NS_WARN_IF(!source)) {
1691     return;
1692   }
1693 
1694   ReadPixelsIntoDataSurface(mGLContext, source);
1695 
1696   // Map from GL space to Cairo space and reverse the world transform.
1697   Matrix glToCairoTransform = aTransform;
1698   glToCairoTransform.Invert();
1699   glToCairoTransform.PreScale(1.0, -1.0);
1700   glToCairoTransform.PreTranslate(0.0, -height);
1701 
1702   glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y);
1703 
1704   Matrix oldMatrix = aTarget->GetTransform();
1705   aTarget->SetTransform(glToCairoTransform);
1706   Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
1707   aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
1708   aTarget->SetTransform(oldMatrix);
1709   aTarget->Flush();
1710 }
1711 
1712 void
Pause()1713 CompositorOGL::Pause()
1714 {
1715 #ifdef MOZ_WIDGET_ANDROID
1716   if (!gl() || gl()->IsDestroyed())
1717     return;
1718 
1719   // ReleaseSurface internally calls MakeCurrent.
1720   gl()->ReleaseSurface();
1721 #endif
1722 }
1723 
1724 bool
Resume()1725 CompositorOGL::Resume()
1726 {
1727 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT)
1728   if (!gl() || gl()->IsDestroyed())
1729     return false;
1730 
1731   // RenewSurface internally calls MakeCurrent.
1732   return gl()->RenewSurface(GetWidget()->RealWidget());
1733 #endif
1734   return true;
1735 }
1736 
1737 already_AddRefed<DataTextureSource>
CreateDataTextureSource(TextureFlags aFlags)1738 CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
1739 {
1740   return MakeAndAddRef<TextureImageTextureSourceOGL>(this, aFlags);
1741 }
1742 
1743 bool
SupportsPartialTextureUpdate()1744 CompositorOGL::SupportsPartialTextureUpdate()
1745 {
1746   return CanUploadSubTextures(mGLContext);
1747 }
1748 
1749 int32_t
GetMaxTextureSize() const1750 CompositorOGL::GetMaxTextureSize() const
1751 {
1752   MOZ_ASSERT(mGLContext);
1753   GLint texSize = 0;
1754   mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
1755                             &texSize);
1756   MOZ_ASSERT(texSize != 0);
1757   return texSize;
1758 }
1759 
1760 void
MakeCurrent(MakeCurrentFlags aFlags)1761 CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
1762   if (mDestroyed) {
1763     NS_WARNING("Call on destroyed layer manager");
1764     return;
1765   }
1766   mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
1767 }
1768 
1769 GLBlitTextureImageHelper*
BlitTextureImageHelper()1770 CompositorOGL::BlitTextureImageHelper()
1771 {
1772     if (!mBlitTextureImageHelper) {
1773         mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this);
1774     }
1775 
1776     return mBlitTextureImageHelper.get();
1777 }
1778 
1779 
1780 
1781 GLuint
GetTemporaryTexture(GLenum aTarget,GLenum aUnit)1782 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
1783 {
1784   if (!mTexturePool) {
1785     mTexturePool = new PerUnitTexturePoolOGL(gl());
1786   }
1787   return mTexturePool->GetTexture(aTarget, aUnit);
1788 }
1789 
1790 GLuint
GetTexture(GLenum aTarget,GLenum aTextureUnit)1791 PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
1792 {
1793   if (mTextureTarget == 0) {
1794     mTextureTarget = aTarget;
1795   }
1796   MOZ_ASSERT(mTextureTarget == aTarget);
1797 
1798   size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
1799   // lazily grow the array of temporary textures
1800   if (mTextures.Length() <= index) {
1801     size_t prevLength = mTextures.Length();
1802     mTextures.SetLength(index + 1);
1803     for(unsigned int i = prevLength; i <= index; ++i) {
1804       mTextures[i] = 0;
1805     }
1806   }
1807   // lazily initialize the temporary textures
1808   if (!mTextures[index]) {
1809     if (!mGL->MakeCurrent()) {
1810       return 0;
1811     }
1812     mGL->fGenTextures(1, &mTextures[index]);
1813     mGL->fBindTexture(aTarget, mTextures[index]);
1814     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1815     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
1816   }
1817   return mTextures[index];
1818 }
1819 
1820 void
DestroyTextures()1821 PerUnitTexturePoolOGL::DestroyTextures()
1822 {
1823   if (mGL && mGL->MakeCurrent()) {
1824     if (mTextures.Length() > 0) {
1825       mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
1826     }
1827   }
1828   mTextures.SetLength(0);
1829 }
1830 
1831 void
DestroyTextures()1832 PerFrameTexturePoolOGL::DestroyTextures()
1833 {
1834   if (!mGL->MakeCurrent()) {
1835     return;
1836   }
1837 
1838   if (mUnusedTextures.Length() > 0) {
1839     mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
1840     mUnusedTextures.Clear();
1841   }
1842 
1843   if (mCreatedTextures.Length() > 0) {
1844     mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
1845     mCreatedTextures.Clear();
1846   }
1847 }
1848 
1849 GLuint
GetTexture(GLenum aTarget,GLenum)1850 PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum)
1851 {
1852   if (mTextureTarget == 0) {
1853     mTextureTarget = aTarget;
1854   }
1855 
1856   // The pool should always use the same texture target because it is illegal
1857   // to change the target of an already exisiting gl texture.
1858   // If we need to use several targets, a pool with several sub-pools (one per
1859   // target) will have to be implemented.
1860   // At the moment this pool is only used with tiling on b2g so we always need
1861   // the same target.
1862   MOZ_ASSERT(mTextureTarget == aTarget);
1863 
1864   GLuint texture = 0;
1865 
1866   if (!mUnusedTextures.IsEmpty()) {
1867     // Try to reuse one from the unused pile first
1868     texture = mUnusedTextures[0];
1869     mUnusedTextures.RemoveElementAt(0);
1870   } else if (mGL->MakeCurrent()) {
1871     // There isn't one to reuse, create one.
1872     mGL->fGenTextures(1, &texture);
1873     mGL->fBindTexture(aTarget, texture);
1874     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1875     mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
1876   }
1877 
1878   if (texture) {
1879     mCreatedTextures.AppendElement(texture);
1880   }
1881 
1882   return texture;
1883 }
1884 
1885 void
EndFrame()1886 PerFrameTexturePoolOGL::EndFrame()
1887 {
1888   if (!mGL->MakeCurrent()) {
1889     // this means the context got destroyed underneith us somehow, and the driver
1890     // already has destroyed the textures.
1891     mCreatedTextures.Clear();
1892     mUnusedTextures.Clear();
1893     return;
1894   }
1895 
1896   // Some platforms have issues unlocking Gralloc buffers even when they're
1897   // rebound.
1898   if (gfxPrefs::OverzealousGrallocUnlocking()) {
1899     mUnusedTextures.AppendElements(mCreatedTextures);
1900     mCreatedTextures.Clear();
1901   }
1902 
1903   // Delete unused textures
1904   for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
1905     GLuint texture = mUnusedTextures[i];
1906     mGL->fDeleteTextures(1, &texture);
1907   }
1908   mUnusedTextures.Clear();
1909 
1910   // Move all created textures into the unused pile
1911   mUnusedTextures.AppendElements(mCreatedTextures);
1912   mCreatedTextures.Clear();
1913 }
1914 
1915 } // namespace layers
1916 } // namespace mozilla
1917