예제 #1
0
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();
}
예제 #2
0
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);
}
예제 #3
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();
}