void
ThebesLayerComposite::RenderLayer(const nsIntPoint& aOffset,
                                  const nsIntRect& aClipRect)
{
  if (!mBuffer || !mBuffer->IsAttached()) {
    return;
  }

  MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() &&
             mBuffer->GetLayer() == this,
             "buffer is corrupted");

  gfx::Matrix4x4 transform;
  ToMatrix4x4(GetEffectiveTransform(), transform);
  gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);

#ifdef MOZ_DUMP_PAINTING
  if (gfxUtils::sDumpPainting) {
    nsRefPtr<gfxImageSurface> surf = mBuffer->GetAsSurface();
    WriteSnapshotToDumpFile(this, surf);
  }
#endif

  EffectChain effectChain;
  LayerManagerComposite::AddMaskEffect(mMaskLayer, effectChain);

  nsIntRegion visibleRegion = GetEffectiveVisibleRegion();

  TiledLayerProperties tiledLayerProps;
  if (mRequiresTiledProperties) {
    // calculating these things can be a little expensive, so don't
    // do them if we don't have to
    tiledLayerProps.mVisibleRegion = visibleRegion;
    tiledLayerProps.mDisplayPort = GetDisplayPort();
    tiledLayerProps.mEffectiveResolution = GetEffectiveResolution();
    tiledLayerProps.mCompositionBounds = GetCompositionBounds();
    tiledLayerProps.mRetainTiles = !mIsFixedPosition;
    tiledLayerProps.mValidRegion = mValidRegion;
  }

  mBuffer->SetPaintWillResample(MayResample());

  mBuffer->Composite(effectChain,
                     GetEffectiveOpacity(),
                     transform,
                     gfx::Point(aOffset.x, aOffset.y),
                     gfx::FILTER_LINEAR,
                     clipRect,
                     &visibleRegion,
                     mRequiresTiledProperties ? &tiledLayerProps
                                              : nullptr);


  if (mRequiresTiledProperties) {
    mValidRegion = tiledLayerProps.mValidRegion;
  }

  LayerManagerComposite::RemoveMaskEffect(mMaskLayer);
  mCompositeManager->GetCompositor()->MakeCurrent();
}
void
ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
{
  if (!mImageHost || !mImageHost->IsAttached()) {
    return;
  }

#ifdef MOZ_DUMP_PAINTING
  if (gfxUtils::sDumpPainting) {
    nsRefPtr<gfxImageSurface> surf = mImageHost->GetAsSurface();
    WriteSnapshotToDumpFile(this, surf);
  }
#endif

  mCompositor->MakeCurrent();

  EffectChain effectChain;
  LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);

  gfx::Matrix4x4 transform;
  ToMatrix4x4(GetEffectiveTransform(), transform);
  gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
  mImageHost->SetCompositor(mCompositor);
  mImageHost->Composite(effectChain,
                        GetEffectiveOpacity(),
                        transform,
                        gfx::ToFilter(mFilter),
                        clipRect);
}
void
ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
{
  if (!mImageHost || !mImageHost->IsAttached()) {
    return;
  }

#ifdef MOZ_DUMP_PAINTING
  if (gfxUtils::sDumpPainting) {
    RefPtr<gfx::DataSourceSurface> dSurf = mImageHost->GetAsSurface();
    gfxPlatform *platform = gfxPlatform::GetPlatform();
    RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
                                                                   dSurf->GetSize(),
                                                                   dSurf->Stride(),
                                                                   dSurf->GetFormat());
    nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
    WriteSnapshotToDumpFile(this, surf);
  }
#endif

  mCompositor->MakeCurrent();

  EffectChain effectChain;
  LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);

  gfx::Matrix4x4 transform;
  ToMatrix4x4(GetEffectiveTransform(), transform);
  gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
  mImageHost->SetCompositor(mCompositor);
  mImageHost->Composite(effectChain,
                        GetEffectiveOpacity(),
                        transform,
                        gfx::ToFilter(mFilter),
                        clipRect);
}
Example #4
0
void
ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
{
  if (!mBuffer || !mBuffer->IsAttached()) {
    return;
  }
  PROFILER_LABEL("ThebesLayerComposite", "RenderLayer",
    js::ProfileEntry::Category::GRAPHICS);

  MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() &&
             mBuffer->GetLayer() == this,
             "buffer is corrupted");

  gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);

