Refactor material shaders generator to use modular features as extensions

This commit is contained in:
Wojtek Figat
2021-02-05 14:54:29 +01:00
parent 300f948515
commit d8304a2178
16 changed files with 185 additions and 259 deletions

View File

@@ -0,0 +1,44 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
@0// Motion Vectors: Defines
@1// Motion Vectors: Includes
@2// Motion Vectors: Constants
@3// Motion Vectors: Resources
@4// Motion Vectors: Utilities
@5// Motion Vectors: Shaders
// Pixel Shader function for Motion Vectors Pass
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_MotionVectors(PixelInput input) : SV_Target0
{
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
ClipLODTransition(input);
#endif
#if MATERIAL_MASKED
// Perform per pixel clipping if material requries it
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
// Calculate this and previosu frame pixel locations in clip space
float4 prevClipPos = mul(float4(input.Geometry.PrevWorldPosition, 1), PrevViewProjectionMatrix);
float4 curClipPos = mul(float4(input.Geometry.WorldPosition, 1), ViewProjectionMatrix);
float2 prevHPos = prevClipPos.xy / prevClipPos.w;
float2 curHPos = curClipPos.xy / curClipPos.w;
// Revert temporal jitter offset
prevHPos -= TemporalAAJitter.zw;
curHPos -= TemporalAAJitter.xy;
// Clip Space -> UV Space
float2 vPosPrev = prevHPos.xy * 0.5f + 0.5f;
float2 vPosCur = curHPos.xy * 0.5f + 0.5f;
vPosPrev.y = 1.0 - vPosPrev.y;
vPosCur.y = 1.0 - vPosCur.y;
// Calculate per-pixel motion vector
return float4(vPosCur - vPosPrev, 0, 1);
}

View File

@@ -32,14 +32,13 @@ struct TessalationDSToPS
MaterialInput GetMaterialInput(TessalationDSToPS input) MaterialInput GetMaterialInput(TessalationDSToPS input)
{ {
MaterialInput result = (MaterialInput)0; MaterialInput output = GetGeometryMaterialInput(input.Geometry);
result.SvPosition = input.Position; output.SvPosition = input.Position;
GetGeometryMaterialInput(result, input.Geometry); output.TwoSidedSign = WorldDeterminantSign;
result.TwoSidedSign = WorldDeterminantSign;
#if USE_CUSTOM_VERTEX_INTERPOLATORS #if USE_CUSTOM_VERTEX_INTERPOLATORS
result.CustomVSToPS = input.CustomVSToPS; output.CustomVSToPS = input.CustomVSToPS;
#endif #endif
return result; return output;
} }
struct TessalationPatch struct TessalationPatch

View File

@@ -141,14 +141,11 @@ MaterialInput GetMaterialInput(PixelInput input)
} }
// Gets the local to world transform matrix (supports instancing) // Gets the local to world transform matrix (supports instancing)
float4x4 GetInstanceTransform(ModelInput input) #if USE_INSTANCING
{ #define GetInstanceTransform(input) float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f))
return WorldMatrix; #else
} #define GetInstanceTransform(input) WorldMatrix;
float4x4 GetInstanceTransform(MaterialInput input) #endif
{
return WorldMatrix;
}
// Removes the scale vector from the local to world transformation matrix (supports instancing) // Removes the scale vector from the local to world transformation matrix (supports instancing)
float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld) float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld)

View File

