예제 #1
0
TemporaryRef<CompositingRenderTarget>
CompositorD3D11::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
                                              const CompositingRenderTarget* aSource,
                                              const gfx::IntPoint &aSourcePoint)
{
  MOZ_ASSERT(aRect.width != 0 && aRect.height != 0);

  if (aRect.width * aRect.height == 0) {
    return nullptr;
  }

  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;
  HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
  NS_ASSERTION(texture, "Could not create texture");
  if (Failed(hr) || !texture) {
    return nullptr;
  }

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

    D3D11_BOX srcBox;
    srcBox.left = aSourcePoint.x;
    srcBox.top = aSourcePoint.y;
    srcBox.front = 0;
    srcBox.right = aSourcePoint.x + aRect.width;
    srcBox.bottom = aSourcePoint.y + aRect.height;
    srcBox.back = 1;

    const IntSize& srcSize = sourceD3D11->GetSize();
    MOZ_ASSERT(srcSize.width >= 0 && srcSize.height >= 0,
               "render targets should have nonnegative sizes");
    if (srcBox.left >= 0 &&
        srcBox.top >= 0 &&
        srcBox.left < srcBox.right &&
        srcBox.top < srcBox.bottom &&
        srcBox.right <= static_cast<uint32_t>(srcSize.width) &&
        srcBox.bottom <= static_cast<uint32_t>(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, aRect.TopLeft());
  rt->SetSize(aRect.Size());

  return rt;
}
예제 #2
0
CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DSurface9* aSurface,
                                                         SurfaceInitMode aInit,
                                                         const gfx::IntRect& aRect)
  : CompositingRenderTarget(aRect.TopLeft())
  , mSurface(aSurface)
  , mInitMode(aInit)
  , mInitialized(false)
{
  MOZ_COUNT_CTOR(CompositingRenderTargetD3D9);
  MOZ_ASSERT(mSurface);
  TextureSourceD3D9::SetSize(aRect.Size());
}
예제 #3
0
CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DTexture9* aTexture,
                                                         SurfaceInitMode aInit,
                                                         const gfx::IntRect& aRect)
  : CompositingRenderTarget(aRect.TopLeft())
  , mInitMode(aInit)
  , mInitialized(false)
{
  MOZ_COUNT_CTOR(CompositingRenderTargetD3D9);
  MOZ_ASSERT(aTexture);

  mTexture = aTexture;
  HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface));
  NS_ASSERTION(mSurface, "Couldn't create surface for texture");
  TextureSourceD3D9::SetSize(aRect.Size());
}
예제 #4
0
gfx::IntRect
ComputeBackdropCopyRect(const gfx::Rect& aRect,
                        const gfx::IntRect& aClipRect,
                        const gfx::Matrix4x4& aTransform,
                        const gfx::IntRect& aRenderTargetRect,
                        gfx::Matrix4x4* aOutTransform,
                        gfx::Rect* aOutLayerQuad)
{
  // Compute the clip.
  IntPoint rtOffset = aRenderTargetRect.TopLeft();
  IntSize rtSize = aRenderTargetRect.Size();

  gfx::IntRect renderBounds(0, 0, rtSize.width, rtSize.height);
  renderBounds.IntersectRect(renderBounds, aClipRect);
  renderBounds.MoveBy(rtOffset);

  // Apply the layer transform.
  RectDouble dest = aTransform.TransformAndClipBounds(
    RectDouble(aRect.x, aRect.y, aRect.width, aRect.height),
    RectDouble(renderBounds.x, renderBounds.y, renderBounds.width, renderBounds.height));
  dest -= rtOffset;

  // Ensure we don't round out to -1, which trips up Direct3D.
  dest.IntersectRect(dest, RectDouble(0, 0, rtSize.width, rtSize.height));

  if (aOutLayerQuad) {
    *aOutLayerQuad = Rect(dest.x, dest.y, dest.width, dest.height);
  }

  // Round out to integer.
  IntRect result;
  dest.RoundOut();
  dest.ToIntRect(&result);

  // Create a transform from adjusted clip space to render target space,
  // translate it for the backdrop rect, then transform it into the backdrop's
  // uv-space.
  Matrix4x4 transform;
  transform.PostScale(rtSize.width, rtSize.height, 1.0);
  transform.PostTranslate(-result.x, -result.y, 0.0);
  transform.PostScale(1 / float(result.width), 1 / float(result.height), 1.0);
  *aOutTransform = transform;
  return result;
}
예제 #5
0
TemporaryRef<CompositingRenderTarget>
CompositorD3D11::CreateRenderTarget(const gfx::IntRect& aRect,
                                    SurfaceInitMode aInit)
{
  MOZ_ASSERT(aRect.width != 0 && aRect.height != 0);

  if (aRect.width * aRect.height == 0) {
    return nullptr;
  }

  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;
  HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
  if (Failed(hr) || !texture) {
    return nullptr;
  }

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

  if (aInit == INIT_MODE_CLEAR) {
    FLOAT clear[] = { 0, 0, 0, 0 };
    mContext->ClearRenderTargetView(rt->mRTView, clear);
  }

  return rt;
}
예제 #6
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);
  }
}
void
GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const gfx::IntRect& aSrcRect,
                                           TextureImage *aDst, const gfx::IntRect& aDstRect)
{
    GLContext *gl = mCompositor->gl();

    if (!aSrc || !aDst || aSrcRect.IsEmpty() || aDstRect.IsEmpty())
        return;

    int savedFb = 0;
    gl->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);

    ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false);
    ScopedGLState scopedBlendState(gl, LOCAL_GL_BLEND, false);

    // 2.0 means scale up by two
    float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
    float blitScaleY = float(aDstRect.height) / float(aSrcRect.height);

    // We start iterating over all destination tiles
    aDst->BeginBigImageIteration();
    do {
        // calculate portion of the tile that is going to be painted to
        gfx::IntRect dstSubRect;
        gfx::IntRect dstTextureRect = aDst->GetTileRect();
        dstSubRect.IntersectRect(aDstRect, dstTextureRect);

        // this tile is not part of the destination rectangle aDstRect
        if (dstSubRect.IsEmpty())
            continue;

        // (*) transform the rect of this tile into the rectangle defined by aSrcRect...
        gfx::IntRect dstInSrcRect(dstSubRect);
        dstInSrcRect.MoveBy(-aDstRect.TopLeft());
        // ...which might be of different size, hence scale accordingly
        dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY);
        dstInSrcRect.MoveBy(aSrcRect.TopLeft());

        SetBlitFramebufferForDestTexture(aDst->GetTextureID());
        UseBlitProgram();

        aSrc->BeginBigImageIteration();
        // now iterate over all tiles in the source Image...
        do {
            // calculate portion of the source tile that is in the source rect
            gfx::IntRect srcSubRect;
            gfx::IntRect srcTextureRect = aSrc->GetTileRect();
            srcSubRect.IntersectRect(aSrcRect, srcTextureRect);

            // this tile is not part of the source rect
            if (srcSubRect.IsEmpty()) {
                continue;
            }
            // calculate intersection of source rect with destination rect
            srcSubRect.IntersectRect(srcSubRect, dstInSrcRect);
            // this tile does not overlap the current destination tile
            if (srcSubRect.IsEmpty()) {
                continue;
            }
            // We now have the intersection of
            //     the current source tile
            // and the desired source rectangle
            // and the destination tile
            // and the desired destination rectange
            // in destination space.
            // We need to transform this back into destination space, inverting the transform from (*)
            gfx::IntRect srcSubInDstRect(srcSubRect);
            srcSubInDstRect.MoveBy(-aSrcRect.TopLeft());
            srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY);
            srcSubInDstRect.MoveBy(aDstRect.TopLeft());

            // we transform these rectangles to be relative to the current src and dst tiles, respectively
            gfx::IntSize srcSize = srcTextureRect.Size();
            gfx::IntSize dstSize = dstTextureRect.Size();
            srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y);
            srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y);

            float dx0 = 2.0f * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0f;
            float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f;
            float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f;
            float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f;
            ScopedViewportRect autoViewportRect(gl, 0, 0, dstSize.width, dstSize.height);

            RectTriangles rects;

            gfx::IntSize realTexSize = srcSize;
            if (!CanUploadNonPowerOfTwo(gl)) {
                realTexSize = gfx::IntSize(RoundUpPow2(srcSize.width),
                                           RoundUpPow2(srcSize.height));
            }

            if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
                rects.addRect(/* dest rectangle */
                        dx0, dy0, dx1, dy1,
                        /* tex coords */
                        srcSubRect.x / float(realTexSize.width),
                        srcSubRect.y / float(realTexSize.height),
                        srcSubRect.XMost() / float(realTexSize.width),
                        srcSubRect.YMost() / float(realTexSize.height));
            } else {
                DecomposeIntoNoRepeatTriangles(srcSubRect, realTexSize, rects);

                // now put the coords into the d[xy]0 .. d[xy]1 coordinate space
                // from the 0..1 that it comes out of decompose
                InfallibleTArray<RectTriangles::coord>& coords = rects.vertCoords();

                for (unsigned int i = 0; i < coords.Length(); ++i) {
                    coords[i].x = (coords[i].x * (dx1 - dx0)) + dx0;
                    coords[i].y = (coords[i].y * (dy1 - dy0)) + dy0;
                }
            }

            ScopedBindTextureUnit autoTexUnit(gl, LOCAL_GL_TEXTURE0);
            ScopedBindTexture autoTex(gl, aSrc->GetTextureID());
            ScopedVertexAttribPointer autoAttrib0(gl, 0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.vertCoords().Elements());
            ScopedVertexAttribPointer autoAttrib1(gl, 1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.texCoords().Elements());

            gl->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());

        } while (aSrc->NextTile());
    } while (aDst->NextTile());

    // unbind the previous texture from the framebuffer
    SetBlitFramebufferForDestTexture(0);

    gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
}