void
CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
                          const gfx::Rect& aClipRect,
                          const EffectChain& aEffectChain,
                          gfx::Float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::Point& aOffset)
{
  MOZ_ASSERT(mCurrentRT, "No render target");
  memcpy(&mVSConstants.layerTransform, &aTransform._11, 64);
  mVSConstants.renderTargetOffset[0] = aOffset.x;
  mVSConstants.renderTargetOffset[1] = aOffset.y;
  mVSConstants.layerQuad = aRect;

  mPSConstants.layerOpacity[0] = aOpacity;

  bool restoreBlendMode = false;

  MaskType maskType = MaskNone;

  if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
    if (aTransform.Is2D()) {
      maskType = Mask2d;
    } else {
      MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EFFECT_BGRA);
      maskType = Mask3d;
    }

    EffectMask* maskEffect =
      static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
    TextureSourceD3D11* source = maskEffect->mMaskTexture->AsSourceD3D11();

    RefPtr<ID3D11ShaderResourceView> view;
    mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));

    ID3D11ShaderResourceView* srView = view;
    mContext->PSSetShaderResources(3, 1, &srView);

    const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform;
    NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
    Rect bounds = Rect(Point(), Size(maskEffect->mSize));

    mVSConstants.maskQuad = maskTransform.As2D().TransformBounds(bounds);
  }


  D3D11_RECT scissor;
  scissor.left = aClipRect.x;
  scissor.right = aClipRect.XMost();
  scissor.top = aClipRect.y;
  scissor.bottom = aClipRect.YMost();
  mContext->RSSetScissorRects(1, &scissor);
  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);

  SetPSForEffect(aEffectChain.mPrimaryEffect, maskType);

  switch (aEffectChain.mPrimaryEffect->mType) {
  case EFFECT_SOLID_COLOR: {
      Color color =
        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
      mPSConstants.layerColor[0] = color.r * color.a * aOpacity;
      mPSConstants.layerColor[1] = color.g * color.a * aOpacity;
      mPSConstants.layerColor[2] = color.b * color.a * aOpacity;
      mPSConstants.layerColor[3] = color.a * aOpacity;
    }
    break;
  case EFFECT_BGRX:
  case EFFECT_BGRA:
  case EFFECT_RENDER_TARGET:
    {
      TexturedEffect* texturedEffect =
        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());

      mVSConstants.textureCoords = texturedEffect->mTextureCoords;

      TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();

      RefPtr<ID3D11ShaderResourceView> view;
      mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));

      ID3D11ShaderResourceView* srView = view;
      mContext->PSSetShaderResources(0, 1, &srView);

      if (!texturedEffect->mPremultiplied) {
        mContext->OMSetBlendState(mAttachments->mNonPremulBlendState, sBlendFactor, 0xFFFFFFFF);
        restoreBlendMode = true;
      }

      SetSamplerForFilter(texturedEffect->mFilter);
    }
    break;
  case EFFECT_YCBCR: {
      EffectYCbCr* ycbcrEffect =
        static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());

      SetSamplerForFilter(FILTER_LINEAR);

      mVSConstants.textureCoords = ycbcrEffect->mTextureCoords;

      TextureSourceD3D11* source = ycbcrEffect->mTexture->AsSourceD3D11();
      TextureSourceD3D11::YCbCrTextures textures = source->GetYCbCrTextures();

      RefPtr<ID3D11ShaderResourceView> views[3];
      mDevice->CreateShaderResourceView(textures.mY, nullptr, byRef(views[0]));
      mDevice->CreateShaderResourceView(textures.mCb, nullptr, byRef(views[1]));
      mDevice->CreateShaderResourceView(textures.mCr, nullptr, byRef(views[2]));

      ID3D11ShaderResourceView* srViews[3] = { views[0], views[1], views[2] };
      mContext->PSSetShaderResources(0, 3, srViews);
    }
    break;
  case EFFECT_COMPONENT_ALPHA:
    {
      MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
      EffectComponentAlpha* effectComponentAlpha =
        static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
      TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11();
      TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11();
      SetSamplerForFilter(effectComponentAlpha->mFilter);

      mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords;
      RefPtr<ID3D11ShaderResourceView> views[2];
      mDevice->CreateShaderResourceView(sourceOnBlack->GetD3D11Texture(), nullptr, byRef(views[0]));
      mDevice->CreateShaderResourceView(sourceOnWhite->GetD3D11Texture(), nullptr, byRef(views[1]));

      ID3D11ShaderResourceView* srViews[2] = { views[0], views[1] };
      mContext->PSSetShaderResources(0, 2, srViews);

      mContext->OMSetBlendState(mAttachments->mComponentBlendState, sBlendFactor, 0xFFFFFFFF);
      restoreBlendMode = true;
    }
    break;
  default:
    NS_WARNING("Unknown shader type");
    return;
  }
  UpdateConstantBuffers();

  mContext->Draw(4, 0);
  if (restoreBlendMode) {
    mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
  }
}
Exemple #2
0
void
CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
                          const gfx::Rect& aClipRect,
                          const EffectChain& aEffectChain,
                          gfx::Float aOpacity,
                          const gfx::Matrix4x4& aTransform)
{
  MOZ_ASSERT(mCurrentRT, "No render target");
  memcpy(&mVSConstants.layerTransform, &aTransform._11, 64);
  IntPoint origin = mCurrentRT->GetOrigin();
  mVSConstants.renderTargetOffset[0] = origin.x;
  mVSConstants.renderTargetOffset[1] = origin.y;

  mPSConstants.layerOpacity[0] = aOpacity;

  bool restoreBlendMode = false;

  MaskType maskType = MaskType::MaskNone;

  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
    if (aTransform.Is2D()) {
      maskType = MaskType::Mask2d;
    } else {
      MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EffectTypes::RGB);
      maskType = MaskType::Mask3d;
    }

    EffectMask* maskEffect =
      static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
    TextureSourceD3D11* source = maskEffect->mMaskTexture->AsSourceD3D11();

    if (!source) {
      NS_WARNING("Missing texture source!");
      return;
    }

    RefPtr<ID3D11ShaderResourceView> view;
    HRESULT hr = mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));
    if (Failed(hr)) {
      // XXX - There's a chance we won't be able to render anything, should we
      // just crash release builds?
      return;
    }

    ID3D11ShaderResourceView* srView = view;
    mContext->PSSetShaderResources(3, 1, &srView);

    const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform;
    NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
    Rect bounds = Rect(Point(), Size(maskEffect->mSize));

    mVSConstants.maskQuad = maskTransform.As2D().TransformBounds(bounds);
  }


  D3D11_RECT scissor;
  scissor.left = aClipRect.x;
  scissor.right = aClipRect.XMost();
  scissor.top = aClipRect.y;
  scissor.bottom = aClipRect.YMost();
  mContext->RSSetScissorRects(1, &scissor);
  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);

  const Rect* pTexCoordRect = nullptr;

  switch (aEffectChain.mPrimaryEffect->mType) {
  case EffectTypes::SOLID_COLOR: {
      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, SurfaceFormat::UNKNOWN);

      Color color =
        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
      mPSConstants.layerColor[0] = color.r * color.a * aOpacity;
      mPSConstants.layerColor[1] = color.g * color.a * aOpacity;
      mPSConstants.layerColor[2] = color.b * color.a * aOpacity;
      mPSConstants.layerColor[3] = color.a * aOpacity;
    }
    break;
  case EffectTypes::RGB:
  case EffectTypes::RENDER_TARGET:
    {
      TexturedEffect* texturedEffect =
        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());

      pTexCoordRect = &texturedEffect->mTextureCoords;

      TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();

      if (!source) {
        NS_WARNING("Missing texture source!");
        return;
      }

      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, texturedEffect->mTexture->GetFormat());

      RefPtr<ID3D11ShaderResourceView> view;
      HRESULT hr = mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));
      if (Failed(hr)) {
        // XXX - There's a chance we won't be able to render anything, should we
        // just crash release builds?
        return;
      }

      ID3D11ShaderResourceView* srView = view;
      mContext->PSSetShaderResources(0, 1, &srView);

      if (!texturedEffect->mPremultiplied) {
        mContext->OMSetBlendState(mAttachments->mNonPremulBlendState, sBlendFactor, 0xFFFFFFFF);
        restoreBlendMode = true;
      }

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

      SetSamplerForFilter(Filter::LINEAR);

      pTexCoordRect = &ycbcrEffect->mTextureCoords;

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

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

      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, ycbcrEffect->mTexture->GetFormat());

      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;
      }

      TextureSourceD3D11* sourceY  = source->GetSubSource(Y)->AsSourceD3D11();
      TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11();
      TextureSourceD3D11* sourceCr = source->GetSubSource(Cr)->AsSourceD3D11();

      HRESULT hr;

      RefPtr<ID3D11ShaderResourceView> views[3];

      hr = mDevice->CreateShaderResourceView(sourceY->GetD3D11Texture(),
                                             nullptr, byRef(views[0]));
      if (Failed(hr)) {
        return;
      }

      hr = mDevice->CreateShaderResourceView(sourceCb->GetD3D11Texture(),
                                             nullptr, byRef(views[1]));
      if (Failed(hr)) {
        return;
      }

      hr = mDevice->CreateShaderResourceView(sourceCr->GetD3D11Texture(),
                                             nullptr, byRef(views[2]));
      if (Failed(hr)) {
        return;
      }

      ID3D11ShaderResourceView* srViews[3] = { views[0], views[1], views[2] };
      mContext->PSSetShaderResources(0, 3, srViews);
    }
    break;
  case EffectTypes::COMPONENT_ALPHA:
    {
      MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled());
      MOZ_ASSERT(mAttachments->mComponentBlendState);
      EffectComponentAlpha* effectComponentAlpha =
        static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());

      TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11();
      TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11();

      if (!sourceOnWhite || !sourceOnBlack) {
        NS_WARNING("Missing texture source(s)!");
        return;
      }

      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, effectComponentAlpha->mOnWhite->GetFormat());

      SetSamplerForFilter(effectComponentAlpha->mFilter);

      pTexCoordRect = &effectComponentAlpha->mTextureCoords;

      RefPtr<ID3D11ShaderResourceView> views[2];

      HRESULT hr;

      hr = mDevice->CreateShaderResourceView(sourceOnBlack->GetD3D11Texture(), nullptr, byRef(views[0]));
      if (Failed(hr)) {
        return;
      }
      hr = mDevice->CreateShaderResourceView(sourceOnWhite->GetD3D11Texture(), nullptr, byRef(views[1]));
      if (Failed(hr)) {
        return;
      }

      ID3D11ShaderResourceView* srViews[2] = { views[0], views[1] };
      mContext->PSSetShaderResources(0, 2, srViews);

      mContext->OMSetBlendState(mAttachments->mComponentBlendState, sBlendFactor, 0xFFFFFFFF);
      restoreBlendMode = true;
    }
    break;
  default:
    NS_WARNING("Unknown shader type");
    return;
  }

  if (pTexCoordRect) {
    Rect layerRects[4];
    Rect textureRects[4];
    size_t rects = DecomposeIntoNoRepeatRects(aRect,
                                              *pTexCoordRect,
                                              &layerRects,
                                              &textureRects);
    for (size_t i = 0; i < rects; i++) {
      mVSConstants.layerQuad = layerRects[i];
      mVSConstants.textureCoords = textureRects[i];

      if (!UpdateConstantBuffers()) {
        NS_WARNING("Failed to update shader constant buffers");
        break;
      }
      mContext->Draw(4, 0);
    }
  } else {
    mVSConstants.layerQuad = aRect;

    if (!UpdateConstantBuffers()) {
      NS_WARNING("Failed to update shader constant buffers");
    } else {
      mContext->Draw(4, 0);
    }
  }

  if (restoreBlendMode) {
    mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
  }
}
void
CompositorD3D11::DrawVRDistortion(const gfx::Rect& aRect,
                                  const gfx::Rect& aClipRect,
                                  const EffectChain& aEffectChain,
                                  gfx::Float aOpacity,
                                  const gfx::Matrix4x4& aTransform)
{
  MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION);

  if (aEffectChain.mSecondaryEffects[EffectTypes::MASK] ||
      aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE])
  {
    NS_WARNING("DrawVRDistortion: ignoring secondary effect!");
  }

  HRESULT hr;

  EffectVRDistortion* vrEffect =
    static_cast<EffectVRDistortion*>(aEffectChain.mPrimaryEffect.get());

  TextureSourceD3D11* source = vrEffect->mTexture->AsSourceD3D11();
  gfx::IntSize size = vrEffect->mRenderTarget->GetSize(); // XXX source->GetSize()

  VRHMDInfo* hmdInfo = vrEffect->mHMD;
  VRDistortionConstants shaderConstants;

  // do we need to recreate the VR buffers, since the config has changed?
  if (hmdInfo->GetConfiguration() != mAttachments->mVRConfiguration) {
    D3D11_SUBRESOURCE_DATA sdata = { 0 };
    CD3D11_BUFFER_DESC desc(0, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE);

    // XXX as an optimization, we should really pack the indices and vertices for both eyes
    // into one buffer instead of needing one eye each.  Then we can just bind them once.
    for (uint32_t eye = 0; eye < 2; eye++) {
      const gfx::VRDistortionMesh& mesh = hmdInfo->GetDistortionMesh(eye);

      desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
      desc.ByteWidth = mesh.mVertices.Length() * sizeof(gfx::VRDistortionVertex);
      sdata.pSysMem = mesh.mVertices.Elements();
      
      hr = mDevice->CreateBuffer(&desc, &sdata, byRef(mAttachments->mVRDistortionVertices[eye]));
      if (FAILED(hr)) {
        NS_WARNING("CreateBuffer failed");
        return;
      }

      desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
      desc.ByteWidth = mesh.mIndices.Length() * sizeof(uint16_t);
      sdata.pSysMem = mesh.mIndices.Elements();

      hr = mDevice->CreateBuffer(&desc, &sdata, byRef(mAttachments->mVRDistortionIndices[eye]));
      if (FAILED(hr)) {
        NS_WARNING("CreateBuffer failed");
        return;
      }

      mAttachments->mVRDistortionIndexCount[eye] = mesh.mIndices.Length();
    }

    mAttachments->mVRConfiguration = hmdInfo->GetConfiguration();
  }

  // XXX do I need to set a scissor rect? Is this the right scissor rect?
  D3D11_RECT scissor;
  scissor.left = aClipRect.x;
  scissor.right = aClipRect.XMost();
  scissor.top = aClipRect.y;
  scissor.bottom = aClipRect.YMost();
  mContext->RSSetScissorRects(1, &scissor);

  // Triangle lists and same layout for both eyes
  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  mContext->IASetInputLayout(mAttachments->mVRDistortionInputLayout);

  // Shaders for this HMD
  mContext->VSSetShader(mAttachments->mVRDistortionVS[mAttachments->mVRConfiguration.hmdType], nullptr, 0);
  mContext->PSSetShader(mAttachments->mVRDistortionPS[mAttachments->mVRConfiguration.hmdType], nullptr, 0);

  // This is the source texture SRV for the pixel shader
  // XXX, um should we cache this SRV?
  RefPtr<ID3D11ShaderResourceView> view;
  mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));
  ID3D11ShaderResourceView* srView = view;
  mContext->PSSetShaderResources(0, 1, &srView);


  gfx::IntSize vpSizeInt = mCurrentRT->GetSize();
  gfx::Size vpSize(vpSizeInt.width, vpSizeInt.height);
  ID3D11Buffer* vbuffer;
  UINT vsize, voffset;

  for (uint32_t eye = 0; eye < 2; eye++) {
    gfx::IntRect eyeViewport;
    eyeViewport.x = eye * size.width / 2;
    eyeViewport.y = 0;
    eyeViewport.width = size.width / 2;
    eyeViewport.height = size.height;

    hmdInfo->FillDistortionConstants(eye,
                                     size, eyeViewport,
                                     vpSize, aRect,
                                     shaderConstants);

    // D3D has clip space top-left as -1,1 so we need to flip the Y coordinate offset here
    shaderConstants.destinationScaleAndOffset[1] = - shaderConstants.destinationScaleAndOffset[1];

    // XXX I really want to write a templated helper for these next 4 lines
    D3D11_MAPPED_SUBRESOURCE resource;
    mContext->Map(mAttachments->mVRDistortionConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
    *(gfx::VRDistortionConstants*)resource.pData = shaderConstants;
    mContext->Unmap(mAttachments->mVRDistortionConstants, 0);

    // XXX is there a better way to change a bunch of these things from what they were set to
    // in BeginFrame/etc?
    vbuffer = mAttachments->mVRDistortionVertices[eye];
    vsize = sizeof(gfx::VRDistortionVertex);
    voffset = 0;
    mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
    mContext->IASetIndexBuffer(mAttachments->mVRDistortionIndices[eye], DXGI_FORMAT_R16_UINT, 0);

    ID3D11Buffer* constBuf = mAttachments->mVRDistortionConstants;
    mContext->VSSetConstantBuffers(0, 1, &constBuf);

    mContext->DrawIndexed(mAttachments->mVRDistortionIndexCount[eye], 0, 0);
  }

  // restore previous configurations
  vbuffer = mAttachments->mVertexBuffer;
  vsize = sizeof(Vertex);
  voffset = 0;
  mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
  mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
  mContext->IASetInputLayout(mAttachments->mInputLayout);
}