@@ -101,19 +101,21 @@ struct MaterialInput
}; };
// Extracts geometry data to the material input // Extracts geometry data to the material input
void GetGeometryMaterialInput(inout MaterialInput result, in GeometryData geometry) MaterialInput GetGeometryMaterialInput(GeometryData geometry)
{ {
result.WorldPosition = geometry.WorldPosition; MaterialInput output = (MaterialInput)0;
result.TexCoord = geometry.TexCoord; output.WorldPosition = geometry.WorldPosition;
output.TexCoord = geometry.TexCoord;
#if USE_LIGHTMAP #if USE_LIGHTMAP
result.LightmapUV = geometry.LightmapUV; output.LightmapUV = geometry.LightmapUV;
#endif #endif
#if USE_VERTEX_COLOR #if USE_VERTEX_COLOR
result.VertexColor = geometry.VertexColor; output.VertexColor = geometry.VertexColor;
#endif #endif
result.TBN = CalcTangentBasis(geometry.WorldNormal, geometry.WorldTangent); output.TBN = CalcTangentBasis(geometry.WorldNormal, geometry.WorldTangent);
result.InstanceOrigin = geometry.InstanceOrigin; output.InstanceOrigin = geometry.InstanceOrigin;
result.InstanceParams = geometry.InstanceParams; output.InstanceParams = geometry.InstanceParams;
return output;
} }
#if USE_TESSELLATION #if USE_TESSELLATION
@@ -157,111 +159,23 @@ GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, flo
#endif #endif
MaterialInput GetMaterialInput(ModelInput input, VertexOutput output, float3 localNormal)
{
MaterialInput result = (MaterialInput)0;
result.WorldPosition = output.Geometry.WorldPosition;
result.TexCoord = output.Geometry.TexCoord;
#if USE_LIGHTMAP
result.LightmapUV = output.Geometry.LightmapUV;
#endif
#if USE_VERTEX_COLOR
result.VertexColor = output.Geometry.VertexColor;
#endif
result.TBN = CalcTangentBasis(output.Geometry.WorldNormal, output.Geometry.WorldTangent);
result.TwoSidedSign = WorldDeterminantSign;
result.SvPosition = output.Position;
result.PreSkinnedPosition = input.Position.xyz;
result.PreSkinnedNormal = localNormal;
#if USE_INSTANCING
result.InstanceOrigin = input.InstanceOrigin.xyz;
result.InstanceParams = float2(input.InstanceOrigin.w, input.InstanceTransform1.w);
result.InstanceTransform1 = input.InstanceTransform1.xyz;
result.InstanceTransform2 = input.InstanceTransform2.xyz;
result.InstanceTransform3 = input.InstanceTransform3.xyz;
#else
result.InstanceOrigin = WorldMatrix[3].xyz;
result.InstanceParams = float2(PerInstanceRandom, LODDitherFactor);
#endif
return result;
}
MaterialInput GetMaterialInput(VertexOutput output, float3 localPosition, float3 localNormal)
{
MaterialInput result = (MaterialInput)0;
result.WorldPosition = output.Geometry.WorldPosition;
result.TexCoord = output.Geometry.TexCoord;
#if USE_LIGHTMAP
result.LightmapUV = output.Geometry.LightmapUV;
#endif
#if USE_VERTEX_COLOR
result.VertexColor = output.Geometry.VertexColor;
#endif
result.TBN = CalcTangentBasis(output.Geometry.WorldNormal, output.Geometry.WorldTangent);
result.TwoSidedSign = WorldDeterminantSign;
result.InstanceOrigin = WorldMatrix[3].xyz;
result.InstanceParams = float2(PerInstanceRandom, LODDitherFactor);
result.SvPosition = output.Position;
result.PreSkinnedPosition = localPosition;
result.PreSkinnedNormal = localNormal;
return result;
}
MaterialInput GetMaterialInput(PixelInput input) MaterialInput GetMaterialInput(PixelInput input)
{ {
MaterialInput result = (MaterialInput)0; MaterialInput output = GetGeometryMaterialInput(input.Geometry);
result.WorldPosition = input.Geometry.WorldPosition; output.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0);
result.TexCoord = input.Geometry.TexCoord; output.SvPosition = input.Position;
#if USE_LIGHTMAP
result.LightmapUV = input.Geometry.LightmapUV;
#endif
#if USE_VERTEX_COLOR
result.VertexColor = input.Geometry.VertexColor;
#endif
result.TBN = CalcTangentBasis(input.Geometry.WorldNormal, input.Geometry.WorldTangent);
result.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0);
result.InstanceOrigin = input.Geometry.InstanceOrigin;
result.InstanceParams = input.Geometry.InstanceParams;
result.SvPosition = input.Position;
#if USE_CUSTOM_VERTEX_INTERPOLATORS #if USE_CUSTOM_VERTEX_INTERPOLATORS
result.CustomVSToPS = input.CustomVSToPS; output.CustomVSToPS = input.CustomVSToPS;
#endif #endif
return result; return output;
} }
// Gets the local to world transform matrix (supports instancing) // Gets the local to world transform matrix (supports instancing)
float4x4 GetInstanceTransform(ModelInput input)
{
#if USE_INSTANCING #if USE_INSTANCING
return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)); #define GetInstanceTransform(input) float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f))
#else #else
return WorldMatrix; #define GetInstanceTransform(input) WorldMatrix;
#endif #endif
}
float4x4 GetInstanceTransform(ModelInput_Skinned input)
{
#if USE_INSTANCING
return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f));
#else
return WorldMatrix;
#endif
}
float4x4 GetInstanceTransform(ModelInput_PosOnly input)
{
#if USE_INSTANCING
return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f));
#else
return WorldMatrix;
#endif
}
float4x4 GetInstanceTransform(MaterialInput input)
{
#if USE_INSTANCING
return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f));
#else
return WorldMatrix;
#endif
}
// Removes the scale vector from the local to world transformation matrix (supports instancing) // Removes the scale vector from the local to world transformation matrix (supports instancing)
float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld) float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld)
@@ -453,7 +367,16 @@ VertexOutput VS(ModelInput input)
// Get material input params if need to evaluate any material property // Get material input params if need to evaluate any material property
#if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS
MaterialInput materialInput = GetMaterialInput(input, output, tangentToLocal[2].xyz); MaterialInput materialInput = GetGeometryMaterialInput(output.Geometry);
materialInput.TwoSidedSign = WorldDeterminantSign;
materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = input.Position.xyz;
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
#if USE_INSTANCING
materialInput.InstanceTransform1 = input.InstanceTransform1.xyz;
materialInput.InstanceTransform2 = input.InstanceTransform2.xyz;
materialInput.InstanceTransform3 = input.InstanceTransform3.xyz;
#endif
Material material = GetMaterialVS(materialInput); Material material = GetMaterialVS(materialInput);
#endif #endif
@@ -626,7 +549,11 @@ VertexOutput VS_Skinned(ModelInput_Skinned input)
// Get material input params if need to evaluate any material property // Get material input params if need to evaluate any material property
#if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS
MaterialInput materialInput = GetMaterialInput(output, input.Position.xyz, tangentToLocal[2].xyz); MaterialInput materialInput = GetGeometryMaterialInput(output.Geometry);
materialInput.TwoSidedSign = WorldDeterminantSign;
materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = input.Position.xyz;
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
Material material = GetMaterialVS(materialInput); Material material = GetMaterialVS(materialInput);
#endif #endif
@@ -699,40 +626,4 @@ void PS_Depth(PixelInput input
#endif #endif
} }
// Pixel Shader function for Motion Vectors Pass
META_PS(USE_DEFERRED, FEATURE_LEVEL_ES2)
float4 PS_MotionVectors(PixelInput input) : SV_Target0
{
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
ClipLODTransition(input);
#endif
#if MATERIAL_MASKED
// Perform per pixel clipping if material requries it
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
// Calculate this and previosu frame pixel locations in clip space
float4 prevClipPos = mul(float4(input.Geometry.PrevWorldPosition, 1), PrevViewProjectionMatrix);
float4 curClipPos = mul(float4(input.Geometry.WorldPosition, 1), ViewProjectionMatrix);
float2 prevHPos = prevClipPos.xy / prevClipPos.w;
float2 curHPos = curClipPos.xy / curClipPos.w;
// Revert temporal jitter offset
prevHPos -= TemporalAAJitter.zw;
curHPos -= TemporalAAJitter.xy;
// Clip Space -> UV Space
float2 vPosPrev = prevHPos.xy * 0.5f + 0.5f;
float2 vPosCur = curHPos.xy * 0.5f + 0.5f;
vPosPrev.y = 1.0 - vPosPrev.y;
vPosCur.y = 1.0 - vPosCur.y;
// Calculate per-pixel motion vector
return float4(vPosCur - vPosPrev, 0, 1);
}
@9 @9

