Coverage Report

Created: 2018-09-25 14:53

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