Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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/. */
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 "gfx2DGlue.h" // for ThebesFilter
16 #include "gfx3DMatrix.h" // for gfx3DMatrix
17 #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter
18 #include "gfxImageSurface.h" // for gfxImageSurface
19 #include "gfxMatrix.h" // for gfxMatrix
20 #include "GraphicsFilter.h" // for GraphicsFilter
21 #include "gfxPlatform.h" // for gfxPlatform
22 #include "gfxPrefs.h" // for gfxPrefs
23 #include "gfxRect.h" // for gfxRect
24 #include "gfxUtils.h" // for NextPowerOfTwo, gfxUtils, etc
25 #include "mozilla/ArrayUtils.h" // for ArrayLength
26 #include "mozilla/Preferences.h" // for Preferences
27 #include "mozilla/gfx/BasePoint.h" // for BasePoint
28 #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
29 #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc
30 #include "mozilla/layers/CompositingRenderTargetOGL.h"
31 #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc
32 #include "mozilla/layers/TextureHost.h" // for TextureSource, etc
33 #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc
34 #include "mozilla/mozalloc.h" // for operator delete, etc
35 #include "nsAString.h"
36 #include "nsIConsoleService.h" // for nsIConsoleService, etc
37 #include "nsIWidget.h" // for nsIWidget
38 #include "nsLiteralString.h" // for NS_LITERAL_STRING
39 #include "nsMathUtils.h" // for NS_roundf
40 #include "nsRect.h" // for nsIntRect
41 #include "nsServiceManagerUtils.h" // for do_GetService
42 #include "nsString.h" // for nsString, nsAutoCString, etc
43 #include "DecomposeIntoNoRepeatTriangles.h"
44 #include "ScopedGLHelpers.h"
45 #include "GLReadTexImageHelper.h"
46 #include "TiledLayerBuffer.h" // for TiledLayerComposer
48 #if MOZ_ANDROID_OMTC
49 #include "TexturePoolOGL.h"
50 #endif
52 #ifdef XP_MACOSX
53 #include "nsCocoaFeatures.h"
54 #endif
56 #include "GeckoProfiler.h"
58 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
59 #include "libdisplay/GonkDisplay.h" // for GonkDisplay
60 #include <ui/Fence.h>
61 #endif
63 #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
65 namespace mozilla {
67 using namespace std;
68 using namespace gfx;
70 namespace layers {
72 using namespace mozilla::gl;
74 static inline IntSize ns2gfxSize(const nsIntSize& s) {
75 return IntSize(s.width, s.height);
76 }
78 static void
79 BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask,
80 GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
81 {
82 MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
83 aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR);
84 aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
85 aProgram->SetMaskLayerTransform(aTransform);
86 }
88 // Draw the given quads with the already selected shader. Texture coordinates
89 // are supplied if the shader requires them.
90 static void
91 DrawQuads(GLContext *aGLContext,
92 VBOArena &aVBOs,
93 ShaderProgramOGL *aProg,
94 GLenum aMode,
95 RectTriangles &aRects)
96 {
97 NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
98 GLuint vertAttribIndex =
99 aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
100 GLuint texCoordAttribIndex =
101 aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
102 bool texCoords = (texCoordAttribIndex != GLuint(-1));
104 GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
106 GLsizei total = bytes;
107 if (texCoords) {
108 total *= 2;
109 }
111 aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
112 aVBOs.Allocate(aGLContext));
113 aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
114 total,
115 nullptr,
116 LOCAL_GL_STREAM_DRAW);
118 aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
119 0,
120 bytes,
121 aRects.vertCoords().Elements());
122 aGLContext->fEnableVertexAttribArray(vertAttribIndex);
123 aGLContext->fVertexAttribPointer(vertAttribIndex,
124 2, LOCAL_GL_FLOAT,
125 LOCAL_GL_FALSE,
126 0, BUFFER_OFFSET(0));
128 if (texCoords) {
129 aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
130 bytes,
131 bytes,
132 aRects.texCoords().Elements());
133 aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
134 aGLContext->fVertexAttribPointer(texCoordAttribIndex,
135 2, LOCAL_GL_FLOAT,
136 LOCAL_GL_FALSE,
137 0, BUFFER_OFFSET(bytes));
138 } else {
139 aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
140 }
142 aGLContext->fDrawArrays(aMode, 0, aRects.elements());
144 aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
145 }
147 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
148 int aSurfaceHeight, bool aUseExternalSurfaceSize)
149 : mWidget(aWidget)
150 , mWidgetSize(-1, -1)
151 , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
152 , mHasBGRA(0)
153 , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
154 , mFrameInProgress(false)
155 , mDestroyed(false)
156 , mHeight(0)
157 {
158 MOZ_COUNT_CTOR(CompositorOGL);
159 SetBackend(LayersBackend::LAYERS_OPENGL);
160 }
162 CompositorOGL::~CompositorOGL()
163 {
164 MOZ_COUNT_DTOR(CompositorOGL);
165 Destroy();
166 }
168 already_AddRefed<mozilla::gl::GLContext>
169 CompositorOGL::CreateContext()
170 {
171 nsRefPtr<GLContext> context;
173 #ifdef XP_WIN
174 if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
175 printf_stderr("Trying GL layers...\n");
176 context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
177 }
178 #endif
180 if (!context)
181 context = gl::GLContextProvider::CreateForWindow(mWidget);
183 if (!context) {
184 NS_WARNING("Failed to create CompositorOGL context");
185 }
187 return context.forget();
188 }
190 void
191 CompositorOGL::Destroy()
192 {
193 if (gl() && gl()->MakeCurrent()) {
194 mVBOs.Flush(gl());
195 }
197 if (mTexturePool) {
198 mTexturePool->Clear();
199 mTexturePool = nullptr;
200 }
202 if (!mDestroyed) {
203 mDestroyed = true;
204 CleanupResources();
205 }
206 }
208 void
209 CompositorOGL::CleanupResources()
210 {
211 if (!mGLContext)
212 return;
214 nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext();
215 if (!ctx) {
216 ctx = mGLContext;
217 }
219 for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin();
220 iter != mPrograms.end();
221 iter++) {
222 delete iter->second;
223 }
224 mPrograms.clear();
226 if (!ctx->MakeCurrent()) {
227 mQuadVBO = 0;
228 mGLContext = nullptr;
229 return;
230 }
232 ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
234 if (mQuadVBO) {
235 ctx->fDeleteBuffers(1, &mQuadVBO);
236 mQuadVBO = 0;
237 }
239 mGLContext = nullptr;
240 }
242 bool
243 CompositorOGL::Initialize()
244 {
245 ScopedGfxFeatureReporter reporter("GL Layers", true);
247 // Do not allow double initialization
248 NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
250 mGLContext = CreateContext();
252 #ifdef MOZ_WIDGET_ANDROID
253 if (!mGLContext)
254 NS_RUNTIMEABORT("We need a context on Android");
255 #endif
257 if (!mGLContext)
258 return false;
260 MakeCurrent();
262 mHasBGRA =
263 mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
264 mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
266 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
267 LOCAL_GL_ONE, LOCAL_GL_ONE);
268 mGLContext->fEnable(LOCAL_GL_BLEND);
270 // initialise a common shader to check that we can actually compile a shader
271 RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
272 ShaderConfigOGL config = GetShaderConfigFor(effect);
273 if (!GetShaderProgramFor(config)) {
274 return false;
275 }
277 if (mGLContext->WorkAroundDriverBugs()) {
278 /**
279 * We'll test the ability here to bind NPOT textures to a framebuffer, if
280 * this fails we'll try ARB_texture_rectangle.
281 */
283 GLenum textureTargets[] = {
284 LOCAL_GL_TEXTURE_2D,
285 LOCAL_GL_NONE
286 };
288 if (!mGLContext->IsGLES()) {
289 // No TEXTURE_RECTANGLE_ARB available on ES2
290 textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB;
291 }
293 mFBOTextureTarget = LOCAL_GL_NONE;
295 GLuint testFBO = 0;
296 mGLContext->fGenFramebuffers(1, &testFBO);
297 GLuint testTexture = 0;
299 for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) {
300 GLenum target = textureTargets[i];
301 if (!target)
302 continue;
304 mGLContext->fGenTextures(1, &testTexture);
305 mGLContext->fBindTexture(target, testTexture);
306 mGLContext->fTexParameteri(target,
307 LOCAL_GL_TEXTURE_MIN_FILTER,
308 LOCAL_GL_NEAREST);
309 mGLContext->fTexParameteri(target,
310 LOCAL_GL_TEXTURE_MAG_FILTER,
311 LOCAL_GL_NEAREST);
312 mGLContext->fTexImage2D(target,
313 0,
314 LOCAL_GL_RGBA,
315 5, 3, /* sufficiently NPOT */
316 0,
317 LOCAL_GL_RGBA,
318 LOCAL_GL_UNSIGNED_BYTE,
319 nullptr);
321 // unbind this texture, in preparation for binding it to the FBO
322 mGLContext->fBindTexture(target, 0);
324 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO);
325 mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
326 LOCAL_GL_COLOR_ATTACHMENT0,
327 target,
328 testTexture,
329 0);
331 if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
332 LOCAL_GL_FRAMEBUFFER_COMPLETE)
333 {
334 mFBOTextureTarget = target;
335 mGLContext->fDeleteTextures(1, &testTexture);
336 break;
337 }
339 mGLContext->fDeleteTextures(1, &testTexture);
340 }
342 if (testFBO) {
343 mGLContext->fDeleteFramebuffers(1, &testFBO);
344 }
346 if (mFBOTextureTarget == LOCAL_GL_NONE) {
347 /* Unable to find a texture target that works with FBOs and NPOT textures */
348 return false;
349 }
350 } else {
351 // not trying to work around driver bugs, so TEXTURE_2D should just work
352 mFBOTextureTarget = LOCAL_GL_TEXTURE_2D;
353 }
355 // back to default framebuffer, to avoid confusion
356 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
358 if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
359 /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
360 * extension -- the EXT variant does not provide support for
361 * texture rectangle access inside GLSL (sampler2DRect,
362 * texture2DRect).
363 */
364 if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
365 return false;
366 }
368 /* Create a simple quad VBO */
370 mGLContext->fGenBuffers(1, &mQuadVBO);
371 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
373 GLfloat vertices[] = {
374 /* First quad vertices */
375 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
376 /* Then quad texcoords */
377 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
378 };
379 mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
380 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
382 nsCOMPtr<nsIConsoleService>
383 console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
385 if (console) {
386 nsString msg;
387 msg +=
388 NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: ");
389 msg += NS_ConvertUTF8toUTF16(
390 nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
391 msg += NS_LITERAL_STRING("\nVendor: ");
392 msg += NS_ConvertUTF8toUTF16(
393 nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
394 msg += NS_LITERAL_STRING("\nRenderer: ");
395 msg += NS_ConvertUTF8toUTF16(
396 nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
397 msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
398 if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
399 msg += NS_LITERAL_STRING("TEXTURE_2D");
400 else
401 msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
402 console->LogStringMessage(msg.get());
403 }
405 reporter.SetSuccessful();
406 return true;
407 }
409 // |aTextureTransform| is the texture transform that will be set on
410 // aProg, possibly multiplied with another texture transform of our
411 // own.
412 // |aTexCoordRect| is the rectangle from the texture that we want to
413 // draw using the given program. The program already has a necessary
414 // offset and scale, so the geometry that needs to be drawn is a unit
415 // square from 0,0 to 1,1.
416 //
417 // |aTexture| is the texture we are drawing. Its actual size can be
418 // larger than the rectangle given by |aTexCoordRect|.
419 void
420 CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
421 const gfx3DMatrix& aTextureTransform,
422 const Rect& aTexCoordRect,
423 TextureSource *aTexture)
424 {
425 // Given what we know about these textures and coordinates, we can
426 // compute fmod(t, 1.0f) to get the same texture coordinate out. If
427 // the texCoordRect dimension is < 0 or > width/height, then we have
428 // wraparound that we need to deal with by drawing multiple quads,
429 // because we can't rely on full non-power-of-two texture support
430 // (which is required for the REPEAT wrap mode).
432 RectTriangles rects;
434 GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
436 IntSize realTexSize = aTexture->GetSize();
437 if (!CanUploadNonPowerOfTwo(mGLContext)) {
438 realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
439 NextPowerOfTwo(realTexSize.height));
440 }
442 // We need to convert back to actual texels here to get proper behaviour with
443 // our GL helper functions. Should fix this sometime.
444 // I want to vomit.
445 IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
446 NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
447 NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
448 NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));
450 // This is fairly disgusting - if the texture should be flipped it will have a
451 // negative height, in which case we un-invert the texture coords and pass the
452 // flipped 'flag' to the functions below. We can't just use the inverted coords
453 // because our GL funtions use an explicit flag.
454 bool flipped = false;
455 if (texCoordRect.height < 0) {
456 flipped = true;
457 texCoordRect.y = texCoordRect.YMost();
458 texCoordRect.height = -texCoordRect.height;
459 }
461 if (wrapMode == LOCAL_GL_REPEAT) {
462 rects.addRect(/* dest rectangle */
463 0.0f, 0.0f, 1.0f, 1.0f,
464 /* tex coords */
465 texCoordRect.x / GLfloat(realTexSize.width),
466 texCoordRect.y / GLfloat(realTexSize.height),
467 texCoordRect.XMost() / GLfloat(realTexSize.width),
468 texCoordRect.YMost() / GLfloat(realTexSize.height),
469 flipped);
470 } else {
471 nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
472 texCoordRect.width, texCoordRect.height);
473 DecomposeIntoNoRepeatTriangles(tcRect,
474 nsIntSize(realTexSize.width, realTexSize.height),
475 rects, flipped);
476 }
478 gfx3DMatrix textureTransform;
479 if (rects.isSimpleQuad(textureTransform)) {
480 Matrix4x4 transform;
481 ToMatrix4x4(aTextureTransform * textureTransform, transform);
482 aProg->SetTextureTransform(transform);
483 BindAndDrawQuad(aProg);
484 } else {
485 Matrix4x4 transform;
486 ToMatrix4x4(aTextureTransform, transform);
487 aProg->SetTextureTransform(transform);
488 DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects);
489 }
490 }
492 void
493 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
494 const Matrix& aWorldTransform)
495 {
496 // Set the viewport correctly.
497 mGLContext->fViewport(0, 0, aSize.width, aSize.height);
499 mHeight = aSize.height;
501 // We flip the view matrix around so that everything is right-side up; we're
502 // drawing directly into the window's back buffer, so this keeps things
503 // looking correct.
504 // XXX: We keep track of whether the window size changed, so we could skip
505 // this update if it hadn't changed since the last call. We will need to
506 // track changes to aTransformPolicy and aWorldTransform for this to work
507 // though.
509 // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
510 // 2, 2) and flip the contents.
511 Matrix viewMatrix;
512 viewMatrix.Translate(-1.0, 1.0);
513 viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
514 viewMatrix.Scale(1.0f, -1.0f);
515 if (!mTarget) {
516 viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y);
517 }
519 viewMatrix = aWorldTransform * viewMatrix;
521 Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
522 matrix3d._33 = 0.0f;
524 mProjMatrix = matrix3d;
525 }
527 TemporaryRef<CompositingRenderTarget>
528 CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
529 {
530 GLuint tex = 0;
531 GLuint fbo = 0;
532 CreateFBOWithTexture(aRect, false, 0, &fbo, &tex);
533 RefPtr<CompositingRenderTargetOGL> surface
534 = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
535 surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit);
536 return surface.forget();
537 }
539 TemporaryRef<CompositingRenderTarget>
540 CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect,
541 const CompositingRenderTarget *aSource,
542 const IntPoint &aSourcePoint)
543 {
544 GLuint tex = 0;
545 GLuint fbo = 0;
546 const CompositingRenderTargetOGL* sourceSurface
547 = static_cast<const CompositingRenderTargetOGL*>(aSource);
548 IntRect sourceRect(aSourcePoint, aRect.Size());
549 if (aSource) {
550 CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(),
551 &fbo, &tex);
552 } else {
553 CreateFBOWithTexture(sourceRect, true, 0,
554 &fbo, &tex);
555 }
557 RefPtr<CompositingRenderTargetOGL> surface
558 = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo);
559 surface->Initialize(aRect.Size(),
560 mFBOTextureTarget,
561 INIT_MODE_NONE);
562 return surface.forget();
563 }
565 void
566 CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface)
567 {
568 MOZ_ASSERT(aSurface);
569 CompositingRenderTargetOGL* surface
570 = static_cast<CompositingRenderTargetOGL*>(aSurface);
571 if (mCurrentRenderTarget != surface) {
572 surface->BindRenderTarget();
573 mCurrentRenderTarget = surface;
574 }
575 }
577 CompositingRenderTarget*
578 CompositorOGL::GetCurrentRenderTarget() const
579 {
580 return mCurrentRenderTarget;
581 }
583 static GLenum
584 GetFrameBufferInternalFormat(GLContext* gl,
585 GLuint aFrameBuffer,
586 nsIWidget* aWidget)
587 {
588 if (aFrameBuffer == 0) { // default framebuffer
589 return aWidget->GetGLFrameBufferFormat();
590 }
591 return LOCAL_GL_RGBA;
592 }
594 /*
595 * Returns a size that is larger than and closest to aSize where both
596 * width and height are powers of two.
597 * If the OpenGL setup is capable of using non-POT textures, then it
598 * will just return aSize.
599 */
600 static IntSize
601 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
602 {
603 if (CanUploadNonPowerOfTwo(gl))
604 return aSize;
606 return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
607 }
609 void
610 CompositorOGL::ClearRect(const gfx::Rect& aRect)
611 {
612 // Map aRect to OGL coordinates, origin:bottom-left
613 GLint y = mHeight - (aRect.y + aRect.height);
615 ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
616 ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height);
617 mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
618 mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
619 }
621 void
622 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
623 const Rect *aClipRectIn,
624 const gfx::Matrix& aTransform,
625 const Rect& aRenderBounds,
626 Rect *aClipRectOut,
627 Rect *aRenderBoundsOut)
628 {
629 PROFILER_LABEL("CompositorOGL", "BeginFrame");
630 MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
632 LayerScope::BeginFrame(mGLContext, PR_Now());
634 mVBOs.Reset();
636 mFrameInProgress = true;
637 gfx::Rect rect;
638 if (mUseExternalSurfaceSize) {
639 rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
640 } else {
641 rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
642 // If render bounds is not updated explicitly, try to infer it from widget
643 if (rect.width == 0 || rect.height == 0) {
644 // FIXME/bug XXXXXX this races with rotation changes on the main
645 // thread, and undoes all the care we take with layers txns being
646 // sent atomically with rotation changes
647 nsIntRect intRect;
648 mWidget->GetClientBounds(intRect);
649 rect = gfx::Rect(0, 0, intRect.width, intRect.height);
650 }
651 }
653 rect = aTransform.TransformBounds(rect);
654 if (aRenderBoundsOut) {
655 *aRenderBoundsOut = rect;
656 }
658 GLint width = rect.width;
659 GLint height = rect.height;
661 // We can't draw anything to something with no area
662 // so just return
663 if (width == 0 || height == 0)
664 return;
666 // If the widget size changed, we have to force a MakeCurrent
667 // to make sure that GL sees the updated widget size.
668 if (mWidgetSize.width != width ||
669 mWidgetSize.height != height)
670 {
671 MakeCurrent(ForceMakeCurrent);
673 mWidgetSize.width = width;
674 mWidgetSize.height = height;
675 } else {
676 MakeCurrent();
677 }
679 mPixelsPerFrame = width * height;
680 mPixelsFilled = 0;
682 #if MOZ_ANDROID_OMTC
683 TexturePoolOGL::Fill(gl());
684 #endif
686 mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this,
687 IntSize(width, height),
688 aTransform);
689 mCurrentRenderTarget->BindRenderTarget();
690 #ifdef DEBUG
691 mWindowRenderTarget = mCurrentRenderTarget;
692 #endif
694 // Default blend function implements "OVER"
695 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
696 LOCAL_GL_ONE, LOCAL_GL_ONE);
697 mGLContext->fEnable(LOCAL_GL_BLEND);
699 mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
701 if (aClipRectOut && !aClipRectIn) {
702 aClipRectOut->SetRect(0, 0, width, height);
703 }
705 // If the Android compositor is being used, this clear will be done in
706 // DrawWindowUnderlay. Make sure the bits used here match up with those used
707 // in mobile/android/base/gfx/LayerRenderer.java
708 #ifndef MOZ_ANDROID_OMTC
709 mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
710 mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
711 #endif
712 }
714 void
715 CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource,
716 GLuint aSourceFrameBuffer,
717 GLuint *aFBO, GLuint *aTexture)
718 {
719 GLuint tex, fbo;
721 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
722 mGLContext->fGenTextures(1, &tex);
723 mGLContext->fBindTexture(mFBOTextureTarget, tex);
725 if (aCopyFromSource) {
726 GLuint curFBO = mCurrentRenderTarget->GetFBO();
727 if (curFBO != aSourceFrameBuffer) {
728 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer);
729 }
731 // We're going to create an RGBA temporary fbo. But to
732 // CopyTexImage() from the current framebuffer, the framebuffer's
733 // format has to be compatible with the new texture's. So we
734 // check the format of the framebuffer here and take a slow path
735 // if it's incompatible.
736 GLenum format =
737 GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget);
739 bool isFormatCompatibleWithRGBA
740 = gl()->IsGLES() ? (format == LOCAL_GL_RGBA)
741 : true;
743 if (isFormatCompatibleWithRGBA) {
744 mGLContext->fCopyTexImage2D(mFBOTextureTarget,
745 0,
746 LOCAL_GL_RGBA,
747 aRect.x, FlipY(aRect.y + aRect.height),
748 aRect.width, aRect.height,
749 0);
750 } else {
751 // Curses, incompatible formats. Take a slow path.
753 // RGBA
754 size_t bufferSize = aRect.width * aRect.height * 4;
755 nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]);
757 mGLContext->fReadPixels(aRect.x, aRect.y,
758 aRect.width, aRect.height,
759 LOCAL_GL_RGBA,
760 LOCAL_GL_UNSIGNED_BYTE,
761 buf);
762 mGLContext->fTexImage2D(mFBOTextureTarget,
763 0,
764 LOCAL_GL_RGBA,
765 aRect.width, aRect.height,
766 0,
767 LOCAL_GL_RGBA,
768 LOCAL_GL_UNSIGNED_BYTE,
769 buf);
770 }
771 GLenum error = mGLContext->GetAndClearError();
772 if (error != LOCAL_GL_NO_ERROR) {
773 nsAutoCString msg;
774 msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d",
775 error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA);
776 NS_ERROR(msg.get());
777 }
778 } else {
779 mGLContext->fTexImage2D(mFBOTextureTarget,
780 0,
781 LOCAL_GL_RGBA,
782 aRect.width, aRect.height,
783 0,
784 LOCAL_GL_RGBA,
785 LOCAL_GL_UNSIGNED_BYTE,
786 nullptr);
787 }
788 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
789 LOCAL_GL_LINEAR);
790 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
791 LOCAL_GL_LINEAR);
792 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S,
793 LOCAL_GL_CLAMP_TO_EDGE);
794 mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T,
795 LOCAL_GL_CLAMP_TO_EDGE);
796 mGLContext->fBindTexture(mFBOTextureTarget, 0);
798 mGLContext->fGenFramebuffers(1, &fbo);
800 *aFBO = fbo;
801 *aTexture = tex;
802 }
804 ShaderConfigOGL
805 CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
806 {
807 ShaderConfigOGL config;
809 switch(aEffect->mType) {
810 case EFFECT_SOLID_COLOR:
811 config.SetRenderColor(true);
812 break;
813 case EFFECT_YCBCR:
814 config.SetYCbCr(true);
815 break;
816 case EFFECT_COMPONENT_ALPHA:
817 {
818 config.SetComponentAlpha(true);
819 EffectComponentAlpha* effectComponentAlpha =
820 static_cast<EffectComponentAlpha*>(aEffect);
821 gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat();
822 config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 ||
823 format == gfx::SurfaceFormat::B8G8R8X8);
824 break;
825 }
826 case EFFECT_RENDER_TARGET:
827 config.SetTextureTarget(mFBOTextureTarget);
828 break;
829 default:
830 {
831 MOZ_ASSERT(aEffect->mType == EFFECT_RGB);
832 TexturedEffect* texturedEffect =
833 static_cast<TexturedEffect*>(aEffect);
834 TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
835 MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
836 source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8);
837 MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
838 source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
839 source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
840 source->GetFormat() == gfx::SurfaceFormat::R5G6B5);
841 config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(),
842 source->GetFormat());
843 break;
844 }
845 }
846 config.SetMask2D(aMask == Mask2d);
847 config.SetMask3D(aMask == Mask3d);
848 return config;
849 }
851 ShaderProgramOGL*
852 CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
853 {
854 std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
855 if (iter != mPrograms.end())
856 return iter->second;
858 ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig);
859 ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
860 if (!shader->Initialize()) {
861 delete shader;
862 return nullptr;
863 }
865 mPrograms[aConfig] = shader;
866 return shader;
867 }
869 void
870 CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect& aClipRect,
871 const gfx::Color& aColor,
872 gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform)
873 {
874 mGLContext->fLineWidth(2.0);
876 EffectChain effects;
877 effects.mPrimaryEffect = new EffectSolidColor(aColor);
879 for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) {
880 const gfx::Point& p1 = aLines[i];
881 const gfx::Point& p2 = aLines[i+1];
882 DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y),
883 aClipRect, effects, aOpacity, aTransform,
884 LOCAL_GL_LINE_STRIP);
885 }
886 }
888 void
889 CompositorOGL::DrawQuadInternal(const Rect& aRect,
890 const Rect& aClipRect,
891 const EffectChain &aEffectChain,
892 Float aOpacity,
893 const gfx::Matrix4x4 &aTransform,
894 GLuint aDrawMode)
895 {
896 PROFILER_LABEL("CompositorOGL", "DrawQuad");
897 MOZ_ASSERT(mFrameInProgress, "frame not started");
899 Rect clipRect = aClipRect;
900 if (!mTarget) {
901 clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
902 }
903 IntRect intClipRect;
904 clipRect.ToIntRect(&intClipRect);
906 gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height),
907 intClipRect.width, intClipRect.height);
909 LayerScope::SendEffectChain(mGLContext, aEffectChain,
910 aRect.width, aRect.height);
912 MaskType maskType;
913 EffectMask* effectMask;
914 TextureSourceOGL* sourceMask = nullptr;
915 gfx::Matrix4x4 maskQuadTransform;
916 if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
917 effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
918 sourceMask = effectMask->mMaskTexture->AsSourceOGL();
920 // NS_ASSERTION(textureMask->IsAlpha(),
921 // "OpenGL mask layers must be backed by alpha surfaces");
923 // We're assuming that the gl backend won't cheat and use NPOT
924 // textures when glContext says it can't (which seems to happen
925 // on a mac when you force POT textures)
926 IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext);
928 const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform;
929 NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
930 Rect bounds = Rect(Point(), Size(maskSize));
931 bounds = maskTransform.As2D().TransformBounds(bounds);
933 maskQuadTransform._11 = 1.0f/bounds.width;
934 maskQuadTransform._22 = 1.0f/bounds.height;
935 maskQuadTransform._41 = float(-bounds.x)/bounds.width;
936 maskQuadTransform._42 = float(-bounds.y)/bounds.height;
938 maskType = effectMask->mIs3D
939 ? Mask3d
940 : Mask2d;
941 } else {
942 maskType = MaskNone;
943 }
945 mPixelsFilled += aRect.width * aRect.height;
947 // Determine the color if this is a color shader and fold the opacity into
948 // the color since color shaders don't have an opacity uniform.
949 Color color;
950 if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) {
951 EffectSolidColor* effectSolidColor =
952 static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
953 color = effectSolidColor->mColor;
955 Float opacity = aOpacity * color.a;
956 color.r *= opacity;
957 color.g *= opacity;
958 color.b *= opacity;
959 color.a = opacity;
961 // We can fold opacity into the color, so no need to consider it further.
962 aOpacity = 1.f;
963 }
965 ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType);
966 config.SetOpacity(aOpacity != 1.f);
967 ShaderProgramOGL *program = GetShaderProgramFor(config);
968 program->Activate();
969 program->SetProjectionMatrix(mProjMatrix);
970 program->SetLayerQuadRect(aRect);
971 program->SetLayerTransform(aTransform);
972 IntPoint offset = mCurrentRenderTarget->GetOrigin();
973 program->SetRenderOffset(offset.x, offset.y);
974 if (aOpacity != 1.f)
975 program->SetLayerOpacity(aOpacity);
976 if (config.mFeatures & ENABLE_TEXTURE_RECT) {
977 TexturedEffect* texturedEffect =
978 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
979 TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
980 // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
981 program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
982 }
984 switch (aEffectChain.mPrimaryEffect->mType) {
985 case EFFECT_SOLID_COLOR: {
986 program->SetRenderColor(color);
988 if (maskType != MaskNone) {
989 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform);
990 }
992 BindAndDrawQuad(program, aDrawMode);
993 }
994 break;
996 case EFFECT_RGB: {
997 TexturedEffect* texturedEffect =
998 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
999 TextureSource *source = texturedEffect->mTexture;
1001 if (!texturedEffect->mPremultiplied) {
1002 mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1003 LOCAL_GL_ONE, LOCAL_GL_ONE);
1004 }
1006 gfx::Filter filter = texturedEffect->mFilter;
1007 gfx3DMatrix textureTransform;
1008 gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform);
1010 #ifdef MOZ_WIDGET_ANDROID
1011 gfxMatrix textureTransform2D;
1012 if (filter != gfx::Filter::POINT &&
1013 aTransform.Is2DIntegerTranslation() &&
1014 textureTransform.Is2D(&textureTransform2D) &&
1015 textureTransform2D.HasOnlyIntegerTranslation()) {
1016 // On Android we encounter small resampling errors in what should be
1017 // pixel-aligned compositing operations. This works around them. This
1018 // code should not be needed!
1019 filter = gfx::Filter::POINT;
1020 }
1021 #endif
1022 source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
1024 program->SetTextureUnit(0);
1026 if (maskType != MaskNone) {
1027 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
1028 }
1030 BindAndDrawQuadWithTextureRect(program, textureTransform,
1031 texturedEffect->mTextureCoords, source);
1033 if (!texturedEffect->mPremultiplied) {
1034 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1035 LOCAL_GL_ONE, LOCAL_GL_ONE);
1036 }
1037 }
1038 break;
1039 case EFFECT_YCBCR: {
1040 EffectYCbCr* effectYCbCr =
1041 static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
1042 TextureSource* sourceYCbCr = effectYCbCr->mTexture;
1043 const int Y = 0, Cb = 1, Cr = 2;
1044 TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
1045 TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL();
1046 TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL();
1048 if (!sourceY && !sourceCb && !sourceCr) {
1049 NS_WARNING("Invalid layer texture.");
1050 return;
1051 }
1053 sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter);
1054 sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter);
1055 sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter);
1057 program->SetYCbCrTextureUnits(Y, Cb, Cr);
1059 if (maskType != MaskNone) {
1060 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
1061 }
1062 BindAndDrawQuadWithTextureRect(program,
1063 gfx3DMatrix(),
1064 effectYCbCr->mTextureCoords,
1065 sourceYCbCr->GetSubSource(Y));
1066 }
1067 break;
1068 case EFFECT_RENDER_TARGET: {
1069 EffectRenderTarget* effectRenderTarget =
1070 static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
1071 RefPtr<CompositingRenderTargetOGL> surface
1072 = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
1074 surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
1076 // Drawing is always flipped, but when copying between surfaces we want to avoid
1077 // this, so apply a flip here to cancel the other one out.
1078 Matrix transform;
1079 transform.Translate(0.0, 1.0);
1080 transform.Scale(1.0f, -1.0f);
1081 program->SetTextureTransform(Matrix4x4::From2D(transform));
1082 program->SetTextureUnit(0);
1084 if (maskType != MaskNone) {
1085 sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR);
1086 program->SetMaskTextureUnit(1);
1087 program->SetMaskLayerTransform(maskQuadTransform);
1088 }
1090 if (config.mFeatures & ENABLE_TEXTURE_RECT) {
1091 // 2DRect case, get the multiplier right for a sampler2DRect
1092 program->SetTexCoordMultiplier(aRect.width, aRect.height);
1093 }
1095 // Drawing is always flipped, but when copying between surfaces we want to avoid
1096 // this. Pass true for the flip parameter to introduce a second flip
1097 // that cancels the other one out.
1098 BindAndDrawQuad(program);
1099 }
1100 break;
1101 case EFFECT_COMPONENT_ALPHA: {
1102 MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
1103 EffectComponentAlpha* effectComponentAlpha =
1104 static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
1105 TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL();
1106 TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
1108 if (!sourceOnBlack->IsValid() ||
1109 !sourceOnWhite->IsValid()) {
1110 NS_WARNING("Invalid layer texture for component alpha");
1111 return;
1112 }
1114 sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter);
1115 sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter);
1117 program->SetBlackTextureUnit(0);
1118 program->SetWhiteTextureUnit(1);
1119 program->SetTextureTransform(gfx::Matrix4x4());
1121 if (maskType != MaskNone) {
1122 BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
1123 }
1124 // Pass 1.
1125 gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
1126 LOCAL_GL_ONE, LOCAL_GL_ONE);
1127 program->SetTexturePass2(false);
1128 BindAndDrawQuadWithTextureRect(program,
1129 gfx3DMatrix(),
1130 effectComponentAlpha->mTextureCoords,
1131 effectComponentAlpha->mOnBlack);
1133 // Pass 2.
1134 gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
1135 LOCAL_GL_ONE, LOCAL_GL_ONE);
1137 #ifdef XP_MACOSX
1138 if (gl()->WorkAroundDriverBugs() &&
1139 gl()->Vendor() == GLVendor::NVIDIA &&
1140 !nsCocoaFeatures::OnMavericksOrLater()) {
1141 // Bug 987497: With some GPUs the nvidia driver on 10.8 and below
1142 // won't pick up the TexturePass2 uniform change below if we don't do
1143 // something to force it. Re-activating the shader seems to be one way
1144 // of achieving that.
1145 program->Activate();
1146 }
1147 #endif
1149 program->SetTexturePass2(true);
1150 BindAndDrawQuadWithTextureRect(program,
1151 gfx3DMatrix(),
1152 effectComponentAlpha->mTextureCoords,
1153 effectComponentAlpha->mOnBlack);
1155 mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
1156 LOCAL_GL_ONE, LOCAL_GL_ONE);
1157 }
1158 break;
1159 default:
1160 MOZ_ASSERT(false, "Unhandled effect type");
1161 break;
1162 }
1164 // in case rendering has used some other GL context
1165 MakeCurrent();
1166 }
1168 void
1169 CompositorOGL::EndFrame()
1170 {
1171 PROFILER_LABEL("CompositorOGL", "EndFrame");
1172 MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
1174 #ifdef MOZ_DUMP_PAINTING
1175 if (gfxUtils::sDumpPainting) {
1176 nsIntRect rect;
1177 if (mUseExternalSurfaceSize) {
1178 rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
1179 } else {
1180 mWidget->GetBounds(rect);
1181 }
1182 RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8);
1183 CopyToTarget(target, mCurrentRenderTarget->GetTransform());
1185 WriteSnapshotToDumpFile(this, target);
1186 }
1187 #endif
1189 mFrameInProgress = false;
1191 LayerScope::EndFrame(mGLContext);
1193 if (mTarget) {
1194 CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
1195 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1196 mCurrentRenderTarget = nullptr;
1197 return;
1198 }
1200 mCurrentRenderTarget = nullptr;
1202 if (mTexturePool) {
1203 mTexturePool->EndFrame();
1204 }
1206 mGLContext->SwapBuffers();
1207 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1209 // Unbind all textures
1210 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
1211 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
1212 if (!mGLContext->IsGLES()) {
1213 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
1214 }
1216 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
1217 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
1218 if (!mGLContext->IsGLES()) {
1219 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
1220 }
1222 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2);
1223 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
1224 if (!mGLContext->IsGLES()) {
1225 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
1226 }
1227 }
1229 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
1230 void
1231 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
1232 {
1233 // OpenGL does not provide ReleaseFence for rendering.
1234 // Instead use FBAcquireFence as layer buffer's ReleaseFence
1235 // to prevent flickering and tearing.
1236 // FBAcquireFence is FramebufferSurface's AcquireFence.
1237 // AcquireFence will be signaled when a buffer's content is available.
1238 // See Bug 974152.
1240 if (!aLayer) {
1241 return;
1242 }
1244 const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
1245 if (visibleRegion.IsEmpty()) {
1246 return;
1247 }
1249 // Set FBAcquireFence on ContainerLayer's childs
1250 ContainerLayer* container = aLayer->AsContainerLayer();
1251 if (container) {
1252 for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
1253 SetFBAcquireFence(child);
1254 }
1255 return;
1256 }
1258 // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
1259 TiledLayerComposer* composer = nullptr;
1260 LayerComposite* shadow = aLayer->AsLayerComposite();
1261 if (shadow) {
1262 composer = shadow->GetTiledLayerComposer();
1263 if (composer) {
1264 composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
1265 return;
1266 }
1267 }
1269 // Set FBAcquireFence as layer buffer's ReleaseFence
1270 LayerRenderState state = aLayer->GetRenderState();
1271 if (!state.mTexture) {
1272 return;
1273 }
1274 TextureHostOGL* texture = state.mTexture->AsHostOGL();
1275 if (!texture) {
1276 return;
1277 }
1278 texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
1279 }
1280 #else
1281 void
1282 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
1283 {
1284 }
1285 #endif
1287 void
1288 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
1289 {
1290 // This lets us reftest and screenshot content rendered externally
1291 if (mTarget) {
1292 MakeCurrent();
1293 CopyToTarget(mTarget, aTransform);
1294 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1295 }
1296 if (mTexturePool) {
1297 mTexturePool->EndFrame();
1298 }
1299 }
1301 void
1302 CompositorOGL::AbortFrame()
1303 {
1304 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
1305 mFrameInProgress = false;
1306 mCurrentRenderTarget = nullptr;
1308 if (mTexturePool) {
1309 mTexturePool->EndFrame();
1310 }
1311 }
1313 void
1314 CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
1315 {
1316 mSurfaceSize.width = aSize.width;
1317 mSurfaceSize.height = aSize.height;
1318 }
1320 void
1321 CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform)
1322 {
1323 IntRect rect;
1324 if (mUseExternalSurfaceSize) {
1325 rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
1326 } else {
1327 rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height);
1328 }
1329 GLint width = rect.width;
1330 GLint height = rect.height;
1332 if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) {
1333 NS_ERROR("Widget size too big - integer overflow!");
1334 return;
1335 }
1337 mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
1339 if (!mGLContext->IsGLES()) {
1340 // GLES2 promises that binding to any custom FBO will attach
1341 // to GL_COLOR_ATTACHMENT0 attachment point.
1342 mGLContext->fReadBuffer(LOCAL_GL_BACK);
1343 }
1345 RefPtr<DataSourceSurface> source =
1346 Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8);
1348 DataSourceSurface::MappedSurface map;
1349 source->Map(DataSourceSurface::MapType::WRITE, &map);
1350 // XXX we should do this properly one day without using the gfxImageSurface
1351 nsRefPtr<gfxImageSurface> surf =
1352 new gfxImageSurface(map.mData,
1353 gfxIntSize(width, height),
1354 map.mStride,
1355 gfxImageFormat::ARGB32);
1356 ReadPixelsIntoImageSurface(mGLContext, surf);
1357 source->Unmap();
1359 // Map from GL space to Cairo space and reverse the world transform.
1360 Matrix glToCairoTransform = aTransform;
1361 glToCairoTransform.Invert();
1362 glToCairoTransform.Scale(1.0, -1.0);
1363 glToCairoTransform.Translate(0.0, -height);
1365 Matrix oldMatrix = aTarget->GetTransform();
1366 aTarget->SetTransform(glToCairoTransform);
1367 Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
1368 aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
1369 aTarget->SetTransform(oldMatrix);
1370 aTarget->Flush();
1371 }
1373 void
1374 CompositorOGL::Pause()
1375 {
1376 #ifdef MOZ_WIDGET_ANDROID
1377 if (!gl() || gl()->IsDestroyed())
1378 return;
1380 // ReleaseSurface internally calls MakeCurrent.
1381 gl()->ReleaseSurface();
1382 #endif
1383 }
1385 bool
1386 CompositorOGL::Resume()
1387 {
1388 #ifdef MOZ_WIDGET_ANDROID
1389 if (!gl() || gl()->IsDestroyed())
1390 return false;
1392 // RenewSurface internally calls MakeCurrent.
1393 return gl()->RenewSurface();
1394 #endif
1395 return true;
1396 }
1398 TemporaryRef<DataTextureSource>
1399 CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
1400 {
1401 RefPtr<DataTextureSource> result =
1402 new TextureImageTextureSourceOGL(mGLContext, aFlags);
1403 return result;
1404 }
1406 bool
1407 CompositorOGL::SupportsPartialTextureUpdate()
1408 {
1409 return CanUploadSubTextures(mGLContext);
1410 }
1412 int32_t
1413 CompositorOGL::GetMaxTextureSize() const
1414 {
1415 MOZ_ASSERT(mGLContext);
1416 GLint texSize = 0;
1417 mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
1418 &texSize);
1419 MOZ_ASSERT(texSize != 0);
1420 return texSize;
1421 }
1423 void
1424 CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) {
1425 if (mDestroyed) {
1426 NS_WARNING("Call on destroyed layer manager");
1427 return;
1428 }
1429 mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
1430 }
1432 void
1433 CompositorOGL::BindQuadVBO() {
1434 mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
1435 }
1437 void
1438 CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) {
1439 mGLContext->fVertexAttribPointer(aAttribIndex, 2,
1440 LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
1441 (GLvoid*) QuadVBOVertexOffset());
1442 }
1444 void
1445 CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
1446 mGLContext->fVertexAttribPointer(aAttribIndex, 2,
1447 LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
1448 (GLvoid*) QuadVBOTexCoordOffset());
1449 }
1451 void
1452 CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex,
1453 GLuint aTexCoordAttribIndex,
1454 GLuint aDrawMode)
1455 {
1456 BindQuadVBO();
1457 QuadVBOVerticesAttrib(aVertAttribIndex);
1459 if (aTexCoordAttribIndex != GLuint(-1)) {
1460 QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
1461 mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
1462 }
1464 mGLContext->fEnableVertexAttribArray(aVertAttribIndex);
1465 if (aDrawMode == LOCAL_GL_LINE_STRIP) {
1466 mGLContext->fDrawArrays(aDrawMode, 1, 2);
1467 } else {
1468 mGLContext->fDrawArrays(aDrawMode, 0, 4);
1469 }
1470 }
1472 void
1473 CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
1474 GLuint aDrawMode)
1475 {
1476 NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
1477 BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib),
1478 aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib),
1479 aDrawMode);
1480 }
1482 GLuint
1483 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
1484 {
1485 if (!mTexturePool) {
1486 #ifdef MOZ_WIDGET_GONK
1487 mTexturePool = new PerFrameTexturePoolOGL(gl());
1488 #else
1489 mTexturePool = new PerUnitTexturePoolOGL(gl());
1490 #endif
1491 }
1492 return mTexturePool->GetTexture(aTarget, aUnit);
1493 }
1495 GLuint
1496 PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit)
1497 {
1498 if (mTextureTarget == 0) {
1499 mTextureTarget = aTarget;
1500 }
1501 MOZ_ASSERT(mTextureTarget == aTarget);
1503 size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
1504 // lazily grow the array of temporary textures
1505 if (mTextures.Length() <= index) {
1506 size_t prevLength = mTextures.Length();
1507 mTextures.SetLength(index + 1);
1508 for(unsigned int i = prevLength; i <= index; ++i) {
1509 mTextures[i] = 0;
1510 }
1511 }
1512 // lazily initialize the temporary textures
1513 if (!mTextures[index]) {
1514 if (!mGL->MakeCurrent()) {
1515 return 0;
1516 }
1517 mGL->fGenTextures(1, &mTextures[index]);
1518 mGL->fBindTexture(aTarget, mTextures[index]);
1519 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1520 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
1521 }
1522 return mTextures[index];
1523 }
1525 void
1526 PerUnitTexturePoolOGL::DestroyTextures()
1527 {
1528 if (mGL && mGL->MakeCurrent()) {
1529 if (mTextures.Length() > 0) {
1530 mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
1531 }
1532 }
1533 mTextures.SetLength(0);
1534 }
1536 void
1537 PerFrameTexturePoolOGL::DestroyTextures()
1538 {
1539 if (!mGL->MakeCurrent()) {
1540 return;
1541 }
1543 if (mUnusedTextures.Length() > 0) {
1544 mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
1545 mUnusedTextures.Clear();
1546 }
1548 if (mCreatedTextures.Length() > 0) {
1549 mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
1550 mCreatedTextures.Clear();
1551 }
1552 }
1554 GLuint
1555 PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum)
1556 {
1557 if (mTextureTarget == 0) {
1558 mTextureTarget = aTarget;
1559 }
1561 // The pool should always use the same texture target because it is illegal
1562 // to change the target of an already exisiting gl texture.
1563 // If we need to use several targets, a pool with several sub-pools (one per
1564 // target) will have to be implemented.
1565 // At the moment this pool is only used with tiling on b2g so we always need
1566 // the same target.
1567 MOZ_ASSERT(mTextureTarget == aTarget);
1569 GLuint texture = 0;
1571 if (!mUnusedTextures.IsEmpty()) {
1572 // Try to reuse one from the unused pile first
1573 texture = mUnusedTextures[0];
1574 mUnusedTextures.RemoveElementAt(0);
1575 } else if (mGL->MakeCurrent()) {
1576 // There isn't one to reuse, create one.
1577 mGL->fGenTextures(1, &texture);
1578 mGL->fBindTexture(aTarget, texture);
1579 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1580 mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
1581 }
1583 if (texture) {
1584 mCreatedTextures.AppendElement(texture);
1585 }
1587 return texture;
1588 }
1590 void
1591 PerFrameTexturePoolOGL::EndFrame()
1592 {
1593 if (!mGL->MakeCurrent()) {
1594 // this means the context got destroyed underneith us somehow, and the driver
1595 // already has destroyed the textures.
1596 mCreatedTextures.Clear();
1597 mUnusedTextures.Clear();
1598 return;
1599 }
1601 // Some platforms have issues unlocking Gralloc buffers even when they're
1602 // rebound.
1603 if (gfxPrefs::OverzealousGrallocUnlocking()) {
1604 mUnusedTextures.AppendElements(mCreatedTextures);
1605 mCreatedTextures.Clear();
1606 }
1608 // Delete unused textures
1609 for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
1610 GLuint texture = mUnusedTextures[i];
1611 mGL->fDeleteTextures(1, &texture);
1612 }
1613 mUnusedTextures.Clear();
1615 // Move all created textures into the unused pile
1616 mUnusedTextures.AppendElements(mCreatedTextures);
1617 mCreatedTextures.Clear();
1618 }
1620 } /* layers */
1621 } /* mozilla */