View File

@@ -37,14 +37,16 @@ void DecalMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0); byte* cb = _cbData.Get();
const bool hasCb0 = cb0->GetSize() != 0; auto materialData = reinterpret_cast<DecalMaterialShaderData*>(cb);
cb += sizeof(DecalMaterialShaderData);
int32 srv = 0;
const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains; const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains;
// Setup parameters // Setup parameters
MaterialParameter::BindMeta bindMeta; MaterialParameter::BindMeta bindMeta;
bindMeta.Context = context; bindMeta.Context = context;
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(DecalMaterialShaderData) : nullptr; bindMeta.Constants = cb;
bindMeta.Input = nullptr; bindMeta.Input = nullptr;
bindMeta.Buffers = nullptr; bindMeta.Buffers = nullptr;
bindMeta.CanSampleDepth = true; bindMeta.CanSampleDepth = true;
@@ -55,10 +57,7 @@ void DecalMaterialShader::Bind(BindParameters& params)
context->BindSR(0, GET_TEXTURE_VIEW_SAFE(params.RenderContext.Buffers->DepthBuffer)); context->BindSR(0, GET_TEXTURE_VIEW_SAFE(params.RenderContext.Buffers->DepthBuffer));
// Setup material constants data // Setup material constants data
if (hasCb0)
{ {
const auto materialData = reinterpret_cast<DecalMaterialShaderData*>(_cb0Data.Get());
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
Matrix::Transpose(view.View, materialData->ViewMatrix); Matrix::Transpose(view.View, materialData->ViewMatrix);
@@ -85,10 +84,10 @@ void DecalMaterialShader::Bind(BindParameters& params)
} }
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Bind pipeline // Bind pipeline

