Bug 1036602 - add D3D11 support for VR rendering; r=bas

From fbb1e2ba9936896a1eb932585218401f4c95e411 Mon Sep 17 00:00:00 2001
---
 gfx/layers/d3d11/CompositorD3D11.cpp  | 212 +++++++++++++++++++++++++++++++++-
 gfx/layers/d3d11/CompositorD3D11.fx   |   1 +
 gfx/layers/d3d11/CompositorD3D11.h    |   9 ++
 gfx/layers/d3d11/CompositorD3D11VR.fx |  71 ++++++++++++
 4 files changed, 290 insertions(+), 3 deletions(-)
 create mode 100644 gfx/layers/d3d11/CompositorD3D11VR.fx
This commit is contained in:
Vladimir Vukicevic 2014-07-09 12:26:51 -07:00
parent 5fbe924d85
commit 4949616691
4 changed files with 290 additions and 3 deletions

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -7,6 +7,7 @@
#include "TextureD3D11.h"
#include "CompositorD3D11Shaders.h"
#include "CompositorD3D11ShadersVR.h"
#include "gfxWindowsPlatform.h"
#include "nsIWidget.h"
@ -16,6 +17,7 @@
#include "nsWindowsHelpers.h"
#include "gfxPrefs.h"
#include "gfxCrashReporterUtils.h"
#include "gfxVR.h"
#include "mozilla/EnumeratedArray.h"
@ -67,6 +69,27 @@ struct DeviceAttachmentsD3D11
RefPtr<ID3D11BlendState> mComponentBlendState;
RefPtr<ID3D11BlendState> mDisabledBlendState;
RefPtr<IDXGIResource> mSyncTexture;
//
// VR pieces
//
RefPtr<ID3D11InputLayout> mVRDistortionInputLayout;
RefPtr<ID3D11Buffer> mVRDistortionConstants;
typedef EnumeratedArray<VRHMDType, VRHMDType::NumHMDTypes, RefPtr<ID3D11VertexShader>>
VRVertexShaderArray;
typedef EnumeratedArray<VRHMDType, VRHMDType::NumHMDTypes, RefPtr<ID3D11PixelShader>>
VRPixelShaderArray;
VRVertexShaderArray mVRDistortionVS;
VRPixelShaderArray mVRDistortionPS;
// These will be created/filled in as needed during rendering whenever the configuration
// changes.
VRHMDConfiguration mVRConfiguration;
RefPtr<ID3D11Buffer> mVRDistortionVertices[2]; // one for each eye
RefPtr<ID3D11Buffer> mVRDistortionIndices[2];
uint32_t mVRDistortionIndexCount[2];
};
CompositorD3D11::CompositorD3D11(nsIWidget* aWidget)
@ -282,13 +305,34 @@ CompositorD3D11::Initialize()
RefPtr<ID3D11Texture2D> texture;
hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(texture));
if (FAILED(hr)) {
return false;
}
hr = texture->QueryInterface((IDXGIResource**)byRef(mAttachments->mSyncTexture));
if (FAILED(hr)) {
return false;
}
//
// VR additions
//
D3D11_INPUT_ELEMENT_DESC vrlayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
hr = mDevice->CreateInputLayout(vrlayout,
sizeof(vrlayout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
OculusVRDistortionVS,
sizeof(OculusVRDistortionVS),
byRef(mAttachments->mVRDistortionInputLayout));
cBufferDesc.ByteWidth = sizeof(gfx::VRDistortionConstants);
hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, byRef(mAttachments->mVRDistortionConstants));
if (FAILED(hr)) {
return false;
}
@ -589,6 +633,141 @@ CompositorD3D11::ClearRect(const gfx::Rect& aRect)
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);
}
void
CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
const gfx::Rect& aClipRect,
@ -601,6 +780,12 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
}
MOZ_ASSERT(mCurrentRT, "No render target");
if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
return;
}
memcpy(&mVSConstants.layerTransform, &aTransform._11, 64);
IntPoint origin = mCurrentRT->GetOrigin();
mVSConstants.renderTargetOffset[0] = origin.x;
@ -966,7 +1151,7 @@ CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize)
{
D3D11_VIEWPORT viewport;
viewport.MaxDepth = 1.0f;
viewport.MinDepth = 0;
viewport.MinDepth = 0.0f;
viewport.Width = aSize.width;
viewport.Height = aSize.height;
viewport.TopLeftX = 0;
@ -974,6 +1159,8 @@ CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize)
mContext->RSSetViewports(1, &viewport);
// This view matrix translates coordinates from 0..width and 0..height to
// -1..1 on the X axis, and -1..1 on the Y axis (flips the Y coordinate)
Matrix viewMatrix = Matrix::Translation(-1.0, 1.0);
viewMatrix.PreScale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
viewMatrix.PreScale(1.0f, -1.0f);
@ -1113,6 +1300,25 @@ CompositorD3D11::CreateShaders()
return false;
}
/* VR stuff */
hr = mDevice->CreateVertexShader(OculusVRDistortionVS,
sizeof(OculusVRDistortionVS),
nullptr,
byRef(mAttachments->mVRDistortionVS[VRHMDType::Oculus]));
if (FAILED(hr)) {
return false;
}
hr = mDevice->CreatePixelShader(OculusVRDistortionPS,
sizeof(OculusVRDistortionPS),
nullptr,
byRef(mAttachments->mVRDistortionPS[VRHMDType::Oculus]));
if (FAILED(hr)) {
return false;
}
return true;
}

