2 // Copyright (c) Microsoft. All rights reserved.
3 // This code is licensed under the MIT License (MIT).
4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
9 // Developed by Minigraph
11 // Author: James Stanard
15 #include "MotionBlur.h"
17 #include "BufferManager.h"
18 #include "GraphicsCore.h"
19 #include "CommandContext.h"
21 #include "PostEffects.h"
22 #include "SystemTime.h"
24 #include "compiled_shaders/ScreenQuadVS.h"
25 #include "compiled_shaders/CameraMotionBlurPrePassCS.h"
26 #include "compiled_shaders/CameraMotionBlurPrePassLinearZCS.h"
27 #include "compiled_shaders/MotionBlurPrePassCS.h"
28 #include "compiled_shaders/MotionBlurFinalPassCS.h"
29 #include "compiled_shaders/MotionBlurFinalPassPS.h"
30 #include "compiled_shaders/CameraVelocityCS.h"
31 #include "compiled_shaders/TemporalBlendCS.h"
32 #include "compiled_shaders/BoundNeighborhoodCS.h"
34 using namespace Graphics
;
39 BoolVar
Enable("Graphics/Motion Blur/Enable", false);
41 RootSignature s_RootSignature
;
42 ComputePSO s_CameraMotionBlurPrePassCS
[2];
43 ComputePSO s_MotionBlurPrePassCS
;
44 ComputePSO s_MotionBlurFinalPassCS
;
45 GraphicsPSO s_MotionBlurFinalPassPS
;
46 ComputePSO s_CameraVelocityCS
[2];
49 void MotionBlur::Initialize( void )
51 s_RootSignature
.Reset(4, 1);
52 s_RootSignature
.InitStaticSampler(0, SamplerLinearBorderDesc
);
53 s_RootSignature
[0].InitAsConstants(0, 4);
54 s_RootSignature
[1].InitAsConstantBuffer(1);
55 s_RootSignature
[2].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_UAV
, 0, 8);
56 s_RootSignature
[3].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV
, 0, 8);
57 s_RootSignature
.Finalize(L
"Motion Blur");
59 #define CreatePSO( ObjName, ShaderByteCode ) \
60 ObjName.SetRootSignature(s_RootSignature); \
61 ObjName.SetComputeShader(ShaderByteCode, sizeof(ShaderByteCode) ); \
64 if (g_bTypedUAVLoadSupport_R11G11B10_FLOAT
)
66 CreatePSO(s_MotionBlurFinalPassCS
, g_pMotionBlurFinalPassCS
);
70 s_MotionBlurFinalPassPS
.SetRootSignature(s_RootSignature
);
71 s_MotionBlurFinalPassPS
.SetRasterizerState( RasterizerTwoSided
);
72 s_MotionBlurFinalPassPS
.SetBlendState( BlendPreMultiplied
);
73 s_MotionBlurFinalPassPS
.SetDepthStencilState( DepthStateDisabled
);
74 s_MotionBlurFinalPassPS
.SetSampleMask(0xFFFFFFFF);
75 s_MotionBlurFinalPassPS
.SetInputLayout(0, nullptr);
76 s_MotionBlurFinalPassPS
.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE
);
77 s_MotionBlurFinalPassPS
.SetVertexShader( g_pScreenQuadVS
, sizeof(g_pScreenQuadVS
) );
78 s_MotionBlurFinalPassPS
.SetPixelShader( g_pMotionBlurFinalPassPS
, sizeof(g_pMotionBlurFinalPassPS
) );
79 s_MotionBlurFinalPassPS
.SetRenderTargetFormat(g_SceneColorBuffer
.GetFormat(), DXGI_FORMAT_UNKNOWN
);
80 s_MotionBlurFinalPassPS
.Finalize();
83 CreatePSO( s_CameraMotionBlurPrePassCS
[0], g_pCameraMotionBlurPrePassCS
);
84 CreatePSO( s_CameraMotionBlurPrePassCS
[1], g_pCameraMotionBlurPrePassLinearZCS
);
85 CreatePSO( s_MotionBlurPrePassCS
, g_pMotionBlurPrePassCS
);
86 CreatePSO( s_CameraVelocityCS
[0], g_pCameraVelocityCS
);
87 CreatePSO( s_CameraVelocityCS
[1], g_pCameraVelocityCS
);
92 void MotionBlur::Shutdown( void )
96 // Linear Z ends up being faster since we haven't officially decompressed the depth buffer. You
97 // would think that it might be slower to use linear Z because we have to convert it back to
98 // hyperbolic Z for the reprojection. Nevertheless, the reduced bandwidth and decompress eliminate
99 // make Linear Z the better choice. (The choice also lets you evict the depth buffer from ESRAM.)
101 void MotionBlur::GenerateCameraVelocityBuffer( CommandContext
& BaseContext
, const Camera
& camera
, bool UseLinearZ
)
103 GenerateCameraVelocityBuffer(BaseContext
, camera
.GetReprojectionMatrix(), camera
.GetNearClip(), camera
.GetFarClip(), UseLinearZ
);
106 void MotionBlur::GenerateCameraVelocityBuffer( CommandContext
& BaseContext
, const Matrix4
& reprojectionMatrix
, float nearClip
, float farClip
, bool UseLinearZ
)
108 ScopedTimer
_prof(L
"Generate Camera Velocity", BaseContext
);
110 ComputeContext
& Context
= BaseContext
.GetComputeContext();
112 Context
.SetRootSignature(s_RootSignature
);
114 uint32_t Width
= g_SceneColorBuffer
.GetWidth();
115 uint32_t Height
= g_SceneColorBuffer
.GetHeight();
117 float RcpHalfDimX
= 2.0f
/ Width
;
118 float RcpHalfDimY
= 2.0f
/ Height
;
119 float RcpZMagic
= nearClip
/ (farClip
- nearClip
);
121 Matrix4 preMult
= Matrix4(
122 Vector4( RcpHalfDimX
, 0.0f
, 0.0f
, 0.0f
),
123 Vector4( 0.0f
, -RcpHalfDimY
, 0.0f
, 0.0f
),
124 Vector4( 0.0f
, 0.0f
, UseLinearZ
? RcpZMagic
: 1.0f
, 0.0f
),
125 Vector4( -1.0f
, 1.0f
, UseLinearZ
? -RcpZMagic
: 0.0f
, 1.0f
)
128 Matrix4 postMult
= Matrix4(
129 Vector4( 1.0f
/ RcpHalfDimX
, 0.0f
, 0.0f
, 0.0f
),
130 Vector4( 0.0f
, -1.0f
/ RcpHalfDimY
, 0.0f
, 0.0f
),
131 Vector4( 0.0f
, 0.0f
, 1.0f
, 0.0f
),
132 Vector4( 1.0f
/ RcpHalfDimX
, 1.0f
/ RcpHalfDimY
, 0.0f
, 1.0f
) );
135 Matrix4 CurToPrevXForm
= postMult
* reprojectionMatrix
* preMult
;
137 Context
.SetDynamicConstantBufferView(1, sizeof(CurToPrevXForm
), &CurToPrevXForm
);
138 Context
.TransitionResource(g_VelocityBuffer
, D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
140 ColorBuffer
& LinearDepth
= g_LinearDepth
[ Graphics::GetFrameCount() % 2 ];
142 Context
.TransitionResource(LinearDepth
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
144 Context
.TransitionResource(g_SceneDepthBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
146 Context
.SetPipelineState(s_CameraVelocityCS
[UseLinearZ
? 1 : 0]);
147 Context
.SetDynamicDescriptor(3, 0, UseLinearZ
? LinearDepth
.GetSRV() : g_SceneDepthBuffer
.GetDepthSRV());
148 Context
.SetDynamicDescriptor(2, 0, g_VelocityBuffer
.GetUAV());
149 Context
.Dispatch2D(Width
, Height
);
153 void MotionBlur::RenderCameraBlur( CommandContext
& BaseContext
, const Camera
& camera
, bool UseLinearZ
)
155 RenderCameraBlur(BaseContext
, camera
.GetReprojectionMatrix(), camera
.GetNearClip(), camera
.GetFarClip(), UseLinearZ
);
158 void MotionBlur::RenderCameraBlur( CommandContext
& BaseContext
, const Matrix4
& reprojectionMatrix
, float nearClip
, float farClip
, bool UseLinearZ
)
160 ScopedTimer
_prof(L
"MotionBlur", BaseContext
);
165 ComputeContext
& Context
= BaseContext
.GetComputeContext();
167 Context
.SetRootSignature(s_RootSignature
);
169 uint32_t Width
= g_SceneColorBuffer
.GetWidth();
170 uint32_t Height
= g_SceneColorBuffer
.GetHeight();
172 float RcpHalfDimX
= 2.0f
/ Width
;
173 float RcpHalfDimY
= 2.0f
/ Height
;
174 float RcpZMagic
= nearClip
/ (farClip
- nearClip
);
176 Matrix4 preMult
= Matrix4(
177 Vector4( RcpHalfDimX
, 0.0f
, 0.0f
, 0.0f
),
178 Vector4( 0.0f
, -RcpHalfDimY
, 0.0f
, 0.0f
),
179 Vector4( 0.0f
, 0.0f
, UseLinearZ
? RcpZMagic
: 1.0f
, 0.0f
),
180 Vector4( -1.0f
, 1.0f
, UseLinearZ
? -RcpZMagic
: 0.0f
, 1.0f
)
183 Matrix4 postMult
= Matrix4(
184 Vector4( 1.0f
/ RcpHalfDimX
, 0.0f
, 0.0f
, 0.0f
),
185 Vector4( 0.0f
, -1.0f
/ RcpHalfDimY
, 0.0f
, 0.0f
),
186 Vector4( 0.0f
, 0.0f
, 1.0f
, 0.0f
),
187 Vector4( 1.0f
/ RcpHalfDimX
, 1.0f
/ RcpHalfDimY
, 0.0f
, 1.0f
) );
189 Matrix4 CurToPrevXForm
= postMult
* reprojectionMatrix
* preMult
;
191 Context
.SetDynamicConstantBufferView(1, sizeof(CurToPrevXForm
), &CurToPrevXForm
);
193 ColorBuffer
& LinearDepth
= g_LinearDepth
[ Graphics::GetFrameCount() % 2 ];
195 Context
.TransitionResource(LinearDepth
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
197 Context
.TransitionResource(g_SceneDepthBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
201 Context
.TransitionResource(g_VelocityBuffer
, D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
202 Context
.TransitionResource(g_MotionPrepBuffer
, D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
203 Context
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
205 Context
.SetPipelineState(s_CameraMotionBlurPrePassCS
[UseLinearZ
? 1 : 0]);
206 Context
.SetDynamicDescriptor(3, 0, g_SceneColorBuffer
.GetSRV());
207 Context
.SetDynamicDescriptor(3, 1, UseLinearZ
? LinearDepth
.GetSRV() : g_SceneDepthBuffer
.GetDepthSRV());
208 Context
.SetDynamicDescriptor(2, 0, g_MotionPrepBuffer
.GetUAV());
209 Context
.SetDynamicDescriptor(2, 1, g_VelocityBuffer
.GetUAV());
210 Context
.Dispatch2D(g_MotionPrepBuffer
.GetWidth(), g_MotionPrepBuffer
.GetHeight());
212 if (g_bTypedUAVLoadSupport_R11G11B10_FLOAT
)
214 Context
.SetPipelineState(s_MotionBlurFinalPassCS
);
215 Context
.SetConstants(0, 1.0f
/ Width
, 1.0f
/ Height
);
217 Context
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
218 Context
.TransitionResource(g_VelocityBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
219 Context
.TransitionResource(g_MotionPrepBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
220 Context
.SetDynamicDescriptor(2, 0, g_SceneColorBuffer
.GetUAV());
221 Context
.SetDynamicDescriptor(3, 0, g_VelocityBuffer
.GetSRV());
222 Context
.SetDynamicDescriptor(3, 1, g_MotionPrepBuffer
.GetSRV());
224 Context
.Dispatch2D(Width
, Height
);
226 Context
.InsertUAVBarrier(g_SceneColorBuffer
);
230 GraphicsContext
& GrContext
= BaseContext
.GetGraphicsContext();
231 GrContext
.SetRootSignature(s_RootSignature
);
232 GrContext
.SetPipelineState(s_MotionBlurFinalPassPS
);
233 GrContext
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_RENDER_TARGET
);
234 GrContext
.TransitionResource(g_VelocityBuffer
, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
235 GrContext
.TransitionResource(g_MotionPrepBuffer
, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
236 GrContext
.SetDynamicDescriptor(3, 0, g_VelocityBuffer
.GetSRV());
237 GrContext
.SetDynamicDescriptor(3, 1, g_MotionPrepBuffer
.GetSRV());
238 GrContext
.SetConstants(0, 1.0f
/ Width
, 1.0f
/ Height
);
239 GrContext
.SetRenderTarget(g_SceneColorBuffer
.GetRTV());
240 GrContext
.SetViewportAndScissor(0, 0, Width
, Height
);
246 Context
.SetPipelineState(s_CameraVelocityCS
[UseLinearZ
? 1 : 0]);
247 Context
.SetDynamicDescriptor(3, 0, UseLinearZ
? LinearDepth
.GetSRV() : g_SceneDepthBuffer
.GetDepthSRV());
248 Context
.SetDynamicDescriptor(2, 0, g_VelocityBuffer
.GetUAV());
249 Context
.Dispatch2D(Width
, Height
);
253 void MotionBlur::RenderObjectBlur( CommandContext
& BaseContext
, ColorBuffer
& velocityBuffer
)
255 ScopedTimer
_prof(L
"MotionBlur", BaseContext
);
260 uint32_t Width
= g_SceneColorBuffer
.GetWidth();
261 uint32_t Height
= g_SceneColorBuffer
.GetHeight();
263 ComputeContext
& Context
= BaseContext
.GetComputeContext();
265 Context
.SetRootSignature(s_RootSignature
);
267 Context
.TransitionResource(g_MotionPrepBuffer
, D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
268 Context
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
269 Context
.TransitionResource(velocityBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
271 Context
.SetDynamicDescriptor(2, 0, g_MotionPrepBuffer
.GetUAV());
272 Context
.SetDynamicDescriptor(3, 0, g_SceneColorBuffer
.GetSRV());
273 Context
.SetDynamicDescriptor(3, 1, velocityBuffer
.GetSRV());
275 Context
.SetPipelineState(s_MotionBlurPrePassCS
);
276 Context
.Dispatch2D(g_MotionPrepBuffer
.GetWidth(), g_MotionPrepBuffer
.GetHeight());
278 if (g_bTypedUAVLoadSupport_R11G11B10_FLOAT
)
280 Context
.SetPipelineState(s_MotionBlurFinalPassCS
);
282 Context
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
283 Context
.TransitionResource(velocityBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
284 Context
.TransitionResource(g_MotionPrepBuffer
, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
286 Context
.SetDynamicDescriptor(2, 0, g_SceneColorBuffer
.GetUAV());
287 Context
.SetDynamicDescriptor(3, 0, velocityBuffer
.GetSRV());
288 Context
.SetDynamicDescriptor(3, 1, g_MotionPrepBuffer
.GetSRV());
289 Context
.SetConstants(0, 1.0f
/ Width
, 1.0f
/ Height
);
291 Context
.Dispatch2D(Width
, Height
);
293 Context
.InsertUAVBarrier(g_SceneColorBuffer
);
297 GraphicsContext
& GrContext
= BaseContext
.GetGraphicsContext();
298 GrContext
.SetRootSignature(s_RootSignature
);
299 GrContext
.SetPipelineState(s_MotionBlurFinalPassPS
);
301 GrContext
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_RENDER_TARGET
);
302 GrContext
.TransitionResource(velocityBuffer
, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
303 GrContext
.TransitionResource(g_MotionPrepBuffer
, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
305 GrContext
.SetDynamicDescriptor(3, 0, velocityBuffer
.GetSRV());
306 GrContext
.SetDynamicDescriptor(3, 1, g_MotionPrepBuffer
.GetSRV());
307 GrContext
.SetConstants(0, 1.0f
/ Width
, 1.0f
/ Height
);
308 GrContext
.SetRenderTarget(g_SceneColorBuffer
.GetRTV());
309 GrContext
.SetViewportAndScissor(0, 0, Width
, Height
);