View File

@@ -61,10 +61,7 @@ void DeferredMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0); byte* cb = _cbData.Get();
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb); auto materialData = reinterpret_cast<DeferredMaterialShaderData*>(cb);
cb += sizeof(DeferredMaterialShaderData); cb += sizeof(DeferredMaterialShaderData);
int32 srv = 2; int32 srv = 2;
@@ -82,8 +79,6 @@ void DeferredMaterialShader::Bind(BindParameters& params)
bindMeta.CanSampleGBuffer = false; bindMeta.CanSampleGBuffer = false;
MaterialParams::Bind(params.ParamsLink, bindMeta); MaterialParams::Bind(params.ParamsLink, bindMeta);
// Setup material constants data
if (hasCb0)
{ {
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
@@ -131,10 +126,10 @@ void DeferredMaterialShader::Bind(BindParameters& params)
} }
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Select pipeline state based on current pass and render mode // Select pipeline state based on current pass and render mode

View File

@@ -58,10 +58,7 @@ void ForwardMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0); byte* cb = _cbData.Get();
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb); auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb);
cb += sizeof(ForwardMaterialShaderData); cb += sizeof(ForwardMaterialShaderData);
int32 srv = 2; int32 srv = 2;
@@ -89,7 +86,6 @@ void ForwardMaterialShader::Bind(BindParameters& params)
} }
// Setup material constants data // Setup material constants data
if (hasCb0)
{ {
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
@@ -121,10 +117,10 @@ void ForwardMaterialShader::Bind(BindParameters& params)
} }
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Select pipeline state based on current pass and render mode // Select pipeline state based on current pass and render mode

View File

