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