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