@@ -28,15 +28,16 @@ void GUIMaterialShader::Bind(BindParameters& params)
{ {
// Prepare // Prepare
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; byte* cb = _cbData.Get();
const auto cb0 = _shader->GetCB(0); auto materialData = reinterpret_cast<GUIMaterialShaderData*>(cb);
const bool hasCb0 = cb0->GetSize() != 0; cb += sizeof(GUIMaterialShaderData);
int32 srv = 0;
const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth; const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth;
// Setup parameters // Setup parameters
MaterialParameter::BindMeta bindMeta; MaterialParameter::BindMeta bindMeta;
bindMeta.Context = context; bindMeta.Context = context;
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(GUIMaterialShaderData) : nullptr; bindMeta.Constants = cb;
bindMeta.Input = nullptr; bindMeta.Input = nullptr;
bindMeta.Buffers = nullptr; bindMeta.Buffers = nullptr;
bindMeta.CanSampleDepth = false; bindMeta.CanSampleDepth = false;
@@ -44,10 +45,7 @@ void GUIMaterialShader::Bind(BindParameters& params)
MaterialParams::Bind(params.ParamsLink, bindMeta); MaterialParams::Bind(params.ParamsLink, bindMeta);
// Setup material constants data // Setup material constants data
if (hasCb0)
{ {
auto materialData = reinterpret_cast<GUIMaterialShaderData*>(_cb0Data.Get());
const auto viewProjectionMatrix = (Matrix*)params.CustomData; const auto viewProjectionMatrix = (Matrix*)params.CustomData;
Matrix::Transpose(*viewProjectionMatrix, materialData->ViewProjectionMatrix); Matrix::Transpose(*viewProjectionMatrix, materialData->ViewProjectionMatrix);
Matrix::Transpose(Matrix::Identity, materialData->WorldMatrix); Matrix::Transpose(Matrix::Identity, materialData->WorldMatrix);
@@ -62,10 +60,10 @@ void GUIMaterialShader::Bind(BindParameters& params)
} }
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Bind pipeline // Bind pipeline

View File

@@ -14,18 +14,15 @@
#include "GUIMaterialShader.h" #include "GUIMaterialShader.h"
#include "TerrainMaterialShader.h" #include "TerrainMaterialShader.h"
#include "ParticleMaterialShader.h" #include "ParticleMaterialShader.h"
//#include "DeformableMaterialShader.h"
GPUPipelineState* MaterialShader::PipelineStateCache::GetPS(CullMode mode, bool wireframe) GPUPipelineState* MaterialShader::PipelineStateCache::InitPS(CullMode mode, bool wireframe)
{ {
const int32 index = static_cast<int32>(mode) + (wireframe ? 3 : 0);
if (PS[index])
return PS[index];
Desc.CullMode = mode; Desc.CullMode = mode;
Desc.Wireframe = wireframe; Desc.Wireframe = wireframe;
PS[index] = GPUDevice::Instance->CreatePipelineState(); auto ps = GPUDevice::Instance->CreatePipelineState();
PS[index]->Init(Desc); ps->Init(Desc);
return PS[index]; return ps;
} }
MaterialShader::MaterialShader(const String& name) MaterialShader::MaterialShader(const String& name)
@@ -65,6 +62,9 @@ MaterialShader* MaterialShader::Create(const String& name, MemoryReadStream& sha
case MaterialDomain::Particle: case MaterialDomain::Particle:
material = New<ParticleMaterialShader>(name); material = New<ParticleMaterialShader>(name);
break; break;
/*case MaterialDomain::Deformable:
material = New<DeformableMaterialShader>(name);
break;*/
default: default:
LOG(Fatal, "Unknown material type."); LOG(Fatal, "Unknown material type.");
return nullptr; return nullptr;
@@ -138,10 +138,17 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf
} }
// Init memory for a constant buffer // Init memory for a constant buffer
const auto cb0 = _shader->GetCB(0); _cb = _shader->GetCB(0);
if (cb0) if (_cb)
{ {
_cb0Data.Resize(cb0->GetSize(), false); int32 cbSize = _cb->GetSize();
if (cbSize == 0)
{
// Handle unused constant buffer (eg. postFx returning solid color)
cbSize = 1024;
_cb = nullptr;
}
_cbData.Resize(cbSize, false);
} }
// Initialize the material based on type (create pipeline states and setup) // Initialize the material based on type (create pipeline states and setup)
@@ -157,6 +164,7 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf
void MaterialShader::Unload() void MaterialShader::Unload()
{ {
_isLoaded = false; _isLoaded = false;
_cb0Data.Resize(0, false); _cb = nullptr;
_cbData.Resize(0, false);
_shader->ReleaseGPU(); _shader->ReleaseGPU();
} }

View File

@@ -9,10 +9,11 @@
/// <summary> /// <summary>
/// Current materials shader version. /// Current materials shader version.
/// </summary> /// </summary>
#define MATERIAL_GRAPH_VERSION 146 #define MATERIAL_GRAPH_VERSION 147
class Material; class Material;
class GPUShader; class GPUShader;
class GPUConstantBuffer;
class MemoryReadStream; class MemoryReadStream;
/// <summary> /// <summary>
@@ -37,7 +38,16 @@ protected:
Desc = desc; Desc = desc;
} }
GPUPipelineState* GetPS(CullMode mode, bool wireframe); GPUPipelineState* GetPS(CullMode mode, bool wireframe)
{
const int32 index = static_cast<int32>(mode) + (wireframe ? 3 : 0);
auto ps = PS[index];
if (!ps)
PS[index] = ps = InitPS(mode, wireframe);
return ps;
}
GPUPipelineState* InitPS(CullMode mode, bool wireframe);
void Release() void Release()
{ {
@@ -52,7 +62,8 @@ protected:
bool _isLoaded; bool _isLoaded;
GPUShader* _shader; GPUShader* _shader;
Array<byte> _cb0Data; GPUConstantBuffer* _cb;
Array<byte> _cbData;
MaterialInfo _info; MaterialInfo _info;
protected: protected:
@@ -89,10 +100,8 @@ public:
/// <returns>The created and loaded material or null if failed.</returns> /// <returns>The created and loaded material or null if failed.</returns>
static MaterialShader* CreateDummy(MemoryReadStream& shaderCacheStream, const MaterialInfo& info); static MaterialShader* CreateDummy(MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
public:
/// <summary> /// <summary>
/// Clear loaded data /// Clears the loaded data.
/// </summary> /// </summary>
virtual void Unload(); virtual void Unload();

View File

@@ -158,36 +158,31 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, in
void ForwardShadingFeature::Generate(GeneratorData& data) void ForwardShadingFeature::Generate(GeneratorData& data)
{ {
data.Template = TEXT("Features/ForwardShading.hlsl"); data.Template = TEXT("Features/ForwardShading.hlsl");
data.ConstantsSize = sizeof(Data);
data.ResourcesCount = SRVs;
} }
void DeferredShadingFeature::Generate(GeneratorData& data) void DeferredShadingFeature::Generate(GeneratorData& data)
{ {
data.Template = TEXT("Features/DeferredShading.hlsl"); data.Template = TEXT("Features/DeferredShading.hlsl");
data.ConstantsSize = 0;
data.ResourcesCount = 0;
} }
void TessellationFeature::Generate(GeneratorData& data) void TessellationFeature::Generate(GeneratorData& data)
{ {
data.Template = TEXT("Features/Tessellation.hlsl"); data.Template = TEXT("Features/Tessellation.hlsl");
data.ConstantsSize = 0;
data.ResourcesCount = 0;
} }
void LightmapFeature::Generate(GeneratorData& data) void LightmapFeature::Generate(GeneratorData& data)
{ {
data.Template = TEXT("Features/Lightmap.hlsl"); data.Template = TEXT("Features/Lightmap.hlsl");
data.ConstantsSize = sizeof(Data);
data.ResourcesCount = SRVs;
} }
void DistortionFeature::Generate(GeneratorData& data) void DistortionFeature::Generate(GeneratorData& data)
{ {
data.Template = TEXT("Features/Distortion.hlsl"); data.Template = TEXT("Features/Distortion.hlsl");
data.ConstantsSize = 0; }
data.ResourcesCount = 0;
void MotionVectorsFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Features/MotionVectors.hlsl");
} }
#endif #endif

View File

@@ -12,8 +12,6 @@ struct MaterialShaderFeature
struct GeneratorData struct GeneratorData
{ {
const Char* Template; const Char* Template;
int32 ConstantsSize;
int32 ResourcesCount;
}; };
#endif; #endif;
}; };
@@ -82,3 +80,11 @@ struct DistortionFeature : MaterialShaderFeature
static void Generate(GeneratorData& data); static void Generate(GeneratorData& data);
#endif #endif
}; };
// Material shader feature that adds motion vectors rendering pass.
struct MotionVectorsFeature : MaterialShaderFeature
{
#if USE_EDITOR
static void Generate(GeneratorData& data);
#endif
};

