Refactor material shaders generator to use modular features as extensions

This commit is contained in:
Wojtek Figat
2021-02-05 11:22:47 +01:00
parent b5847eb0d6
commit 01777a2c1b
16 changed files with 182 additions and 563 deletions

View File

@@ -4,13 +4,14 @@
#include "MaterialShaderFeatures.h"
#include "MaterialParams.h"
#include "Engine/Engine/Time.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPULimits.h"
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Level/Actors/EnvironmentProbe.h"
#include "Engine/Renderer/DepthOfFieldPass.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/ShadowsPass.h"
#include "Engine/Renderer/RenderList.h"
#if USE_EDITOR
#include "Engine/Renderer/Lightmaps.h"
@@ -39,17 +40,6 @@ PACK_STRUCT(struct ForwardMaterialShaderData {
float Dummy1;
});
PACK_STRUCT(struct ForwardMaterialShaderLightingData {
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
Vector3 Dummy2;
uint32 LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
});
DrawPass ForwardMaterialShader::GetDrawModes() const
{
return _drawModes;
@@ -66,19 +56,17 @@ void ForwardMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto cache = params.RenderContext.List;
auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0);
const bool hasCb0 = cb0 && cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
const auto cb1 = _shader->GetCB(1);
const bool hasCb1 = cb1 && cb1->GetSize() != 0;
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<ForwardMaterialShaderData*>(cb);
cb += sizeof(ForwardMaterialShaderData);
int32 srv = 0;
// Setup features
ForwardShadingFeature::Bind(params, cb, srv);
// Setup parameters
MaterialParameter::BindMeta bindMeta;
@@ -131,124 +119,12 @@ void ForwardMaterialShader::Bind(BindParameters& params)
materialData->GeometrySize = drawCall.Surface.GeometrySize;
}
// Setup lighting constants data
if (hasCb1)
{
auto& lightingData = *reinterpret_cast<ForwardMaterialShaderLightingData*>(_cb1Data.Get());
const int32 envProbeShaderRegisterIndex = 0;
const int32 skyLightShaderRegisterIndex = 1;
const int32 dirLightShaderRegisterIndex = 2;
// Set fog input
if (cache->Fog)
{
cache->Fog->GetExponentialHeightFogData(view, lightingData.ExponentialHeightFog);
}
else
{
lightingData.ExponentialHeightFog.FogMinOpacity = 1.0f;
lightingData.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
}
// Set directional light input
if (cache->DirectionalLights.HasItems())
{
const auto& dirLight = cache->DirectionalLights.First();
const auto shadowPass = ShadowsPass::Instance();
const bool useShadow = shadowPass->LastDirLightIndex == 0;
if (useShadow)
{
lightingData.DirectionalLightShadow = shadowPass->LastDirLight;
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
}
else
{
context->UnBindSR(dirLightShaderRegisterIndex);
}
dirLight.SetupLightData(&lightingData.DirectionalLight, view, useShadow);
}
else
{
lightingData.DirectionalLight.Color = Vector3::Zero;
lightingData.DirectionalLight.CastShadows = 0.0f;
context->UnBindSR(dirLightShaderRegisterIndex);
}
// Set sky light
if (cache->SkyLights.HasItems())
{
auto& skyLight = cache->SkyLights.First();
skyLight.SetupLightData(&lightingData.SkyLight, view, false);
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
context->BindSR(skyLightShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
}
else
{
Platform::MemoryClear(&lightingData.SkyLight, sizeof(lightingData.SkyLight));
context->UnBindSR(skyLightShaderRegisterIndex);
}
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (p->GetSphere().Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
probe = p;
break;
}
}
if (probe && probe->GetProbe())
{
probe->SetupProbeData(&lightingData.EnvironmentProbe);
const auto texture = probe->GetProbe()->GetTexture();
context->BindSR(envProbeShaderRegisterIndex, GET_TEXTURE_VIEW_SAFE(texture));
}
else
{
lightingData.EnvironmentProbe.Data1 = Vector4::Zero;
context->UnBindSR(envProbeShaderRegisterIndex);
}
// Set local lights
lightingData.LocalLightsCount = 0;
for (int32 i = 0; i < cache->PointLights.Count(); i++)
{
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
for (int32 i = 0; i < cache->SpotLights.Count(); i++)
{
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
}
// Bind constants
if (hasCb0)
{
context->UpdateCB(cb0, _cb0Data.Get());
context->BindCB(0, cb0);
}
if (hasCb1)
{
context->UpdateCB(cb1, _cb1Data.Get());
context->BindCB(1, cb1);
}
// Select pipeline state based on current pass and render mode
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;

View File

@@ -143,11 +143,6 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf
{
_cb0Data.Resize(cb0->GetSize(), false);
}
const auto cb1 = _shader->GetCB(1);
if (cb1)
{
_cb1Data.Resize(cb1->GetSize(), false);
}
// Initialize the material based on type (create pipeline states and setup)
if (Load())
@@ -163,6 +158,5 @@ void MaterialShader::Unload()
{
_isLoaded = false;
_cb0Data.Resize(0, false);
_cb1Data.Resize(0, false);
_shader->ReleaseGPU();
}

View File

@@ -53,7 +53,6 @@ protected:
bool _isLoaded;
GPUShader* _shader;
Array<byte> _cb0Data;
Array<byte> _cb1Data;
MaterialInfo _info;
protected:

View File

@@ -155,23 +155,30 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, in
#if USE_EDITOR
void ForwardShadingFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Features/ForwardShading.hlsl");
data.ConstantsSize = sizeof(Data);
data.ResourcesCount = SRVs;
}
void TessellationFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Tessellation.hlsl");
data.Template = TEXT("Features/Tessellation.hlsl");
data.ConstantsSize = 0;
data.ResourcesCount = 0;
}
void LightmapFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Lightmap.hlsl");
data.Template = TEXT("Features/Lightmap.hlsl");
data.ConstantsSize = sizeof(Data);
data.ResourcesCount = SRVs;
}
void DistortionFeature::Generate(GeneratorData& data)
{
data.Template = TEXT("Distortion.hlsl");
data.Template = TEXT("Features/Distortion.hlsl");
data.ConstantsSize = 0;
data.ResourcesCount = 0;
}