View File

@ -71,6 +71,7 @@ SamplerState LayerTextureSamplerLinear
float4 TransformedPosition(float2 aInPosition)
{
// the current vertex's position on the quad
// [x,y,0,1] is mandated by the CSS Transforms spec as the point value to transform
float4 position = float4(0, 0, 0, 1);
// We use 4 component floats to uniquely describe a rectangle, by the structure

View File

@ -27,6 +27,8 @@ struct VertexShaderConstants
gfx::Rect textureCoords;
gfx::Rect layerQuad;
gfx::Rect maskQuad;
float vrEyeToSourceUVScale[2];
float vrEyeToSourceUVOffset[2];
};
struct PixelShaderConstants
@ -94,6 +96,13 @@ public:
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE;
/* Helper for when the primary effect is VR_DISTORTION */
void DrawVRDistortion(const gfx::Rect &aRect,
const gfx::Rect &aClipRect,
const EffectChain &aEffectChain,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform);
/**
* Start a new frame. If aClipRectIn is null, sets *aClipRectOut to the
* screen dimensions.

View File

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* These constants should match mozilla:gfx::VRDistortionConstants */
float4 VREyeToSource : register(vs, c0);
float4 VRDestinationScaleAndOffset : register(vs, c1);
/* This is the input undistorted texture */
Texture2D Texture : register(ps, t0);
/* This maps to mozilla::gfx::VRDistortionVertex in gfxVR.h.
* It's shared amongst all of the different rendering types;
* some might not be in use for a particular distortion effect.
*/
struct VS_VR_INPUT {
float2 vPosition : POSITION;
float2 vTexCoord0 : TEXCOORD0;
float2 vTexCoord1 : TEXCOORD1;
float2 vTexCoord2 : TEXCOORD2;
float4 vGenericAttribs : COLOR0;
};
struct VS_VR_OUTPUT {
float4 vPosition : SV_Position;
float3 vTexCoord0 : TEXCOORD0;
float3 vTexCoord1 : TEXCOORD1;
float3 vTexCoord2 : TEXCOORD2;
float4 vGenericAttribs : COLOR;
};
SamplerState Linear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};
VS_VR_OUTPUT OculusVRDistortionVS(const VS_VR_INPUT aVertex)
{
VS_VR_OUTPUT res;
float2 tc0 = VREyeToSource.xy * aVertex.vTexCoord0 + VREyeToSource.zw;
float2 tc1 = VREyeToSource.xy * aVertex.vTexCoord1 + VREyeToSource.zw;
float2 tc2 = VREyeToSource.xy * aVertex.vTexCoord2 + VREyeToSource.zw;
//res.vPosition.xy = aVertex.vPosition.xy;
res.vPosition.xy = aVertex.vPosition.xy * VRDestinationScaleAndOffset.zw + VRDestinationScaleAndOffset.xy;
res.vPosition.zw = float2(0.5, 1.0);
res.vTexCoord0 = float3(tc0, 1);
res.vTexCoord1 = float3(tc1, 1);
res.vTexCoord2 = float3(tc2, 1);
res.vGenericAttribs = aVertex.vGenericAttribs;
return res;
}
float4 OculusVRDistortionPS(const VS_VR_OUTPUT aVertex) : SV_Target
{
float resR = Texture.Sample(Linear, aVertex.vTexCoord0.xy).r;
float resG = Texture.Sample(Linear, aVertex.vTexCoord1.xy).g;
float resB = Texture.Sample(Linear, aVertex.vTexCoord2.xy).b;
return float4(resR * aVertex.vGenericAttribs.r,
resG * aVertex.vGenericAttribs.r,
resB * aVertex.vGenericAttribs.r,
1.0);
}