Пример #1
0
void
CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
                         const gfx::Rect &aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4 &aTransform)
{
  if (!mDeviceManager) {
    return;
  }

  IDirect3DDevice9* d3d9Device = device();
  MOZ_ASSERT(d3d9Device, "We should be able to get a device now");

  MOZ_ASSERT(mCurrentRT, "No render target");
  d3d9Device->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4);

  IntPoint origin = mCurrentRT->GetOrigin();
  float renderTargetOffset[] = { origin.x, origin.y, 0, 0 };
  d3d9Device->SetVertexShaderConstantF(CBvRenderTargetOffset,
                                       renderTargetOffset,
                                       1);
  d3d9Device->SetVertexShaderConstantF(CBvLayerQuad,
                                       ShaderConstantRect(aRect.x,
                                                          aRect.y,
                                                          aRect.width,
                                                          aRect.height),
                                       1);
  bool target = false;

  if (aEffectChain.mPrimaryEffect->mType != EffectTypes::SOLID_COLOR) {
    float opacity[4];
    /*
     * We always upload a 4 component float, but the shader will use only the
     * first component since it's declared as a 'float'.
     */
    opacity[0] = aOpacity;
    d3d9Device->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
  }

  bool isPremultiplied = true;

  MaskType maskType = MaskType::MaskNone;

  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
    if (aTransform.Is2D()) {
      maskType = MaskType::Mask2d;
    } else {
      maskType = MaskType::Mask3d;
    }
  }

  RECT scissor;
  scissor.left = aClipRect.x;
  scissor.right = aClipRect.XMost();
  scissor.top = aClipRect.y;
  scissor.bottom = aClipRect.YMost();
  d3d9Device->SetScissorRect(&scissor);

  uint32_t maskTexture = 0;
  switch (aEffectChain.mPrimaryEffect->mType) {
  case EffectTypes::SOLID_COLOR:
    {
      // output color is premultiplied, so we need to adjust all channels.
      Color layerColor =
        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
      float color[4];
      color[0] = layerColor.r * layerColor.a * aOpacity;
      color[1] = layerColor.g * layerColor.a * aOpacity;
      color[2] = layerColor.b * layerColor.a * aOpacity;
      color[3] = layerColor.a * aOpacity;

      d3d9Device->SetPixelShaderConstantF(CBvColor, color, 1);

      maskTexture = mDeviceManager
        ->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER, maskType);
    }
    break;
  case EffectTypes::RENDER_TARGET:
  case EffectTypes::RGB:
    {
      TexturedEffect* texturedEffect =
        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());

      Rect textureCoords = texturedEffect->mTextureCoords;
      d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                           ShaderConstantRect(
                                             textureCoords.x,
                                             textureCoords.y,
                                             textureCoords.width,
                                             textureCoords.height),
                                           1);

      SetSamplerForFilter(texturedEffect->mFilter);

      TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9();
      d3d9Device->SetTexture(0, source->GetD3D9Texture());

      maskTexture = mDeviceManager
        ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType,
                                                texturedEffect->mTexture->GetFormat()),
                        maskType);

      isPremultiplied = texturedEffect->mPremultiplied;
    }
    break;
  case EffectTypes::YCBCR:
    {
      EffectYCbCr* ycbcrEffect =
        static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());

      SetSamplerForFilter(Filter::LINEAR);

      Rect textureCoords = ycbcrEffect->mTextureCoords;
      d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                           ShaderConstantRect(
                                             textureCoords.x,
                                             textureCoords.y,
                                             textureCoords.width,
                                             textureCoords.height),
                                           1);

      const int Y = 0, Cb = 1, Cr = 2;
      TextureSource* source = ycbcrEffect->mTexture;

      if (!source) {
        NS_WARNING("No texture to composite");
        return;
      }

      if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) {
        // This can happen if we failed to upload the textures, most likely
        // because of unsupported dimensions (we don't tile YCbCr textures).
        return;
      }

      TextureSourceD3D9* sourceY  = source->GetSubSource(Y)->AsSourceD3D9();
      TextureSourceD3D9* sourceCb = source->GetSubSource(Cb)->AsSourceD3D9();
      TextureSourceD3D9* sourceCr = source->GetSubSource(Cr)->AsSourceD3D9();


      MOZ_ASSERT(sourceY->GetD3D9Texture());
      MOZ_ASSERT(sourceCb->GetD3D9Texture());
      MOZ_ASSERT(sourceCr->GetD3D9Texture());

      /*
       * Send 3d control data and metadata
       */
      if (mDeviceManager->GetNv3DVUtils()) {
        Nv_Stereo_Mode mode;
        switch (source->AsSourceD3D9()->GetStereoMode()) {
        case StereoMode::LEFT_RIGHT:
          mode = NV_STEREO_MODE_LEFT_RIGHT;
          break;
        case StereoMode::RIGHT_LEFT:
          mode = NV_STEREO_MODE_RIGHT_LEFT;
          break;
        case StereoMode::BOTTOM_TOP:
          mode = NV_STEREO_MODE_BOTTOM_TOP;
          break;
        case StereoMode::TOP_BOTTOM:
          mode = NV_STEREO_MODE_TOP_BOTTOM;
          break;
        case StereoMode::MONO:
          mode = NV_STEREO_MODE_MONO;
          break;
        }

        // Send control data even in mono case so driver knows to leave stereo mode.
        mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);

        if (source->AsSourceD3D9()->GetStereoMode() != StereoMode::MONO) {
          mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);

          nsRefPtr<IDirect3DSurface9> renderTarget;
          d3d9Device->GetRenderTarget(0, getter_AddRefs(renderTarget));
          mDeviceManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)aRect.width,
                                                             (unsigned int)aRect.height,
                                                             (HANDLE)(sourceY->GetD3D9Texture()),
                                                             (HANDLE)(renderTarget));
        }
      }

      // Linear scaling is default here, adhering to mFilter is difficult since
      // presumably even with point filtering we'll still want chroma upsampling
      // to be linear. In the current approach we can't.
      device()->SetTexture(Y, sourceY->GetD3D9Texture());
      device()->SetTexture(Cb, sourceCb->GetD3D9Texture());
      device()->SetTexture(Cr, sourceCr->GetD3D9Texture());
      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, maskType);
    }
    break;
  case EffectTypes::COMPONENT_ALPHA:
    {
      MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
      EffectComponentAlpha* effectComponentAlpha =
        static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
      TextureSourceD3D9* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D9();
      TextureSourceD3D9* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D9();

      Rect textureCoords = effectComponentAlpha->mTextureCoords;
      d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                           ShaderConstantRect(
                                             textureCoords.x,
                                             textureCoords.y,
                                             textureCoords.width,
                                             textureCoords.height),
                                           1);

      SetSamplerForFilter(effectComponentAlpha->mFilter);

      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, maskType);
      SetMask(aEffectChain, maskTexture);
      d3d9Device->SetTexture(0, sourceOnBlack->GetD3D9Texture());
      d3d9Device->SetTexture(1, sourceOnWhite->GetD3D9Texture());
      d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
      d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
      d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, maskType);
      SetMask(aEffectChain, maskTexture);
      d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
      d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
      d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

      // Restore defaults
      d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
      d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
      d3d9Device->SetTexture(1, nullptr);
    }
    return;
  default:
    NS_WARNING("Unknown shader type");
    return;
  }

  SetMask(aEffectChain, maskTexture);

  if (!isPremultiplied) {
    d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  }

  HRESULT hr = d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

  if (!isPremultiplied) {
    d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
  }
}
Пример #2
0
void
CompositorD3D9::DrawQuad(const gfx::Rect &aRect,
                         const gfx::Rect &aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect)
{
  if (!mDeviceManager) {
    return;
  }

  IDirect3DDevice9* d3d9Device = device();
  MOZ_ASSERT(d3d9Device, "We should be able to get a device now");

  MOZ_ASSERT(mCurrentRT, "No render target");
  d3d9Device->SetVertexShaderConstantF(CBmLayerTransform, &aTransform._11, 4);

  IntPoint origin = mCurrentRT->GetOrigin();
  float renderTargetOffset[] = { float(origin.x), float(origin.y), 0, 0 };
  d3d9Device->SetVertexShaderConstantF(CBvRenderTargetOffset,
                                       renderTargetOffset,
                                       1);
  d3d9Device->SetVertexShaderConstantF(CBvLayerQuad,
                                       ShaderConstantRect(aRect.x,
                                                          aRect.y,
                                                          aRect.width,
                                                          aRect.height),
                                       1);

  if (aEffectChain.mPrimaryEffect->mType != EffectTypes::SOLID_COLOR) {
    float opacity[4];
    /*
     * We always upload a 4 component float, but the shader will use only the
     * first component since it's declared as a 'float'.
     */
    opacity[0] = aOpacity;
    d3d9Device->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
  }

  bool isPremultiplied = true;

  MaskType maskType = MaskType::MaskNone;

  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
    maskType = MaskType::Mask;
  }

  gfx::Rect backdropDest;
  gfx::IntRect backdropRect;
  gfx::Matrix4x4 backdropTransform;
  RefPtr<IDirect3DTexture9> backdropTexture;
  gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;

  if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
    EffectBlendMode *blendEffect =
      static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
    blendMode = blendEffect->mBlendMode;

    // Pixel Shader Model 2.0 is too limited to perform blending in the same way
    // as Direct3D 11 - there are too many instructions, and we don't have
    // configurable shaders (as we do with OGL) that would avoid a huge shader
    // matrix.
    //
    // Instead, we use a multi-step process for blending on D3D9:
    //  (1) Capture the backdrop into a temporary surface.
    //  (2) Render the effect chain onto the backdrop, with OP_SOURCE.
    //  (3) Capture the backdrop again into another surface - these are our source pixels.
    //  (4) Perform a final blend step using software.
    //  (5) Blit the blended result back to the render target.
    if (BlendOpIsMixBlendMode(blendMode)) {
      backdropRect = ComputeBackdropCopyRect(
        aRect, aClipRect, aTransform, &backdropTransform, &backdropDest);

      // If this fails, don't set a blend op.
      backdropTexture = CreateTexture(backdropRect, mCurrentRT, backdropRect.TopLeft());
      if (!backdropTexture) {
        blendMode = gfx::CompositionOp::OP_OVER;
      }
    }
  }

  RECT scissor;
  scissor.left = aClipRect.x;
  scissor.right = aClipRect.XMost();
  scissor.top = aClipRect.y;
  scissor.bottom = aClipRect.YMost();
  d3d9Device->SetScissorRect(&scissor);

  uint32_t maskTexture = 0;
  switch (aEffectChain.mPrimaryEffect->mType) {
  case EffectTypes::SOLID_COLOR:
    {
      // output color is premultiplied, so we need to adjust all channels.
      Color layerColor =
        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
      float color[4];
      color[0] = layerColor.r * layerColor.a * aOpacity;
      color[1] = layerColor.g * layerColor.a * aOpacity;
      color[2] = layerColor.b * layerColor.a * aOpacity;
      color[3] = layerColor.a * aOpacity;

      d3d9Device->SetPixelShaderConstantF(CBvColor, color, 1);

      maskTexture = mDeviceManager
        ->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER, maskType);
    }
    break;
  case EffectTypes::RENDER_TARGET:
  case EffectTypes::RGB:
    {
      TexturedEffect* texturedEffect =
        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());

      Rect textureCoords = texturedEffect->mTextureCoords;
      d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                           ShaderConstantRect(
                                             textureCoords.x,
                                             textureCoords.y,
                                             textureCoords.width,
                                             textureCoords.height),
                                           1);

      SetSamplerForFilter(texturedEffect->mFilter);

      TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9();
      d3d9Device->SetTexture(0, source->GetD3D9Texture());

      maskTexture = mDeviceManager
        ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType,
                                                texturedEffect->mTexture->GetFormat()),
                        maskType);

      isPremultiplied = texturedEffect->mPremultiplied;
    }
    break;
  case EffectTypes::YCBCR:
    {
      EffectYCbCr* ycbcrEffect =
        static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());

      SetSamplerForFilter(Filter::LINEAR);

      Rect textureCoords = ycbcrEffect->mTextureCoords;
      d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                           ShaderConstantRect(
                                             textureCoords.x,
                                             textureCoords.y,
                                             textureCoords.width,
                                             textureCoords.height),
                                           1);

      const int Y = 0, Cb = 1, Cr = 2;
      TextureSource* source = ycbcrEffect->mTexture;

      if (!source) {
        NS_WARNING("No texture to composite");
        return;
      }

      if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) {
        // This can happen if we failed to upload the textures, most likely
        // because of unsupported dimensions (we don't tile YCbCr textures).
        return;
      }

      TextureSourceD3D9* sourceY  = source->GetSubSource(Y)->AsSourceD3D9();
      TextureSourceD3D9* sourceCb = source->GetSubSource(Cb)->AsSourceD3D9();
      TextureSourceD3D9* sourceCr = source->GetSubSource(Cr)->AsSourceD3D9();


      MOZ_ASSERT(sourceY->GetD3D9Texture());
      MOZ_ASSERT(sourceCb->GetD3D9Texture());
      MOZ_ASSERT(sourceCr->GetD3D9Texture());

      /*
       * Send 3d control data and metadata
       */
      if (mDeviceManager->GetNv3DVUtils()) {
        Nv_Stereo_Mode mode;
        switch (source->AsSourceD3D9()->GetStereoMode()) {
        case StereoMode::LEFT_RIGHT:
          mode = NV_STEREO_MODE_LEFT_RIGHT;
          break;
        case StereoMode::RIGHT_LEFT:
          mode = NV_STEREO_MODE_RIGHT_LEFT;
          break;
        case StereoMode::BOTTOM_TOP:
          mode = NV_STEREO_MODE_BOTTOM_TOP;
          break;
        case StereoMode::TOP_BOTTOM:
          mode = NV_STEREO_MODE_TOP_BOTTOM;
          break;
        case StereoMode::MONO:
          mode = NV_STEREO_MODE_MONO;
          break;
        }

        // Send control data even in mono case so driver knows to leave stereo mode.
        mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);

        if (source->AsSourceD3D9()->GetStereoMode() != StereoMode::MONO) {
          mDeviceManager->GetNv3DVUtils()->SendNv3DVControl(mode, true, FIREFOX_3DV_APP_HANDLE);

          RefPtr<IDirect3DSurface9> renderTarget;
          d3d9Device->GetRenderTarget(0, getter_AddRefs(renderTarget));
          mDeviceManager->GetNv3DVUtils()->SendNv3DVMetaData((unsigned int)aRect.width,
                                                             (unsigned int)aRect.height,
                                                             (HANDLE)(sourceY->GetD3D9Texture()),
                                                             (HANDLE)(renderTarget));
        }
      }

      // Linear scaling is default here, adhering to mFilter is difficult since
      // presumably even with point filtering we'll still want chroma upsampling
      // to be linear. In the current approach we can't.
      device()->SetTexture(Y, sourceY->GetD3D9Texture());
      device()->SetTexture(Cb, sourceCb->GetD3D9Texture());
      device()->SetTexture(Cr, sourceCr->GetD3D9Texture());
      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER, maskType);
    }
    break;
  case EffectTypes::COMPONENT_ALPHA:
    {
      MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
      EffectComponentAlpha* effectComponentAlpha =
        static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
      TextureSourceD3D9* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D9();
      TextureSourceD3D9* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D9();

      Rect textureCoords = effectComponentAlpha->mTextureCoords;
      d3d9Device->SetVertexShaderConstantF(CBvTextureCoords,
                                           ShaderConstantRect(
                                             textureCoords.x,
                                             textureCoords.y,
                                             textureCoords.width,
                                             textureCoords.height),
                                           1);

      SetSamplerForFilter(effectComponentAlpha->mFilter);

      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, maskType);
      SetMask(aEffectChain, maskTexture);
      d3d9Device->SetTexture(0, sourceOnBlack->GetD3D9Texture());
      d3d9Device->SetTexture(1, sourceOnWhite->GetD3D9Texture());
      d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
      d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
      d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

      maskTexture = mDeviceManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, maskType);
      SetMask(aEffectChain, maskTexture);
      d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
      d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
      d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

      // Restore defaults
      d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
      d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
      d3d9Device->SetTexture(1, nullptr);
    }
    return;
  default:
    NS_WARNING("Unknown shader type");
    return;
  }

  SetMask(aEffectChain, maskTexture);

  if (BlendOpIsMixBlendMode(blendMode)) {
    // Use SOURCE instead of OVER to get the original source pixels without
    // having to render to another intermediate target.
    d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
  }
  if (!isPremultiplied) {
    d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  }

  d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

  // Restore defaults.
  if (BlendOpIsMixBlendMode(blendMode)) {
    d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  }
  if (!isPremultiplied) {
    d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
  }

  // Final pass - if mix-blending, do it now that we have the backdrop and
  // source textures.
  if (BlendOpIsMixBlendMode(blendMode)) {
    FinishMixBlend(
      backdropRect,
      backdropDest,
      backdropTransform,
      backdropTexture,
      blendMode);
  }
}