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