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