void DeprecatedContentHostBase::Composite(EffectChain& aEffectChain, float aOpacity, const gfx::Matrix4x4& aTransform, const Filter& aFilter, const Rect& aClipRect, const nsIntRegion* aVisibleRegion, TiledLayerProperties* aLayerProperties) { NS_ASSERTION(aVisibleRegion, "Requires a visible region"); AutoLockDeprecatedTextureHost lock(mDeprecatedTextureHost); AutoLockDeprecatedTextureHost lockOnWhite(mDeprecatedTextureHostOnWhite); if (!mDeprecatedTextureHost || !lock.IsValid() || !lockOnWhite.IsValid()) { return; } RefPtr<TexturedEffect> effect = CreateTexturedEffect(mDeprecatedTextureHost, mDeprecatedTextureHostOnWhite, aFilter); if (!effect) { return; } aEffectChain.mPrimaryEffect = effect; nsIntRegion tmpRegion; const nsIntRegion* renderRegion; if (PaintWillResample()) { // If we're resampling, then the texture image will contain exactly the // entire visible region's bounds, and we should draw it all in one quad // to avoid unexpected aliasing. tmpRegion = aVisibleRegion->GetBounds(); renderRegion = &tmpRegion; } else { renderRegion = aVisibleRegion; } nsIntRegion region(*renderRegion); nsIntPoint origin = GetOriginOffset(); region.MoveBy(-origin); // translate into TexImage space, buffer origin might not be at texture (0,0) // Figure out the intersecting draw region TextureSource* source = mDeprecatedTextureHost; MOZ_ASSERT(source); gfx::IntSize texSize = source->GetSize(); nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height); textureRect.MoveBy(region.GetBounds().TopLeft()); nsIntRegion subregion; subregion.And(region, textureRect); if (subregion.IsEmpty()) { // Region is empty, nothing to draw return; } nsIntRegion screenRects; nsIntRegion regionRects; // Collect texture/screen coordinates for drawing nsIntRegionRectIterator iter(subregion); while (const nsIntRect* iterRect = iter.Next()) { nsIntRect regionRect = *iterRect; nsIntRect screenRect = regionRect; screenRect.MoveBy(origin); screenRects.Or(screenRects, screenRect); regionRects.Or(regionRects, regionRect); } TileIterator* tileIter = source->AsTileIterator(); TileIterator* iterOnWhite = nullptr; if (tileIter) { tileIter->BeginTileIteration(); } if (mDeprecatedTextureHostOnWhite) { iterOnWhite = mDeprecatedTextureHostOnWhite->AsTileIterator(); MOZ_ASSERT(!tileIter || tileIter->GetTileCount() == iterOnWhite->GetTileCount(), "Tile count mismatch on component alpha texture"); if (iterOnWhite) { iterOnWhite->BeginTileIteration(); } } bool usingTiles = (tileIter && tileIter->GetTileCount() > 1); do { if (iterOnWhite) { MOZ_ASSERT(iterOnWhite->GetTileRect() == tileIter->GetTileRect(), "component alpha textures should be the same size."); } nsIntRect texRect = tileIter ? tileIter->GetTileRect() : nsIntRect(0, 0, texSize.width, texSize.height); // Draw texture. If we're using tiles, we do repeating manually, as texture // repeat would cause each individual tile to repeat instead of the // compound texture as a whole. This involves drawing at most 4 sections, // 2 for each axis that has texture repeat. for (int y = 0; y < (usingTiles ? 2 : 1); y++) { for (int x = 0; x < (usingTiles ? 2 : 1); x++) { nsIntRect currentTileRect(texRect); currentTileRect.MoveBy(x * texSize.width, y * texSize.height); nsIntRegionRectIterator screenIter(screenRects); nsIntRegionRectIterator regionIter(regionRects); const nsIntRect* screenRect; const nsIntRect* regionRect; while ((screenRect = screenIter.Next()) && (regionRect = regionIter.Next())) { nsIntRect tileScreenRect(*screenRect); nsIntRect tileRegionRect(*regionRect); // When we're using tiles, find the intersection between the tile // rect and this region rect. Tiling is then handled by the // outer for-loops and modifying the tile rect. if (usingTiles) { tileScreenRect.MoveBy(-origin); tileScreenRect = tileScreenRect.Intersect(currentTileRect); tileScreenRect.MoveBy(origin); if (tileScreenRect.IsEmpty()) continue; tileRegionRect = regionRect->Intersect(currentTileRect); tileRegionRect.MoveBy(-currentTileRect.TopLeft()); } gfx::Rect rect(tileScreenRect.x, tileScreenRect.y, tileScreenRect.width, tileScreenRect.height); effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width, Float(tileRegionRect.y) / texRect.height, Float(tileRegionRect.width) / texRect.width, Float(tileRegionRect.height) / texRect.height); GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform); if (usingTiles) { DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT | DIAGNOSTIC_BIGIMAGE; diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect, aTransform); } } } } if (iterOnWhite) { iterOnWhite->NextTile(); } } while (usingTiles && tileIter->NextTile()); if (tileIter) { tileIter->EndTileIteration(); } if (iterOnWhite) { iterOnWhite->EndTileIteration(); } DiagnosticTypes diagnostics = DIAGNOSTIC_CONTENT; diagnostics |= iterOnWhite ? DIAGNOSTIC_COMPONENT_ALPHA : 0; GetCompositor()->DrawDiagnostics(diagnostics, *aVisibleRegion, aClipRect, aTransform); }
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 ImageRenderable::drawContent(const DrawContext& context) { WidgetRenderable::drawContent(context); TextureSource* tex = myOwner->getTexture(); if(tex != NULL) { DrawInterface* di = getRenderer(); di->fillTexture(tex); di->textureRegion(0, 0, 1, 1); if(!myOwner->myUseFullSource) { Rect& r = myOwner->mySourceRect; int w = tex->getWidth(); int h = tex->getHeight(); float su = (float)r.x() / w; float sv = 1 - (float)r.y() / h; float eu = (float)(r.x() + r.width()) / w; float ev = 1 - (float)(r.y() + r.height()) / h; di->textureRegion(su, ev, eu, sv); } else if(myOwner->myTile) { int w = tex->getWidth(); int h = tex->getHeight(); int W = myOwner->getWidth(); int H = myOwner->getHeight(); float eu = (float)(W) / w; float ev = (float)(H) / h; di->textureRegion(0, 0, eu, ev); } if(myTextureUniform != 0) { glUniform1i(myTextureUniform, 0); } if(myOwner->isStereo()) { DrawContext::Eye eye = context.eye; if(eye == DrawContext::EyeLeft) { di->textureRegion(0, 0, 0.5f, 1); } else if(eye == DrawContext::EyeRight) { di->textureRegion(0.5f, 0, 1, 1); } } Vector2f size = myOwner->getSize(); if(myOwner->myUseFullDest) { di->rect(0, 0, size[0], size[1]); } else { Rect& r = myOwner->myDestRect; di->rect(r.x(), r.y(), r.width(), r.height()); } } else { refresh(); } oassert(!oglError); }
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); } }
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); } }