View File

@@ -60,10 +60,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset; const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset;
const auto cb0 = _shader->GetCB(0); byte* cb = _cbData.Get();
const bool hasCb0 = cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb); auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb);
cb += sizeof(ParticleMaterialShaderData); cb += sizeof(ParticleMaterialShaderData);
int32 srv = 2; int32 srv = 2;
@@ -86,7 +83,6 @@ void ParticleMaterialShader::Bind(BindParameters& params)
context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices ? drawCall.Particle.Particles->GPU.SortedIndices->View() : nullptr); context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices ? drawCall.Particle.Particles->GPU.SortedIndices->View() : nullptr);
// Setup particles attributes binding info // Setup particles attributes binding info
if (hasCb0)
{ {
const auto& p = *params.ParamsLink->This; const auto& p = *params.ParamsLink->This;
for (int32 i = 0; i < p.Count(); i++) for (int32 i = 0; i < p.Count(); i++)
@@ -129,19 +125,16 @@ void ParticleMaterialShader::Bind(BindParameters& params)
static StringView ParticleRibbonTwist(TEXT("RibbonTwist")); static StringView ParticleRibbonTwist(TEXT("RibbonTwist"));
static StringView ParticleRibbonFacingVector(TEXT("RibbonFacingVector")); static StringView ParticleRibbonFacingVector(TEXT("RibbonFacingVector"));
if (hasCb0) materialData->RibbonWidthOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1);
{ materialData->RibbonTwistOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1);
materialData->RibbonWidthOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1); materialData->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1);
materialData->RibbonTwistOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1);
materialData->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1);
materialData->RibbonUVTilingDistance = drawCall.Particle.Ribbon.UVTilingDistance; materialData->RibbonUVTilingDistance = drawCall.Particle.Ribbon.UVTilingDistance;
materialData->RibbonUVScale.X = drawCall.Particle.Ribbon.UVScaleX; materialData->RibbonUVScale.X = drawCall.Particle.Ribbon.UVScaleX;
materialData->RibbonUVScale.Y = drawCall.Particle.Ribbon.UVScaleY; materialData->RibbonUVScale.Y = drawCall.Particle.Ribbon.UVScaleY;
materialData->RibbonUVOffset.X = drawCall.Particle.Ribbon.UVOffsetX; materialData->RibbonUVOffset.X = drawCall.Particle.Ribbon.UVOffsetX;
materialData->RibbonUVOffset.Y = drawCall.Particle.Ribbon.UVOffsetY; materialData->RibbonUVOffset.Y = drawCall.Particle.Ribbon.UVOffsetY;
materialData->RibbonSegmentCount = drawCall.Particle.Ribbon.SegmentCount; materialData->RibbonSegmentCount = drawCall.Particle.Ribbon.SegmentCount;
}
if (drawCall.Particle.Ribbon.SegmentDistances) if (drawCall.Particle.Ribbon.SegmentDistances)
context->BindSR(1, drawCall.Particle.Ribbon.SegmentDistances->View()); context->BindSR(1, drawCall.Particle.Ribbon.SegmentDistances->View());
@@ -153,7 +146,6 @@ void ParticleMaterialShader::Bind(BindParameters& params)
GPUPipelineState* state = psCache->GetPS(cullMode, wireframe); GPUPipelineState* state = psCache->GetPS(cullMode, wireframe);
// Setup material constants data // Setup material constants data
if (hasCb0)
{ {
static StringView ParticlePosition(TEXT("Position")); static StringView ParticlePosition(TEXT("Position"));
static StringView ParticleSpriteSize(TEXT("SpriteSize")); static StringView ParticleSpriteSize(TEXT("SpriteSize"));
@@ -188,10 +180,10 @@ void ParticleMaterialShader::Bind(BindParameters& params)
} }
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Bind pipeline // Bind pipeline

