void LayerManagerComposite::Destroy() { if (!mDestroyed) { mCompositor->GetWidget()->CleanupWindowEffects(); if (mRoot) { RootLayer()->Destroy(); } mRoot = nullptr; mDestroyed = true; } }
void LayerManagerComposite::Destroy() { if (!mDestroyed) { mCompositor->GetWidget()->CleanupWindowEffects(); if (mRoot) { RootLayer()->Destroy(); } mCompositor->CancelFrame(); mRoot = nullptr; mClonedLayerTreeProperties = nullptr; mPaintCounter = nullptr; mDestroyed = true; } }
void LayerManagerOGL::Render() { SAMPLE_LABEL("LayerManagerOGL", "Render"); if (mDestroyed) { NS_WARNING("Call on destroyed layer manager"); return; } nsIntRect rect; mWidget->GetClientBounds(rect); WorldTransformRect(rect); GLint width = rect.width; GLint height = rect.height; // We can't draw anything to something with no area // so just return if (width == 0 || height == 0) return; // If the widget size changed, we have to force a MakeCurrent // to make sure that GL sees the updated widget size. if (mWidgetSize.width != width || mWidgetSize.height != height) { MakeCurrent(true); mWidgetSize.width = width; mWidgetSize.height = height; } else { MakeCurrent(); } SetupBackBuffer(width, height); SetupPipeline(width, height, ApplyWorldTransform); // Default blend function implements "OVER" mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, LOCAL_GL_ONE, LOCAL_GL_ONE); mGLContext->fEnable(LOCAL_GL_BLEND); const nsIntRect *clipRect = mRoot->GetClipRect(); if (clipRect) { nsIntRect r = *clipRect; WorldTransformRect(r); mGLContext->fScissor(r.x, r.y, r.width, r.height); } else { mGLContext->fScissor(0, 0, width, height); } mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); // Render our layers. RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO, nsIntPoint(0, 0)); mWidget->DrawWindowOverlay(this, rect); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { nsIntRect rect; mWidget->GetBounds(rect); nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(rect.Size(), gfxASurface::CONTENT_COLOR_ALPHA); nsRefPtr<gfxContext> ctx = new gfxContext(surf); CopyToTarget(ctx); WriteSnapshotToDumpFile(this, surf); } #endif if (mTarget) { CopyToTarget(mTarget); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); return; } if (sDrawFPS) { mFPS.DrawFPS(mGLContext, GetCopy2DProgram()); } if (mGLContext->IsDoubleBuffered()) { mGLContext->SwapBuffers(); LayerManager::PostPresent(); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); return; } mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); CopyProgram *copyprog = GetCopy2DProgram(); if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { copyprog = GetCopy2DRectProgram(); } mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture); copyprog->Activate(); copyprog->SetTextureUnit(0); if (copyprog->GetTexCoordMultiplierUniformLocation() != -1) { float f[] = { float(width), float(height) }; copyprog->SetUniform(copyprog->GetTexCoordMultiplierUniformLocation(), 2, f); } // we're going to use client-side vertex arrays for this. mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); // "COPY" mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO, LOCAL_GL_ONE, LOCAL_GL_ZERO); // enable our vertex attribs; we'll call glVertexPointer below // to fill with the correct data. GLint vcattr = copyprog->AttribLocation(CopyProgram::VertexCoordAttrib); GLint tcattr = copyprog->AttribLocation(CopyProgram::TexCoordAttrib); mGLContext->fEnableVertexAttribArray(vcattr); mGLContext->fEnableVertexAttribArray(tcattr); const nsIntRect *r; nsIntRegionRectIterator iter(mClippingRegion); while ((r = iter.Next()) != nsnull) { nsIntRect cRect = *r; r = &cRect; WorldTransformRect(cRect); float left = (GLfloat)r->x / width; float right = (GLfloat)r->XMost() / width; float top = (GLfloat)r->y / height; float bottom = (GLfloat)r->YMost() / height; float vertices[] = { left * 2.0f - 1.0f, -(top * 2.0f - 1.0f), right * 2.0f - 1.0f, -(top * 2.0f - 1.0f), left * 2.0f - 1.0f, -(bottom * 2.0f - 1.0f), right * 2.0f - 1.0f, -(bottom * 2.0f - 1.0f) }; // Use flipped texture coordinates since our // projection matrix also has a flip and we // need to cancel that out. float coords[] = { left, bottom, right, bottom, left, top, right, top }; mGLContext->fVertexAttribPointer(vcattr, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, vertices); mGLContext->fVertexAttribPointer(tcattr, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, coords); mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); } mGLContext->fDisableVertexAttribArray(vcattr); mGLContext->fDisableVertexAttribArray(tcattr); mGLContext->fFlush(); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); }
void LayerManagerComposite::RenderToPresentationSurface() { if (!AndroidBridge::Bridge()) { return; } void* window = AndroidBridge::Bridge()->GetPresentationWindow(); if (!window) { return; } EGLSurface surface = AndroidBridge::Bridge()->GetPresentationSurface(); if (!surface) { //create surface; surface = GLContextProviderEGL::CreateEGLSurface(window); if (!surface) { return; } AndroidBridge::Bridge()->SetPresentationSurface(surface); } CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get()); GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); if (!egl) { return; } const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window); if ((windowSize.width <= 0) || (windowSize.height <= 0)) { return; } const int actualWidth = windowSize.width; const int actualHeight = windowSize.height; const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); const int pageWidth = originalSize.width; const int pageHeight = originalSize.height; float scale = 1.0; if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { const float scaleWidth = (float)actualWidth / (float)pageWidth; const float scaleHeight = (float)actualHeight / (float)pageHeight; scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; } const gfx::IntSize actualSize(actualWidth, actualHeight); ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); ScopedCompositorRenderOffset overrideRenderOffset(compositor, offset); ScopedContextSurfaceOverride overrideSurface(egl, surface); nsIntRegion invalid; Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); Rect rect, actualBounds; mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds); // Override the projection matrix since the presentation frame buffer // is probably not the same size as the device frame buffer. The override // projection matrix also scales the content to fit into the presentation // frame buffer. Matrix viewMatrix; viewMatrix.PreTranslate(-1.0, 1.0); viewMatrix.PreScale((2.0f * scale) / (float)actualWidth, (2.0f * scale) / (float)actualHeight); viewMatrix.PreScale(1.0f, -1.0f); viewMatrix.PreTranslate((int)((float)offset.x / scale), offset.y); Matrix4x4 projMatrix = Matrix4x4::From2D(viewMatrix); ScopedCompositorProjMatrix overrideProjMatrix(compositor, projMatrix); // The Java side of Fennec sets a scissor rect that accounts for // chrome such as the URL bar. Override that so that the entire frame buffer // is cleared. ScopedScissorRect screen(egl, 0, 0, actualWidth, actualHeight); egl->fClearColor(0.0, 0.0, 0.0, 0.0); egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); const IntRect clipRect = IntRect(0, 0, (int)(scale * pageWidth), actualHeight); RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect)); RootLayer()->RenderLayer(clipRect); mCompositor->EndFrame(); mCompositor->SetDispAcquireFence(mRoot); }
void LayerManagerComposite::Render() { PROFILER_LABEL("LayerManagerComposite", "Render", js::ProfileEntry::Category::GRAPHICS); if (mDestroyed) { NS_WARNING("Call on destroyed layer manager"); return; } // At this time, it doesn't really matter if these preferences change // during the execution of the function; we should be safe in all // permutations. However, may as well just get the values onces and // then use them, just in case the consistency becomes important in // the future. bool invertVal = gfxPrefs::LayersEffectInvert(); bool grayscaleVal = gfxPrefs::LayersEffectGrayscale(); float contrastVal = gfxPrefs::LayersEffectContrast(); bool haveLayerEffects = (invertVal || grayscaleVal || contrastVal != 0.0); // Set LayerScope begin/end frame LayerScopeAutoFrame frame(PR_Now()); // Dump to console if (gfxPrefs::LayersDump()) { this->Dump(); } else if (profiler_feature_active("layersdump")) { std::stringstream ss; Dump(ss); profiler_log(ss.str().c_str()); } // Dump to LayerScope Viewer if (LayerScope::CheckSendable()) { // Create a LayersPacket, dump Layers into it and transfer the // packet('s ownership) to LayerScope. auto packet = MakeUnique<layerscope::Packet>(); layerscope::LayersPacket* layersPacket = packet->mutable_layers(); this->Dump(layersPacket); LayerScope::SendLayerDump(Move(packet)); } /** Our more efficient but less powerful alter ego, if one is available. */ nsRefPtr<Composer2D> composer2D; composer2D = mCompositor->GetWidget()->GetComposer2D(); // We can't use composert2D if we have layer effects if (!mTarget && !haveLayerEffects && gfxPrefs::Composer2DCompositionEnabled() && composer2D && composer2D->HasHwc() && composer2D->TryRenderWithHwc(mRoot, mCompositor->GetWidget(), mGeometryChanged)) { LayerScope::SetHWComposed(); if (mFPS) { double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now()); if (gfxPrefs::LayersDrawFPS()) { printf_stderr("HWComposer: FPS is %g\n", fps); } } mCompositor->EndFrameForExternalComposition(Matrix()); // Reset the invalid region as compositing is done mInvalidRegion.SetEmpty(); mLastFrameMissedHWC = false; return; } else if (!mTarget && !haveLayerEffects) { mLastFrameMissedHWC = !!composer2D; } { PROFILER_LABEL("LayerManagerComposite", "PreRender", js::ProfileEntry::Category::GRAPHICS); if (!mCompositor->GetWidget()->PreRender(this)) { return; } } nsIntRegion invalid; if (mTarget) { invalid = mTargetBounds; } else { invalid = mInvalidRegion; // Reset the invalid region now that we've begun compositing. mInvalidRegion.SetEmpty(); } ParentLayerIntRect clipRect; Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height); Rect actualBounds; CompositorBench(mCompositor, bounds); if (mRoot->GetClipRect()) { clipRect = *mRoot->GetClipRect(); Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); mCompositor->BeginFrame(invalid, &rect, bounds, nullptr, &actualBounds); } else { gfx::Rect rect; mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds); clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height); } if (actualBounds.IsEmpty()) { mCompositor->GetWidget()->PostRender(this); return; } // Allow widget to render a custom background. mCompositor->GetWidget()->DrawWindowUnderlay(this, IntRect(actualBounds.x, actualBounds.y, actualBounds.width, actualBounds.height)); RefPtr<CompositingRenderTarget> previousTarget; if (haveLayerEffects) { previousTarget = PushGroupForLayerEffects(); } else { mTwoPassTmpTarget = nullptr; } // Render our layers. RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot)); RootLayer()->RenderLayer(ParentLayerIntRect::ToUntyped(clipRect)); if (!mRegionToClear.IsEmpty()) { nsIntRegionRectIterator iter(mRegionToClear); const IntRect *r; while ((r = iter.Next())) { mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height)); } } if (mTwoPassTmpTarget) { MOZ_ASSERT(haveLayerEffects); PopGroupForLayerEffects(previousTarget, ParentLayerIntRect::ToUntyped(clipRect), grayscaleVal, invertVal, contrastVal); } // Allow widget to render a custom foreground. mCompositor->GetWidget()->DrawWindowOverlay(this, IntRect(actualBounds.x, actualBounds.y, actualBounds.width, actualBounds.height)); // Debugging RenderDebugOverlay(actualBounds); { PROFILER_LABEL("LayerManagerComposite", "EndFrame", js::ProfileEntry::Category::GRAPHICS); mCompositor->EndFrame(); mCompositor->SetDispAcquireFence(mRoot); // Call after EndFrame() } if (composer2D) { composer2D->Render(mCompositor->GetWidget()); } mCompositor->GetWidget()->PostRender(this); RecordFrame(); }
void LayerManagerComposite::PopGroupForLayerEffects(RefPtr<CompositingRenderTarget> aPreviousTarget, IntRect aClipRect, bool aGrayscaleEffect, bool aInvertEffect, float aContrastEffect) { MOZ_ASSERT(mTwoPassTmpTarget); // This is currently true, so just making sure that any new use of this // method is flagged for investigation MOZ_ASSERT(aInvertEffect || aGrayscaleEffect || aContrastEffect != 0.0); mCompositor->SetRenderTarget(aPreviousTarget); EffectChain effectChain(RootLayer()); Matrix5x4 effectMatrix; if (aGrayscaleEffect) { // R' = G' = B' = luminance // R' = 0.2126*R + 0.7152*G + 0.0722*B // G' = 0.2126*R + 0.7152*G + 0.0722*B // B' = 0.2126*R + 0.7152*G + 0.0722*B Matrix5x4 grayscaleMatrix(0.2126f, 0.2126f, 0.2126f, 0, 0.7152f, 0.7152f, 0.7152f, 0, 0.0722f, 0.0722f, 0.0722f, 0, 0, 0, 0, 1, 0, 0, 0, 0); effectMatrix = grayscaleMatrix; } if (aInvertEffect) { // R' = 1 - R // G' = 1 - G // B' = 1 - B Matrix5x4 colorInvertMatrix(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 1, 1, 1, 0); effectMatrix = effectMatrix * colorInvertMatrix; } if (aContrastEffect != 0.0) { // Multiplying with: // R' = (1 + c) * (R - 0.5) + 0.5 // G' = (1 + c) * (G - 0.5) + 0.5 // B' = (1 + c) * (B - 0.5) + 0.5 float cP1 = aContrastEffect + 1; float hc = 0.5*aContrastEffect; Matrix5x4 contrastMatrix( cP1, 0, 0, 0, 0, cP1, 0, 0, 0, 0, cP1, 0, 0, 0, 0, 1, -hc, -hc, -hc, 0); effectMatrix = effectMatrix * contrastMatrix; } effectChain.mPrimaryEffect = new EffectRenderTarget(mTwoPassTmpTarget); effectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX] = new EffectColorMatrix(effectMatrix); gfx::Rect clipRectF(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); mCompositor->DrawQuad(Rect(Point(0, 0), Size(mTwoPassTmpTarget->GetSize())), clipRectF, effectChain, 1., Matrix4x4()); }
void LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion) { PROFILER_LABEL("LayerManagerComposite", "Render", js::ProfileEntry::Category::GRAPHICS); if (mDestroyed || !mCompositor || mCompositor->IsDestroyed()) { NS_WARNING("Call on destroyed layer manager"); return; } ClearLayerFlags(mRoot); // At this time, it doesn't really matter if these preferences change // during the execution of the function; we should be safe in all // permutations. However, may as well just get the values onces and // then use them, just in case the consistency becomes important in // the future. bool invertVal = gfxPrefs::LayersEffectInvert(); bool grayscaleVal = gfxPrefs::LayersEffectGrayscale(); float contrastVal = gfxPrefs::LayersEffectContrast(); bool haveLayerEffects = (invertVal || grayscaleVal || contrastVal != 0.0); // Set LayerScope begin/end frame LayerScopeAutoFrame frame(PR_Now()); // Dump to console if (gfxPrefs::LayersDump()) { this->Dump(/* aSorted= */true); } else if (profiler_feature_active("layersdump")) { std::stringstream ss; Dump(ss); profiler_log(ss.str().c_str()); } // Dump to LayerScope Viewer if (LayerScope::CheckSendable()) { // Create a LayersPacket, dump Layers into it and transfer the // packet('s ownership) to LayerScope. auto packet = MakeUnique<layerscope::Packet>(); layerscope::LayersPacket* layersPacket = packet->mutable_layers(); this->Dump(layersPacket); LayerScope::SendLayerDump(Move(packet)); } mozilla::widget::WidgetRenderingContext widgetContext; #if defined(XP_MACOSX) widgetContext.mLayerManager = this; #elif defined(MOZ_WIDGET_ANDROID) widgetContext.mCompositor = GetCompositor(); #endif { PROFILER_LABEL("LayerManagerComposite", "PreRender", js::ProfileEntry::Category::GRAPHICS); if (!mCompositor->GetWidget()->PreRender(&widgetContext)) { return; } } ParentLayerIntRect clipRect; IntRect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height); IntRect actualBounds; CompositorBench(mCompositor, bounds); MOZ_ASSERT(mRoot->GetOpacity() == 1); #if defined(MOZ_WIDGET_ANDROID) LayerMetricsWrapper wrapper = GetRootContentLayer(); if (wrapper) { mCompositor->SetClearColor(wrapper.Metadata().GetBackgroundColor()); } else { mCompositor->SetClearColorToDefault(); } #endif if (mRoot->GetClipRect()) { clipRect = *mRoot->GetClipRect(); IntRect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, aOpaqueRegion, nullptr, &actualBounds); } else { gfx::IntRect rect; mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, aOpaqueRegion, &rect, &actualBounds); clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height); } if (actualBounds.IsEmpty()) { mCompositor->GetWidget()->PostRender(&widgetContext); return; } // Allow widget to render a custom background. mCompositor->GetWidget()->DrawWindowUnderlay( &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds)); RefPtr<CompositingRenderTarget> previousTarget; if (haveLayerEffects) { previousTarget = PushGroupForLayerEffects(); } else { mTwoPassTmpTarget = nullptr; } // Render our layers. RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot)); RootLayer()->RenderLayer(clipRect.ToUnknownRect()); if (!mRegionToClear.IsEmpty()) { for (auto iter = mRegionToClear.RectIter(); !iter.Done(); iter.Next()) { const IntRect& r = iter.Get(); mCompositor->ClearRect(Rect(r.x, r.y, r.width, r.height)); } } if (mTwoPassTmpTarget) { MOZ_ASSERT(haveLayerEffects); PopGroupForLayerEffects(previousTarget, clipRect.ToUnknownRect(), grayscaleVal, invertVal, contrastVal); } // Allow widget to render a custom foreground. mCompositor->GetWidget()->DrawWindowOverlay( &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds)); // Debugging RenderDebugOverlay(actualBounds); { PROFILER_LABEL("LayerManagerComposite", "EndFrame", js::ProfileEntry::Category::GRAPHICS); mCompositor->EndFrame(); // Call after EndFrame() mCompositor->SetDispAcquireFence(mRoot); } mCompositor->GetWidget()->PostRender(&widgetContext); RecordFrame(); }
void LayerManagerComposite::RenderToPresentationSurface() { #ifdef MOZ_WIDGET_ANDROID nsIWidget* const widget = mCompositor->GetWidget()->RealWidget(); auto window = static_cast<ANativeWindow*>( widget->GetNativeData(NS_PRESENTATION_WINDOW)); if (!window) { return; } EGLSurface surface = widget->GetNativeData(NS_PRESENTATION_SURFACE); if (!surface) { //create surface; surface = GLContextProviderEGL::CreateEGLSurface(window); if (!surface) { return; } widget->SetNativeData(NS_PRESENTATION_SURFACE, reinterpret_cast<uintptr_t>(surface)); } CompositorOGL* compositor = mCompositor->AsCompositorOGL(); GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); if (!egl) { return; } const IntSize windowSize(ANativeWindow_getWidth(window), ANativeWindow_getHeight(window)); #endif if ((windowSize.width <= 0) || (windowSize.height <= 0)) { return; } ScreenRotation rotation = compositor->GetScreenRotation(); const int actualWidth = windowSize.width; const int actualHeight = windowSize.height; const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); const nsIntRect originalRect = nsIntRect(0, 0, originalSize.width, originalSize.height); int pageWidth = originalSize.width; int pageHeight = originalSize.height; if (rotation == ROTATION_90 || rotation == ROTATION_270) { pageWidth = originalSize.height; pageHeight = originalSize.width; } float scale = 1.0; if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { const float scaleWidth = (float)actualWidth / (float)pageWidth; const float scaleHeight = (float)actualHeight / (float)pageHeight; scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; } const gfx::IntSize actualSize(actualWidth, actualHeight); ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); ScopedContextSurfaceOverride overrideSurface(egl, surface); Matrix viewMatrix = ComputeTransformForRotation(originalRect, rotation); viewMatrix.Invert(); // unrotate viewMatrix.PostScale(scale, scale); viewMatrix.PostTranslate(offset.x, offset.y); Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix); mRoot->ComputeEffectiveTransforms(matrix); nsIntRegion opaque; LayerIntRegion visible; PostProcessLayers(mRoot, opaque, visible, Nothing()); nsIntRegion invalid; IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight); IntRect rect, actualBounds; MOZ_ASSERT(mRoot->GetOpacity() == 1); mCompositor->BeginFrame(invalid, nullptr, bounds, nsIntRegion(), &rect, &actualBounds); // The Java side of Fennec sets a scissor rect that accounts for // chrome such as the URL bar. Override that so that the entire frame buffer // is cleared. ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight); egl->fClearColor(0.0, 0.0, 0.0, 0.0); egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); const IntRect clipRect = IntRect::Truncate(0, 0, actualWidth, actualHeight); RootLayer()->Prepare(RenderTargetIntRect::FromUnknownRect(clipRect)); RootLayer()->RenderLayer(clipRect); mCompositor->EndFrame(); }
void LayerManagerComposite::RenderToPresentationSurface() { #ifdef MOZ_WIDGET_ANDROID if (!AndroidBridge::Bridge()) { return; } void* window = AndroidBridge::Bridge()->GetPresentationWindow(); if (!window) { return; } EGLSurface surface = AndroidBridge::Bridge()->GetPresentationSurface(); if (!surface) { //create surface; surface = GLContextProviderEGL::CreateEGLSurface(window); if (!surface) { return; } AndroidBridge::Bridge()->SetPresentationSurface(surface); } CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get()); GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); if (!egl) { return; } const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window); #elif defined(MOZ_WIDGET_GONK) CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get()); nsScreenGonk* screen = static_cast<nsWindow*>(mCompositor->GetWidget())->GetScreen(); if (!screen->IsPrimaryScreen()) { // Only primary screen support mirroring return; } nsWindow* mirrorScreenWidget = screen->GetMirroringWidget(); if (!mirrorScreenWidget) { // No mirroring return; } nsScreenGonk* mirrorScreen = mirrorScreenWidget->GetScreen(); if (!mirrorScreen->GetTopWindows().IsEmpty()) { return; } EGLSurface surface = mirrorScreen->GetEGLSurface(); if (surface == LOCAL_EGL_NO_SURFACE) { // Create GLContext nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateForWindow(mirrorScreenWidget); mirrorScreenWidget->SetNativeData(NS_NATIVE_OPENGL_CONTEXT, reinterpret_cast<uintptr_t>(gl.get())); surface = mirrorScreen->GetEGLSurface(); if (surface == LOCAL_EGL_NO_SURFACE) { // Failed to create EGLSurface return; } } GLContext* gl = compositor->gl(); GLContextEGL* egl = GLContextEGL::Cast(gl); const IntSize windowSize = mirrorScreen->GetNaturalBounds().Size(); #endif if ((windowSize.width <= 0) || (windowSize.height <= 0)) { return; } ScreenRotation rotation = compositor->GetScreenRotation(); const int actualWidth = windowSize.width; const int actualHeight = windowSize.height; const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize(); const nsIntRect originalRect = nsIntRect(0, 0, originalSize.width, originalSize.height); int pageWidth = originalSize.width; int pageHeight = originalSize.height; if (rotation == ROTATION_90 || rotation == ROTATION_270) { pageWidth = originalSize.height; pageHeight = originalSize.width; } float scale = 1.0; if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) { const float scaleWidth = (float)actualWidth / (float)pageWidth; const float scaleHeight = (float)actualHeight / (float)pageHeight; scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight; } const gfx::IntSize actualSize(actualWidth, actualHeight); ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize); const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0); ScopedContextSurfaceOverride overrideSurface(egl, surface); Matrix viewMatrix = ComputeTransformForRotation(originalRect, rotation); viewMatrix.Invert(); // unrotate viewMatrix.PostScale(scale, scale); viewMatrix.PostTranslate(offset.x, offset.y); Matrix4x4 matrix = Matrix4x4::From2D(viewMatrix); mRoot->ComputeEffectiveTransforms(matrix); nsIntRegion opaque; ApplyOcclusionCulling(mRoot, opaque); nsIntRegion invalid; Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight); Rect rect, actualBounds; mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds); // The Java side of Fennec sets a scissor rect that accounts for // chrome such as the URL bar. Override that so that the entire frame buffer // is cleared. ScopedScissorRect scissorRect(egl, 0, 0, actualWidth, actualHeight); egl->fClearColor(0.0, 0.0, 0.0, 0.0); egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT); const IntRect clipRect = IntRect(0, 0, actualWidth, actualHeight); RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect)); RootLayer()->RenderLayer(clipRect); mCompositor->EndFrame(); mCompositor->SetDispAcquireFence(mRoot); // Call after EndFrame() #ifdef MOZ_WIDGET_GONK nsRefPtr<Composer2D> composer2D; composer2D = mCompositor->GetWidget()->GetComposer2D(); if (composer2D) { composer2D->Render(mirrorScreenWidget); } #endif }
void LayerManagerComposite::Render() { PROFILER_LABEL("LayerManagerComposite", "Render", js::ProfileEntry::Category::GRAPHICS); if (mDestroyed) { NS_WARNING("Call on destroyed layer manager"); return; } /** Our more efficient but less powerful alter ego, if one is available. */ nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D(); // Set LayerScope begin/end frame LayerScopeAutoFrame frame(PR_Now()); // Dump to console if (gfxPrefs::LayersDump()) { this->Dump(); } // Dump to LayerScope Viewer if (LayerScope::CheckSendable()) { // Create a LayersPacket, dump Layers into it and transfer the // packet('s ownership) to LayerScope. auto packet = MakeUnique<layerscope::Packet>(); layerscope::LayersPacket* layersPacket = packet->mutable_layers(); this->Dump(layersPacket); LayerScope::SendLayerDump(Move(packet)); } if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) { if (mFPS) { double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now()); if (gfxPrefs::LayersDrawFPS()) { printf_stderr("HWComposer: FPS is %g\n", fps); } } mCompositor->EndFrameForExternalComposition(mWorldMatrix); // Reset the invalid region as compositing is done mInvalidRegion.SetEmpty(); return; } { PROFILER_LABEL("LayerManagerComposite", "PreRender", js::ProfileEntry::Category::GRAPHICS); if (!mCompositor->GetWidget()->PreRender(this)) { return; } } nsIntRegion invalid; if (mTarget) { invalid = mTargetBounds; } else { invalid = mInvalidRegion; // Reset the invalid region now that we've begun compositing. mInvalidRegion.SetEmpty(); } nsIntRect clipRect; Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height); Rect actualBounds; CompositorBench(mCompositor, bounds); if (mRoot->GetClipRect()) { clipRect = *mRoot->GetClipRect(); WorldTransformRect(clipRect); Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); mCompositor->BeginFrame(invalid, &rect, mWorldMatrix, bounds, nullptr, &actualBounds); } else { gfx::Rect rect; mCompositor->BeginFrame(invalid, nullptr, mWorldMatrix, bounds, &rect, &actualBounds); clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height); } if (actualBounds.IsEmpty()) { mCompositor->GetWidget()->PostRender(this); return; } // Allow widget to render a custom background. mCompositor->GetWidget()->DrawWindowUnderlay(this, nsIntRect(actualBounds.x, actualBounds.y, actualBounds.width, actualBounds.height)); // Render our layers. RootLayer()->Prepare(clipRect); RootLayer()->RenderLayer(clipRect); if (!mRegionToClear.IsEmpty()) { nsIntRegionRectIterator iter(mRegionToClear); const nsIntRect *r; while ((r = iter.Next())) { mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height)); } } // Allow widget to render a custom foreground. mCompositor->GetWidget()->DrawWindowOverlay(this, nsIntRect(actualBounds.x, actualBounds.y, actualBounds.width, actualBounds.height)); // Debugging RenderDebugOverlay(actualBounds); { PROFILER_LABEL("LayerManagerComposite", "EndFrame", js::ProfileEntry::Category::GRAPHICS); mCompositor->EndFrame(); mCompositor->SetFBAcquireFence(mRoot); } mCompositor->GetWidget()->PostRender(this); RecordFrame(); }