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(); }
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::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(); } // 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; // We can't use composert2D if we have layer effects, so only get it // when we don't have any effects. if (!haveLayerEffects) { composer2D = mCompositor->GetWidget()->GetComposer2D(); } 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)); RefPtr<CompositingRenderTarget> previousTarget; if (haveLayerEffects) { previousTarget = PushGroupForLayerEffects(); } else { mTwoPassTmpTarget = nullptr; } // Render our layers. RootLayer()->Prepare(RenderTargetPixel::FromUntyped(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)); } } if (mTwoPassTmpTarget) { MOZ_ASSERT(haveLayerEffects); PopGroupForLayerEffects(previousTarget, clipRect, grayscaleVal, invertVal, contrastVal); } // 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(); }