View File

@@ -26,13 +26,15 @@ void PostFxMaterialShader::Bind(BindParameters& params)
// Prepare // Prepare
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
const auto cb0 = _shader->GetCB(0); byte* cb = _cbData.Get();
const bool hasCb0 = cb0->GetSize() != 0; auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(cb);
cb += sizeof(PostFxMaterialShaderData);
int32 srv = 0;
// Setup parameters // Setup parameters
MaterialParameter::BindMeta bindMeta; MaterialParameter::BindMeta bindMeta;
bindMeta.Context = context; bindMeta.Context = context;
bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(PostFxMaterialShaderData) : nullptr; bindMeta.Constants = cb;
bindMeta.Input = params.Input; bindMeta.Input = params.Input;
bindMeta.Buffers = params.RenderContext.Buffers; bindMeta.Buffers = params.RenderContext.Buffers;
bindMeta.CanSampleDepth = true; bindMeta.CanSampleDepth = true;
@@ -40,10 +42,7 @@ void PostFxMaterialShader::Bind(BindParameters& params)
MaterialParams::Bind(params.ParamsLink, bindMeta); MaterialParams::Bind(params.ParamsLink, bindMeta);
// Setup material constants data // Setup material constants data
if (hasCb0)
{ {
const auto materialData = reinterpret_cast<PostFxMaterialShaderData*>(_cb0Data.Get());
Matrix::Transpose(view.View, materialData->ViewMatrix); Matrix::Transpose(view.View, materialData->ViewMatrix);
materialData->ViewPos = view.Position; materialData->ViewPos = view.Position;
materialData->ViewFar = view.Far; materialData->ViewFar = view.Far;
@@ -55,10 +54,10 @@ void PostFxMaterialShader::Bind(BindParameters& params)
} }
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Bind pipeline // Bind pipeline