View File

@@ -38,6 +38,9 @@ struct ForwardShadingFeature : MaterialShaderFeature
});
static void Bind(MaterialShader::BindParameters& params, byte*& cb, int32& srv);
#if USE_EDITOR
static void Generate(GeneratorData& data);
#endif
};
// Material shader feature that adds geometry hardware tessellation (using Hull and Domain shaders).

View File

@@ -1,20 +1,19 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "ParticleMaterialShader.h"
#include "MaterialShaderFeatures.h"
#include "MaterialParams.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/ShadowsPass.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Engine/Time.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/GPULimits.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
#include "Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h"
#include "Engine/Content/Assets/CubeTexture.h"
#include "Engine/Level/Actors/EnvironmentProbe.h"
#define MAX_LOCAL_LIGHTS 4
@@ -49,17 +48,6 @@ PACK_STRUCT(struct ParticleMaterialShaderData {
Matrix WorldMatrixInverseTransposed;
});
PACK_STRUCT(struct ParticleMaterialShaderLightingData {
LightData DirectionalLight;
LightShadowData DirectionalLightShadow;
LightData SkyLight;
ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog;
Vector3 Dummy1;
uint32 LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS];
});
DrawPass ParticleMaterialShader::GetDrawModes() const
{
return _drawModes;
@@ -70,20 +58,18 @@ void ParticleMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto cache = params.RenderContext.List;
auto& drawCall = *params.FirstDrawCall;
const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset;
const auto cb0 = _shader->GetCB(0);
const bool hasCb0 = cb0->GetSize() != 0;
ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing
const auto cb1 = _shader->GetCB(1);
const bool hasCb1 = cb1 && cb1->GetSize() != 0;
byte* cb = _cb0Data.Get();
auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(cb);
cb += sizeof(ParticleMaterialShaderData);
int32 srv = 0;
int32 srv = 2;
// Setup features
ForwardShadingFeature::Bind(params, cb, srv);
// Setup parameters
MaterialParameter::BindMeta bindMeta;
@@ -95,25 +81,23 @@ void ParticleMaterialShader::Bind(BindParameters& params)
bindMeta.CanSampleGBuffer = true;
MaterialParams::Bind(params.ParamsLink, bindMeta);
// Setup particles data and attributes binding info
// Setup particles data
context->BindSR(0, drawCall.Particle.Particles->GPU.Buffer->View());
context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices ? drawCall.Particle.Particles->GPU.SortedIndices->View() : nullptr);
// Setup particles attributes binding info
if (hasCb0)
{
context->BindSR(0, drawCall.Particle.Particles->GPU.Buffer->View());
if (drawCall.Particle.Particles->GPU.SortedIndices)
context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices->View());
if (hasCb0)
const auto& p = *params.ParamsLink->This;
for (int32 i = 0; i < p.Count(); i++)
{
const auto& p = *params.ParamsLink->This;
for (int32 i = 0; i < p.Count(); i++)
const auto& param = p.At(i);
if (param.GetParameterType() == MaterialParameterType::Integer && param.GetName().StartsWith(TEXT("Particle.")))
{
const auto& param = p.At(i);
if (param.GetParameterType() == MaterialParameterType::Integer && param.GetName().StartsWith(TEXT("Particle.")))
{
auto name = StringView(param.GetName().Get() + 9);
auto name = StringView(param.GetName().Get() + 9);
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
}
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Constants + param.GetBindOffset())) = offset;
}
}
}
@@ -147,8 +131,6 @@ void ParticleMaterialShader::Bind(BindParameters& params)
if (hasCb0)
{
const auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(_cb0Data.Get());
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->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1);
@@ -173,8 +155,6 @@ void ParticleMaterialShader::Bind(BindParameters& params)
// Setup material constants data
if (hasCb0)
{
const auto materialData = reinterpret_cast<ParticleMaterialShaderData*>(_cb0Data.Get());
static StringView ParticlePosition(TEXT("Position"));
static StringView ParticleSpriteSize(TEXT("SpriteSize"));
static StringView ParticleSpriteFacingMode(TEXT("SpriteFacingMode"));
@@ -207,124 +187,12 @@ void ParticleMaterialShader::Bind(BindParameters& params)
Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed);
}
// Setup lighting constants data
if (hasCb1)
{
auto& lightingData = *reinterpret_cast<ParticleMaterialShaderLightingData*>(_cb1Data.Get());
const int32 envProbeShaderRegisterIndex = 2;
const int32 skyLightShaderRegisterIndex = 3;
const int32 dirLightShaderRegisterIndex = 4;
// Set fog input
if (cache->Fog)
{
cache->Fog->GetExponentialHeightFogData(view, lightingData.ExponentialHeightFog);
}
else
{
lightingData.ExponentialHeightFog.FogMinOpacity = 1.0f;
lightingData.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
}
// Set directional light input
if (cache->DirectionalLights.HasItems())
{
const auto& dirLight = cache->DirectionalLights.First();
const auto shadowPass = ShadowsPass::Instance();
const bool useShadow = shadowPass->LastDirLightIndex == 0;
if (useShadow)
{
lightingData.DirectionalLightShadow = shadowPass->LastDirLight;
context->BindSR(dirLightShaderRegisterIndex, shadowPass->LastDirLightShadowMap);
}
else
{
context->UnBindSR(dirLightShaderRegisterIndex);
}
dirLight.SetupLightData(&lightingData.DirectionalLight, view, useShadow);
}
else
{
lightingData.DirectionalLight.Color = Vector3::Zero;
lightingData.DirectionalLight.CastShadows = 0.0f;
context->UnBindSR(dirLightShaderRegisterIndex);
}
// Set sky light
if (cache->SkyLights.HasItems())
{
auto& skyLight = cache->SkyLights.Last();
skyLight.SetupLightData(&lightingData.SkyLight, view, false);
const auto texture = skyLight.Image ? skyLight.Image->GetTexture() : nullptr;
context->BindSR(skyLightShaderRegisterIndex, texture);
}
else
{
Platform::MemoryClear(&lightingData.SkyLight, sizeof(lightingData.SkyLight));
context->UnBindSR(skyLightShaderRegisterIndex);
}
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (p->GetSphere().Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
probe = p;
break;
}
}
if (probe && probe->GetProbe())
{
probe->SetupProbeData(&lightingData.EnvironmentProbe);
const auto texture = probe->GetProbe()->GetTexture();
context->BindSR(envProbeShaderRegisterIndex, texture);
}
else
{
lightingData.EnvironmentProbe.Data1 = Vector4::Zero;
context->UnBindSR(envProbeShaderRegisterIndex);
}
// Set local lights
lightingData.LocalLightsCount = 0;
for (int32 i = 0; i < cache->PointLights.Count(); i++)
{
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
for (int32 i = 0; i < cache->SpotLights.Count(); i++)
{
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.World.GetTranslation()) != ContainmentType::Disjoint)
{
light.SetupLightData(&lightingData.LocalLights[lightingData.LocalLightsCount], view, false);
lightingData.LocalLightsCount++;
if (lightingData.LocalLightsCount == MAX_LOCAL_LIGHTS)
break;
}
}
}
// Bind constants
if (hasCb0)
{
context->UpdateCB(cb0, _cb0Data.Get());
context->BindCB(0, cb0);
}
if (hasCb1)
{
context->UpdateCB(cb1, _cb1Data.Get());
context->BindCB(1, cb1);
}
// Bind pipeline
context->SetState(state);

View File

@@ -26,7 +26,6 @@ void PostFxMaterialShader::Bind(BindParameters& params)
// Prepare
auto context = params.GPUContext;
auto& view = params.RenderContext.View;
auto& drawCall = *params.FirstDrawCall;
const auto cb0 = _shader->GetCB(0);
const bool hasCb0 = cb0->GetSize() != 0;