Ejemplo n.º 1
0
void
ContainerLayerD3D9::RenderLayer()
{
  nsRefPtr<IDirect3DSurface9> previousRenderTarget;
  nsRefPtr<IDirect3DTexture9> renderTexture;
  float previousRenderTargetOffset[4];
  float renderTargetOffset[] = { 0, 0, 0, 0 };
  float oldViewMatrix[4][4];

  RECT containerD3D9ClipRect; 
  device()->GetScissorRect(&containerD3D9ClipRect);
  // Convert scissor to an nsIntRect. RECT's are exclusive on the bottom and
  // right values.
  nsIntRect oldScissor(containerD3D9ClipRect.left, 
                       containerD3D9ClipRect.top,
                       containerD3D9ClipRect.right - containerD3D9ClipRect.left,
                       containerD3D9ClipRect.bottom - containerD3D9ClipRect.top);

  ReadbackProcessor readback;
  readback.BuildUpdates(this);

  nsIntRect visibleRect = GetEffectiveVisibleRegion().GetBounds();
  bool useIntermediate = UseIntermediateSurface();

  mSupportsComponentAlphaChildren = false;
  if (useIntermediate) {
    nsRefPtr<IDirect3DSurface9> renderSurface;
    if (!mD3DManager->CompositingDisabled()) {
      device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
      HRESULT hr = device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
                                           D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                                           D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
                                           nullptr);
      if (FAILED(hr)) {
        ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
                                hr);
        return;
      }

      nsRefPtr<IDirect3DSurface9> renderSurface;
      renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
      device()->SetRenderTarget(0, renderSurface);
    }

    if (mVisibleRegion.GetNumRects() == 1 && 
        (GetContentFlags() & CONTENT_OPAQUE)) {
      // don't need a background, we're going to paint all opaque stuff
      mSupportsComponentAlphaChildren = true;
    } else {
      Matrix4x4 transform3D = GetEffectiveTransform();
      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.
      HRESULT hr = E_FAIL;
      if (HasOpaqueAncestorLayer(this) &&
          transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) {
        // Copy background up from below
        RECT dest = { 0, 0, visibleRect.width, visibleRect.height };
        RECT src = dest;
        ::OffsetRect(&src,
                     visibleRect.x + int32_t(transform._31),
                     visibleRect.y + int32_t(transform._32));
        if (!mD3DManager->CompositingDisabled()) {
          hr = device()->
            StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
        }
      }
      if (hr == S_OK) {
        mSupportsComponentAlphaChildren = true;
      } else if (!mD3DManager->CompositingDisabled()) {
        device()->
          Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
      }
    }

    device()->
      GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
    renderTargetOffset[0] = (float)visibleRect.x;
    renderTargetOffset[1] = (float)visibleRect.y;
    device()->
      SetVertexShaderConstantF(CBvRenderTargetOffset, renderTargetOffset, 1);

    gfx3DMatrix viewMatrix;
    /*
     * Matrix to transform to viewport space ( <-1.0, 1.0> topleft,
     * <1.0, -1.0> bottomright)
     */
    viewMatrix._11 = 2.0f / visibleRect.width;
    viewMatrix._22 = -2.0f / visibleRect.height;
    viewMatrix._41 = -1.0f;
    viewMatrix._42 = 1.0f;

    device()->
      GetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
    device()->
      SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4);
  } else {
    mSupportsComponentAlphaChildren = 
        (GetContentFlags() & CONTENT_OPAQUE) ||
        (mParent && 
         mParent->SupportsComponentAlphaChildren());
  }

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

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

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

    nsIntRect scissorRect =
      RenderTargetPixel::ToUntyped(layerToRender->GetLayer()->CalculateScissorRect(RenderTargetPixel::FromUntyped(oldScissor), nullptr));
    if (scissorRect.IsEmpty()) {
      continue;
    }

    RECT d3drect;
    d3drect.left = scissorRect.x;
    d3drect.top = scissorRect.y;
    d3drect.right = scissorRect.x + scissorRect.width;
    d3drect.bottom = scissorRect.y + scissorRect.height;
    device()->SetScissorRect(&d3drect);

    if (layerToRender->GetLayer()->GetType() == TYPE_THEBES) {
      static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback);
    } else {
      layerToRender->RenderLayer();
    }
  }
    
  if (useIntermediate && !mD3DManager->CompositingDisabled()) {
    device()->SetRenderTarget(0, previousRenderTarget);
    device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
    device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);

    device()->SetVertexShaderConstantF(CBvLayerQuad,
                                       ShaderConstantRect(visibleRect.x,
                                                          visibleRect.y,
                                                          visibleRect.width,
                                                          visibleRect.height),
                                       1);

    SetShaderTransformAndOpacity();
    mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER,
                               GetMaskLayer(),
                               GetTransform().CanDraw2D());

    device()->SetTexture(0, renderTexture);
    device()->SetScissorRect(&containerD3D9ClipRect);
    device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
  } else {
    device()->SetScissorRect(&containerD3D9ClipRect);
  }
}
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();
  }
}
Ejemplo n.º 3
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());
    }
}
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));
  }
}
Ejemplo n.º 5
0
void
ContainerLayerD3D9::RenderLayer()
{
  nsRefPtr<IDirect3DSurface9> previousRenderTarget;
  nsRefPtr<IDirect3DTexture9> renderTexture;
  float previousRenderTargetOffset[4];
  RECT containerClipRect;
  float renderTargetOffset[] = { 0, 0, 0, 0 };
  float oldViewMatrix[4][4];

  device()->GetScissorRect(&containerClipRect);

  ReadbackProcessor readback;
  readback.BuildUpdates(this);

  nsIntRect visibleRect = mVisibleRegion.GetBounds();
  PRBool useIntermediate = UseIntermediateSurface();

  mSupportsComponentAlphaChildren = PR_FALSE;
  gfxMatrix contTransform;
  if (useIntermediate) {
    device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
    device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
                            D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                            D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
                            NULL);
    nsRefPtr<IDirect3DSurface9> renderSurface;
    renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
    device()->SetRenderTarget(0, renderSurface);

    if (mVisibleRegion.GetNumRects() == 1 && (GetContentFlags() & CONTENT_OPAQUE)) {
      // don't need a background, we're going to paint all opaque stuff
      mSupportsComponentAlphaChildren = PR_TRUE;
    } else {
      const gfx3DMatrix& transform3D = 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.
      HRESULT hr = E_FAIL;
      if (HasOpaqueAncestorLayer(this) &&
          transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
        // Copy background up from below
        RECT dest = { 0, 0, visibleRect.width, visibleRect.height };
        RECT src = dest;
        ::OffsetRect(&src,
                     visibleRect.x + PRInt32(transform.x0),
                     visibleRect.y + PRInt32(transform.y0));
        hr = device()->
          StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
      }
      if (hr == S_OK) {
        mSupportsComponentAlphaChildren = PR_TRUE;
      } else {
        device()->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
      }
    }

    device()->GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
    renderTargetOffset[0] = (float)visibleRect.x;
    renderTargetOffset[1] = (float)visibleRect.y;
    device()->SetVertexShaderConstantF(CBvRenderTargetOffset, renderTargetOffset, 1);

    gfx3DMatrix viewMatrix;
    /*
     * Matrix to transform to viewport space ( <-1.0, 1.0> topleft,
     * <1.0, -1.0> bottomright)
     */
    viewMatrix._11 = 2.0f / visibleRect.width;
    viewMatrix._22 = -2.0f / visibleRect.height;
    viewMatrix._41 = -1.0f;
    viewMatrix._42 = 1.0f;

    device()->GetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
    device()->SetVertexShaderConstantF(CBmProjection, &viewMatrix._11, 4);
  } else {
#ifdef DEBUG
    PRBool is2d =
#endif
    GetEffectiveTransform().Is2D(&contTransform);
    NS_ASSERTION(is2d, "Transform must be 2D");
    mSupportsComponentAlphaChildren = (GetContentFlags() & CONTENT_OPAQUE) ||
        (mParent && mParent->SupportsComponentAlphaChildren());
  }

  /*
   * Render this container's contents.
   */
  for (LayerD3D9* layerToRender = GetFirstChildD3D9();
       layerToRender != nsnull;
       layerToRender = GetNextSiblingD3D9(layerToRender)) {

    const nsIntRect* clipRect = layerToRender->GetLayer()->GetClipRect();
    if ((clipRect && clipRect->IsEmpty()) ||
        layerToRender->GetLayer()->GetEffectiveVisibleRegion().IsEmpty()) {
      continue;
    }

    if (clipRect || useIntermediate) {
      RECT r;
      if (clipRect) {
        r.left = (LONG)(clipRect->x - renderTargetOffset[0]);
        r.top = (LONG)(clipRect->y - renderTargetOffset[1]);
        r.right = (LONG)(clipRect->x - renderTargetOffset[0] + clipRect->width);
        r.bottom = (LONG)(clipRect->y - renderTargetOffset[1] + clipRect->height);
      } else {
        r.left = 0;
        r.top = 0;
        r.right = visibleRect.width;
        r.bottom = visibleRect.height;
      }

      nsRefPtr<IDirect3DSurface9> renderSurface;
      device()->GetRenderTarget(0, getter_AddRefs(renderSurface));

      D3DSURFACE_DESC desc;
      renderSurface->GetDesc(&desc);

      if (!useIntermediate) {
        // Transform clip rect
        if (clipRect) {
          gfxRect cliprect(r.left, r.top, r.right - r.left, r.bottom - r.top);
          gfxRect trScissor = contTransform.TransformBounds(cliprect);
          trScissor.Round();
          nsIntRect trIntScissor;
          if (gfxUtils::GfxRectToIntRect(trScissor, &trIntScissor)) {
            r.left = trIntScissor.x;
            r.top = trIntScissor.y;
            r.right = trIntScissor.XMost();
            r.bottom = trIntScissor.YMost();
          } else {
            r.left = 0;
            r.top = 0;
            r.right = visibleRect.width;
            r.bottom = visibleRect.height;
            clipRect = nsnull;
          }
        }
        // Intersect with current clip rect.
        r.left = NS_MAX<PRInt32>(containerClipRect.left, r.left);
        r.right = NS_MIN<PRInt32>(containerClipRect.right, r.right);
        r.top = NS_MAX<PRInt32>(containerClipRect.top, r.top);
        r.bottom = NS_MIN<PRInt32>(containerClipRect.bottom, r.bottom);
      } else {
        // > 0 is implied during the intersection when useIntermediate == true;
        r.left = NS_MAX<LONG>(0, r.left);
        r.top = NS_MAX<LONG>(0, r.top);
      }
      r.bottom = NS_MIN<LONG>(r.bottom, desc.Height);
      r.right = NS_MIN<LONG>(r.right, desc.Width);

      device()->SetScissorRect(&r);
    }

    if (layerToRender->GetLayer()->GetType() == TYPE_THEBES) {
      static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback);
    } else {
      layerToRender->RenderLayer();
    }

    if (clipRect && !useIntermediate) {
      // In this situation we've set a new scissor rect and we will continue
      // to render directly to our container. We need to restore its scissor.
      // Not setting this when useIntermediate is true is an optimization since
      // we'll get a new one set anyway.
      device()->SetScissorRect(&containerClipRect);
    }
  }

  if (useIntermediate) {
    device()->SetRenderTarget(0, previousRenderTarget);
    device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
    device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);

    device()->SetVertexShaderConstantF(CBvLayerQuad,
                                       ShaderConstantRect(visibleRect.x,
                                                          visibleRect.y,
                                                          visibleRect.width,
                                                          visibleRect.height),
                                       1);

    SetShaderTransformAndOpacity();

    mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);

    device()->SetScissorRect(&containerClipRect);
    device()->SetTexture(0, renderTexture);
    device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
  }
}