TemporaryRef<CompositingRenderTarget>
CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                             const CompositingRenderTarget *aSource)
{
  RefPtr<IDirect3DTexture9> texture;
  HRESULT hr = device()->CreateTexture(aRect.width, aRect.height, 1,
                                       D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                                       D3DPOOL_DEFAULT, byRef(texture),
                                       NULL);
  if (FAILED(hr)) {
    ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to create texture"),
                  hr);
    return nullptr;
  }

  if (aSource) {
    nsRefPtr<IDirect3DSurface9> sourceSurface =
      static_cast<const CompositingRenderTargetD3D9*>(aSource)->GetD3D9Surface();

    nsRefPtr<IDirect3DSurface9> destSurface;
    hr = texture->GetSurfaceLevel(0, getter_AddRefs(destSurface));
    if (FAILED(hr)) {
      NS_WARNING("Failed to get texture surface level for dest.");
    }

    if (sourceSurface && destSurface) {
      RECT sourceRect;
      sourceRect.left = aRect.x;
      sourceRect.right = aRect.XMost();
      sourceRect.top = aRect.y;
      sourceRect.bottom = aRect.YMost();
      RECT destRect;
      destRect.left = 0;
      destRect.right = aRect.width;
      destRect.top = 0;
      destRect.bottom = aRect.height;

      // copy the source to the dest
      hr = device()->StretchRect(sourceSurface,
                                 &sourceRect,
                                 destSurface,
                                 &destRect,
                                 D3DTEXF_NONE);
      if (FAILED(hr)) {
        ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to update texture"),
                      hr);
      }
    }
  }

  RefPtr<CompositingRenderTargetD3D9> rt =
    new CompositingRenderTargetD3D9(texture,
                                    INIT_MODE_NONE,
                                    IntSize(aRect.width, aRect.height));

  return rt;
}
TemporaryRef<CompositingRenderTarget>
CompositorD3D11::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                              const CompositingRenderTarget* aSource)
{
  CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
                             aRect.width, aRect.height, 1, 1,
                             D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);

  RefPtr<ID3D11Texture2D> texture;
  mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
  NS_ASSERTION(texture, "Could not create texture");
  if (!texture) {
    return nullptr;
  }

  if (aSource) {
    const CompositingRenderTargetD3D11* sourceD3D11 =
      static_cast<const CompositingRenderTargetD3D11*>(aSource);

    D3D11_BOX srcBox;
    srcBox.left = aRect.x;
    srcBox.top = aRect.y;
    srcBox.front = 0;
    srcBox.right = aRect.XMost();
    srcBox.bottom = aRect.YMost();
    srcBox.back = 0;

    const IntSize& srcSize = sourceD3D11->GetSize();
    if (srcBox.right <= srcSize.width &&
        srcBox.bottom <= srcSize.height) {
      mContext->CopySubresourceRegion(texture, 0,
                                      0, 0, 0,
                                      sourceD3D11->GetD3D11Texture(), 0,
                                      &srcBox);
    } else {
      NS_WARNING("Could not copy render target - source rect out of bounds");
    }
  }

  RefPtr<CompositingRenderTargetD3D11> rt =
    new CompositingRenderTargetD3D11(texture);
  rt->SetSize(IntSize(aRect.width, aRect.height));

  return rt;
}
Example #3
0
void
CompositorD3D9::FinishMixBlend(const gfx::IntRect& aBackdropRect,
                               const gfx::Rect& aBackdropDest,
                               const gfx::Matrix4x4& aBackdropTransform,
                               RefPtr<IDirect3DTexture9> aBackdrop,
                               gfx::CompositionOp aBlendMode)
{
  HRESULT hr;

  RefPtr<IDirect3DTexture9> source =
    CreateTexture(aBackdropRect, mCurrentRT, aBackdropRect.TopLeft());
  if (!source) {
    return;
  }

  // Slow path - do everything in software. Unfortunately this requires
  // a lot of copying, since we have to readback the source and backdrop,
  // then upload the blended result, then blit it back.

  IDirect3DDevice9* d3d9Device = device();

  // Query geometry/format of the two surfaces.
  D3DSURFACE_DESC backdropDesc, sourceDesc;
  if (FAILED(aBackdrop->GetLevelDesc(0, &backdropDesc)) ||
      FAILED(source->GetLevelDesc(0, &sourceDesc)))
  {
    gfxCriticalNote << "Failed to query mix-blend texture descriptor";
    return;
  }

  MOZ_ASSERT(backdropDesc.Format == D3DFMT_A8R8G8B8);
  MOZ_ASSERT(sourceDesc.Format == D3DFMT_A8R8G8B8);

  // Acquire a temporary data surface for the backdrop texture.
  RefPtr<IDirect3DSurface9> backdropSurface = GetSurfaceOfTexture(aBackdrop);
  if (!backdropSurface) {
    return;
  }
  RefPtr<IDirect3DSurface9> tmpBackdrop =
    CreateDataSurfaceForTexture(d3d9Device, backdropSurface, backdropDesc);
  if (!tmpBackdrop) {
    return;
  }

  // New scope for locks and temporary surfaces.
  {
    // Acquire a temporary data surface for the source texture.
    RefPtr<IDirect3DSurface9> sourceSurface = GetSurfaceOfTexture(source);
    if (!sourceSurface) {
      return;
    }
    RefPtr<IDirect3DSurface9> tmpSource =
      CreateDataSurfaceForTexture(d3d9Device, sourceSurface, sourceDesc);
    if (!tmpSource) {
      return;
    }

    // Perform the readback and blend in software.
    AutoSurfaceLock backdropLock(tmpBackdrop);
    AutoSurfaceLock sourceLock(tmpSource, D3DLOCK_READONLY);
    if (!backdropLock.Okay() || !sourceLock.Okay()) {
      return;
    }

    RefPtr<DataSourceSurface> source = Factory::CreateWrappingDataSourceSurface(
      sourceLock.Bits(), sourceLock.Pitch(),
      gfx::IntSize(sourceDesc.Width, sourceDesc.Height),
      SurfaceFormat::B8G8R8A8);

    RefPtr<DrawTarget> dest = Factory::CreateDrawTargetForData(
      BackendType::CAIRO,
      backdropLock.Bits(),
      gfx::IntSize(backdropDesc.Width, backdropDesc.Height),
      backdropLock.Pitch(),
      SurfaceFormat::B8G8R8A8);

    // The backdrop rect is rounded out - account for any difference between
    // it and the actual destination.
    gfx::Rect destRect(
      aBackdropDest.x - aBackdropRect.x,
      aBackdropDest.y - aBackdropRect.y,
      aBackdropDest.width,
      aBackdropDest.height);

    dest->DrawSurface(
      source, destRect, destRect,
      gfx::DrawSurfaceOptions(),
      gfx::DrawOptions(1.0f, aBlendMode));
  }

  // Upload the new blended surface to the backdrop texture.
  d3d9Device->UpdateSurface(tmpBackdrop, nullptr, backdropSurface, nullptr);

  // Finally, drop in the new backdrop. We don't need to do another
  // DrawPrimitive() since the software blend will have included the
  // final OP_OVER step for us.
  RECT destRect = {
    aBackdropRect.x, aBackdropRect.y,
    aBackdropRect.XMost(), aBackdropRect.YMost()
  };
  hr = d3d9Device->StretchRect(backdropSurface,
                               nullptr,
                               mCurrentRT->GetD3D9Surface(),
                               &destRect,
                               D3DTEXF_NONE);
  if (FAILED(hr)) {
    gfxCriticalNote << "StretcRect with mix-blend failed " << hexa(hr);
  }
}