View File

@@ -54,10 +54,7 @@ void TerrainMaterialShader::Bind(BindParameters& params)
auto context = params.GPUContext; auto context = params.GPUContext;
auto& view = params.RenderContext.View; auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall; auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0); byte* cb = _cbData.Get();
const bool hasCb0 = cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<TerrainMaterialShaderData*>(cb); auto materialData = reinterpret_cast<TerrainMaterialShaderData*>(cb);
cb += sizeof(TerrainMaterialShaderData); cb += sizeof(TerrainMaterialShaderData);
int32 srv = 3; int32 srv = 3;
@@ -76,7 +73,6 @@ void TerrainMaterialShader::Bind(BindParameters& params)
MaterialParams::Bind(params.ParamsLink, bindMeta); MaterialParams::Bind(params.ParamsLink, bindMeta);
// Setup material constants data // Setup material constants data
if (hasCb0)
{ {
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
@@ -114,10 +110,10 @@ void TerrainMaterialShader::Bind(BindParameters& params)
context->BindSR(2, splatmap1); context->BindSR(2, splatmap1);
// Bind constants // Bind constants
if (hasCb0) if (_cb)
{ {
context->UpdateCB(cb0, _cb0Data.Get()); context->UpdateCB(_cb, _cbData.Get());
context->BindCB(0, cb0); context->BindCB(0, _cb);
} }
// Select pipeline state based on current pass and render mode // Select pipeline state based on current pass and render mode

View File

@@ -185,6 +185,8 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
if (materialInfo.TessellationMode != TessellationMethod::None) if (materialInfo.TessellationMode != TessellationMethod::None)
ADD_FEATURE(TessellationFeature); ADD_FEATURE(TessellationFeature);
if (materialInfo.BlendMode == MaterialBlendMode::Opaque) if (materialInfo.BlendMode == MaterialBlendMode::Opaque)
ADD_FEATURE(MotionVectorsFeature);
if (materialInfo.BlendMode == MaterialBlendMode::Opaque)
ADD_FEATURE(LightmapFeature); ADD_FEATURE(LightmapFeature);
if (materialInfo.BlendMode == MaterialBlendMode::Opaque) if (materialInfo.BlendMode == MaterialBlendMode::Opaque)
ADD_FEATURE(DeferredShadingFeature); ADD_FEATURE(DeferredShadingFeature);