#ifdef MOZ_DUMP_PAINTING
  if (gfxUtils::sDumpPainting) {
    RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
    if (surf) {
      WriteSnapshotToDumpFile(this, surf);
    }
  }
#endif

  EffectChain effectChain(this);
  LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
  AddBlendModeEffect(effectChain);

  const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();

  TiledLayerProperties tiledLayerProps;
  if (mRequiresTiledProperties) {
    tiledLayerProps.mVisibleRegion = visibleRegion;
    tiledLayerProps.mEffectiveResolution = GetEffectiveResolution();
    tiledLayerProps.mValidRegion = mValidRegion;
  }

  mBuffer->SetPaintWillResample(MayResample());

  mBuffer->Composite(effectChain,
                     GetEffectiveOpacity(),
                     GetEffectiveTransform(),
                     gfx::Filter::LINEAR,
                     clipRect,
                     &visibleRegion,
                     mRequiresTiledProperties ? &tiledLayerProps
                                              : nullptr);
  mBuffer->BumpFlashCounter();

  if (mRequiresTiledProperties) {
    mValidRegion = tiledLayerProps.mValidRegion;
  }

  mCompositeManager->GetCompositor()->MakeCurrent();
}
void
PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
{
  if (!mBuffer || !mBuffer->IsAttached()) {
    return;
  }
  PROFILER_LABEL("PaintedLayerComposite", "RenderLayer",
    js::ProfileEntry::Category::GRAPHICS);

  Compositor* compositor = mCompositeManager->GetCompositor();

  MOZ_ASSERT(mBuffer->GetCompositor() == compositor &&
             mBuffer->GetLayer() == this,
             "buffer is corrupted");

  const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();

#ifdef MOZ_DUMP_PAINTING
  if (gfxUtils::sDumpPainting) {
    RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
    if (surf) {
      WriteSnapshotToDumpFile(this, surf);
    }
  }
#endif


  RenderWithAllMasks(this, compositor, aClipRect,
                     [&](EffectChain& effectChain, const Rect& clipRect) {
    mBuffer->SetPaintWillResample(MayResample());

    mBuffer->Composite(this, effectChain,
                       GetEffectiveOpacity(),
                       GetEffectiveTransform(),
                       GetEffectFilter(),
                       clipRect,
                       &visibleRegion);
  });

  mBuffer->BumpFlashCounter();

  compositor->MakeCurrent();
}
static void
ContainerRender(Container* aContainer,
                int aPreviousFrameBuffer,
                const nsIntPoint& aOffset,
                LayerManagerOGL* aManager)
{
  /**
   * Setup our temporary texture for rendering the contents of this container.
   */
  GLuint containerSurface;
  GLuint frameBuffer;

  nsIntPoint childOffset(aOffset);
  nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();

  nsIntRect cachedScissor = aContainer->gl()->ScissorRect();
  aContainer->gl()->PushScissorRect();
  aContainer->mSupportsComponentAlphaChildren = false;

  float opacity = aContainer->GetEffectiveOpacity();
  const gfx3DMatrix& transform = aContainer->GetEffectiveTransform();
  bool needsFramebuffer = aContainer->UseIntermediateSurface();
  if (needsFramebuffer) {
    nsIntRect framebufferRect = visibleRect;
    // we're about to create a framebuffer backed by textures to use as an intermediate
    // surface. What to do if its size (as given by framebufferRect) would exceed the
    // maximum texture size supported by the GL? The present code chooses the compromise
    // of just clamping the framebuffer's size to the max supported size.
    // This gives us a lower resolution rendering of the intermediate surface (children layers).
    // See bug 827170 for a discussion.
    GLint maxTexSize;
    aContainer->gl()->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTexSize);
    framebufferRect.width = std::min(framebufferRect.width, maxTexSize);
    framebufferRect.height = std::min(framebufferRect.height, maxTexSize);

    LayerManagerOGL::InitMode mode = LayerManagerOGL::InitModeClear;
    if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 && 
        (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
    {
      // don't need a background, we're going to paint all opaque stuff
      aContainer->mSupportsComponentAlphaChildren = true;
      mode = LayerManagerOGL::InitModeNone;
    } else {
      const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
      gfxMatrix transform;
      // If we have an opaque ancestor layer, then we can be sure that
      // all the pixels we draw into are either opaque already or will be
      // covered by something opaque. Otherwise copying up the background is
      // not safe.
      if (HasOpaqueAncestorLayer(aContainer) &&
          transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
        mode = gfxPlatform::GetPlatform()->UsesSubpixelAATextRendering() ?
		LayerManagerOGL::InitModeCopy :
		LayerManagerOGL::InitModeClear;
        framebufferRect.x += transform.x0;
        framebufferRect.y += transform.y0;
        aContainer->mSupportsComponentAlphaChildren = gfxPlatform::GetPlatform()->UsesSubpixelAATextRendering();
      }
    }

    aContainer->gl()->PushViewportRect();
    framebufferRect -= childOffset;
    if (!aManager->CompositingDisabled()) {
      aManager->CreateFBOWithTexture(framebufferRect,
                                     mode,
                                     aPreviousFrameBuffer,
                                     &frameBuffer,
                                     &containerSurface);
    }
    childOffset.x = visibleRect.x;
    childOffset.y = visibleRect.y;
  } else {
    frameBuffer = aPreviousFrameBuffer;
    aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
      (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
  }

  nsAutoTArray<Layer*, 12> children;
  aContainer->SortChildrenBy3DZOrder(children);

  /**
   * Render this container's contents.
   */
  for (uint32_t i = 0; i < children.Length(); i++) {
    LayerOGL* layerToRender = static_cast<LayerOGL*>(children.ElementAt(i)->ImplData());

    if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) {
      continue;
    }

    nsIntRect scissorRect = layerToRender->GetLayer()->
        CalculateScissorRect(cachedScissor, &aManager->GetWorldTransform());
    if (scissorRect.IsEmpty()) {
      continue;
    }

    aContainer->gl()->fScissor(scissorRect.x, 
                               scissorRect.y, 
                               scissorRect.width, 
                               scissorRect.height);

    layerToRender->RenderLayer(frameBuffer, childOffset);
    aContainer->gl()->MakeCurrent();
  }


  if (needsFramebuffer) {
    // Unbind the current framebuffer and rebind the previous one.
#ifdef MOZ_DUMP_PAINTING
    if (gfxUtils::sDumpPainting) {
      nsRefPtr<gfxImageSurface> surf = 
        aContainer->gl()->GetTexImage(containerSurface, true, aManager->GetFBOLayerProgramType());

      WriteSnapshotToDumpFile(aContainer, surf);
    }
#endif
    
    // Restore the viewport
    aContainer->gl()->PopViewportRect();
    nsIntRect viewport = aContainer->gl()->ViewportRect();
    aManager->SetupPipeline(viewport.width, viewport.height,
                            LayerManagerOGL::ApplyWorldTransform);
    aContainer->gl()->PopScissorRect();
    aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);

    if (!aManager->CompositingDisabled()) {
      aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);

      aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);

      aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);

      MaskType maskType = MaskNone;
      if (aContainer->GetMaskLayer()) {
        if (!aContainer->GetTransform().CanDraw2D()) {
          maskType = Mask3d;
        } else {
          maskType = Mask2d;
        }
      }
      ShaderProgramOGL *rgb =
        aManager->GetFBOLayerProgram(maskType);

      rgb->Activate();
      rgb->SetLayerQuadRect(visibleRect);
      rgb->SetLayerTransform(transform);
      rgb->SetLayerOpacity(opacity);
      rgb->SetRenderOffset(aOffset);
      rgb->SetTextureUnit(0);
      rgb->LoadMask(aContainer->GetMaskLayer());

      if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
        // 2DRect case, get the multiplier right for a sampler2DRect
        rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
      }

      // Drawing is always flipped, but when copying between surfaces we want to avoid
      // this. Pass true for the flip parameter to introduce a second flip
      // that cancels the other one out.
      aManager->BindAndDrawQuad(rgb, true);

      // Clean up resources.  This also unbinds the texture.
      aContainer->gl()->fDeleteTextures(1, &containerSurface);
    }
  } else {
    aContainer->gl()->PopScissorRect();
  }
}
template<class ContainerT> void
ContainerRender(ContainerT* aContainer,
                const nsIntPoint& aOffset,
                LayerManagerComposite* aManager,
                const nsIntRect& aClipRect)
{
  /**
   * Setup our temporary surface for rendering the contents of this container.
   */
  RefPtr<CompositingRenderTarget> surface;

  Compositor* compositor = aManager->GetCompositor();

  RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();

  nsIntPoint childOffset(aOffset);
  nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();

  aContainer->mSupportsComponentAlphaChildren = false;

  float opacity = aContainer->GetEffectiveOpacity();

  bool needsSurface = aContainer->UseIntermediateSurface();
  if (needsSurface) {
    SurfaceInitMode mode = INIT_MODE_CLEAR;
    bool surfaceCopyNeeded = false;
    gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
                                            visibleRect.width, visibleRect.height);
    // we're about to create a framebuffer backed by textures to use as an intermediate
    // surface. What to do if its size (as given by framebufferRect) would exceed the
    // maximum texture size supported by the GL? The present code chooses the compromise
    // of just clamping the framebuffer's size to the max supported size.
    // This gives us a lower resolution rendering of the intermediate surface (children layers).
    // See bug 827170 for a discussion.
    int32_t maxTextureSize = compositor->GetMaxTextureSize();
    surfaceRect.width = std::min(maxTextureSize, surfaceRect.width);
    surfaceRect.height = std::min(maxTextureSize, surfaceRect.height);
    if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 &&
        (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
    {
      // don't need a background, we're going to paint all opaque stuff
      aContainer->mSupportsComponentAlphaChildren = true;
      mode = INIT_MODE_NONE;
    } else {
      const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
      gfxMatrix transform;
      // If we have an opaque ancestor layer, then we can be sure that
      // all the pixels we draw into are either opaque already or will be
      // covered by something opaque. Otherwise copying up the background is
      // not safe.
      if (HasOpaqueAncestorLayer(aContainer) &&
          transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
        mode = gfxPlatform::GetPlatform()->UsesSubpixelAATextRendering() ?
                                            INIT_MODE_COPY : INIT_MODE_CLEAR;
        surfaceCopyNeeded = (mode == INIT_MODE_COPY);
        surfaceRect.x += transform.x0;
        surfaceRect.y += transform.y0;
        aContainer->mSupportsComponentAlphaChildren
          = gfxPlatform::GetPlatform()->UsesSubpixelAATextRendering();
      }
    }

    surfaceRect -= gfx::IntPoint(aOffset.x, aOffset.y);
    if (surfaceCopyNeeded) {
      surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget);
    } else {
      surface = compositor->CreateRenderTarget(surfaceRect, mode);
    }
    compositor->SetRenderTarget(surface);
    childOffset.x = visibleRect.x;
    childOffset.y = visibleRect.y;
  } else {
    surface = previousTarget;
    aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
      (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
  }

  nsAutoTArray<Layer*, 12> children;
  aContainer->SortChildrenBy3DZOrder(children);

  /**
   * Render this container's contents.
   */
  for (uint32_t i = 0; i < children.Length(); i++) {
    LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());

    if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() &&
        !layerToRender->GetLayer()->AsContainerLayer()) {
      continue;
    }

    nsIntRect clipRect = layerToRender->GetLayer()->
        CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
    if (clipRect.IsEmpty()) {
      continue;
    }

    layerToRender->RenderLayer(childOffset, clipRect);
    // invariant: our GL context should be current here, I don't think we can
    // assert it though
  }

  if (needsSurface) {
    // Unbind the current surface and rebind the previous one.
#ifdef MOZ_DUMP_PAINTING
    if (gfxUtils::sDumpPainting) {
      nsRefPtr<gfxImageSurface> surf = surface->Dump(aManager->GetCompositor());
      WriteSnapshotToDumpFile(aContainer, surf);
    }
#endif

    compositor->SetRenderTarget(previousTarget);
    EffectChain effectChain;
    LayerManagerComposite::AddMaskEffect(aContainer->GetMaskLayer(),
                                         effectChain,
                                         !aContainer->GetTransform().CanDraw2D());

    effectChain.mPrimaryEffect = new EffectRenderTarget(surface);

    gfx::Matrix4x4 transform;
    ToMatrix4x4(aContainer->GetEffectiveTransform(), transform);

    gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
    gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
    aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
                                        transform, gfx::Point(aOffset.x, aOffset.y));
  }

  if (aContainer->GetFrameMetrics().IsScrollable()) {
    gfx::Matrix4x4 transform;
    ToMatrix4x4(aContainer->GetEffectiveTransform(), transform);

    const FrameMetrics& frame = aContainer->GetFrameMetrics();
    LayerRect layerViewport = frame.mViewport * frame.LayersPixelsPerCSSPixel();
    gfx::Rect rect(layerViewport.x, layerViewport.y, layerViewport.width, layerViewport.height);
    gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
    aManager->GetCompositor()->DrawDiagnostics(gfx::Color(1.0, 0.0, 0.0, 1.0),
                                               rect, clipRect,
                                               transform, gfx::Point(aOffset.x, aOffset.y));
  }
}
Example #8
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);
}
Example #9
0
template<class ContainerT> void
ContainerRender(ContainerT* aContainer,
                LayerManagerComposite* aManager,
                const nsIntRect& aClipRect)
{
    /**
     * Setup our temporary surface for rendering the contents of this container.
     */
    RefPtr<CompositingRenderTarget> surface;

    Compositor* compositor = aManager->GetCompositor();

    RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();

    nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();

    aContainer->mSupportsComponentAlphaChildren = false;

    float opacity = aContainer->GetEffectiveOpacity();

    bool needsSurface = aContainer->UseIntermediateSurface();
    if (needsSurface) {
        SurfaceInitMode mode = INIT_MODE_CLEAR;
        bool surfaceCopyNeeded = false;
        gfx::IntRect surfaceRect = gfx::IntRect(visibleRect.x, visibleRect.y,
                                                visibleRect.width, visibleRect.height);
        gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.x, visibleRect.y);
        // we're about to create a framebuffer backed by textures to use as an intermediate
        // surface. What to do if its size (as given by framebufferRect) would exceed the
        // maximum texture size supported by the GL? The present code chooses the compromise
        // of just clamping the framebuffer's size to the max supported size.
        // This gives us a lower resolution rendering of the intermediate surface (children layers).
        // See bug 827170 for a discussion.
        int32_t maxTextureSize = compositor->GetMaxTextureSize();
        surfaceRect.width = std::min(maxTextureSize, surfaceRect.width);
        surfaceRect.height = std::min(maxTextureSize, surfaceRect.height);
        if (aContainer->GetEffectiveVisibleRegion().GetNumRects() == 1 &&
                (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE))
        {
            // don't need a background, we're going to paint all opaque stuff
            aContainer->mSupportsComponentAlphaChildren = true;
            mode = INIT_MODE_NONE;
        } else {
            const gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform();
            gfx::Matrix transform;
            // If we have an opaque ancestor layer, then we can be sure that
            // all the pixels we draw into are either opaque already or will be
            // covered by something opaque. Otherwise copying up the background is
            // not safe.
            if (HasOpaqueAncestorLayer(aContainer) &&
                    transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) {
                surfaceCopyNeeded = gfxPlatform::ComponentAlphaEnabled();
                sourcePoint.x += transform._31;
                sourcePoint.y += transform._32;
                aContainer->mSupportsComponentAlphaChildren
                    = gfxPlatform::ComponentAlphaEnabled();
            }
        }

        sourcePoint -= compositor->GetCurrentRenderTarget()->GetOrigin();
        if (surfaceCopyNeeded) {
            surface = compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
        } else {
            surface = compositor->CreateRenderTarget(surfaceRect, mode);
        }

        if (!surface) {
            return;
        }

        compositor->SetRenderTarget(surface);
    } else {
        surface = previousTarget;
        aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
                (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
    }

    nsAutoTArray<Layer*, 12> children;
    aContainer->SortChildrenBy3DZOrder(children);

    /**
     * Render this container's contents.
     */
    for (uint32_t i = 0; i < children.Length(); i++) {
        LayerComposite* layerToRender = static_cast<LayerComposite*>(children.ElementAt(i)->ImplData());

        if (layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty() &&
                !layerToRender->GetLayer()->AsContainerLayer()) {
            continue;
        }

        if (i + 1 < children.Length() &&
                layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) {
            LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData());
            nsIntRect nextLayerOpaqueRect;
            if (nextLayer && nextLayer->GetLayer()) {
                nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer());
            }
            if (!nextLayerOpaqueRect.IsEmpty()) {
                nsIntRegion visibleRegion;
                visibleRegion.Sub(layerToRender->GetShadowVisibleRegion(), nextLayerOpaqueRect);
                layerToRender->SetShadowVisibleRegion(visibleRegion);
                if (visibleRegion.IsEmpty()) {
                    continue;
                }
            }
        }

        nsIntRect clipRect = layerToRender->GetLayer()->
                             CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
        if (clipRect.IsEmpty()) {
            continue;
        }

        if (layerToRender->HasLayerBeenComposited()) {
            // Composer2D will compose this layer so skip GPU composition
            // this time & reset composition flag for next composition phase
            layerToRender->SetLayerComposited(false);
            if (layerToRender->GetClearFB()) {
                // Clear layer's visible rect on FrameBuffer with transparent pixels
                gfx::Rect aRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
                compositor->clearFBRect(&aRect);
                layerToRender->SetClearFB(false);
            }
        } else {
            layerToRender->RenderLayer(clipRect);
        }

        if (gfxPlatform::GetPrefLayersScrollGraph()) {
            DrawVelGraph(clipRect, aManager, layerToRender->GetLayer());
        }
        // invariant: our GL context should be current here, I don't think we can
        // assert it though
    }

    if (needsSurface) {
        // Unbind the current surface and rebind the previous one.
#ifdef MOZ_DUMP_PAINTING
        if (gfxUtils::sDumpPainting) {
            RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
            WriteSnapshotToDumpFile(aContainer, surf);
        }
#endif

        compositor->SetRenderTarget(previousTarget);
        EffectChain effectChain;
        LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(),
                effectChain,
                !aContainer->GetTransform().CanDraw2D());

        effectChain.mPrimaryEffect = new EffectRenderTarget(surface);

        gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
        gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
        aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
                                            aContainer->GetEffectiveTransform());
    }

    if (aContainer->GetFrameMetrics().IsScrollable()) {
        const FrameMetrics& frame = aContainer->GetFrameMetrics();
        LayerRect layerBounds = ScreenRect(frame.mCompositionBounds) * ScreenToLayerScale(1.0);
        gfx::Rect rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height);
        gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
        aManager->GetCompositor()->DrawDiagnostics(DIAGNOSTIC_CONTAINER,
                rect, clipRect,
                aContainer->GetEffectiveTransform());
    }
}