Files
Webcam/include/engine/gpu/gpu_material_shader.cpp

430 lines
17 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "gpu/gpu_material_shader.h"
#include "gpu/gpu_material.h"
#include "gpu/gpu_renderer.h"
#include "log/log.h"
using namespace GS;
using namespace GS::GPU;
using GS::NML::Tag;
//------------------------------------------------------------------------------
bool MaterialShader::SetUserUniformValue(const char *name, const Vector4 &v)
{
uint match_count = 0;
for (uint n = 0; n < variants.GetCount(); ++n)
if (Shader *shader = variants[n].c_ptr())
if (ShaderInput *input = shader->GetInput(name))
{
input->parm_v = v;
++match_count;
}
return match_count > 0;
}
bool MaterialShader::SetUserUniformValue(const char *name, Render::Texture *t)
{
uint match_count = 0;
for (uint n = 0; n < variants.GetCount(); ++n)
if (Shader *shader = variants[n].c_ptr())
if (ShaderInput *input = shader->GetInput(name))
{
input->parm_t = t;
++match_count;
}
return match_count > 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void MaterialShader::CompileForwardPointLight(Core::Shader &shader, bool shadow)
{
shader.Define("_POINT_LIGHT", Core::ShaderInput::Pixel);
CompileShaderSection("OutputForwardLightModel", shader);
if (shadow)
{
shader.Define("_CAST_SHADOW", Core::ShaderInput::Pixel);
shader.DeclareInput("psm", Core::ShaderInput::DataTextureShadow, Core::ShaderInput::LightShadowMap0, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
for (int n = 0; n < 6; ++n)
shader.DeclareInput(String::Format("psm_%d_projection_matrix", n), Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0 + n), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_iss", Core::ShaderInput::Float, Core::ShaderInput::InverseShadowMapSize, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_lsb", Core::ShaderInput::Float, Core::ShaderInput::LightShadowBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_vtl", Core::ShaderInput::Matrix4, Core::ShaderInput::ViewToLightMatrix, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_noise", Core::ShaderInput::DataTexture2D, Core::ShaderInput::NoiseMap, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
if (Tag *t = renderer.GetPCFShaderTag())
shader.pixel_decl += t->GetString();
if (Tag *t = renderer.GetPSMShaderTag())
shader.pixel.Replace("%psm_pcf_evaluation%", t->GetString());
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void MaterialShader::CompileForwardSpotLight(Core::Shader &shader, bool shadow, bool projection_map)
{
shader.Define("_SPOT_LIGHT", Core::ShaderInput::Pixel);
CompileShaderSection("OutputForwardLightModel", shader);
if (shadow)
{
shader.Define("_CAST_SHADOW", Core::ShaderInput::Pixel);
shader.DeclareInput("u_ssm", Core::ShaderInput::DataTextureShadow, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMap0), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_ssm_projection", Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_iss", Core::ShaderInput::Float, Core::ShaderInput::InverseShadowMapSize, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_lsb", Core::ShaderInput::Float, Core::ShaderInput::LightShadowBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_noise", Core::ShaderInput::DataTexture2D, Core::ShaderInput::NoiseMap, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
if (Tag *t = renderer.GetPCFShaderTag())
shader.pixel_decl += t->GetString();
}
if (projection_map)
{
shader.Define("_PROJECTION_MAP", Core::ShaderInput::Pixel);
shader.DeclareInput("u_pjm", Core::ShaderInput::DataTexture2D, Core::ShaderInput::Semantic(Core::ShaderInput::LightProjectionMap), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_pjm_projection", Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void MaterialShader::CompileForwardLinearLight(Core::Shader &shader, bool shadow)
{
shader.Define("_LINEAR_LIGHT", Core::ShaderInput::Pixel);
CompileShaderSection("OutputForwardLightModel", shader);
if (shadow)
{
shader.Define("_CAST_SHADOW", Core::ShaderInput::Pixel);
shader.DeclareInput("pssm", Core::ShaderInput::DataTextureShadow, Core::ShaderInput::LightShadowMap0, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
for (int n = 0; n < renderer.registry.GetInteger("ShadowMapping:PSSM:Split", 3); ++n)
{
shader.DeclareInput(String::Format("pssm_%d_slice_distance", n), Core::ShaderInput::Float, Core::ShaderInput::Semantic(Core::ShaderInput::LightPSSMSliceDistance0 + n), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput(String::Format("pssm_%d_projection_matrix", n), Core::ShaderInput::Matrix4, Core::ShaderInput::Semantic(Core::ShaderInput::LightShadowMatrix0 + n), Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
}
shader.DeclareInput("u_noise", Core::ShaderInput::DataTexture2D, Core::ShaderInput::NoiseMap, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_iss", Core::ShaderInput::Float, Core::ShaderInput::InverseShadowMapSize, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.DeclareInput("u_lsb", Core::ShaderInput::Float, Core::ShaderInput::LightShadowBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
if (Tag *t = renderer.GetPCFShaderTag())
shader.pixel_decl += t->GetString();
if (Tag *t = renderer.GetPSSMShaderTag())
shader.pixel.Replace("%pssm_pcf_evaluation%", t->GetString());
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool MaterialShader::CompileShaderSection(const char *id, Core::Shader &shader)
{
Tag *shader_tag = renderer.GetMaterialDict().GetTag(id);
if (!shader_tag)
__ERR__(__LOG_E__ << "Missing shader section '" << id << "'.\n", false)
if (Tag *tag = shader_tag->GetTag("Input;"))
shader.ParseInputTag(tag);
if (Tag *tag = shader_tag->GetTag("Varying;"))
shader.ParseVaryingTag(tag);
if (Tag *tag = shader_tag->GetTag("Vertex;"))
shader.vertex += tag->GetString();
if (Tag *tag = shader_tag->GetTag("Fragment;"))
shader.pixel += tag->GetString();
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool MaterialShader::SetupMaterialProgram(Variant p, Core::Shader &shader)
{
if (parm.use_alpha_test)
{
shader.DeclareInput("u_alpha_threshold", Core::ShaderInput::Float, Core::ShaderInput::MaterialAlphaThreshold, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
shader.pixel += "if (%opacity% < u_alpha_threshold) discard;\n";
}
if (parm.use_depth_bias)
shader.DeclareInput("u_depth_bias", Core::ShaderInput::Float, Core::ShaderInput::MaterialDepthBias, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
if (parm.use_skinning)
{
shader.Define("_SKINNED", (Core::ShaderInput::Scope)(Core::ShaderInput::Vertex | Core::ShaderInput::Pixel));
shader.DeclareInput("bone_mtx", Core::ShaderInput::Matrix4, Core::ShaderInput::BoneMatrix, Core::ShaderInput::Uniform, Core::ShaderInput::Vertex, __PL_BONE_LIMIT__);
shader.DeclareInput("bone_idx", Core::ShaderInput::Vector4, Core::ShaderInput::BoneIndex, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex);
shader.DeclareInput("bone_w", Core::ShaderInput::Vector4, Core::ShaderInput::BoneWeight, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex);
shader.DeclareVarying("v_skin_mtx", "mat4");
}
CompileShaderSection("InputPosition;", shader);
// Assemble program shader.
switch (p)
{
case Depth:
CompileShaderSection("OutputDepth;", shader);
break;
case FS_Constant:
CompileShaderSection("OutputForwardConstant;", shader);
break;
case FS_PointLight:
case FS_PointLightShadowMapping:
CompileForwardPointLight(shader, p == FS_PointLightShadowMapping);
break;
case FS_SpotLight:
case FS_SpotLightShadowMapping:
case FS_SpotLightProjection:
case FS_SpotLightProjectionShadowMapping:
CompileForwardSpotLight(shader, (p == FS_SpotLightShadowMapping) || (p == FS_SpotLightProjectionShadowMapping), (p == FS_SpotLightProjection) || (p == FS_SpotLightProjectionShadowMapping));
break;
case FS_LinearLight:
case FS_LinearLightShadowMapping:
CompileForwardLinearLight(shader, p == FS_LinearLightShadowMapping);
break;
case DS_GBufferMRT4:
CompileShaderSection("OutputDeferred;", shader);
break;
case PP_NormalDepth:
CompileShaderSection("OutputNormalDepth;", shader);
break;
case PP_Velocity:
if (parm.use_skinning)
shader.DeclareInput("previous_bone_mtx", Core::ShaderInput::Matrix4, Core::ShaderInput::PreviousBoneMatrix, Core::ShaderInput::Uniform, Core::ShaderInput::Vertex, __PL_BONE_LIMIT__);
CompileShaderSection("OutputVelocity;", shader);
break;
case Last:
break;
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool FindVarAssignation(const String &src, const char *var) // TODO fix with proper regex, this is proof of concept code at best...
{
if (src.FindString(String::Format("%s =", var)))
return true;
if (src.FindString(String::Format("%s\t=", var)))
return true;
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void DeclareVertexPosition(Core::Shader &shader, bool declare_varying)
{
String decl = "vec4 %position%;\n";
if (!asbool(FindVarAssignation(shader.vertex, "%position%")))
{
Core::ShaderInput *input = shader.DeclareInput("a_position", Core::ShaderInput::Vector3, Core::ShaderInput::Position, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex);
// Core::ShaderInput *input = shader.GetInput(Core::ShaderInput::Position);
decl << "%position% = vec4(" << input->name << ", 1.0);\n";
}
shader.vertex = decl + shader.vertex;
}
static void DeclareVertexNormal(Core::Shader &shader)
{
String decl = "vec3 %normal%;\n";
if (!asbool(FindVarAssignation(shader.vertex, "%normal%")))
{
Core::ShaderInput *input = shader.DeclareInput("a_normal", Core::ShaderInput::Vector3, Core::ShaderInput::Normal, Core::ShaderInput::Attribute, Core::ShaderInput::Vertex);
// Core::ShaderInput *input = shader.GetInput(Core::ShaderInput::Normal);
decl << "%normal% = " << input->name << ";\n";
}
shader.vertex = decl + shader.vertex;
}
static void InitializeShader(Core::Shader &shader)
{
// Position
{
bool pixel_consumes = asbool(shader.pixel.FindString("%in.position%"));
DeclareVertexPosition(shader, pixel_consumes);
}
// Normal
{
bool pixel_consumes = asbool(shader.pixel.FindString("%in.normal%"));
bool pixel_provides = FindVarAssignation(shader.pixel, "%normal%");
if (pixel_consumes || !pixel_provides)
DeclareVertexNormal(shader);
if (!pixel_provides)
shader.pixel << "%normal% = %in.normal%;\n";
shader.pixel = String("vec3 %normal%;\n") + shader.pixel;
}
{
struct ShaderDefault
{
const char *type, *name, *var;
Core::ShaderInput::DataType data_type;
Core::ShaderInput::Semantic semantic;
};
static ShaderDefault ps_ic[] =
{
{ "vec4", "%diffuse%", "_u_mat_diff", Core::ShaderInput::Vector4, Core::ShaderInput::MaterialDiffuse },
{ "vec4", "%specular%", "_u_mat_spec", Core::ShaderInput::Vector4, Core::ShaderInput::MaterialSpecular },
{ "float", "%glossiness%", "_u_mat_glos", Core::ShaderInput::Float, Core::ShaderInput::MaterialGlossiness },
{ "vec4", "%constant%", "_u_mat_const", Core::ShaderInput::Vector4, Core::ShaderInput::MaterialSelf },
{ "float", "%opacity%", "_u_mat_opac", Core::ShaderInput::Float, Core::ShaderInput::MaterialOpacity },
{ NULL, NULL, NULL }
};
// Declare mandatory outputs and set default value for unprovided entries.
String decl;
for (uint n = 0; ps_ic[n].type; ++n)
{
decl << ps_ic[n].type << " " << ps_ic[n].name << ";\n";
if (!FindVarAssignation(shader.pixel, ps_ic[n].name))
{
Core::ShaderInput *input = shader.DeclareInput(ps_ic[n].var, ps_ic[n].data_type, ps_ic[n].semantic, Core::ShaderInput::Uniform, Core::ShaderInput::Pixel);
decl << ps_ic[n].name << " = " << input->name << ";\n";
}
}
shader.pixel = decl + shader.pixel;
}
}
static void FinalizeShader(Core::Shader &shader)
{
if (asbool(shader.pixel.FindString("%in.position%")))
{
shader.DeclareVarying("_v_position", "vec4");
shader.vertex << "_v_position = %position%;\n";
}
if (asbool(shader.pixel.FindString("%in.normal%")))
{
shader.DeclareVarying("_v_normal", "vec3");
shader.vertex << "_v_normal = %normal%;\n";
}
shader.pixel.ReplaceAll("%in.position%", "_v_position", true);
shader.pixel.ReplaceAll("%in.normal%", "_v_normal", true);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static const char *GetShaderVariantName(MaterialShader::Variant v)
{
switch (v)
{
case MaterialShader::Depth: return "Depth";
case MaterialShader::DS_GBufferMRT4: return "DS_GBufferMRT4";
case MaterialShader::FS_Constant: return "FS_Constant";
case MaterialShader::FS_PointLight: return "FS_PointLight";
case MaterialShader::FS_PointLightShadowMapping: return "FS_PointLightShadowMapping";
case MaterialShader::FS_LinearLight: return "FS_LinearLight";
case MaterialShader::FS_LinearLightShadowMapping: return "FS_LinearLightShadowMapping";
case MaterialShader::FS_SpotLight: return "FS_SpotLight";
case MaterialShader::FS_SpotLightShadowMapping: return "FS_SpotLightShadowMapping";
case MaterialShader::FS_SpotLightProjection: return "FS_SpotLightProjection";
case MaterialShader::FS_SpotLightProjectionShadowMapping: return "FS_SpotLightProjectionShadowMapping";
case MaterialShader::PP_NormalDepth: return "PP_NormalDepth";
case MaterialShader::PP_Velocity: return "PP_Velocity";
case MaterialShader::Last:
break;
}
return "UnknownVariant";
}
bool MaterialShader::Create(Render::ResourceFactory &rf, const Core::Shader &shader, const MaterialShaderStaticParm &static_parm)
{
__LOG_V__ << "Creating material shader '" << shader.name << "' variants.\n";
name = shader.name;
parm = static_parm;
// Build variants.
if (!variants.Allocate(Last))
return false;
for (int n = 0; n < Last; ++n)
{
if (renderer.render_technique == Renderer::TechniqueDeferred)
if ((n >= FS_Constant) && (n <= FS_SpotLightProjectionShadowMapping))
continue; // no forward
if (renderer.render_technique == Renderer::TechniqueForward)
if (n == DS_GBufferMRT4)
continue; // no deferred
if (!renderer.gpu_config.enable_shadow)
if (
(n == Depth) ||
(n == FS_PointLightShadowMapping) ||
(n == FS_LinearLightShadowMapping) ||
(n == FS_SpotLightShadowMapping) ||
(n == FS_SpotLightProjectionShadowMapping)
)
continue; // no shadow-mapping
if (!renderer.gpu_config.use_rtt)
if (
(n == PP_Velocity) ||
(n == PP_NormalDepth)
)
continue; // no post-processes
if (parm.no_lighting)
if ((n > FS_Constant) && (n <= FS_SpotLightProjectionShadowMapping)) // keep constant!
continue; // no lighting pass
// Specialize shader for this program.
Core::Shader shader_variant;
if (!shader.Clone(shader_variant))
return false;
InitializeShader(shader_variant);
if (!SetupMaterialProgram((Variant)n, shader_variant))
return false;
FinalizeShader(shader_variant);
shader_variant.name << "_" << GetShaderVariantName((MaterialShader::Variant)n);
// Compile it.
if ((variants[n] = (Shader *)renderer.NewShader()) != NULL)
if (!variants[n]->Create(rf, shader_variant))
return false;
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
MaterialShader::MaterialShader(Renderer &r) : renderer(r)
{ renderer.material_shaders.Add(this); }
MaterialShader::~MaterialShader()
{ renderer.material_shaders.Remove(this); }
//------------------------------------------------------------------------------